diff --git a/docs/overview/style-props.md b/docs/overview/style-props.md
index bef42e50f..e22697573 100644
--- a/docs/overview/style-props.md
+++ b/docs/overview/style-props.md
@@ -121,7 +121,7 @@ Move the object with this value in Y direction. Applied after layouts, aligns an
### transform_zoom
-Zoom image-like objects. Multiplied with the zoom set on the object. The value 256 (or `LV_IMG_ZOOM_NONE`) means normal size, 128 half size, 512 double size, and so on
+Zoom an objects. The value 256 (or `LV_IMG_ZOOM_NONE`) means normal size, 128 half size, 512 double size, and so on
- Default 0
- Inherited No
@@ -130,7 +130,7 @@ Zoom image-like objects. Multiplied with the zoom set on the object. The value 2
### transform_angle
-Rotate image-like objects. Added to the rotation set on the object. The value is interpreted in 0.1 degree units. E.g. 45 deg. = 450
+Rotate an objects. The value is interpreted in 0.1 degree units. E.g. 450 means 45 deg.
- Default 0
- Inherited No
@@ -138,6 +138,24 @@ Rotate image-like objects. Added to the rotation set on the object. The value is
- Ext. draw Yes
+### transform_pivot_x
+Set the pivot point's X coordinate for transformations. Relative to the object's top left corner'
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### transform_pivot_y
+Set the pivot point's Y coordinate for transformations. Relative to the object's top left corner'
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
## Padding
Properties to describe spacing between the parent's sides and the children and among the children. Very similar to the padding properties in HTML.
diff --git a/docs/overview/style.md b/docs/overview/style.md
index df5a9b5e4..40e1d9d36 100644
--- a/docs/overview/style.md
+++ b/docs/overview/style.md
@@ -268,6 +268,20 @@ lv_style_transition_dsc_init(&trans1, trans_props, lv_anim_path_ease_out, durati
lv_style_set_transition(&style1, &trans1);
```
+## Opacity and Transformations
+If the 'opa ', `transform_angle`, or `transform_zoom` properties are set their non-default value LVGL creates a snapshot about the widget and all its children in order to blend the whole widget with the set opacity and transformation properties.
+
+These properties have this effect only on the `MAIN` part of the widget.
+
+The created snapshot is called "intermediate layer" or simply "layer". If only `opa` is set to a value different from 255 LVGL can build the layer from smaller chunks. The size of these chunks can be configured by the following properties in `lv_conf.h`:
+ - `LV_LAYER_SIMPLE_BUF_SIZE`: [bytes] the optimal target buffer size. LVGL will try to allocate this size of memory.
+ - `LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE`: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.
+
+If transformation properties were also used the layer can not be rendered in chunks, but one larger memory needs to be allocated. The required memory depends on the angle, zoom and pivot parameters, and the size of the area to redraw, but it's never larger than the size of the widget (including the extra draw size used for shadow, outline, etc).
+
+If the widget can fully cover the area to redraw, LVGL creates an RGB layer (which is faster to render and uses less memory). If the opposite case ARGB rendering needs to be used. A widget might not cover its area if it has radius, `bg_opa != 255`, shadow, outline, etc.
+
+The click area of the widget is also transformed accordingly.
## Color filter
TODO
diff --git a/docs/widgets/core/img.md b/docs/widgets/core/img.md
index 11060cba6..bd6b90a30 100644
--- a/docs/widgets/core/img.md
+++ b/docs/widgets/core/img.md
@@ -92,6 +92,11 @@ In other words transformations work only on true color images stored as C array,
Note that the real coordinates of image objects won't change during transformation. That is `lv_obj_get_width/height/x/y()` will return the original, non-zoomed coordinates.
+**IMPORTANT**
+The transformation of the image is independent of the transformation properties coming from styles. (See [here](/overview/style#opacity-and-transformations)). The main differences are that pure image widget transformation
+- doesn't transform the children of the image widget
+- image is transformed directly without creating an intermediate layer (buffer) to snapshot the widget
+
### Size mode
By default, when the image is zoomed or rotated the real coordinates of the image object are not changed.
diff --git a/examples/styles/index.rst b/examples/styles/index.rst
index 52c2b8fad..a76ff1e73 100644
--- a/examples/styles/index.rst
+++ b/examples/styles/index.rst
@@ -89,3 +89,10 @@ Extending the current theme
:language: c
+Opacity and Transformations
+""""""""""""""""""""""""""""""""""
+
+.. lv_example:: styles/lv_example_style_15
+ :language: c
+
+
diff --git a/examples/styles/lv_example_style.h b/examples/styles/lv_example_style.h
index 40d106b05..680443cc5 100644
--- a/examples/styles/lv_example_style.h
+++ b/examples/styles/lv_example_style.h
@@ -39,6 +39,7 @@ void lv_example_style_11(void);
void lv_example_style_12(void);
void lv_example_style_13(void);
void lv_example_style_14(void);
+void lv_example_style_15(void);
/**********************
* MACROS
diff --git a/examples/styles/lv_example_style_15.c b/examples/styles/lv_example_style_15.c
new file mode 100644
index 000000000..0e5184f11
--- /dev/null
+++ b/examples/styles/lv_example_style_15.c
@@ -0,0 +1,50 @@
+#include "../lv_examples.h"
+#if LV_BUILD_EXAMPLES && LV_USE_BTN && LV_USE_LABEL
+
+
+
+/**
+ * Opacity and Transformations
+ */
+void lv_example_style_15(void)
+{
+ lv_obj_t * btn;
+ lv_obj_t * label;
+
+ /*Normal button*/
+ btn = lv_btn_create(lv_scr_act());
+ lv_obj_set_size(btn, 100, 40);
+ lv_obj_align(btn, LV_ALIGN_CENTER, 0, -70);
+
+ label = lv_label_create(btn);
+ lv_label_set_text(label, "Normal");
+ lv_obj_center(label);
+
+ /*Set opacity
+ *The button and the label is rendered to a layer first and that layer is blended*/
+ btn = lv_btn_create(lv_scr_act());
+ lv_obj_set_size(btn, 100, 40);
+ lv_obj_set_style_opa(btn, LV_OPA_50, 0);
+ lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0);
+
+ label = lv_label_create(btn);
+ lv_label_set_text(label, "Opa:50%");
+ lv_obj_center(label);
+
+ /*Set transformations
+ *The button and the label is rendered to a layer first and that layer is transformed*/
+ btn = lv_btn_create(lv_scr_act());
+ lv_obj_set_size(btn, 100, 40);
+ lv_obj_set_style_transform_angle(btn, 150, 0); /*150 deg*/
+ lv_obj_set_style_transform_zoom(btn, 256 + 64, 0); /*1.25x*/
+ lv_obj_set_style_transform_pivot_x(btn, 50, 0);
+ lv_obj_set_style_transform_pivot_y(btn, 20, 0);
+ lv_obj_set_style_opa(btn, LV_OPA_50, 0);
+ lv_obj_align(btn, LV_ALIGN_CENTER, 0, 70);
+
+ label = lv_label_create(btn);
+ lv_label_set_text(label, "Transf.");
+ lv_obj_center(label);
+}
+
+#endif
diff --git a/lv_conf_template.h b/lv_conf_template.h
index bf21ba4f9..0b20d4a50 100644
--- a/lv_conf_template.h
+++ b/lv_conf_template.h
@@ -120,6 +120,24 @@
#define LV_CIRCLE_CACHE_SIZE 4
#endif /*LV_DRAW_COMPLEX*/
+/**
+ * "Simple layers" are used when a widget has `style_opa < 255` to buffer the widget into a layer
+ * and blend it as an image with the given opacity.
+ * Note that `bg_opa`, `text_opa` etc don't require buffering into layer)
+ * The widget can be buffered in smaller chunks to avoid using large buffers.
+ * `draw_area` (`lv_area_t` meaning the area to draw and `px_size` (size of a pixel in bytes)
+ * can be used the set the buffer size adaptively.
+ *
+ * - LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate it
+ * - LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.
+ *
+ * Both buffer sizes are in bytes.
+ * "Transformed layers" (where transform_angle/zoom properties are used) use larger buffers
+ * and can't be drawn in chunks. So these settings affects only widgets with opacity.
+ */
+#define LV_LAYER_SIMPLE_BUF_SIZE (24 * 1024)
+#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE LV_MAX(lv_area_get_width(&draw_area) * px_size, 2048)
+
/*Default image cache size. Image caching keeps the images opened.
*If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added)
*With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
diff --git a/scripts/code-format.cfg b/scripts/code-format.cfg
index fbe687e29..159ef46c8 100644
--- a/scripts/code-format.cfg
+++ b/scripts/code-format.cfg
@@ -23,6 +23,7 @@
--preserve-date
--formatted
--ignore-exclude-errors
+--ignore-exclude-errors-x
--exclude=assets
--exclude=../src/core/lv_obj_style_gen.c
--exclude=../src/core/lv_obj_style_gen.h
diff --git a/scripts/code-format.py b/scripts/code-format.py
index 42faee6ee..fc126c8df 100755
--- a/scripts/code-format.py
+++ b/scripts/code-format.py
@@ -2,7 +2,14 @@
import os
+print("Formatting src")
os.system('astyle --options=code-format.cfg --recursive "../src/*.c,*.h"')
+
+print("\nFormatting demos")
os.system('astyle --options=code-format.cfg --recursive "../demos/*.c,*.h"')
+
+print("\nFormatting examples")
os.system('astyle --options=code-format.cfg --recursive "../examples/*.c,*.h"')
+
+print("\nFormatting tests")
os.system('astyle --options=code-format.cfg --recursive "../tests/src/test_cases/*.c"')
diff --git a/scripts/style_api_gen.py b/scripts/style_api_gen.py
index 8e1f008d2..5bcddede5 100755
--- a/scripts/style_api_gen.py
+++ b/scripts/style_api_gen.py
@@ -60,11 +60,19 @@ props = [
{'name': 'TRANSFORM_ZOOM',
'style_type': 'num', 'var_type': 'lv_coord_t', 'default':0, 'inherited': 0, 'layout': 1, 'ext_draw': 1,
- 'dsc': "Zoom image-like objects. Multiplied with the zoom set on the object. The value 256 (or `LV_IMG_ZOOM_NONE`) means normal size, 128 half size, 512 double size, and so on" },
+ 'dsc': "Zoom an objects. The value 256 (or `LV_IMG_ZOOM_NONE`) means normal size, 128 half size, 512 double size, and so on" },
{'name': 'TRANSFORM_ANGLE',
'style_type': 'num', 'var_type': 'lv_coord_t', 'default':0, 'inherited': 0, 'layout': 1, 'ext_draw': 1,
- 'dsc': "Rotate image-like objects. Added to the rotation set on the object. The value is interpreted in 0.1 degree units. E.g. 45 deg. = 450"},
+ 'dsc': "Rotate an objects. The value is interpreted in 0.1 degree units. E.g. 450 means 45 deg."},
+
+{'name': 'TRANSFORM_PIVOT_X',
+ 'style_type': 'num', 'var_type': 'lv_coord_t', 'default':0, 'inherited': 0, 'layout': 0, 'ext_draw': 0,
+ 'dsc': "Set the pivot point's X coordinate for transformations. Relative to the object's top left corner'"},
+
+{'name': 'TRANSFORM_PIVOT_Y',
+ 'style_type': 'num', 'var_type': 'lv_coord_t', 'default':0, 'inherited': 0, 'layout': 0, 'ext_draw': 0,
+ 'dsc': "Set the pivot point's Y coordinate for transformations. Relative to the object's top left corner'"},
{'section': 'Padding', 'dsc' : "Properties to describe spacing between the parent's sides and the children and among the children. Very similar to the padding properties in HTML."},
{'name': 'PAD_TOP',
diff --git a/src/core/lv_indev.c b/src/core/lv_indev.c
index 538c6bdc1..57f530689 100644
--- a/src/core/lv_indev.c
+++ b/src/core/lv_indev.c
@@ -296,6 +296,7 @@ lv_timer_t * lv_indev_get_read_timer(lv_disp_t * indev)
return indev->refr_timer;
}
+
lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point)
{
lv_obj_t * found_p = NULL;
@@ -303,16 +304,20 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point)
/*If this obj is hidden the children are hidden too so return immediately*/
if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return NULL;
- bool hit_test_ok = lv_obj_hit_test(obj, point);
+ lv_point_t p_trans = *point;
+ lv_obj_transform_point(obj, &p_trans, false, true);
+
+ bool hit_test_ok = lv_obj_hit_test(obj, &p_trans);
/*If the point is on this object or has overflow visible check its children too*/
- if(_lv_area_is_point_on(&obj->coords, point, 0) || lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
+ if(_lv_area_is_point_on(&obj->coords, &p_trans, 0) || lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
int32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
+
/*If a child matches use it*/
for(i = child_cnt - 1; i >= 0; i--) {
lv_obj_t * child = obj->spec_attr->children[i];
- found_p = lv_indev_search_obj(child, point);
+ found_p = lv_indev_search_obj(child, &p_trans);
if(found_p) return found_p;
}
}
@@ -847,7 +852,9 @@ static void indev_proc_press(_lv_indev_proc_t * proc)
if(indev_reset_check(proc)) return;
}
- /*If a new object was found reset some variables and send a pressed Call the ancestor's event handler*/
+ lv_obj_transform_point(indev_obj_act, &proc->types.pointer.act_point, true, true);
+
+ /*If a new object was found reset some variables and send a pressed event handler*/
if(indev_obj_act != proc->types.pointer.act_obj) {
proc->types.pointer.last_point.x = proc->types.pointer.act_point.x;
proc->types.pointer.last_point.y = proc->types.pointer.act_point.y;
diff --git a/src/core/lv_obj.c b/src/core/lv_obj.c
index 5b6fe112f..286fdef8a 100644
--- a/src/core/lv_obj.c
+++ b/src/core/lv_obj.c
@@ -273,6 +273,7 @@ void lv_obj_clear_flag(lv_obj_t * obj, lv_obj_flag_t f)
if((was_on_layout != lv_obj_is_layout_positioned(obj)) || (f & (LV_OBJ_FLAG_LAYOUT_1 | LV_OBJ_FLAG_LAYOUT_2))) {
lv_obj_mark_layout_as_dirty(lv_obj_get_parent(obj));
}
+
}
void lv_obj_add_state(lv_obj_t * obj, lv_state_t state)
@@ -503,11 +504,6 @@ static void lv_obj_draw(lv_event_t * e)
return;
}
#endif
- if(lv_obj_get_style_opa(obj, LV_PART_MAIN) < LV_OPA_MAX) {
- info->res = LV_COVER_RES_NOT_COVER;
- return;
- }
-
info->res = LV_COVER_RES_COVER;
}
@@ -539,7 +535,6 @@ static void lv_obj_draw(lv_event_t * e)
part_dsc.part = LV_PART_MAIN;
lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_dsc);
-
#if LV_DRAW_COMPLEX
/*With clip corner enabled draw the bg img separately to make it clipped*/
bool clip_corner = (lv_obj_get_style_clip_corner(obj, LV_PART_MAIN) && draw_dsc.radius != 0) ? true : false;
@@ -854,9 +849,8 @@ static void lv_obj_event(const lv_obj_class_t * class_p, lv_event_t * e)
}
}
else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
- lv_coord_t * s = lv_event_get_param(e);
lv_coord_t d = lv_obj_calculate_ext_draw_size(obj, LV_PART_MAIN);
- *s = LV_MAX(*s, d);
+ lv_event_set_ext_draw_size(e, d);
}
else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST || code == LV_EVENT_COVER_CHECK) {
lv_obj_draw(e);
diff --git a/src/core/lv_obj_draw.c b/src/core/lv_obj_draw.c
index db7c6ea54..67a9e5b05 100644
--- a/src/core/lv_obj_draw.c
+++ b/src/core/lv_obj_draw.c
@@ -41,17 +41,6 @@ void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, uint32_t part, lv_draw_rect_dsc_t
#if LV_DRAW_COMPLEX
draw_dsc->radius = lv_obj_get_style_radius(obj, part);
-
- lv_opa_t main_opa = part != LV_PART_MAIN ? lv_obj_get_style_opa(obj, part) : LV_OPA_COVER;
- lv_opa_t opa = lv_obj_get_style_opa(obj, part);
- if(opa <= LV_OPA_MIN || main_opa <= LV_OPA_MIN) {
- draw_dsc->bg_opa = LV_OPA_TRANSP;
- draw_dsc->border_opa = LV_OPA_TRANSP;
- draw_dsc->shadow_opa = LV_OPA_TRANSP;
- draw_dsc->outline_opa = LV_OPA_TRANSP;
- return;
- }
-
draw_dsc->blend_mode = lv_obj_get_style_blend_mode(obj, part);
if(draw_dsc->bg_opa != LV_OPA_TRANSP) {
@@ -130,17 +119,6 @@ void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, uint32_t part, lv_draw_rect_dsc_t
}
}
- if(main_opa < LV_OPA_MAX) {
- opa = (uint16_t)((uint16_t) main_opa * opa) >> 8;
- }
-
- if(opa < LV_OPA_MAX) {
- draw_dsc->bg_opa = (uint16_t)((uint16_t)draw_dsc->bg_opa * opa) >> 8;
- draw_dsc->bg_img_opa = (uint16_t)((uint16_t)draw_dsc->bg_img_opa * opa) >> 8;
- draw_dsc->border_opa = (uint16_t)((uint16_t)draw_dsc->border_opa * opa) >> 8;
- draw_dsc->shadow_opa = (uint16_t)((uint16_t)draw_dsc->shadow_opa * opa) >> 8;
- draw_dsc->outline_opa = (uint16_t)((uint16_t)draw_dsc->outline_opa * opa) >> 8;
- }
#else /*LV_DRAW_COMPLEX*/
if(draw_dsc->bg_opa != LV_OPA_TRANSP) {
draw_dsc->bg_opa = lv_obj_get_style_bg_opa(obj, part);
@@ -196,12 +174,6 @@ void lv_obj_init_draw_label_dsc(lv_obj_t * obj, uint32_t part, lv_draw_label_dsc
draw_dsc->opa = lv_obj_get_style_text_opa(obj, part);
if(draw_dsc->opa <= LV_OPA_MIN) return;
- lv_opa_t opa = lv_obj_get_style_opa(obj, part);
- if(opa < LV_OPA_MAX) {
- draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa) >> 8;
- }
- if(draw_dsc->opa <= LV_OPA_MIN) return;
-
draw_dsc->color = lv_obj_get_style_text_color_filtered(obj, part);
draw_dsc->letter_space = lv_obj_get_style_text_letter_space(obj, part);
draw_dsc->line_space = lv_obj_get_style_text_line_space(obj, part);
@@ -224,12 +196,6 @@ void lv_obj_init_draw_img_dsc(lv_obj_t * obj, uint32_t part, lv_draw_img_dsc_t *
draw_dsc->opa = lv_obj_get_style_img_opa(obj, part);
if(draw_dsc->opa <= LV_OPA_MIN) return;
- lv_opa_t opa_scale = lv_obj_get_style_opa(obj, part);
- if(opa_scale < LV_OPA_MAX) {
- draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa_scale) >> 8;
- }
- if(draw_dsc->opa <= LV_OPA_MIN) return;
-
draw_dsc->angle = 0;
draw_dsc->zoom = LV_IMG_ZOOM_NONE;
draw_dsc->pivot.x = lv_area_get_width(&obj->coords) / 2;
@@ -252,12 +218,6 @@ void lv_obj_init_draw_line_dsc(lv_obj_t * obj, uint32_t part, lv_draw_line_dsc_t
draw_dsc->opa = lv_obj_get_style_line_opa(obj, part);
if(draw_dsc->opa <= LV_OPA_MIN) return;
- lv_opa_t opa = lv_obj_get_style_opa(obj, part);
- if(opa < LV_OPA_MAX) {
- draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa) >> 8;
- }
- if(draw_dsc->opa <= LV_OPA_MIN) return;
-
draw_dsc->color = lv_obj_get_style_line_color_filtered(obj, part);
draw_dsc->dash_width = lv_obj_get_style_line_dash_width(obj, part);
@@ -281,12 +241,6 @@ void lv_obj_init_draw_arc_dsc(lv_obj_t * obj, uint32_t part, lv_draw_arc_dsc_t *
draw_dsc->opa = lv_obj_get_style_arc_opa(obj, part);
if(draw_dsc->opa <= LV_OPA_MIN) return;
- lv_opa_t opa = lv_obj_get_style_opa(obj, part);
- if(opa < LV_OPA_MAX) {
- draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa) >> 8;
- }
- if(draw_dsc->opa <= LV_OPA_MIN) return;
-
draw_dsc->color = lv_obj_get_style_arc_color_filtered(obj, part);
draw_dsc->img_src = lv_obj_get_style_arc_img_src(obj, part);
@@ -373,6 +327,14 @@ lv_coord_t _lv_obj_get_ext_draw_size(const lv_obj_t * obj)
else return 0;
}
+lv_intermediate_layer_type_t _lv_obj_is_intermediate_layer(const lv_obj_t * obj)
+{
+ if(lv_obj_get_style_transform_angle(obj, 0) != 0) return LV_INTERMEDIATE_LAYER_TYPE_TRANSFORM;
+ if(lv_obj_get_style_transform_zoom(obj, 0) != 256) return LV_INTERMEDIATE_LAYER_TYPE_TRANSFORM;
+ if(lv_obj_get_style_opa(obj, 0) != LV_OPA_COVER) return LV_INTERMEDIATE_LAYER_TYPE_SIMPLE;
+ return LV_INTERMEDIATE_LAYER_TYPE_NONE;
+}
+
/**********************
* STATIC FUNCTIONS
**********************/
diff --git a/src/core/lv_obj_draw.h b/src/core/lv_obj_draw.h
index 311ba6b4e..f981e6013 100644
--- a/src/core/lv_obj_draw.h
+++ b/src/core/lv_obj_draw.h
@@ -33,6 +33,12 @@ typedef enum {
LV_COVER_RES_MASKED = 2,
} lv_cover_res_t;
+typedef enum {
+ LV_INTERMEDIATE_LAYER_TYPE_NONE,
+ LV_INTERMEDIATE_LAYER_TYPE_SIMPLE,
+ LV_INTERMEDIATE_LAYER_TYPE_TRANSFORM,
+} lv_intermediate_layer_type_t;
+
typedef struct {
lv_draw_ctx_t * draw_ctx; /**< Draw context*/
const struct _lv_obj_class_t * class_p; /**< The class that sent the event */
@@ -50,14 +56,14 @@ typedef struct {
arc_dsc; /**< A draw descriptor that can be modified to changed what LVGL will draw. Set only for arc-like parts*/
const lv_point_t *
p1; /**< A point calculated during drawing. E.g. a point of chart or the center of an arc.*/
- const lv_point_t * p2; /**< A point calculated during drawing. E.g. a point of chart.*/
+ const lv_point_t * p2; /**< A point calculated during drawing. E.g. a point of chart.*/
char * text; /**< A text calculated during drawing. Can be modified. E.g. tick labels on a chart axis.*/
- uint32_t text_length; /**< Size of the text buffer containing null-terminated text string calculated during drawing.*/
- uint32_t part; /**< The current part for which the event is sent*/
- uint32_t id; /**< The index of the part. E.g. a button's index on button matrix or table cell index.*/
- lv_coord_t radius; /**< E.g. the radius of an arc (not the corner radius).*/
- int32_t value; /**< A value calculated during drawing. E.g. Chart's tick line value.*/
- const void * sub_part_ptr; /**< A pointer the identifies something in the part. E.g. chart series. */
+ uint32_t text_length; /**< Size of the text buffer containing null-terminated text string calculated during drawing.*/
+ uint32_t part; /**< The current part for which the event is sent*/
+ uint32_t id; /**< The index of the part. E.g. a button's index on button matrix or table cell index.*/
+ lv_coord_t radius; /**< E.g. the radius of an arc (not the corner radius).*/
+ int32_t value; /**< A value calculated during drawing. E.g. Chart's tick line value.*/
+ const void * sub_part_ptr; /**< A pointer the identifies something in the part. E.g. chart series. */
} lv_obj_draw_part_dsc_t;
/**********************
@@ -66,11 +72,11 @@ typedef struct {
/**
* Initialize a rectangle draw descriptor from an object's styles in its current state
- * @param obj pointer to an object
- * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
- * @param draw_dsc the descriptor to initialize.
- * If an `..._opa` field is set to `LV_OPA_TRANSP` the related properties won't be initialized.
- * Should be initialized with `lv_draw_rect_dsc_init(draw_dsc)`.
+ * @param obj pointer to an object
+ * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
+ * @param draw_dsc the descriptor to initialize.
+ * If an `..._opa` field is set to `LV_OPA_TRANSP` the related properties won't be initialized.
+ * Should be initialized with `lv_draw_rect_dsc_init(draw_dsc)`.
* @note Only the relevant fields will be set.
* E.g. if `border width == 0` the other border properties won't be evaluated.
*/
@@ -78,20 +84,20 @@ void lv_obj_init_draw_rect_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_re
/**
* Initialize a label draw descriptor from an object's styles in its current state
- * @param obj pointer to an object
- * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
- * @param draw_dsc the descriptor to initialize.
- * If the `opa` field is set to or the property is equal to `LV_OPA_TRANSP` the rest won't be initialized.
- * Should be initialized with `lv_draw_label_dsc_init(draw_dsc)`.
+ * @param obj pointer to an object
+ * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
+ * @param draw_dsc the descriptor to initialize.
+ * If the `opa` field is set to or the property is equal to `LV_OPA_TRANSP` the rest won't be initialized.
+ * Should be initialized with `lv_draw_label_dsc_init(draw_dsc)`.
*/
void lv_obj_init_draw_label_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_label_dsc_t * draw_dsc);
/**
* Initialize an image draw descriptor from an object's styles in its current state
- * @param obj pointer to an object
- * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
- * @param draw_dsc the descriptor to initialize.
- * Should be initialized with `lv_draw_image_dsc_init(draw_dsc)`.
+ * @param obj pointer to an object
+ * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
+ * @param draw_dsc the descriptor to initialize.
+ * Should be initialized with `lv_draw_image_dsc_init(draw_dsc)`.
*/
void lv_obj_init_draw_img_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_img_dsc_t * draw_dsc);
@@ -99,33 +105,33 @@ void lv_obj_init_draw_img_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_img
/**
* Initialize a line draw descriptor from an object's styles in its current state
* @param obj pointer to an object
- * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
- * @param draw_dsc the descriptor to initialize.
- * Should be initialized with `lv_draw_line_dsc_init(draw_dsc)`.
+ * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
+ * @param draw_dsc the descriptor to initialize.
+ * Should be initialized with `lv_draw_line_dsc_init(draw_dsc)`.
*/
void lv_obj_init_draw_line_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_line_dsc_t * draw_dsc);
/**
* Initialize an arc draw descriptor from an object's styles in its current state
- * @param obj pointer to an object
- * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
- * @param draw_dsc the descriptor to initialize.
- * Should be initialized with `lv_draw_arc_dsc_init(draw_dsc)`.
+ * @param obj pointer to an object
+ * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
+ * @param draw_dsc the descriptor to initialize.
+ * Should be initialized with `lv_draw_arc_dsc_init(draw_dsc)`.
*/
void lv_obj_init_draw_arc_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_arc_dsc_t * draw_dsc);
/**
* Get the required extra size (around the object's part) to draw shadow, outline, value etc.
- * @param obj pointer to an object
- * @param part part of the object
- * @return the extra size required around the object
+ * @param obj pointer to an object
+ * @param part part of the object
+ * @return the extra size required around the object
*/
lv_coord_t lv_obj_calculate_ext_draw_size(struct _lv_obj_t * obj, uint32_t part);
/**
* Initialize a draw descriptor used in events.
- * @param dsc pointer to a descriptor. Later it should be passed as parameter to an `LV_EVENT_DRAW_PART_BEGIN/END` event.
- * @param draw the current draw context. (usually returned by `lv_event_get_draw_ctx(e)`)
+ * @param dsc pointer to a descriptor. Later it should be passed as parameter to an `LV_EVENT_DRAW_PART_BEGIN/END` event.
+ * @param draw the current draw context. (usually returned by `lv_event_get_draw_ctx(e)`)
*/
void lv_obj_draw_dsc_init(lv_obj_draw_part_dsc_t * dsc, lv_draw_ctx_t * draw_ctx);
@@ -141,17 +147,20 @@ bool lv_obj_draw_part_check_type(lv_obj_draw_part_dsc_t * dsc, const struct _lv_
/**
* Send a 'LV_EVENT_REFR_EXT_DRAW_SIZE' Call the ancestor's event handler to the object to refresh the value of the extended draw size.
* The result will be saved in `obj`.
- * @param obj pointer to an object
+ * @param obj pointer to an object
*/
void lv_obj_refresh_ext_draw_size(struct _lv_obj_t * obj);
/**
* Get the extended draw area of an object.
- * @param obj pointer to an object
- * @return the size extended draw area around the real coordinates
+ * @param obj pointer to an object
+ * @return the size extended draw area around the real coordinates
*/
lv_coord_t _lv_obj_get_ext_draw_size(const struct _lv_obj_t * obj);
+
+lv_intermediate_layer_type_t _lv_obj_is_intermediate_layer(const struct _lv_obj_t * obj);
+
/**********************
* MACROS
**********************/
diff --git a/src/core/lv_obj_pos.c b/src/core/lv_obj_pos.c
index 92d4bc4d9..f65970249 100644
--- a/src/core/lv_obj_pos.c
+++ b/src/core/lv_obj_pos.c
@@ -26,6 +26,7 @@
static lv_coord_t calc_content_width(lv_obj_t * obj);
static lv_coord_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 VARIABLES
@@ -206,6 +207,8 @@ bool lv_obj_refr_size(lv_obj_t * obj)
bool on2 = _lv_area_is_in(&obj->coords, &parent_fit_area, 0);
if(on1 || (!on1 && on2)) lv_obj_scrollbar_invalidate(parent);
+ lv_obj_refresh_ext_draw_size(obj);
+
return true;
}
@@ -627,6 +630,7 @@ void lv_obj_refr_pos(lv_obj_t * obj)
{
if(lv_obj_is_layout_positioned(obj)) return;
+
lv_obj_t * parent = lv_obj_get_parent(obj);
lv_coord_t x = lv_obj_get_style_x(obj, LV_PART_MAIN);
lv_coord_t y = lv_obj_get_style_y(obj, LV_PART_MAIN);
@@ -791,6 +795,41 @@ void lv_obj_move_children_by(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_dif
}
}
+void lv_obj_transform_point(const lv_obj_t * obj, lv_point_t * p, bool recursive, bool inv)
+{
+ if(obj) {
+ if(inv) {
+ if(recursive) lv_obj_transform_point(lv_obj_get_parent(obj), p, recursive, inv);
+ transform_point(obj, p, inv);
+ }
+ else {
+ transform_point(obj, p, inv);
+ if(recursive) lv_obj_transform_point(lv_obj_get_parent(obj), p, recursive, inv);
+ }
+ }
+}
+
+void lv_obj_get_transformed_area(const lv_obj_t * obj, lv_area_t * area, bool recursive,
+ bool inv)
+{
+ lv_point_t p[4] = {
+ {area->x1, area->y1},
+ {area->x1, area->y2},
+ {area->x2, area->y1},
+ {area->x2, area->y2},
+ };
+ 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);
+
+ 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);
+ area->y1 = LV_MIN4(p[0].y, p[1].y, p[2].y, p[3].y);
+ area->y2 = LV_MAX4(p[0].y, p[1].y, p[2].y, p[3].y);
+ lv_area_increase(area, 5, 5);
+}
+
void lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area)
{
@@ -798,21 +837,15 @@ 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);
- bool visible = lv_obj_area_is_visible(obj, &area_tmp);
+ if(!lv_obj_area_is_visible(obj, &area_tmp)) return;
- if(visible) _lv_inv_area(lv_obj_get_disp(obj), &area_tmp);
+ _lv_inv_area(lv_obj_get_disp(obj), &area_tmp);
}
void lv_obj_invalidate(const lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
- /*If the object has overflow visible it can be drawn anywhere on its parent
- *It needs to be checked recursively*/
- while(lv_obj_get_parent(obj) && lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
- obj = lv_obj_get_parent(obj);
- }
-
/*Truncate the area to the object*/
lv_area_t obj_coords;
lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
@@ -841,7 +874,7 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area)
}
/*Truncate the area to the object*/
- if(!lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
+ if(!lv_obj_has_flag_any(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
lv_area_t obj_coords;
lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
lv_area_copy(&obj_coords, &obj->coords);
@@ -854,6 +887,9 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area)
if(!_lv_area_intersect(area, area, &obj_coords)) return false;
}
+ lv_obj_get_transformed_area(obj, area, true, false);
+
+
/*Truncate recursively to the parents*/
lv_obj_t * par = lv_obj_get_parent(obj);
while(par != NULL) {
@@ -861,8 +897,10 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area)
if(lv_obj_has_flag(par, LV_OBJ_FLAG_HIDDEN)) return false;
/*Truncate to the parent and if no common parts break*/
- if(!lv_obj_has_flag(par, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
- if(!_lv_area_intersect(area, area, &par->coords)) return false;
+ if(!lv_obj_has_flag_any(par, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
+ lv_area_t par_area = par->coords;
+ lv_obj_get_transformed_area(par, &par_area, true, false);
+ if(!_lv_area_intersect(area, area, &par_area)) return false;
}
par = lv_obj_get_parent(par);
@@ -1108,3 +1146,19 @@ static void layout_update_core(lv_obj_t * obj)
}
}
}
+
+static void transform_point(const lv_obj_t * obj, lv_point_t * p, bool inv)
+{
+ lv_point_t pivot;
+ pivot.x = obj->coords.x1 + lv_obj_get_style_transform_pivot_x(obj, 0);
+ pivot.y = obj->coords.y1 + lv_obj_get_style_transform_pivot_y(obj, 0);
+ int16_t angle = lv_obj_get_style_transform_angle(obj, 0);
+ int16_t zoom = lv_obj_get_style_transform_zoom(obj, 0);
+
+ if(inv) {
+ angle = -angle;
+ zoom = (256 * 256) / zoom;
+ }
+
+ lv_point_transform(p, angle, zoom, &pivot);
+}
diff --git a/src/core/lv_obj_pos.h b/src/core/lv_obj_pos.h
index 60130398e..d20ee9656 100644
--- a/src/core/lv_obj_pos.h
+++ b/src/core/lv_obj_pos.h
@@ -348,6 +348,24 @@ void lv_obj_move_to(struct _lv_obj_t * obj, lv_coord_t x, lv_coord_t y);
void lv_obj_move_children_by(struct _lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff, bool ignore_floating);
+/**
+ * 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)
+ */
+void lv_obj_transform_point(const struct _lv_obj_t * obj, lv_point_t * p, bool recursive, bool inv);
+
+/**
+ * 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)
+ */
+void lv_obj_get_transformed_area(const struct _lv_obj_t * obj, lv_area_t * area, bool recursive, bool inv);
+
/**
* Mark an area of an object as invalid.
* The area will be truncated to the object's area and marked for redraw.
diff --git a/src/core/lv_obj_style.c b/src/core/lv_obj_style.c
index b77f5b8d2..117b7b4b2 100644
--- a/src/core/lv_obj_style.c
+++ b/src/core/lv_obj_style.c
@@ -571,13 +571,12 @@ static bool get_prop_core(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t
}
for(; i < obj->style_cnt; i++) {
+ if((obj->styles[i].style->has_group & group) == 0) continue;
_lv_obj_style_t * obj_style = &obj->styles[i];
lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
lv_state_t state_act = lv_obj_style_get_selector_state(obj->styles[i].selector);
if(part_act != part) continue;
- if((obj_style->style->has_group & group) == 0) continue;
-
/*Be sure the style not specifies other state than the requested.
*E.g. For HOVER+PRESS object state, HOVER style only is OK, but HOVER+FOCUS style is not*/
if((state_act & state_inv)) continue;
diff --git a/src/core/lv_obj_style_gen.c b/src/core/lv_obj_style_gen.c
index cc51506d8..b87e0f490 100644
--- a/src/core/lv_obj_style_gen.c
+++ b/src/core/lv_obj_style_gen.c
@@ -120,6 +120,22 @@ void lv_obj_set_style_transform_angle(struct _lv_obj_t * obj, lv_coord_t value,
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_ANGLE, v, selector);
}
+void lv_obj_set_style_transform_pivot_x(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_PIVOT_X, v, selector);
+}
+
+void lv_obj_set_style_transform_pivot_y(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_PIVOT_Y, v, selector);
+}
+
void lv_obj_set_style_pad_top(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector)
{
lv_style_value_t v = {
@@ -584,7 +600,8 @@ void lv_obj_set_style_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selec
lv_obj_set_local_style_prop(obj, LV_STYLE_OPA, v, selector);
}
-void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector)
+void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value,
+ lv_style_selector_t selector)
{
lv_style_value_t v = {
.ptr = value
@@ -624,7 +641,8 @@ void lv_obj_set_style_anim_speed(struct _lv_obj_t * obj, uint32_t value, lv_styl
lv_obj_set_local_style_prop(obj, LV_STYLE_ANIM_SPEED, v, selector);
}
-void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value, lv_style_selector_t selector)
+void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value,
+ lv_style_selector_t selector)
{
lv_style_value_t v = {
.ptr = value
diff --git a/src/core/lv_obj_style_gen.h b/src/core/lv_obj_style_gen.h
index 4a72a5a76..462cfa6dc 100644
--- a/src/core/lv_obj_style_gen.h
+++ b/src/core/lv_obj_style_gen.h
@@ -88,6 +88,18 @@ static inline lv_coord_t lv_obj_get_style_transform_angle(const struct _lv_obj_t
return (lv_coord_t)v.num;
}
+static inline lv_coord_t lv_obj_get_style_transform_pivot_x(const struct _lv_obj_t * obj, uint32_t part)
+{
+ lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_PIVOT_X);
+ return (lv_coord_t)v.num;
+}
+
+static inline lv_coord_t lv_obj_get_style_transform_pivot_y(const struct _lv_obj_t * obj, uint32_t part)
+{
+ lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_PIVOT_Y);
+ return (lv_coord_t)v.num;
+}
+
static inline lv_coord_t lv_obj_get_style_pad_top(const struct _lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_TOP);
@@ -150,7 +162,8 @@ static inline lv_color_t lv_obj_get_style_bg_grad_color(const struct _lv_obj_t *
static inline lv_color_t lv_obj_get_style_bg_grad_color_filtered(const struct _lv_obj_t * obj, uint32_t part)
{
- lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_COLOR));
+ lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
+ LV_STYLE_BG_GRAD_COLOR));
return v.color;
}
@@ -204,7 +217,8 @@ static inline lv_color_t lv_obj_get_style_bg_img_recolor(const struct _lv_obj_t
static inline lv_color_t lv_obj_get_style_bg_img_recolor_filtered(const struct _lv_obj_t * obj, uint32_t part)
{
- lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMG_RECOLOR));
+ lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
+ LV_STYLE_BG_IMG_RECOLOR));
return v.color;
}
@@ -228,7 +242,8 @@ static inline lv_color_t lv_obj_get_style_border_color(const struct _lv_obj_t *
static inline lv_color_t lv_obj_get_style_border_color_filtered(const struct _lv_obj_t * obj, uint32_t part)
{
- lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_COLOR));
+ lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
+ LV_STYLE_BORDER_COLOR));
return v.color;
}
@@ -270,7 +285,8 @@ static inline lv_color_t lv_obj_get_style_outline_color(const struct _lv_obj_t *
static inline lv_color_t lv_obj_get_style_outline_color_filtered(const struct _lv_obj_t * obj, uint32_t part)
{
- lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_COLOR));
+ lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
+ LV_STYLE_OUTLINE_COLOR));
return v.color;
}
@@ -318,7 +334,8 @@ static inline lv_color_t lv_obj_get_style_shadow_color(const struct _lv_obj_t *
static inline lv_color_t lv_obj_get_style_shadow_color_filtered(const struct _lv_obj_t * obj, uint32_t part)
{
- lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_COLOR));
+ lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
+ LV_STYLE_SHADOW_COLOR));
return v.color;
}
@@ -342,7 +359,8 @@ static inline lv_color_t lv_obj_get_style_img_recolor(const struct _lv_obj_t * o
static inline lv_color_t lv_obj_get_style_img_recolor_filtered(const struct _lv_obj_t * obj, uint32_t part)
{
- lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_IMG_RECOLOR));
+ lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
+ LV_STYLE_IMG_RECOLOR));
return v.color;
}
@@ -496,7 +514,8 @@ static inline lv_opa_t lv_obj_get_style_opa(const struct _lv_obj_t * obj, uint32
return (lv_opa_t)v.num;
}
-static inline const lv_color_filter_dsc_t * lv_obj_get_style_color_filter_dsc(const struct _lv_obj_t * obj, uint32_t part)
+static inline const lv_color_filter_dsc_t * lv_obj_get_style_color_filter_dsc(const struct _lv_obj_t * obj,
+ uint32_t part)
{
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_COLOR_FILTER_DSC);
return (const lv_color_filter_dsc_t *)v.ptr;
@@ -565,6 +584,8 @@ void lv_obj_set_style_translate_x(struct _lv_obj_t * obj, lv_coord_t value, lv_s
void lv_obj_set_style_translate_y(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
void lv_obj_set_style_transform_zoom(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
void lv_obj_set_style_transform_angle(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
+void lv_obj_set_style_transform_pivot_x(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
+void lv_obj_set_style_transform_pivot_y(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
void lv_obj_set_style_pad_top(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
void lv_obj_set_style_pad_bottom(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
void lv_obj_set_style_pad_left(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
@@ -623,12 +644,14 @@ void lv_obj_set_style_text_align(struct _lv_obj_t * obj, lv_text_align_t value,
void lv_obj_set_style_radius(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
void lv_obj_set_style_clip_corner(struct _lv_obj_t * obj, bool value, lv_style_selector_t selector);
void lv_obj_set_style_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
-void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector);
+void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value,
+ lv_style_selector_t selector);
void lv_obj_set_style_color_filter_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
void lv_obj_set_style_anim(struct _lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector);
void lv_obj_set_style_anim_time(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
void lv_obj_set_style_anim_speed(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
-void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value, lv_style_selector_t selector);
+void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value,
+ lv_style_selector_t selector);
void lv_obj_set_style_blend_mode(struct _lv_obj_t * obj, lv_blend_mode_t value, lv_style_selector_t selector);
void lv_obj_set_style_layout(struct _lv_obj_t * obj, uint16_t value, lv_style_selector_t selector);
void lv_obj_set_style_base_dir(struct _lv_obj_t * obj, lv_base_dir_t value, lv_style_selector_t selector);
diff --git a/src/core/lv_refr.c b/src/core/lv_refr.c
index 2cef6ef28..8cd91d627 100644
--- a/src/core/lv_refr.c
+++ b/src/core/lv_refr.c
@@ -17,6 +17,7 @@
#include "../misc/lv_gc.h"
#include "../draw/lv_draw.h"
#include "../font/lv_font_fmt_txt.h"
+#include "../extra/others/snapshot/lv_snapshot.h"
#if LV_USE_PERF_MONITOR || LV_USE_MEM_MONITOR
#include "../widgets/lv_label.h"
@@ -51,11 +52,12 @@ typedef struct {
* STATIC PROTOTYPES
**********************/
static void lv_refr_join_area(void);
-static void lv_refr_areas(void);
-static void lv_refr_area(const lv_area_t * area_p);
-static void lv_refr_area_part(lv_draw_ctx_t * draw_ctx);
+static void refr_invalid_areas(void);
+static void refr_area(const lv_area_t * area_p);
+static void refr_area_part(lv_draw_ctx_t * draw_ctx);
static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj);
-static void lv_refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_obj);
+static void refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_obj);
+static void refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj);
static uint32_t get_max_row(lv_disp_t * disp, lv_coord_t area_w, lv_coord_t area_h);
static void draw_buf_flush(lv_disp_t * disp);
static void call_flush_cb(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
@@ -124,11 +126,8 @@ void lv_refr_now(lv_disp_t * disp)
}
}
-void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
+void lv_obj_redraw(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
{
- /*Do not refresh hidden objects*/
- if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return;
-
const lv_area_t * clip_area_ori = draw_ctx->clip_area;
lv_area_t clip_coords_for_obj;
@@ -138,18 +137,15 @@ void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
lv_coord_t ext_draw_size = _lv_obj_get_ext_draw_size(obj);
lv_area_increase(&obj_coords_ext, ext_draw_size, ext_draw_size);
bool com_clip_res = _lv_area_intersect(&clip_coords_for_obj, clip_area_ori, &obj_coords_ext);
-
/*If the object is visible on the current clip area OR has overflow visible draw it.
*With overflow visible drawing should happen to apply the masks which might affect children */
bool should_draw = com_clip_res || lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE);
if(should_draw) {
draw_ctx->clip_area = &clip_coords_for_obj;
- /*Draw the object*/
lv_event_send(obj, LV_EVENT_DRAW_MAIN_BEGIN, draw_ctx);
lv_event_send(obj, LV_EVENT_DRAW_MAIN, draw_ctx);
lv_event_send(obj, LV_EVENT_DRAW_MAIN_END, draw_ctx);
-
#if LV_USE_REFR_DEBUG
lv_color_t debug_color = lv_color_make(lv_rand(0, 0xFF), lv_rand(0, 0xFF), lv_rand(0, 0xFF));
lv_draw_rect_dsc_t draw_dsc;
@@ -165,8 +161,8 @@ void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
/*With overflow visible keep the previous clip area to let the children visible out of this object too
*With not overflow visible limit the clip are to the object's coordinates to clip the children*/
- bool refr_children = true;
lv_area_t clip_coords_for_children;
+ bool refr_children = true;
if(lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
clip_coords_for_children = *clip_area_ori;
}
@@ -182,7 +178,7 @@ void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = obj->spec_attr->children[i];
- lv_refr_obj(draw_ctx, child);
+ refr_obj(draw_ctx, child);
}
}
@@ -199,6 +195,7 @@ void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
draw_ctx->clip_area = clip_area_ori;
}
+
/**
* Invalidate an area on display to redraw it
* @param area_p pointer to area which should be invalidated (NULL: delete the invalidated areas)
@@ -323,7 +320,8 @@ void _lv_disp_refr_timer(lv_timer_t * tmr)
lv_refr_join_area();
- lv_refr_areas();
+ refr_invalid_areas();
+
/*If refresh happened ...*/
if(disp_refr->inv_p != 0) {
@@ -340,6 +338,7 @@ void _lv_disp_refr_timer(lv_timer_t * tmr)
disp_refr->inv_p = 0;
elaps = lv_tick_elaps(start);
+
/*Call monitor cb if present*/
if(disp_refr->driver->monitor_cb) {
disp_refr->driver->monitor_cb(disp_refr->driver, elaps, px_num);
@@ -433,9 +432,14 @@ void _lv_disp_refr_timer(lv_timer_t * tmr)
uint32_t used_size = mon.total_size - mon.free_size;;
uint32_t used_kb = used_size / 1024;
uint32_t used_kb_tenth = (used_size - (used_kb * 1024)) / 102;
- lv_label_set_text_fmt(mem_label, "%" LV_PRIu32 ".%" LV_PRIu32 " kB used (%d %%)\n" \
- "%d%% frag.", used_kb, used_kb_tenth, mon.used_pct,
- mon.frag_pct);
+ uint32_t max_size = mon.max_used;
+ uint32_t max_kb = max_size / 1024;
+ uint32_t max_kb_tenth = (max_size - (max_kb * 1024)) / 102;
+ lv_label_set_text_fmt(mem_label,
+ "%"LV_PRIu32 ".%"LV_PRIu32 " kB used (%d %%)\n"
+ "%"LV_PRIu32 ".%"LV_PRIu32 " kB max, %d%% frag.",
+ used_kb, used_kb_tenth, mon.used_pct,
+ max_kb, max_kb_tenth, mon.frag_pct);
}
#endif
@@ -503,7 +507,7 @@ static void lv_refr_join_area(void)
/**
* Refresh the joined areas
*/
-static void lv_refr_areas(void)
+static void refr_invalid_areas(void)
{
px_num = 0;
@@ -534,7 +538,7 @@ static void lv_refr_areas(void)
if(i == last_i) disp_refr->driver->draw_buf->last_area = 1;
disp_refr->driver->draw_buf->last_part = 0;
- lv_refr_area(&disp_refr->inv_areas[i]);
+ refr_area(&disp_refr->inv_areas[i]);
px_num += lv_area_get_size(&disp_refr->inv_areas[i]);
}
@@ -547,7 +551,7 @@ static void lv_refr_areas(void)
* Refresh an area if there is Virtual Display Buffer
* @param area_p pointer to an area to refresh
*/
-static void lv_refr_area(const lv_area_t * area_p)
+static void refr_area(const lv_area_t * area_p)
{
lv_draw_ctx_t * draw_ctx = disp_refr->driver->draw_ctx;
draw_ctx->buf = disp_refr->driver->draw_buf->buf_act;
@@ -562,12 +566,12 @@ static void lv_refr_area(const lv_area_t * area_p)
if(disp_refr->driver->full_refresh) {
disp_refr->driver->draw_buf->last_part = 1;
draw_ctx->clip_area = &disp_area;
- lv_refr_area_part(draw_ctx);
+ refr_area_part(draw_ctx);
}
else {
disp_refr->driver->draw_buf->last_part = disp_refr->driver->draw_buf->last_area;
draw_ctx->clip_area = area_p;
- lv_refr_area_part(draw_ctx);
+ refr_area_part(draw_ctx);
}
return;
}
@@ -596,7 +600,7 @@ static void lv_refr_area(const lv_area_t * area_p)
if(sub_area.y2 > y2) sub_area.y2 = y2;
row_last = sub_area.y2;
if(y2 == row_last) disp_refr->driver->draw_buf->last_part = 1;
- lv_refr_area_part(draw_ctx);
+ refr_area_part(draw_ctx);
}
/*If the last y coordinates are not handled yet ...*/
@@ -610,11 +614,11 @@ static void lv_refr_area(const lv_area_t * area_p)
draw_ctx->clip_area = &sub_area;
draw_ctx->buf = disp_refr->driver->draw_buf->buf_act;
disp_refr->driver->draw_buf->last_part = 1;
- lv_refr_area_part(draw_ctx);
+ refr_area_part(draw_ctx);
}
}
-static void lv_refr_area_part(lv_draw_ctx_t * draw_ctx)
+static void refr_area_part(lv_draw_ctx_t * draw_ctx)
{
lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp_refr);
@@ -624,6 +628,18 @@ static void lv_refr_area_part(lv_draw_ctx_t * draw_ctx)
while(draw_buf->flushing) {
if(disp_refr->driver->wait_cb) disp_refr->driver->wait_cb(disp_refr->driver);
}
+
+ /*If the screen is transparent initialize it when the flushing is ready*/
+#if LV_COLOR_SCREEN_TRANSP
+ if(disp_refr->driver->screen_transp) {
+ if(disp_refr->driver->clear_cb) {
+ disp_refr->driver->clear_cb(disp_refr->driver, disp_refr->driver->draw_buf->buf_act, disp_refr->driver->draw_buf->size);
+ }
+ else {
+ lv_memset_00(disp_refr->driver->draw_buf->buf_act, disp_refr->driver->draw_buf->size * LV_IMG_PX_SIZE_ALPHA_BYTE);
+ }
+ }
+#endif
}
lv_obj_t * top_act_scr = NULL;
@@ -673,28 +689,28 @@ static void lv_refr_area_part(lv_draw_ctx_t * draw_ctx)
if(disp_refr->draw_prev_over_act) {
if(top_act_scr == NULL) top_act_scr = disp_refr->act_scr;
- lv_refr_obj_and_children(draw_ctx, top_act_scr);
+ refr_obj_and_children(draw_ctx, top_act_scr);
/*Refresh the previous screen if any*/
if(disp_refr->prev_scr) {
if(top_prev_scr == NULL) top_prev_scr = disp_refr->prev_scr;
- lv_refr_obj_and_children(draw_ctx, top_prev_scr);
+ refr_obj_and_children(draw_ctx, top_prev_scr);
}
}
else {
/*Refresh the previous screen if any*/
if(disp_refr->prev_scr) {
if(top_prev_scr == NULL) top_prev_scr = disp_refr->prev_scr;
- lv_refr_obj_and_children(draw_ctx, top_prev_scr);
+ refr_obj_and_children(draw_ctx, top_prev_scr);
}
if(top_act_scr == NULL) top_act_scr = disp_refr->act_scr;
- lv_refr_obj_and_children(draw_ctx, top_act_scr);
+ refr_obj_and_children(draw_ctx, top_act_scr);
}
/*Also refresh top and sys layer unconditionally*/
- lv_refr_obj_and_children(draw_ctx, lv_disp_get_layer_top(disp_refr));
- lv_refr_obj_and_children(draw_ctx, lv_disp_get_layer_sys(disp_refr));
+ refr_obj_and_children(draw_ctx, lv_disp_get_layer_top(disp_refr));
+ refr_obj_and_children(draw_ctx, lv_disp_get_layer_sys(disp_refr));
/*In true double buffered mode flush only once when all areas were rendered.
*In normal mode flush after every area*/
@@ -713,32 +729,32 @@ static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj)
{
lv_obj_t * found_p = NULL;
+ if(_lv_area_is_in(area_p, &obj->coords, 0) == false) return NULL;
+ if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return NULL;
+ if(_lv_obj_is_intermediate_layer(obj)) return NULL;
+
/*If this object is fully cover the draw area then check the children too*/
- if(_lv_area_is_in(area_p, &obj->coords, 0) && lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN) == false) {
- lv_cover_check_info_t info;
- info.res = LV_COVER_RES_COVER;
- info.area = area_p;
- lv_event_send(obj, LV_EVENT_COVER_CHECK, &info);
- if(info.res == LV_COVER_RES_MASKED) return NULL;
+ lv_cover_check_info_t info;
+ info.res = LV_COVER_RES_COVER;
+ info.area = area_p;
+ lv_event_send(obj, LV_EVENT_COVER_CHECK, &info);
+ if(info.res == LV_COVER_RES_MASKED) return NULL;
- uint32_t i;
- uint32_t child_cnt = lv_obj_get_child_cnt(obj);
- for(i = 0; i < child_cnt; i++) {
- lv_obj_t * child = obj->spec_attr->children[i];
- found_p = lv_refr_get_top_obj(area_p, child);
+ uint32_t i;
+ uint32_t child_cnt = lv_obj_get_child_cnt(obj);
+ for(i = 0; i < child_cnt; i++) {
+ lv_obj_t * child = obj->spec_attr->children[i];
+ found_p = lv_refr_get_top_obj(area_p, child);
- /*If a children is ok then break*/
- if(found_p != NULL) {
- break;
- }
+ /*If a children is ok then break*/
+ if(found_p != NULL) {
+ break;
}
+ }
- /*If no better children use this object*/
- if(found_p == NULL) {
- if(info.res == LV_COVER_RES_COVER) {
- found_p = obj;
- }
- }
+ /*If no better children use this object*/
+ if(found_p == NULL && info.res == LV_COVER_RES_COVER) {
+ found_p = obj;
}
return found_p;
@@ -749,7 +765,7 @@ static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj)
* @param top_p pointer to an objects. Start the drawing from it.
* @param mask_p pointer to an area, the objects will be drawn only here
*/
-static void lv_refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_obj)
+static void refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_obj)
{
/*Normally always will be a top_obj (at least the screen)
*but in special cases (e.g. if the screen has alpha) it won't.
@@ -758,7 +774,7 @@ static void lv_refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_ob
if(top_obj == NULL) return; /*Shouldn't happen*/
/*Refresh the top object and its children*/
- lv_refr_obj(draw_ctx, top_obj);
+ refr_obj(draw_ctx, top_obj);
/*Draw the 'younger' sibling objects because they can be on top_obj*/
lv_obj_t * parent;
@@ -778,7 +794,7 @@ static void lv_refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_ob
}
else {
/*Refresh the objects*/
- lv_refr_obj(draw_ctx, child);
+ refr_obj(draw_ctx, child);
}
}
@@ -795,6 +811,200 @@ static void lv_refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_ob
}
}
+void refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
+{
+ /*Do not refresh hidden objects*/
+ if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return;
+ lv_intermediate_layer_type_t inlayer = _lv_obj_is_intermediate_layer(obj);
+ if(inlayer == LV_INTERMEDIATE_LAYER_TYPE_NONE) {
+ lv_obj_redraw(draw_ctx, obj);
+ }
+ else {
+ lv_opa_t opa = lv_obj_get_style_opa(obj, 0);
+ if(opa < LV_OPA_MIN) return;
+
+ lv_area_t draw_area;
+ const lv_area_t * clip_area_ori = draw_ctx->clip_area;
+ lv_coord_t ext_draw_size = _lv_obj_get_ext_draw_size(obj);
+ lv_area_t obj_coords_ext;
+ lv_obj_get_coords(obj, &obj_coords_ext);
+ lv_area_increase(&obj_coords_ext, ext_draw_size, ext_draw_size);
+ uint32_t buf_size_sub;
+
+ if(inlayer == LV_INTERMEDIATE_LAYER_TYPE_TRANSFORM) {
+ lv_area_t clip_coords_for_obj;
+ lv_area_t tranf_coords = obj_coords_ext;
+ lv_obj_get_transformed_area(obj, &tranf_coords, false, false);
+ if(!_lv_area_intersect(&clip_coords_for_obj, clip_area_ori, &tranf_coords)) {
+ return;
+ }
+
+ 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);
+ if(!_lv_area_intersect(&inverse_clip_coords_for_obj, &inverse_clip_coords_for_obj, &obj_coords_ext)) {
+ return;
+ }
+
+ draw_area = inverse_clip_coords_for_obj;
+ }
+ else if(inlayer == LV_INTERMEDIATE_LAYER_TYPE_SIMPLE) {
+ lv_area_t clip_coords_for_obj;
+ if(!_lv_area_intersect(&clip_coords_for_obj, clip_area_ori, &obj_coords_ext)) {
+ return;
+ }
+ draw_area = clip_coords_for_obj;
+ }
+ else {
+ LV_LOG_WARN("Unhandled intermediate layer type");
+ return;
+ }
+
+ bool full_cover = false;
+ if(_lv_area_is_in(&draw_area, &obj->coords, 0)) {
+ lv_cover_check_info_t info;
+ info.res = LV_COVER_RES_COVER;
+ info.area = &draw_area;
+ lv_event_send(obj, LV_EVENT_COVER_CHECK, &info);
+ if(info.res == LV_COVER_RES_COVER) full_cover = true;
+ }
+
+ if(LV_COLOR_SCREEN_TRANSP == 0 && !full_cover) {
+ LV_LOG_WARN("Rendering this widget needs LV_COLOR_SCREEN_TRANSP 1");
+ return;
+ }
+
+ uint32_t px_size = full_cover ? sizeof(lv_color_t) : LV_IMG_PX_SIZE_ALPHA_BYTE;
+
+ if(inlayer == LV_INTERMEDIATE_LAYER_TYPE_SIMPLE) {
+ buf_size_sub = LV_LAYER_SIMPLE_BUF_SIZE;
+ }
+ else {
+ buf_size_sub = lv_area_get_size(&draw_area) * px_size;
+ }
+
+ uint32_t buf_size_full = lv_area_get_size(&draw_area) * px_size;
+ if(buf_size_sub > buf_size_full) buf_size_sub = buf_size_full;
+
+ uint8_t * layer_buf = lv_mem_alloc(buf_size_sub);
+ /*Try again with a smaller buf size*/
+ if(inlayer == LV_INTERMEDIATE_LAYER_TYPE_SIMPLE) {
+ if(layer_buf == NULL) {
+ LV_LOG_WARN("Cannot allocate %"LV_PRIu32" bytes for layer buffer. Allocating %"LV_PRIu32" bytes instead. (Reduced performance)",
+ (uint32_t)buf_size_sub * px_size, (uint32_t)LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE * px_size);
+ buf_size_sub = LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE;
+ if(buf_size_sub > buf_size_full) buf_size_sub = buf_size_full;
+ layer_buf = lv_mem_alloc(buf_size_sub);
+ }
+ }
+ if(layer_buf == NULL) {
+ LV_LOG_ERROR("Out of memory: couldn't allocate %"LV_PRIu32" bytes for layer buffer.", (uint32_t)buf_size_sub * px_size);
+ LV_ASSERT_MALLOC(layer_buf);
+ return;
+ }
+
+ int32_t row_cnt;
+ lv_draw_ctx_t * new_draw_ctx = lv_mem_alloc(disp_refr->driver->draw_ctx_size);
+ LV_ASSERT_MALLOC(new_draw_ctx);
+ if(new_draw_ctx == NULL) {
+ LV_LOG_ERROR("Out of memory: couldn't allocate new draw context.");
+ lv_mem_free(layer_buf);
+ return;
+ }
+
+ lv_area_t draw_area_sub = draw_area;
+
+ /*Set-up a new draw_ctx*/
+ bool old_scr_transp = disp_refr->driver->screen_transp;
+ disp_refr->driver->draw_ctx_init(disp_refr->driver, new_draw_ctx);
+ new_draw_ctx->clip_area = &draw_area_sub;
+ new_draw_ctx->buf_area = &draw_area_sub;
+ new_draw_ctx->buf = (void *)layer_buf;
+
+ lv_draw_img_dsc_t draw_dsc;
+ lv_draw_img_dsc_init(&draw_dsc);
+ draw_dsc.opa = opa;
+ draw_dsc.angle = lv_obj_get_style_transform_angle(obj, 0);
+ draw_dsc.zoom = lv_obj_get_style_transform_zoom(obj, 0);
+ draw_dsc.antialias = disp_refr->driver->antialiasing;
+
+ lv_point_t pivot;
+ pivot.x = lv_obj_get_style_transform_pivot_x(obj, 0);
+ pivot.y = lv_obj_get_style_transform_pivot_y(obj, 0);
+
+ lv_img_dsc_t img;
+ img.data = layer_buf;
+ img.header.always_zero = 0;
+ img.header.w = lv_area_get_width(&draw_area);
+
+ /*If the whole area is covers calculate the row count only once*/
+ if(full_cover) {
+ row_cnt = buf_size_sub / (sizeof(lv_color_t) * lv_area_get_width(&draw_area));
+ draw_area_sub.y2 = draw_area_sub.y1 + row_cnt - 1;
+ if(draw_area_sub.y2 > draw_area.y2) draw_area_sub.y2 = draw_area.y2;
+ }
+
+ while(draw_area_sub.y1 <= draw_area.y2) {
+ /* If the widget covers the area of as many rows as an RGB buffer provides,
+ * draw it as RGB instead of ARGB because it's much faster
+ * `full_cover_global == true` indicates that the widget covers the whole draw_area anyway*/
+ if(!full_cover) {
+ row_cnt = buf_size_sub / (sizeof(lv_color_t) * lv_area_get_width(&draw_area));
+ }
+
+ draw_area_sub.y2 = draw_area_sub.y1 + row_cnt - 1;
+ if(draw_area_sub.y2 > draw_area.y2) draw_area_sub.y2 = draw_area.y2;
+
+ bool full_cover_sub = false;
+ if(_lv_area_is_in(&draw_area_sub, &obj->coords, 0)) {
+ lv_cover_check_info_t info;
+ info.res = LV_COVER_RES_COVER;
+ info.area = &draw_area_sub;
+ lv_event_send(obj, LV_EVENT_COVER_CHECK, &info);
+ if(info.res == LV_COVER_RES_COVER) full_cover_sub = true;
+ }
+
+ /* In the area is not covered by the widget recalculate the row count using ARGB pixel size
+ * It can happen that this smaller area is already covered by the widget but ignore this case
+ * in favor of fewer LV_EVENT_COVER_CHECK calls */
+ if(!full_cover_sub) {
+ row_cnt = buf_size_sub / (LV_IMG_PX_SIZE_ALPHA_BYTE * lv_area_get_width(&draw_area));
+ draw_area_sub.y2 = draw_area_sub.y1 + row_cnt - 1;
+ if(draw_area_sub.y2 > draw_area.y2) draw_area_sub.y2 = draw_area.y2;
+ disp_refr->driver->screen_transp = 1;
+ img.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
+ }
+ else {
+ disp_refr->driver->screen_transp = 0;
+ img.header.cf = LV_IMG_CF_TRUE_COLOR;
+ }
+
+ draw_dsc.pivot.x = obj->coords.x1 + pivot.x - draw_area_sub.x1;
+ draw_dsc.pivot.y = obj->coords.y1 + pivot.y - draw_area_sub.y1;
+
+ if(!full_cover_sub) lv_memset_00(layer_buf, buf_size_sub);
+ lv_obj_redraw(new_draw_ctx, obj);
+
+ lv_img_cache_invalidate_src(&img);
+
+ img.header.h = lv_area_get_height(&draw_area_sub);
+
+ disp_refr->driver->screen_transp = old_scr_transp;
+ lv_draw_img(draw_ctx, &draw_dsc, &draw_area_sub, &img);
+
+ draw_area_sub.y1 = draw_area_sub.y2 + 1;
+ if(draw_area_sub.y2 > draw_area.y2) draw_area_sub.y2 = draw_area.y2;
+ }
+
+ disp_refr->driver->draw_ctx_deinit(disp_refr->driver, new_draw_ctx);
+ lv_mem_free(layer_buf);
+ lv_mem_free(new_draw_ctx);
+ disp_refr->driver->screen_transp = old_scr_transp;
+ }
+}
+
+
+
+
static uint32_t get_max_row(lv_disp_t * disp, lv_coord_t area_w, lv_coord_t area_h)
{
int32_t max_row = (uint32_t)disp->driver->draw_buf->size / area_w;
@@ -1027,6 +1237,18 @@ static void draw_buf_flush(lv_disp_t * disp)
while(draw_buf->flushing) {
if(disp_refr->driver->wait_cb) disp_refr->driver->wait_cb(disp_refr->driver);
}
+
+ /*If the screen is transparent initialize it when the flushing is ready*/
+#if LV_COLOR_SCREEN_TRANSP
+ if(disp_refr->driver->screen_transp) {
+ if(disp_refr->driver->clear_cb) {
+ disp_refr->driver->clear_cb(disp_refr->driver, disp_refr->driver->draw_buf->buf_act, disp_refr->driver->draw_buf->size);
+ }
+ else {
+ lv_memset_00(disp_refr->driver->draw_buf->buf_act, disp_refr->driver->draw_buf->size * LV_IMG_PX_SIZE_ALPHA_BYTE);
+ }
+ }
+#endif
}
draw_buf->flushing = 1;
diff --git a/src/core/lv_refr.h b/src/core/lv_refr.h
index 984168a96..72e8d6c39 100644
--- a/src/core/lv_refr.h
+++ b/src/core/lv_refr.h
@@ -61,7 +61,7 @@ void lv_refr_now(lv_disp_t * disp);
* @param draw pointer to an initialized draw context
* @param obj the start object from the redraw should start
*/
-void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj);
+void lv_obj_redraw(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj);
/**
* Invalidate an area on display to redraw it
diff --git a/src/draw/lv_draw.h b/src/draw/lv_draw.h
index 9995330dc..84a3aef1c 100644
--- a/src/draw/lv_draw.h
+++ b/src/draw/lv_draw.h
@@ -27,6 +27,7 @@ extern "C" {
#include "lv_draw_triangle.h"
#include "lv_draw_arc.h"
#include "lv_draw_mask.h"
+#include "lv_draw_transform.h"
/*********************
* DEFINES
@@ -80,6 +81,24 @@ typedef struct _lv_draw_ctx_t {
void (*draw_polygon)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc,
const lv_point_t * points, uint16_t point_cnt);
+
+ /**
+ * Get an area of a transformed image (zoomed and/or rotated)
+ * @param draw_ctx pointer to a draw context
+ * @param dest_area get this area of the result image. It assumes that the original image is placed to the 0;0 position.
+ * @param src_buf the source image
+ * @param src_w width of the source image in [px]
+ * @param src_h height of the source image in [px]
+ * @param src_stride the stride in [px].
+ * @param draw_dsc an `lv_draw_img_dsc_t` descriptor containing the transformation parameters
+ * @param cf the color format of `src_buf`
+ * @param cbuf place the colors of the pixels on `dest_area` here in RGB format
+ * @param abuf place the opacity of the pixels on `dest_area` here
+ */
+ void (*draw_transform)(struct _lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
+ lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
+ const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
+
/**
* Replace the buffer with a rect without decoration like radius or borders
*/
diff --git a/src/draw/lv_draw_img.h b/src/draw/lv_draw_img.h
index 504bedae4..a88a33caf 100644
--- a/src/draw/lv_draw_img.h
+++ b/src/draw/lv_draw_img.h
@@ -31,7 +31,7 @@ extern "C" {
typedef struct {
- uint16_t angle;
+ int16_t angle;
uint16_t zoom;
lv_point_t pivot;
diff --git a/src/draw/lv_draw_transform.c b/src/draw/lv_draw_transform.c
new file mode 100644
index 000000000..580351d6d
--- /dev/null
+++ b/src/draw/lv_draw_transform.c
@@ -0,0 +1,54 @@
+/**
+ * @file lv_draw_transform.c
+ *
+ */
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "lv_draw.h"
+#include "lv_draw_transform.h"
+#include "../misc/lv_assert.h"
+#include "../misc/lv_area.h"
+
+/*********************
+ * DEFINES
+ *********************/
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ * STATIC VARIABLES
+ **********************/
+
+/**********************
+ * MACROS
+ **********************/
+
+/**********************
+ * GLOBAL FUNCTIONS
+ **********************/
+void lv_draw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w,
+ lv_coord_t src_h,
+ lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf)
+{
+ LV_ASSERT_NULL(draw_ctx);
+ if(draw_ctx->draw_transform == NULL) {
+ LV_LOG_WARN("draw_ctx->draw_transform == NULL");
+ return;
+ }
+
+ draw_ctx->draw_transform(draw_ctx, dest_area, src_buf, src_w, src_h, src_stride, draw_dsc, cf, cbuf, abuf);
+
+}
+
+
+/**********************
+ * STATIC FUNCTIONS
+ **********************/
diff --git a/src/draw/lv_draw_transform.h b/src/draw/lv_draw_transform.h
new file mode 100644
index 000000000..1926c2fc2
--- /dev/null
+++ b/src/draw/lv_draw_transform.h
@@ -0,0 +1,44 @@
+/**
+ * @file lv_draw_transform.h
+ *
+ */
+
+#ifndef LV_DRAW_TRANSFORM_H
+#define LV_DRAW_TRANSFORM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "../lv_conf_internal.h"
+#include "../misc/lv_area.h"
+
+/*********************
+ * DEFINES
+ *********************/
+
+/**********************
+ * TYPEDEFS
+ **********************/
+struct _lv_draw_ctx_t;
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+
+void lv_draw_transform(struct _lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
+ lv_coord_t src_w, lv_coord_t src_h,
+ lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
+
+/**********************
+ * MACROS
+ **********************/
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif /*LV_DRAW_TRANSFORM_H*/
diff --git a/src/draw/lv_img_buf.c b/src/draw/lv_img_buf.c
index a6d0efc36..342eebd6c 100644
--- a/src/draw/lv_img_buf.c
+++ b/src/draw/lv_img_buf.c
@@ -410,58 +410,6 @@ uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
}
}
-#if LV_DRAW_COMPLEX
-/**
- * Initialize a descriptor to transform an image
- * @param dsc pointer to an `lv_img_transform_dsc_t` variable whose `cfg` field is initialized
- */
-void _lv_img_buf_transform_init(lv_img_transform_dsc_t * dsc)
-{
- dsc->tmp.pivot_x_256 = dsc->cfg.pivot_x * 256;
- dsc->tmp.pivot_y_256 = dsc->cfg.pivot_y * 256;
-
- int32_t angle_low = dsc->cfg.angle / 10;
- int32_t angle_high = angle_low + 1;
- int32_t angle_rem = dsc->cfg.angle - (angle_low * 10);
-
- int32_t s1 = lv_trigo_sin(-angle_low);
- int32_t s2 = lv_trigo_sin(-angle_high);
-
- int32_t c1 = lv_trigo_sin(-angle_low + 90);
- int32_t c2 = lv_trigo_sin(-angle_high + 90);
-
- dsc->tmp.sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
- dsc->tmp.cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
-
- /*Use smaller value to avoid overflow*/
- dsc->tmp.sinma = dsc->tmp.sinma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
- dsc->tmp.cosma = dsc->tmp.cosma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
-
- dsc->tmp.chroma_keyed = lv_img_cf_is_chroma_keyed(dsc->cfg.cf) ? 1 : 0;
- dsc->tmp.has_alpha = lv_img_cf_has_alpha(dsc->cfg.cf) ? 1 : 0;
- if(dsc->cfg.cf == LV_IMG_CF_TRUE_COLOR || dsc->cfg.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
- dsc->cfg.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
- dsc->tmp.native_color = 1;
- }
- else {
- dsc->tmp.native_color = 0;
- }
-
- dsc->tmp.img_dsc.data = dsc->cfg.src;
- dsc->tmp.img_dsc.header.always_zero = 0;
- dsc->tmp.img_dsc.header.cf = dsc->cfg.cf;
- dsc->tmp.img_dsc.header.w = dsc->cfg.src_w;
- dsc->tmp.img_dsc.header.h = dsc->cfg.src_h;
-
- /*The inverse of the zoom will be sued during the transformation
- * + dsc->cfg.zoom / 2 for rounding*/
- dsc->tmp.zoom_inv = (((256 * 256) << _LV_ZOOM_INV_UPSCALE) + dsc->cfg.zoom / 2) / dsc->cfg.zoom;
-
- dsc->res.opa = LV_OPA_COVER;
- dsc->res.color = dsc->cfg.color;
-}
-#endif
-
/**
* Get the area of a rectangle if its rotated and scaled
* @param res store the coordinates here
@@ -483,68 +431,21 @@ void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t
return;
}
- res->x1 = (((int32_t)(-pivot->x) * zoom) >> 8) - 1;
- res->y1 = (((int32_t)(-pivot->y) * zoom) >> 8) - 1;
- res->x2 = (((int32_t)(w - pivot->x) * zoom) >> 8) + 2;
- res->y2 = (((int32_t)(h - pivot->y) * zoom) >> 8) + 2;
+ lv_point_t p[4] = {
+ {0, 0},
+ {w - 1, 0},
+ {0, h - 1},
+ {w - 1, h - 1},
+ };
+ lv_point_transform(&p[0], angle, zoom, pivot);
+ lv_point_transform(&p[1], angle, zoom, pivot);
+ lv_point_transform(&p[2], angle, zoom, pivot);
+ lv_point_transform(&p[3], angle, zoom, pivot);
+ res->x1 = LV_MIN4(p[0].x, p[1].x, p[2].x, p[3].x) - 2;
+ res->x2 = LV_MAX4(p[0].x, p[1].x, p[2].x, p[3].x) + 2;
+ res->y1 = LV_MIN4(p[0].y, p[1].y, p[2].y, p[3].y) - 2;
+ res->y2 = LV_MAX4(p[0].y, p[1].y, p[2].y, p[3].y) + 2;
- if(angle == 0) {
- res->x1 += pivot->x;
- res->y1 += pivot->y;
- res->x2 += pivot->x;
- res->y2 += pivot->y;
- return;
- }
-
- int32_t angle_low = angle / 10;
- int32_t angle_high = angle_low + 1;
- int32_t angle_rem = angle - (angle_low * 10);
-
- int32_t s1 = lv_trigo_sin(angle_low);
- int32_t s2 = lv_trigo_sin(angle_high);
-
- 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;
- int32_t cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
-
- /*Use smaller value to avoid overflow*/
- sinma = sinma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
- cosma = cosma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
-
- lv_point_t lt;
- lv_point_t rt;
- lv_point_t lb;
- lv_point_t rb;
-
- lv_coord_t xt;
- lv_coord_t yt;
-
- xt = res->x1;
- yt = res->y1;
- lt.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
- lt.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
-
- xt = res->x2;
- yt = res->y1;
- rt.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
- rt.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
-
- xt = res->x1;
- yt = res->y2;
- lb.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
- lb.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
-
- xt = res->x2;
- yt = res->y2;
- rb.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
- rb.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
-
- res->x1 = LV_MIN4(lb.x, lt.x, rb.x, rt.x);
- res->x2 = LV_MAX4(lb.x, lt.x, rb.x, rt.x);
- res->y1 = LV_MIN4(lb.y, lt.y, rb.y, rt.y);
- res->y2 = LV_MAX4(lb.y, lt.y, rb.y, rt.y);
#else
LV_UNUSED(angle);
LV_UNUSED(zoom);
@@ -556,217 +457,6 @@ void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t
#endif
}
-
-#if LV_DRAW_COMPLEX
-/**
- * Get which color and opa would come to a pixel if it were rotated
- * @param dsc a descriptor initialized by `lv_img_buf_rotate_init`
- * @param x the coordinate which color and opa should be get
- * @param y the coordinate which color and opa should be get
- * @return true: there is valid pixel on these x/y coordinates; false: the rotated pixel was out of the image
- * @note the result is written back to `dsc->res_color` and `dsc->res_opa`
- */
-bool _lv_img_buf_transform(lv_img_transform_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
-{
- const uint8_t * src_u8 = (const uint8_t *)dsc->cfg.src;
-
- /*Get the target point relative coordinates to the pivot*/
- int32_t xt = x - dsc->cfg.pivot_x;
- int32_t yt = y - dsc->cfg.pivot_y;
-
- int32_t xs;
- int32_t ys;
- if(dsc->cfg.zoom == LV_IMG_ZOOM_NONE) {
- /*Get the source pixel from the upscaled image*/
- xs = ((dsc->tmp.cosma * xt - dsc->tmp.sinma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT - 8)) + dsc->tmp.pivot_x_256;
- ys = ((dsc->tmp.sinma * xt + dsc->tmp.cosma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT - 8)) + dsc->tmp.pivot_y_256;
- }
- else if(dsc->cfg.angle == 0) {
- xt = (int32_t)((int32_t)xt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
- yt = (int32_t)((int32_t)yt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
- xs = xt + dsc->tmp.pivot_x_256;
- ys = yt + dsc->tmp.pivot_y_256;
- }
- else {
- xt = (int32_t)((int32_t)xt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
- yt = (int32_t)((int32_t)yt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
- xs = ((dsc->tmp.cosma * xt - dsc->tmp.sinma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT)) + dsc->tmp.pivot_x_256;
- ys = ((dsc->tmp.sinma * xt + dsc->tmp.cosma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT)) + dsc->tmp.pivot_y_256;
- }
-
- /*Get the integer part of the source pixel*/
- int32_t xs_int = xs >> 8;
- int32_t ys_int = ys >> 8;
-
- if(xs_int >= dsc->cfg.src_w) return false;
- else if(xs_int < 0) return false;
-
- if(ys_int >= dsc->cfg.src_h) return false;
- else if(ys_int < 0) return false;
-
- uint8_t px_size;
- uint32_t pxi;
- if(dsc->tmp.native_color) {
- if(dsc->tmp.has_alpha == 0) {
- px_size = LV_COLOR_SIZE >> 3;
-
- pxi = dsc->cfg.src_w * ys_int * px_size + xs_int * px_size;
- lv_memcpy_small(&dsc->res.color, &src_u8[pxi], px_size);
- }
- else {
- px_size = LV_IMG_PX_SIZE_ALPHA_BYTE;
- pxi = dsc->cfg.src_w * ys_int * px_size + xs_int * px_size;
- lv_memcpy_small(&dsc->res.color, &src_u8[pxi], px_size - 1);
- dsc->res.opa = src_u8[pxi + px_size - 1];
- }
- }
- else {
- pxi = 0; /*unused*/
- px_size = 0; /*unused*/
- dsc->res.color = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, xs_int, ys_int, dsc->cfg.color);
- dsc->res.opa = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, xs_int, ys_int);
- }
-
- if(dsc->tmp.chroma_keyed) {
- lv_color_t ct = LV_COLOR_CHROMA_KEY;
- if(dsc->res.color.full == ct.full) return false;
- }
-
- if(dsc->cfg.antialias == false) return true;
-
- dsc->tmp.xs = xs;
- dsc->tmp.ys = ys;
- dsc->tmp.xs_int = xs_int;
- dsc->tmp.ys_int = ys_int;
- dsc->tmp.pxi = pxi;
- dsc->tmp.px_size = px_size;
-
- bool ret;
- ret = _lv_img_buf_transform_anti_alias(dsc);
-
- return ret;
-}
-
-/**
- * Continue transformation by taking the neighbors into account
- * @param dsc pointer to the transformation descriptor
- */
-bool _lv_img_buf_transform_anti_alias(lv_img_transform_dsc_t * dsc)
-{
- const uint8_t * src_u8 = dsc->cfg.src;
-
- /*Get the fractional part of the source pixel*/
- int xs_fract = dsc->tmp.xs & 0xff;
- int ys_fract = dsc->tmp.ys & 0xff;
- int32_t xn; /*x neighbor*/
- lv_opa_t xr; /*x mix ratio*/
-
- if(xs_fract < 0x70) {
- xn = - 1;
- if(dsc->tmp.xs_int + xn < 0) xn = 0;
- xr = xs_fract + 0x80;
- }
- else if(xs_fract > 0x90) {
- xn = 1;
- if(dsc->tmp.xs_int + xn >= dsc->cfg.src_w) xn = 0;
- xr = (0xFF - xs_fract) + 0x80;
- }
- else {
- xn = 0;
- xr = 0xFF;
- }
-
- int32_t yn; /*x neighbor*/
- lv_opa_t yr; /*x mix ratio*/
-
- if(ys_fract < 0x70) {
- yn = - 1;
- if(dsc->tmp.ys_int + yn < 0) yn = 0;
-
- yr = ys_fract + 0x80;
- }
- else if(ys_fract > 0x90) {
- yn = 1;
- if(dsc->tmp.ys_int + yn >= dsc->cfg.src_h) yn = 0;
-
- yr = (0xFF - ys_fract) + 0x80;
- }
- else {
- yn = 0;
- yr = 0xFF;
- }
-
- lv_color_t c00 = dsc->res.color;
- lv_color_t c01;
- lv_color_t c10;
- lv_color_t c11;
-
- lv_opa_t a00 = dsc->res.opa;
- lv_opa_t a10 = 0;
- lv_opa_t a01 = 0;
- lv_opa_t a11 = 0;
-
- if(dsc->tmp.native_color) {
- lv_memcpy_small(&c01, &src_u8[dsc->tmp.pxi + dsc->tmp.px_size * xn], sizeof(lv_color_t));
- lv_memcpy_small(&c10, &src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn], sizeof(lv_color_t));
- lv_memcpy_small(&c11, &src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn + dsc->tmp.px_size * xn],
- sizeof(lv_color_t));
- if(dsc->tmp.has_alpha) {
- a10 = src_u8[dsc->tmp.pxi + dsc->tmp.px_size * xn + dsc->tmp.px_size - 1];
- a01 = src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn + dsc->tmp.px_size - 1];
- a11 = src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn + dsc->tmp.px_size * xn + dsc->tmp.px_size - 1];
- }
- }
- else {
- c01 = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int, dsc->cfg.color);
- c10 = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, dsc->tmp.xs_int, dsc->tmp.ys_int + yn, dsc->cfg.color);
- c11 = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int + yn, dsc->cfg.color);
-
- if(dsc->tmp.has_alpha) {
- a10 = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int);
- a01 = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, dsc->tmp.xs_int, dsc->tmp.ys_int + yn);
- a11 = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int + yn);
- }
- }
-
- lv_opa_t xr0 = xr;
- lv_opa_t xr1 = xr;
- if(dsc->tmp.has_alpha) {
- lv_opa_t a0 = (a00 * xr + (a10 * (255 - xr))) >> 8;
- lv_opa_t a1 = (a01 * xr + (a11 * (255 - xr))) >> 8;
- dsc->res.opa = (a0 * yr + (a1 * (255 - yr))) >> 8;
-
- if(a0 <= LV_OPA_MIN && a1 <= LV_OPA_MIN) return false;
- if(a0 <= LV_OPA_MIN) yr = LV_OPA_TRANSP;
- if(a1 <= LV_OPA_MIN) yr = LV_OPA_COVER;
- if(a00 <= LV_OPA_MIN) xr0 = LV_OPA_TRANSP;
- if(a10 <= LV_OPA_MIN) xr0 = LV_OPA_COVER;
- if(a01 <= LV_OPA_MIN) xr1 = LV_OPA_TRANSP;
- if(a11 <= LV_OPA_MIN) xr1 = LV_OPA_COVER;
- }
- else {
- xr0 = xr;
- xr1 = xr;
- dsc->res.opa = LV_OPA_COVER;
- }
-
- lv_color_t c0;
- if(xr0 == LV_OPA_TRANSP) c0 = c01;
- else if(xr0 == LV_OPA_COVER) c0 = c00;
- else c0 = lv_color_mix(c00, c01, xr0);
-
- lv_color_t c1;
- if(xr1 == LV_OPA_TRANSP) c1 = c11;
- else if(xr1 == LV_OPA_COVER) c1 = c10;
- else c1 = lv_color_mix(c10, c11, xr1);
-
- if(yr == LV_OPA_TRANSP) dsc->res.color = c1;
- else if(yr == LV_OPA_COVER) dsc->res.color = c0;
- else dsc->res.color = lv_color_mix(c0, c1, yr);
-
- return true;
-}
-#endif
/**********************
* STATIC FUNCTIONS
**********************/
diff --git a/src/draw/lv_img_buf.h b/src/draw/lv_img_buf.h
index de8819c8e..1be7bb652 100644
--- a/src/draw/lv_img_buf.h
+++ b/src/draw/lv_img_buf.h
@@ -45,7 +45,6 @@ extern "C" {
#define LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) + 4 * 16)
#define LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) + 4 * 256)
-#define _LV_TRANSFORM_TRIGO_SHIFT 10
#define _LV_ZOOM_INV_UPSCALE 5
/**********************
@@ -77,6 +76,13 @@ enum {
LV_IMG_CF_ALPHA_4BIT, /**< Can have one color but 16 different alpha value*/
LV_IMG_CF_ALPHA_8BIT, /**< Can have one color but 256 different alpha value*/
+ LV_IMG_CF_RGB888,
+ LV_IMG_CF_RGBA8888,
+ LV_IMG_CF_RGBX8888,
+ LV_IMG_CF_RGB565,
+ LV_IMG_CF_RGBA5658,
+ LV_IMG_CF_RGB565A8,
+
LV_IMG_CF_RESERVED_15, /**< Reserved for further use.*/
LV_IMG_CF_RESERVED_16, /**< Reserved for further use.*/
LV_IMG_CF_RESERVED_17, /**< Reserved for further use.*/
@@ -138,49 +144,6 @@ typedef struct {
const uint8_t * data; /**< Pointer to the data of the image*/
} lv_img_dsc_t;
-typedef struct {
- struct {
- const void * src; /*image source (array of pixels)*/
- lv_coord_t src_w; /*width of the image source*/
- lv_coord_t src_h; /*height of the image source*/
- lv_coord_t pivot_x; /*pivot x*/
- lv_coord_t pivot_y; /*pivot y*/
- int16_t angle; /*angle to rotate*/
- uint16_t zoom; /*256 no zoom, 128 half size, 512 double size*/
- lv_color_t color; /*a color used for `LV_IMG_CF_INDEXED_1/2/4/8BIT` color formats*/
- lv_img_cf_t cf; /*color format of the image to rotate*/
- bool antialias;
- } cfg;
-
- struct {
- lv_color_t color;
- lv_opa_t opa;
- } res;
-
- struct {
- lv_img_dsc_t img_dsc;
- int32_t pivot_x_256;
- int32_t pivot_y_256;
- int32_t sinma;
- int32_t cosma;
-
- uint8_t chroma_keyed : 1;
- uint8_t has_alpha : 1;
- uint8_t native_color : 1;
-
- uint32_t zoom_inv;
-
- /*Runtime data*/
- lv_coord_t xs;
- lv_coord_t ys;
- lv_coord_t xs_int;
- lv_coord_t ys_int;
- uint32_t pxi;
- uint8_t px_size;
- } tmp;
-} lv_img_transform_dsc_t;
-
-
/**********************
* GLOBAL PROTOTYPES
**********************/
@@ -263,30 +226,6 @@ void lv_img_buf_free(lv_img_dsc_t * dsc);
*/
uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf);
-#if LV_DRAW_COMPLEX
-/**
- * Initialize a descriptor to rotate an image
- * @param dsc pointer to an `lv_img_transform_dsc_t` variable whose `cfg` field is initialized
- */
-void _lv_img_buf_transform_init(lv_img_transform_dsc_t * dsc);
-
-/**
- * Continue transformation by taking the neighbors into account
- * @param dsc pointer to the transformation descriptor
- */
-bool _lv_img_buf_transform_anti_alias(lv_img_transform_dsc_t * dsc);
-
-/**
- * Get which color and opa would come to a pixel if it were rotated
- * @param dsc a descriptor initialized by `lv_img_buf_rotate_init`
- * @param x the coordinate which color and opa should be get
- * @param y the coordinate which color and opa should be get
- * @return true: there is valid pixel on these x/y coordinates; false: the rotated pixel was out of the image
- * @note the result is written back to `dsc->res_color` and `dsc->res_opa`
- */
-bool _lv_img_buf_transform(lv_img_transform_dsc_t * dsc, lv_coord_t x, lv_coord_t y);
-
-#endif
/**
* Get the area of a rectangle if its rotated and scaled
* @param res store the coordinates here
diff --git a/src/draw/lv_img_decoder.c b/src/draw/lv_img_decoder.c
index a8fe94b98..88c756048 100644
--- a/src/draw/lv_img_decoder.c
+++ b/src/draw/lv_img_decoder.c
@@ -15,8 +15,8 @@
/*********************
* DEFINES
*********************/
-#define CF_BUILT_IN_FIRST LV_IMG_CF_TRUE_COLOR
-#define CF_BUILT_IN_LAST LV_IMG_CF_ALPHA_8BIT
+#define CF_BUILT_IN_FIRST LV_IMG_CF_TRUE_COLOR
+#define CF_BUILT_IN_LAST LV_IMG_CF_RGB565A8
/**********************
* TYPEDEFS
diff --git a/src/draw/sw/lv_draw_sw.c b/src/draw/sw/lv_draw_sw.c
index c4cd84ba7..376ec4d23 100644
--- a/src/draw/sw/lv_draw_sw.c
+++ b/src/draw/sw/lv_draw_sw.c
@@ -51,6 +51,9 @@ void lv_draw_sw_init_ctx(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
draw_sw_ctx->base_draw.draw_img_decoded = lv_draw_sw_img_decoded;
draw_sw_ctx->base_draw.draw_line = lv_draw_sw_line;
draw_sw_ctx->base_draw.draw_polygon = lv_draw_sw_polygon;
+#if LV_DRAW_COMPLEX
+ draw_sw_ctx->base_draw.draw_transform = lv_draw_sw_transform;
+#endif
draw_sw_ctx->base_draw.wait_for_finish = lv_draw_sw_wait_for_finish;
draw_sw_ctx->base_draw.buffer_copy = lv_draw_sw_buffer_copy;
draw_sw_ctx->blend = lv_draw_sw_blend_basic;
diff --git a/src/draw/sw/lv_draw_sw.h b/src/draw/sw/lv_draw_sw.h
index 323783e9d..521deba7e 100644
--- a/src/draw/sw/lv_draw_sw.h
+++ b/src/draw/sw/lv_draw_sw.h
@@ -66,6 +66,12 @@ void lv_draw_sw_polygon(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc
void lv_draw_sw_buffer_copy(lv_draw_ctx_t * draw_ctx,
void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area,
void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area);
+
+
+void lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
+ lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
+ const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
+
/***********************
* GLOBAL VARIABLES
***********************/
diff --git a/src/draw/sw/lv_draw_sw_blend.c b/src/draw/sw/lv_draw_sw_blend.c
index 82d013888..3b4d5416b 100644
--- a/src/draw/sw/lv_draw_sw_blend.c
+++ b/src/draw/sw/lv_draw_sw_blend.c
@@ -25,8 +25,16 @@
static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride,
lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide);
+
LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
+
+
+#if LV_COLOR_SCREEN_TRANSP
+LV_ATTRIBUTE_FAST_MEM static void fill_argb(lv_color_t * dest_buf, const lv_area_t * dest_area,
+ lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
+#endif /*LV_COLOR_SCREEN_TRANSP*/
+
#if LV_DRAW_COMPLEX
static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, lv_color_t color,
lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode);
@@ -38,6 +46,12 @@ static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_co
LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
+#if LV_COLOR_SCREEN_TRANSP
+LV_ATTRIBUTE_FAST_MEM static void map_argb(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
+ const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
+
+#endif /*LV_COLOR_SCREEN_TRANSP*/
+
#if LV_DRAW_COMPLEX
static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
@@ -55,22 +69,12 @@ static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color
/**********************
* MACROS
**********************/
-#if LV_COLOR_SCREEN_TRANSP == 0
#define FILL_NORMAL_MASK_PX(color) \
if(*mask == LV_OPA_COVER) *dest_buf = color; \
else *dest_buf = lv_color_mix(color, *dest_buf, *mask); \
mask++; \
dest_buf++;
-#else
-#define FILL_NORMAL_MASK_PX(color) \
- if(*mask == LV_OPA_COVER) *dest_buf = color; \
- else if(disp->driver->screen_transp) lv_color_mix_with_alpha(*dest_buf, dest_buf->ch.alpha, color, *mask, dest_buf, &dest_buf->ch.alpha); \
- else *dest_buf = lv_color_mix(color, *dest_buf, *mask); \
- mask++; \
- dest_buf++;
-#endif
-
#define MAP_NORMAL_MASK_PX(x) \
if(*mask_tmp_x) { \
if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x]; \
@@ -78,15 +82,6 @@ static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color
} \
mask_tmp_x++;
-#define MAP_NORMAL_MASK_PX_SCR_TRANSP(x) \
- if(*mask_tmp_x) { \
- if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x]; \
- else if(disp->driver->screen_transp) lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, \
- src_buf[x], *mask_tmp_x, &dest_buf[x], &dest_buf[x].ch.alpha); \
- else dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], *mask_tmp_x); \
- } \
- mask_tmp_x++;
-
/**********************
* GLOBAL FUNCTIONS
@@ -121,9 +116,19 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, cons
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
lv_color_t * dest_buf = draw_ctx->buf;
if(disp->driver->set_px_cb == NULL) {
- dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
+ if(disp->driver->screen_transp == 0) {
+ dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
+ }
+ else {
+ /*With LV_COLOR_DEPTH 16 it means ARGB8565 (3 bytes format)*/
+ uint8_t * dest_buf8 = (uint8_t *) dest_buf;
+ dest_buf8 += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ dest_buf8 += (blend_area.x1 - draw_ctx->buf_area->x1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ dest_buf = (lv_color_t *)dest_buf8;
+ }
}
+
const lv_color_t * src_buf = dsc->src_buf;
lv_coord_t src_stride;
if(src_buf) {
@@ -154,21 +159,29 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, cons
map_set_px(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
}
}
- else if(dsc->src_buf == NULL) {
- if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
+#if LV_COLOR_SCREEN_TRANSP
+ else if(disp->driver->screen_transp) {
+ if(dsc->src_buf == NULL) {
+ fill_argb(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
+ }
+ else {
+ map_argb(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
+ }
+ }
+#endif
+ else if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
+ if(dsc->src_buf == NULL) {
fill_normal(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
}
-#if LV_DRAW_COMPLEX
else {
- fill_blended(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride, dsc->blend_mode);
- }
-#endif
- }
- else {
- if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
map_normal(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
}
+ }
+ else {
#if LV_DRAW_COMPLEX
+ if(dsc->src_buf == NULL) {
+ fill_blended(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride, dsc->blend_mode);
+ }
else {
map_blended(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride, dsc->blend_mode);
}
@@ -203,6 +216,8 @@ static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_
for(y = 0; y < h; y++) {
for(x = 0; x < w; x++) {
if(mask[x]) {
+
+
disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, blend_area->x1 + x, blend_area->y1 + y, color,
(uint32_t)((uint32_t)opa * mask[x]) >> 8);
}
@@ -215,7 +230,6 @@ static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_
LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
{
- lv_disp_t * disp = _lv_refr_get_disp_refreshing();
int32_t w = lv_area_get_width(dest_area);
int32_t h = lv_area_get_height(dest_area);
@@ -243,19 +257,7 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_ar
for(x = 0; x < w; x++) {
if(last_dest_color.full != dest_buf[x].full) {
last_dest_color = dest_buf[x];
-
-#if LV_COLOR_SCREEN_TRANSP
- if(disp->driver->screen_transp) {
- lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, color, opa, &last_res_color,
- &last_res_color.ch.alpha);
- }
- else
-#else
- LV_UNUSED(disp);
-#endif
- {
- last_res_color = lv_color_mix_premult(color_premult, dest_buf[x], opa_inv);
- }
+ last_res_color = lv_color_mix_premult(color_premult, dest_buf[x], opa_inv);
}
dest_buf[x] = last_res_color;
}
@@ -335,17 +337,8 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_ar
if(*mask != last_mask) opa_tmp = *mask == LV_OPA_COVER ? opa :
(uint32_t)((uint32_t)(*mask) * opa) >> 8;
if(*mask != last_mask || last_dest_color.full != dest_buf[x].full) {
-#if LV_COLOR_SCREEN_TRANSP
- if(disp->driver->screen_transp) {
- lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, color, opa_tmp, &last_res_color,
- &last_res_color.ch.alpha);
- }
- else
-#endif
- {
- if(opa_tmp == LV_OPA_COVER) last_res_color = color;
- else last_res_color = lv_color_mix(color, dest_buf[x], opa_tmp);
- }
+ if(opa_tmp == LV_OPA_COVER) last_res_color = color;
+ else last_res_color = lv_color_mix(color, dest_buf[x], opa_tmp);
last_mask = *mask;
last_dest_color.full = dest_buf[x].full;
}
@@ -360,6 +353,118 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_ar
}
}
+#if LV_COLOR_SCREEN_TRANSP
+static inline void set_px_argb(uint8_t * buf, lv_color_t color, lv_opa_t opa)
+{
+ lv_color_t bg_color;
+ lv_color_t res_color;
+ lv_opa_t bg_opa = buf[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
+#if LV_COLOR_DEPTH == 8
+ bg_color.full = buf[0];
+ lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf[1]);
+ if(buf[1] <= LV_OPA_MIN) return;
+ buf[0] = res_color.full;
+#elif LV_COLOR_DEPTH == 16
+ bg_color.full = buf[0] + (buf[1] << 8);
+ lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf[2]);
+ if(buf[2] <= LV_OPA_MIN) return;
+ buf[0] = res_color.full & 0xff;
+ buf[1] = res_color.full >> 8;
+#elif LV_COLOR_DEPTH == 32
+ bg_color = *((lv_color_t *)buf);
+ lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf[3]);
+ if(buf[3] <= LV_OPA_MIN) return;
+ buf[0] = res_color.ch.blue;
+ buf[1] = res_color.ch.green;
+ buf[2] = res_color.ch.red;
+#endif
+
+}
+
+LV_ATTRIBUTE_FAST_MEM static void fill_argb(lv_color_t * dest_buf, const lv_area_t * dest_area,
+ lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
+{
+ uint8_t * dest_buf8 = (uint8_t *) dest_buf;
+ int32_t w = lv_area_get_width(dest_area);
+ int32_t h = lv_area_get_height(dest_area);
+
+ int32_t x;
+ int32_t y;
+
+ uint8_t ctmp[LV_IMG_PX_SIZE_ALPHA_BYTE];
+ lv_memcpy(ctmp, &color, sizeof(lv_color_t));
+ ctmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = opa;
+
+ /*No mask*/
+ if(mask == NULL) {
+ if(opa >= LV_OPA_MAX) {
+ for(x = 0; x < w; x++) {
+ lv_memcpy(dest_buf8, ctmp, LV_IMG_PX_SIZE_ALPHA_BYTE);
+ dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
+ }
+
+ dest_buf8 += (dest_stride - w) * LV_IMG_PX_SIZE_ALPHA_BYTE;
+
+ for(y = 1; y < h; y++) {
+ lv_memcpy(dest_buf8, (uint8_t *) dest_buf, w * LV_IMG_PX_SIZE_ALPHA_BYTE);
+ dest_buf8 += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ }
+ }
+ /*Has opacity*/
+ else {
+ uint8_t * dest_buf8_row = dest_buf8;
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ set_px_argb(dest_buf8, color, opa);
+ dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
+ }
+ dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ dest_buf8 = dest_buf8_row;
+ }
+ }
+ }
+ /*Masked*/
+ else {
+ /*Only the mask matters*/
+ if(opa >= LV_OPA_MAX) {
+ uint8_t * dest_buf8_row = dest_buf8;
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ set_px_argb(dest_buf8, color, *mask);
+ mask++;
+ dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
+ }
+ dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ dest_buf8 = dest_buf8_row;
+ }
+ }
+ /*With opacity*/
+ else {
+ /*Buffer the result color to avoid recalculating the same color*/
+ lv_opa_t last_mask = LV_OPA_TRANSP;
+ lv_opa_t opa_tmp = LV_OPA_TRANSP;
+
+ uint8_t * dest_buf8_row = dest_buf8;
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ if(*mask) {
+ if(*mask != last_mask) opa_tmp = *mask == LV_OPA_COVER ? opa :
+ (uint32_t)((uint32_t)(*mask) * opa) >> 8;
+
+ set_px_argb(dest_buf8, color, opa_tmp);
+ }
+ dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
+ mask++;
+ }
+ dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ dest_buf8 = dest_buf8_row;
+ mask += (mask_stride - w);
+ }
+ }
+ }
+}
+#endif
+
#if LV_DRAW_COMPLEX
static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area,
lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride,
@@ -477,10 +582,6 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
int32_t x;
int32_t y;
-#if LV_COLOR_SCREEN_TRANSP
- lv_disp_t * disp = _lv_refr_get_disp_refreshing();
-#endif
-
/*Simple fill (maybe with opacity), no masking*/
if(mask == NULL) {
if(opa >= LV_OPA_MAX) {
@@ -493,16 +594,7 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
else {
for(y = 0; y < h; y++) {
for(x = 0; x < w; x++) {
-#if LV_COLOR_SCREEN_TRANSP
- if(disp->driver->screen_transp) {
- lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa, &dest_buf[x],
- &dest_buf[x].ch.alpha);
- }
- else
-#endif
- {
- dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa);
- }
+ dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa);
}
dest_buf += dest_stride;
src_buf += src_stride;
@@ -523,11 +615,7 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
}
#else
for(x = 0; x < w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) {
-#if LV_COLOR_SCREEN_TRANSP
- MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
-#else
MAP_NORMAL_MASK_PX(x)
-#endif
}
uint32_t * mask32 = (uint32_t *)mask_tmp_x;
@@ -541,17 +629,10 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
}
else {
mask_tmp_x = (const lv_opa_t *)mask32;
-#if LV_COLOR_SCREEN_TRANSP
- MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
- MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 1)
- MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 2)
- MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 3)
-#else
MAP_NORMAL_MASK_PX(x)
MAP_NORMAL_MASK_PX(x + 1)
MAP_NORMAL_MASK_PX(x + 2)
MAP_NORMAL_MASK_PX(x + 3)
-#endif
}
}
mask32++;
@@ -559,11 +640,7 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
mask_tmp_x = (const lv_opa_t *)mask32;
for(; x < w ; x++) {
-#if LV_COLOR_SCREEN_TRANSP
- MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
-#else
MAP_NORMAL_MASK_PX(x)
-#endif
}
#endif
dest_buf += dest_stride;
@@ -577,16 +654,7 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
for(x = 0; x < w; x++) {
if(mask[x]) {
lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
-#if LV_COLOR_SCREEN_TRANSP
- if(disp->driver->screen_transp) {
- lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa_tmp,
- &dest_buf[x], &dest_buf[x].ch.alpha);
- }
- else
-#endif
- {
- dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa_tmp);
- }
+ dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa_tmp);
}
}
dest_buf += dest_stride;
@@ -596,6 +664,101 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
}
}
}
+
+
+
+#if LV_COLOR_SCREEN_TRANSP
+LV_ATTRIBUTE_FAST_MEM static void map_argb(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
+ const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
+
+{
+
+ uint8_t * dest_buf8 = (uint8_t *) dest_buf;
+
+ int32_t w = lv_area_get_width(dest_area);
+ int32_t h = lv_area_get_height(dest_area);
+
+ int32_t x;
+ int32_t y;
+
+ /*Simple fill (maybe with opacity), no masking*/
+ if(mask == NULL) {
+ if(opa >= LV_OPA_MAX) {
+#if LV_COLOR_DEPTH == 32
+ for(y = 0; y < h; y++) {
+ lv_memcpy(dest_buf, src_buf, w * sizeof(lv_color_t));
+ dest_buf += dest_stride;
+ src_buf += src_stride;
+ }
+#else
+ uint8_t * dest_buf8_row = dest_buf8;
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ set_px_argb(dest_buf8, src_buf[x], LV_OPA_COVER);
+ dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
+ }
+
+ dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ dest_buf8 = dest_buf8_row;
+ src_buf += src_stride;
+ }
+#endif
+ }
+ else {
+ uint8_t * dest_buf8_row = dest_buf8;
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ set_px_argb(dest_buf8, src_buf[x], opa);
+ dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
+ }
+
+ dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ dest_buf8 = dest_buf8_row;
+ src_buf += src_stride;
+ }
+ }
+ }
+ /*Masked*/
+ else {
+ /*Only the mask matters*/
+ if(opa > LV_OPA_MAX) {
+ uint8_t * dest_buf8_row = dest_buf8;
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ set_px_argb(dest_buf8, src_buf[x], mask[x]);
+ dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
+
+ }
+ dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ dest_buf8 = dest_buf8_row;
+ src_buf += src_stride;
+ mask += mask_stride;
+ }
+ }
+ /*Handle opa and mask values too*/
+ else {
+ uint8_t * dest_buf8_row = dest_buf8;
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ if(mask[x]) {
+ lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
+
+ set_px_argb(dest_buf8, src_buf[x], opa_tmp);
+
+ }
+ dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
+ }
+ dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
+ dest_buf8 = dest_buf8_row;
+ src_buf += src_stride;
+ mask += mask_stride;
+ }
+ }
+ }
+}
+#endif
+
+
#if LV_DRAW_COMPLEX
static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
diff --git a/src/draw/sw/lv_draw_sw_img.c b/src/draw/sw/lv_draw_sw_img.c
index 339a46db4..3489420c4 100644
--- a/src/draw/sw/lv_draw_sw_img.c
+++ b/src/draw/sw/lv_draw_sw_img.c
@@ -17,6 +17,7 @@
/*********************
* DEFINES
*********************/
+#define MAX_BUF_SIZE (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing())
/**********************
* TYPEDEFS
@@ -25,6 +26,8 @@
/**********************
* STATIC PROTOTYPES
**********************/
+static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w, lv_coord_t src_h,
+ lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
/**********************
* STATIC VARIABLES
@@ -38,6 +41,7 @@
* GLOBAL FUNCTIONS
**********************/
+
LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc,
const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t cf)
{
@@ -46,278 +50,199 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_c
lv_area_copy(&draw_area, draw_ctx->clip_area);
bool mask_any = lv_draw_mask_is_any(&draw_area);
+ bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false;
+ lv_area_t blend_area;
lv_draw_sw_blend_dsc_t blend_dsc;
- lv_memset_00(&blend_dsc, sizeof(blend_dsc));
+
+ lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t));
blend_dsc.opa = draw_dsc->opa;
blend_dsc.blend_mode = draw_dsc->blend_mode;
+ blend_dsc.blend_area = &blend_area;
/*The simplest case just copy the pixels into the draw_buf*/
- if(!mask_any && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE &&
- cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
- blend_dsc.blend_area = coords;
+ if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
blend_dsc.src_buf = (const lv_color_t *)src_buf;
+
+ blend_dsc.blend_area = coords;
lv_draw_sw_blend(draw_ctx, &blend_dsc);
}
/*In the other cases every pixel need to be checked one-by-one*/
else {
- //#if LV_DRAW_COMPLEX
- /*The pixel size in byte is different if an alpha byte is added too*/
- uint8_t px_size_byte = cf == LV_IMG_CF_TRUE_COLOR_ALPHA ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
+ blend_area.x1 = draw_ctx->clip_area->x1;
+ blend_area.x2 = draw_ctx->clip_area->x2;
+ blend_area.y1 = draw_ctx->clip_area->y1;
+ blend_area.y2 = draw_ctx->clip_area->y2;
- /*Go to the first displayed pixel of the map*/
- int32_t src_stride = lv_area_get_width(coords);
+ lv_coord_t src_w = lv_area_get_width(coords);
+ lv_coord_t src_h = lv_area_get_height(coords);
+ lv_coord_t blend_h = lv_area_get_height(&blend_area);
+ lv_coord_t blend_w = lv_area_get_width(&blend_area);
- lv_color_t c;
- lv_color_t chroma_keyed_color = LV_COLOR_CHROMA_KEY;
- uint32_t px_i = 0;
-
- const uint8_t * map_px;
-
- lv_coord_t draw_area_h = lv_area_get_height(&draw_area);
- lv_coord_t draw_area_w = lv_area_get_width(&draw_area);
-
- lv_area_t blend_area;
- blend_area.x1 = draw_area.x1;
- blend_area.x2 = draw_area.x2;
- blend_area.y1 = draw_area.y1;
- blend_area.y2 = blend_area.y1;
- blend_dsc.blend_area = &blend_area;
-
- bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false;
- /*Simple ARGB image. Handle it as special case because it's very common*/
- if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR_ALPHA && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
- uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing());
- uint32_t mask_buf_size = lv_area_get_size(&draw_area) > (uint32_t) hor_res ? hor_res : lv_area_get_size(&draw_area);
- lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
- lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
- blend_dsc.mask_buf = mask_buf;
- blend_dsc.mask_area = &blend_area;
- blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
- blend_dsc.src_buf = src_buf_rgb;
-
- const uint8_t * src_buf_tmp = src_buf;
- src_buf_tmp += src_stride * (draw_area.y1 - coords->y1) * px_size_byte;
- src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte;
-
- int32_t x;
- int32_t y;
- for(y = 0; y < draw_area_h; y++) {
- map_px = src_buf_tmp;
- for(x = 0; x < draw_area_w; x++, map_px += px_size_byte, px_i++) {
- lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
- mask_buf[px_i] = px_opa;
- if(px_opa) {
-#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
- src_buf_rgb[px_i].full = map_px[0];
-#elif LV_COLOR_DEPTH == 16
- src_buf_rgb[px_i].full = map_px[0] + (map_px[1] << 8);
-#elif LV_COLOR_DEPTH == 32
- src_buf_rgb[px_i].full = *((uint32_t *)map_px);
-#endif
- }
-#if LV_COLOR_DEPTH == 32
- src_buf_rgb[px_i].ch.alpha = 0xFF;
-#endif
- }
-
- src_buf_tmp += src_stride * px_size_byte;
- if(px_i + draw_area_w <= mask_buf_size) {
- blend_area.y2 ++;
- }
- else {
- lv_draw_sw_blend(draw_ctx, &blend_dsc);
-
- blend_area.y1 = blend_area.y2 + 1;
- blend_area.y2 = blend_area.y1;
-
- px_i = 0;
- }
- }
- /*Flush the last part*/
- if(blend_area.y1 != blend_area.y2) {
- blend_area.y2--;
- lv_draw_sw_blend(draw_ctx, &blend_dsc);
- }
-
- lv_mem_buf_release(mask_buf);
- lv_mem_buf_release(src_buf_rgb);
+ uint32_t max_buf_size = MAX_BUF_SIZE;
+ uint32_t blend_size = lv_area_get_size(&blend_area);
+ uint32_t buf_h;
+ uint32_t buf_w = blend_w;
+ if(blend_size <= max_buf_size) {
+ buf_h = blend_h;
}
- /*Most complicated case: transform or other mask or chroma keyed*/
else {
- /*Build the image and a mask line-by-line*/
- uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing());
- uint32_t mask_buf_size = lv_area_get_size(&draw_area) > hor_res ? hor_res : lv_area_get_size(&draw_area);
- lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
- lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
- blend_dsc.mask_buf = mask_buf;
- blend_dsc.mask_area = &blend_area;
- blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
- blend_dsc.src_buf = src_buf_rgb;
-
- const uint8_t * src_buf_tmp = NULL;
-#if LV_DRAW_COMPLEX
- lv_img_transform_dsc_t trans_dsc;
- lv_memset_00(&trans_dsc, sizeof(lv_img_transform_dsc_t));
- if(transform) {
- trans_dsc.cfg.angle = draw_dsc->angle;
- trans_dsc.cfg.zoom = draw_dsc->zoom;
- trans_dsc.cfg.src = src_buf;
- trans_dsc.cfg.src_w = src_stride;
- trans_dsc.cfg.src_h = lv_area_get_height(coords);
- trans_dsc.cfg.cf = cf;
- trans_dsc.cfg.pivot_x = draw_dsc->pivot.x;
- trans_dsc.cfg.pivot_y = draw_dsc->pivot.y;
- trans_dsc.cfg.color = draw_dsc->recolor;
- trans_dsc.cfg.antialias = draw_dsc->antialias;
-
- _lv_img_buf_transform_init(&trans_dsc);
- }
- else
-#endif
- {
- src_buf_tmp = src_buf;
- src_buf_tmp += src_stride * (draw_area.y1 - coords->y1) * px_size_byte;
- src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte;
- }
-
- uint16_t recolor_premult[3] = {0};
- lv_opa_t recolor_opa_inv = 255 - draw_dsc->recolor_opa;
- if(draw_dsc->recolor_opa != 0) {
- lv_color_premult(draw_dsc->recolor, draw_dsc->recolor_opa, recolor_premult);
- }
-
- blend_dsc.mask_res = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle ||
- draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
-
- /*Prepare the `mask_buf`if there are other masks*/
- if(mask_any) {
- lv_memset_ff(mask_buf, mask_buf_size);
- }
-
- int32_t x;
- int32_t y;
-#if LV_DRAW_COMPLEX
- int32_t rot_y = blend_area.y1 - coords->y1;
-#endif
- for(y = 0; y < draw_area_h; y++) {
- map_px = src_buf_tmp;
-#if LV_DRAW_COMPLEX
- uint32_t px_i_start = px_i;
- int32_t rot_x = blend_area.x1 - coords->x1;
-#endif
-
- for(x = 0; x < draw_area_w; x++, px_i++, map_px += px_size_byte) {
-
-#if LV_DRAW_COMPLEX
- if(transform) {
-
- /*Transform*/
- bool ret;
- ret = _lv_img_buf_transform(&trans_dsc, rot_x + x, rot_y + y);
- if(ret == false) {
- mask_buf[px_i] = LV_OPA_TRANSP;
- continue;
- }
- else {
- mask_buf[px_i] = trans_dsc.res.opa;
- c.full = trans_dsc.res.color.full;
- }
- }
- /*No transform*/
- else
-#endif
- {
- if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
- lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
- mask_buf[px_i] = px_opa;
- if(px_opa == 0) {
-#if LV_COLOR_DEPTH == 32
- src_buf_rgb[px_i].full = 0;
-#endif
- continue;
- }
- }
- else {
- mask_buf[px_i] = 0xFF;
- }
-
-#if LV_COLOR_DEPTH == 1
- c.full = map_px[0];
-#elif LV_COLOR_DEPTH == 8
- c.full = map_px[0];
-#elif LV_COLOR_DEPTH == 16
- c.full = map_px[0] + (map_px[1] << 8);
-#elif LV_COLOR_DEPTH == 32
- c.full = *((uint32_t *)map_px);
- c.ch.alpha = 0xFF;
-#endif
- if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
- if(c.full == chroma_keyed_color.full) {
- mask_buf[px_i] = LV_OPA_TRANSP;
-#if LV_COLOR_DEPTH == 32
- src_buf_rgb[px_i].full = 0;
-#endif
- continue;
- }
- }
-
- }
- if(draw_dsc->recolor_opa != 0) {
- c = lv_color_mix_premult(recolor_premult, c, recolor_opa_inv);
- }
-
- src_buf_rgb[px_i].full = c.full;
- }
-#if LV_DRAW_COMPLEX
- /*Apply the masks if any*/
- if(mask_any) {
- lv_draw_mask_res_t mask_res_sub;
- mask_res_sub = lv_draw_mask_apply(mask_buf + px_i_start, blend_area.x1,
- y + draw_area.y1, draw_area_w);
- if(mask_res_sub == LV_DRAW_MASK_RES_TRANSP) {
- lv_memset_00(mask_buf + px_i_start, draw_area_w);
- blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
- }
- else if(mask_res_sub == LV_DRAW_MASK_RES_CHANGED) {
- blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
- }
- }
-#endif
-
- src_buf_tmp += src_stride * px_size_byte;
- if(px_i + draw_area_w < mask_buf_size) {
- blend_area.y2 ++;
- }
- else {
- lv_draw_sw_blend(draw_ctx, &blend_dsc);
-
- blend_area.y1 = blend_area.y2 + 1;
- blend_area.y2 = blend_area.y1;
-
- px_i = 0;
- blend_dsc.mask_res = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle ||
- draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
-
- /*Prepare the `mask_buf`if there are other masks*/
- if(mask_any) {
- lv_memset_ff(mask_buf, mask_buf_size);
- }
- }
- }
-
- /*Flush the last part*/
- if(blend_area.y1 != blend_area.y2) {
- blend_area.y2--;
- lv_draw_sw_blend(draw_ctx, &blend_dsc);
- }
-
- lv_mem_buf_release(mask_buf);
- lv_mem_buf_release(src_buf_rgb);
+ /*Round to full lines*/
+ buf_h = max_buf_size / blend_w;
}
+
+ /*Create buffers and masks*/
+ uint32_t buf_size = buf_w * buf_h;
+
+ lv_color_t * rgb_buf = lv_mem_buf_get(buf_size * sizeof(lv_color_t));
+ lv_opa_t * mask_buf = lv_mem_buf_get(buf_size);
+ blend_dsc.mask_buf = mask_buf;
+ blend_dsc.mask_area = &blend_area;
+ blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
+ blend_dsc.src_buf = rgb_buf;
+ lv_coord_t y_last = blend_area.y2;
+ blend_area.y2 = blend_area.y1 + buf_h - 1;
+
+ lv_draw_mask_res_t mask_res_def = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle ||
+ draw_dsc->zoom != LV_IMG_ZOOM_NONE) ?
+ LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
+ blend_dsc.mask_res = mask_res_def;
+
+ while(blend_area.y1 <= y_last) {
+ /*Apply transformations if any or separate the channels*/
+ lv_area_t transform_area;
+ lv_area_copy(&transform_area, &blend_area);
+ lv_area_move(&transform_area, -coords->x1, -coords->y1);
+ if(transform) {
+ lv_draw_transform(draw_ctx, &transform_area, src_buf, src_w, src_h, src_w,
+ draw_dsc, cf, rgb_buf, mask_buf);
+ }
+ else {
+ convert_cb(&transform_area, src_buf, src_w, src_h, src_w, draw_dsc, cf, rgb_buf, mask_buf);
+ }
+
+ /*Apply recolor*/
+ if(draw_dsc->recolor_opa > LV_OPA_MIN) {
+ uint16_t premult_v[3];
+ lv_opa_t recolor_opa = draw_dsc->recolor_opa;
+ lv_color_t recolor = draw_dsc->recolor;
+ lv_color_premult(recolor, recolor_opa, premult_v);
+ uint32_t i;
+ for(i = 0; i < buf_size; i++) {
+ rgb_buf[i] = lv_color_mix_premult(premult_v, rgb_buf[i], recolor_opa);
+ }
+ }
+#if LV_DRAW_COMPLEX
+ /*Apply the masks if any*/
+ if(mask_any) {
+ lv_coord_t y;
+ lv_opa_t * mask_buf_tmp = mask_buf;
+ for(y = blend_area.y1; y <= blend_area.y2; y++) {
+ lv_draw_mask_res_t mask_res_line;
+ mask_res_line = lv_draw_mask_apply(mask_buf_tmp, blend_area.x1, y, blend_w);
+
+ if(mask_res_line == LV_DRAW_MASK_RES_TRANSP) {
+ lv_memset_00(mask_buf_tmp, blend_w);
+ blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
+ }
+ else if(mask_res_line == LV_DRAW_MASK_RES_CHANGED) {
+ blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
+ }
+ mask_buf_tmp += blend_w;
+ }
+ }
+#endif
+
+ /*Blend*/
+ lv_draw_sw_blend(draw_ctx, &blend_dsc);
+
+ /*Go the the next lines*/
+ blend_area.y1 = blend_area.y2 + 1;
+ blend_area.y2 = blend_area.y1 + buf_h - 1;
+ if(blend_area.y2 > y_last) blend_area.y2 = y_last;
+ }
+
+ lv_mem_buf_release(mask_buf);
+ lv_mem_buf_release(rgb_buf);
}
}
/**********************
* STATIC FUNCTIONS
**********************/
+
+/* Separate the image channels to RGB and Alpha to match LV_COLOR_DEPTH settings*/
+static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w, lv_coord_t src_h,
+ lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf)
+{
+ LV_UNUSED(draw_dsc);
+ LV_UNUSED(src_h);
+ LV_UNUSED(src_w);
+
+ const uint8_t * src_tmp8 = (const uint8_t *)src_buf;
+ lv_coord_t y;
+ lv_coord_t x;
+
+ if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
+ uint32_t px_cnt = lv_area_get_size(dest_area);
+ lv_memset_ff(abuf, px_cnt);
+
+ src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t);
+ uint32_t dest_w = lv_area_get_width(dest_area);
+ uint32_t dest_w_byte = dest_w * sizeof(lv_color_t);
+
+ lv_coord_t src_stride_byte = src_stride * sizeof(lv_color_t);
+ lv_color_t * cbuf_tmp = cbuf;
+ for(y = dest_area->y1; y <= dest_area->y2; y++) {
+ lv_memcpy(cbuf_tmp, src_tmp8, dest_w_byte);
+ src_tmp8 += src_stride_byte;
+ cbuf_tmp += dest_w;
+ }
+
+ /*Make "holes" for with Chroma keying*/
+ if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
+ uint32_t i;
+ lv_color_t chk = LV_COLOR_CHROMA_KEY;
+#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
+ uint8_t * cbuf_uint = (uint8_t *)cbuf;
+ uint8_t chk_v = chk.full;
+#elif LV_COLOR_DEPTH == 16
+ uint16_t * cbuf_uint = (uint16_t *)cbuf;
+ uint16_t chk_v = chk.full;
+#elif LV_COLOR_DEPTH == 32
+ uint32_t * cbuf_uint = (uint32_t *)cbuf;
+ uint32_t chk_v = chk.full;
+#endif
+ for(i = 0; i < px_cnt; i++) {
+ if(chk_v == cbuf_uint[i]) abuf[i] = 0x00;
+ }
+ }
+ }
+ else if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
+ src_tmp8 += (src_stride * dest_area->y1 * LV_IMG_PX_SIZE_ALPHA_BYTE) + dest_area->x1 * LV_IMG_PX_SIZE_ALPHA_BYTE;
+
+ lv_coord_t src_new_line_step_px = (src_stride - lv_area_get_width(dest_area));
+ lv_coord_t src_new_line_step_byte = src_new_line_step_px * LV_IMG_PX_SIZE_ALPHA_BYTE;
+
+ lv_coord_t dest_h = lv_area_get_height(dest_area);
+ lv_coord_t dest_w = lv_area_get_width(dest_area);
+ for(y = 0; y < dest_h; y++) {
+ for(x = 0; x < dest_w; x++) {
+ abuf[x] = src_tmp8[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
+#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
+ cbuf[x].full = *src_tmp8;
+#elif LV_COLOR_DEPTH == 16
+ cbuf[x].full = *src_tmp8 + ((*(src_tmp8 + 1)) << 8);
+#elif LV_COLOR_DEPTH == 32
+ cbuf[x] = *((lv_color_t *) src_tmp8);
+ cbuf[x].ch.alpha = 0xff;
+#endif
+ src_tmp8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
+
+ }
+ cbuf += dest_w;
+ abuf += dest_w;
+ src_tmp8 += src_new_line_step_byte;
+ }
+ }
+}
diff --git a/src/draw/sw/lv_draw_sw_transform.c b/src/draw/sw/lv_draw_sw_transform.c
new file mode 100644
index 000000000..b47cc32b5
--- /dev/null
+++ b/src/draw/sw/lv_draw_sw_transform.c
@@ -0,0 +1,363 @@
+/**
+ * @file lv_draw_sw_tranform.c
+ *
+ */
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "lv_draw_sw.h"
+#include "../../misc/lv_assert.h"
+#include "../../misc/lv_area.h"
+
+#if LV_DRAW_COMPLEX
+/*********************
+ * DEFINES
+ *********************/
+
+/**********************
+ * TYPEDEFS
+ **********************/
+typedef struct {
+ int32_t x_in;
+ int32_t y_in;
+ int32_t x_out;
+ int32_t y_out;
+ int32_t sinma;
+ int32_t cosma;
+ int32_t zoom;
+ int32_t angle;
+ lv_point_t pivot;
+} point_transform_dsc_t;
+
+/**********************
+ * STATIC PROTOTYPES
+ **********************/
+/**
+ * Transform a point with 1/256 precision (the output coordinates are upscaled by 256)
+ * @param t pointer to n initialized `point_transform_dsc_t` structure
+ * @param xin X coordinate to rotate
+ * @param yin Y coordinate to rotate
+ * @param xout upscaled, transformed X
+ * @param yout upscaled, transformed Y
+ */
+static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int32_t yin, int32_t * xout,
+ int32_t * yout);
+
+static void argb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
+ int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
+ int32_t x_end, lv_color_t * cbuf, uint8_t * abuf);
+
+static void rgb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
+ int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
+ int32_t x_end, lv_color_t * cbuf, uint8_t * abuf);
+
+static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
+ int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
+ int32_t x_end, lv_color_t * cbuf, uint8_t * abuf, bool has_alpha);
+
+/**********************
+ * STATIC VARIABLES
+ **********************/
+
+/**********************
+ * MACROS
+ **********************/
+
+/**********************
+ * GLOBAL FUNCTIONS
+ **********************/
+
+void lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
+ lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
+ const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf)
+{
+ LV_UNUSED(draw_ctx);
+
+ point_transform_dsc_t tr_dsc;
+ tr_dsc.angle = -draw_dsc->angle;
+ tr_dsc.zoom = (256 * 256) / draw_dsc->zoom;
+ tr_dsc.pivot = draw_dsc->pivot;
+
+ int32_t angle_low = tr_dsc.angle / 10;
+ int32_t angle_high = angle_low + 1;
+ int32_t angle_rem = tr_dsc.angle - (angle_low * 10);
+
+ int32_t s1 = lv_trigo_sin(angle_low);
+ int32_t s2 = lv_trigo_sin(angle_high);
+
+ int32_t c1 = lv_trigo_sin(angle_low + 90);
+ int32_t c2 = lv_trigo_sin(angle_high + 90);
+
+ tr_dsc.sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
+ tr_dsc.cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
+ tr_dsc.sinma = tr_dsc.sinma >> (LV_TRIGO_SHIFT - 10);
+ tr_dsc.cosma = tr_dsc.cosma >> (LV_TRIGO_SHIFT - 10);
+
+ lv_coord_t dest_w = lv_area_get_width(dest_area);
+ lv_coord_t dest_h = lv_area_get_height(dest_area);
+ lv_coord_t y;
+ bool has_alpha = lv_img_cf_has_alpha(cf);
+ for(y = 0; y < dest_h; y++) {
+ int32_t xs1_ups, ys1_ups, xs2_ups, ys2_ups;
+
+ transform_point_upscaled(&tr_dsc, dest_area->x1, dest_area->y1 + y, &xs1_ups, &ys1_ups);
+ transform_point_upscaled(&tr_dsc, dest_area->x2, dest_area->y1 + y, &xs2_ups, &ys2_ups);
+
+ int32_t xs_diff = xs2_ups - xs1_ups;
+ int32_t ys_diff = ys2_ups - ys1_ups;
+ int32_t xs_step_256 = 0;
+ int32_t ys_step_256 = 0;
+ if(dest_w > 1) {
+ xs_step_256 = (256 * xs_diff) / (dest_w - 1);
+ ys_step_256 = (256 * ys_diff) / (dest_w - 1);
+ }
+ int32_t xs_ups = xs1_ups + 1 * xs_step_256 / 2 / 256; /*Init. + go the center of the pixel*/
+ int32_t ys_ups = ys1_ups + 1 * ys_step_256 / 2 / 256;
+
+ if(draw_dsc->antialias == 0) {
+ if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
+ argb_no_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf);
+ }
+ else {
+ rgb_no_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf);
+ }
+ }
+ else {
+ argb_and_rgb_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf,
+ has_alpha);
+ }
+ cbuf += dest_w;
+ abuf += dest_w;
+ }
+}
+
+/**********************
+ * STATIC FUNCTIONS
+ **********************/
+
+static void rgb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
+ int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
+ int32_t x_end, lv_color_t * cbuf, uint8_t * abuf)
+{
+ int32_t xs_ups_start = xs_ups;
+ int32_t ys_ups_start = ys_ups;
+
+ lv_memset_ff(abuf, x_end);
+
+ lv_coord_t x;
+ for(x = 0; x < x_end; x++) {
+ xs_ups = xs_ups_start + ((xs_step * x) >> 8);
+ ys_ups = ys_ups_start + ((ys_step * x) >> 8);
+
+ int32_t xs_int = xs_ups >> 8;
+ int32_t ys_int = ys_ups >> 8;
+ if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
+ abuf[x] = 0;
+ }
+ else {
+ const uint8_t * src_tmp = src;
+ src_tmp += (ys_int * src_stride * sizeof(lv_color_t)) + xs_int * sizeof(lv_color_t);
+
+#if LV_COLOR_DEPTH == 8
+ cbuf[x].full = src_tmp[0];
+#elif LV_COLOR_DEPTH == 16
+ cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8);
+#elif LV_COLOR_DEPTH == 32
+ cbuf[x].full = *((uint32_t *)src_tmp);
+#endif
+ }
+ }
+}
+
+static void argb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
+ int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
+ int32_t x_end, lv_color_t * cbuf, uint8_t * abuf)
+{
+ int32_t xs_ups_start = xs_ups;
+ int32_t ys_ups_start = ys_ups;
+
+ lv_coord_t x;
+ for(x = 0; x < x_end; x++) {
+ xs_ups = xs_ups_start + ((xs_step * x) >> 8);
+ ys_ups = ys_ups_start + ((ys_step * x) >> 8);
+
+ int32_t xs_int = xs_ups >> 8;
+ int32_t ys_int = ys_ups >> 8;
+ if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
+ abuf[x] = 0;
+ }
+ else {
+ const uint8_t * src_tmp = src;
+ src_tmp += (ys_int * src_stride * LV_IMG_PX_SIZE_ALPHA_BYTE) + xs_int * LV_IMG_PX_SIZE_ALPHA_BYTE;
+
+#if LV_COLOR_DEPTH == 8
+ cbuf[x].full = src_tmp[0];
+#elif LV_COLOR_DEPTH == 16
+ cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8);
+#elif LV_COLOR_DEPTH == 32
+ cbuf[x].full = *((uint32_t *)src_tmp);
+#endif
+ abuf[x] = src_tmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
+ }
+ }
+}
+
+static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
+ int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
+ int32_t x_end, lv_color_t * cbuf, uint8_t * abuf, bool has_alpha)
+{
+
+ int32_t xs_ups_start = xs_ups;
+ int32_t ys_ups_start = ys_ups;
+ const int32_t px_size = has_alpha ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
+
+ lv_coord_t x;
+ for(x = 0; x < x_end; x++) {
+ xs_ups = xs_ups_start + ((xs_step * x) >> 8);
+ ys_ups = ys_ups_start + ((ys_step * x) >> 8);
+
+ int32_t xs_int = xs_ups >> 8;
+ int32_t ys_int = ys_ups >> 8;
+
+ /*Fully out of the image*/
+ if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
+ abuf[x] = 0x00;
+ continue;
+ }
+
+
+ /*Get the direction the hor and ver neighbor
+ *`fract` will be in range of 0x00..0xFF and `next` (+/-1) indicates the direction*/
+ int32_t xs_fract = xs_ups & 0xFF;
+ int32_t ys_fract = ys_ups & 0xFF;
+
+ int32_t x_next;
+ int32_t y_next;
+ if(xs_fract < 0x80) {
+ x_next = -1;
+ xs_fract = (0x7F - xs_fract) * 2;
+ }
+ else {
+ x_next = 1;
+ xs_fract = (xs_fract - 0x80) * 2;
+ }
+ if(ys_fract < 0x80) {
+ y_next = -1;
+ ys_fract = (0x7F - ys_fract) * 2;
+ }
+ else {
+ y_next = 1;
+ ys_fract = (ys_fract - 0x80) * 2;
+ }
+
+ const uint8_t * src_tmp = src;
+ src_tmp += (ys_int * src_stride * px_size) + xs_int * px_size;
+
+ if(xs_int + x_next >= 0 &&
+ xs_int + x_next <= src_w - 1 &&
+ ys_int + y_next >= 0 &&
+ ys_int + y_next <= src_h - 1) {
+
+ const uint8_t * px_base = src_tmp;
+ const uint8_t * px_hor = src_tmp + x_next * px_size;
+ const uint8_t * px_ver = src_tmp + y_next * src_stride * px_size;
+ lv_color_t c_base;
+ lv_color_t c_ver;
+ lv_color_t c_hor;
+
+ if(has_alpha) {
+ lv_opa_t a_base = px_base[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
+ lv_opa_t a_ver = px_ver[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
+ lv_opa_t a_hor = px_hor[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
+
+ if(a_ver != a_base) a_ver = ((a_ver * ys_fract) + (a_base * (0x100 - ys_fract))) >> 8;
+ if(a_hor != a_base) a_hor = ((a_hor * xs_fract) + (a_base * (0x100 - xs_fract))) >> 8;
+ abuf[x] = (a_ver + a_hor) >> 1;
+
+ if(abuf[x] == 0x00) continue;
+
+#if LV_COLOR_DEPTH == 8
+ c_base.full = px_base[0];
+ c_ver.full = px_ver[0];
+ c_hor.full = px_hor[0];
+#elif LV_COLOR_DEPTH == 16
+ c_base.full = px_base[0] + (px_base[1] << 8);
+ c_ver.full = px_ver[0] + (px_ver[1] << 8);
+ c_hor.full = px_hor[0] + (px_hor[1] << 8);
+#elif LV_COLOR_DEPTH == 32
+ c_base.full = *((uint32_t *)px_base);
+ c_ver.full = *((uint32_t *)px_ver);
+ c_hor.full = *((uint32_t *)px_hor);
+#endif
+ }
+ /*No alpha channel -> RGB*/
+ else {
+ c_base = *((const lv_color_t *) px_base);
+ c_hor = *((const lv_color_t *) px_hor);
+ c_ver = *((const lv_color_t *) px_ver);
+ abuf[x] = 0xff;
+ }
+
+ if(c_base.full == c_ver.full && c_base.full == c_hor.full) {
+ cbuf[x] = c_base;
+ }
+ else {
+ c_ver = lv_color_mix(c_ver, c_base, ys_fract);
+ c_hor = lv_color_mix(c_hor, c_base, xs_fract);
+ cbuf[x] = lv_color_mix(c_hor, c_ver, LV_OPA_50);
+ }
+ }
+ /*Partially out of the image*/
+ else {
+#if LV_COLOR_DEPTH == 8
+ cbuf[x].full = src_tmp[0];
+#elif LV_COLOR_DEPTH == 16
+ cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8);
+#elif LV_COLOR_DEPTH == 32
+ cbuf[x].full = *((uint32_t *)src_tmp);
+#endif
+
+ lv_opa_t a = has_alpha ? src_tmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1] : 0xff;
+
+ if((xs_int == 0 && x_next < 0) || (xs_int == src_w - 1 && x_next > 0)) {
+ abuf[x] = (a * (0xFF - xs_fract)) >> 8;
+ }
+ else if((ys_int == 0 && y_next < 0) || (ys_int == src_h - 1 && y_next > 0)) {
+ abuf[x] = (a * (0xFF - ys_fract)) >> 8;
+ }
+ else {
+ abuf[x] = 0x00;
+ }
+ }
+ }
+}
+
+static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int32_t yin, int32_t * xout,
+ int32_t * yout)
+{
+ if(t->angle == 0 && t->zoom == LV_IMG_ZOOM_NONE) {
+ *xout = xin << 8;
+ *yout = yin << 8;
+ return;
+ }
+
+ xin -= t->pivot.x;
+ yin -= t->pivot.y;
+
+ if(t->angle == 0) {
+ *xout = ((int32_t)(xin * t->zoom)) + (t->pivot.x << 8);
+ *yout = ((int32_t)(yin * t->zoom)) + (t->pivot.y << 8);
+ }
+ else if(t->zoom == LV_IMG_ZOOM_NONE) {
+ *xout = ((t->cosma * xin - t->sinma * yin) >> 2) + (t->pivot.x << 8);
+ *yout = ((t->sinma * xin + t->cosma * yin) >> 2) + (t->pivot.y << 8);
+ }
+ else {
+ *xout = (((t->cosma * xin - t->sinma * yin) * t->zoom) >> 10) + (t->pivot.x << 8);
+ *yout = (((t->sinma * xin + t->cosma * yin) * t->zoom) >> 10) + (t->pivot.y << 8);
+ }
+}
+
+#endif
+
diff --git a/src/extra/others/snapshot/lv_snapshot.c b/src/extra/others/snapshot/lv_snapshot.c
index f48b5f728..1b2275115 100644
--- a/src/extra/others/snapshot/lv_snapshot.c
+++ b/src/extra/others/snapshot/lv_snapshot.c
@@ -47,6 +47,7 @@ uint32_t lv_snapshot_buf_size_needed(lv_obj_t * obj, lv_img_cf_t cf)
{
LV_ASSERT_NULL(obj);
switch(cf) {
+ case LV_IMG_CF_TRUE_COLOR:
case LV_IMG_CF_TRUE_COLOR_ALPHA:
case LV_IMG_CF_ALPHA_1BIT:
case LV_IMG_CF_ALPHA_2BIT:
@@ -87,6 +88,7 @@ lv_res_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t *
LV_ASSERT_NULL(buf);
switch(cf) {
+ case LV_IMG_CF_TRUE_COLOR:
case LV_IMG_CF_TRUE_COLOR_ALPHA:
case LV_IMG_CF_ALPHA_1BIT:
case LV_IMG_CF_ALPHA_2BIT:
@@ -126,7 +128,6 @@ lv_res_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t *
lv_memset_00(&fake_disp, sizeof(lv_disp_t));
fake_disp.driver = &driver;
-
lv_draw_ctx_t * draw_ctx = lv_mem_alloc(obj_disp->driver->draw_ctx_size);
LV_ASSERT_MALLOC(draw_ctx);
if(draw_ctx == NULL) return LV_RES_INV;
@@ -140,7 +141,7 @@ lv_res_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t *
lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
_lv_refr_set_disp_refreshing(&fake_disp);
- lv_refr_obj(draw_ctx, obj);
+ lv_obj_redraw(draw_ctx, obj);
_lv_refr_set_disp_refreshing(refr_ori);
obj_disp->driver->draw_ctx_deinit(fake_disp.driver, draw_ctx);
diff --git a/src/hal/lv_hal_disp.c b/src/hal/lv_hal_disp.c
index 56f6b3acb..20f171217 100644
--- a/src/hal/lv_hal_disp.c
+++ b/src/hal/lv_hal_disp.c
@@ -507,18 +507,6 @@ lv_coord_t lv_disp_get_dpi(const lv_disp_t * disp)
*/
LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv)
{
- /*If the screen is transparent initialize it when the flushing is ready*/
-#if LV_COLOR_SCREEN_TRANSP
- if(disp_drv->screen_transp) {
- if(disp_drv->clear_cb) {
- disp_drv->clear_cb(disp_drv, disp_drv->draw_buf->buf_act, disp_drv->draw_buf->size);
- }
- else {
- lv_memset_00(disp_drv->draw_buf->buf_act, disp_drv->draw_buf->size * sizeof(lv_color32_t));
- }
- }
-#endif
-
disp_drv->draw_buf->flushing = 0;
disp_drv->draw_buf->flushing_last = 0;
}
@@ -687,28 +675,35 @@ static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, l
lv_img_buf_set_px_alpha(d, x, y, br);
}
-static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x,
- lv_coord_t y,
+static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w,
+ lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
- if(opa <= LV_OPA_MIN) return;
- lv_img_dsc_t d;
- d.data = buf;
- d.header.always_zero = 0;
- d.header.h = 1; /*Doesn't matter*/;
- d.header.w = buf_w;
- d.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
+ uint8_t * buf_px = buf + (buf_w * y * LV_IMG_PX_SIZE_ALPHA_BYTE + x * LV_IMG_PX_SIZE_ALPHA_BYTE);
- lv_color_t bg_color = lv_img_buf_get_px_color(&d, x, y, lv_color_black());
- lv_opa_t bg_opa = lv_img_buf_get_px_alpha(&d, x, y);
-
- lv_opa_t res_opa;
+ lv_color_t bg_color;
lv_color_t res_color;
+ lv_opa_t bg_opa = buf_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
+#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
+ bg_color.full = buf_px[0];
+ lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf_px[2]);
+ if(buf_px[1] <= LV_OPA_MIN) return;
+ buf_px[0] = res_color.full;
+#elif LV_COLOR_DEPTH == 16
+ bg_color.full = buf_px[0] + (buf_px[1] << 8);
+ lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf_px[2]);
+ if(buf_px[2] <= LV_OPA_MIN) return;
+ buf_px[0] = res_color.full & 0xff;
+ buf_px[1] = res_color.full >> 8;
+#elif LV_COLOR_DEPTH == 32
+ bg_color = *((lv_color_t *)buf_px);
+ lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf_px[3]);
+ if(buf_px[3] <= LV_OPA_MIN) return;
+ buf_px[0] = res_color.ch.blue;
+ buf_px[1] = res_color.ch.green;
+ buf_px[2] = res_color.ch.red;
+#endif
- lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &res_opa);
-
- lv_img_buf_set_px_alpha(&d, x, y, res_opa);
- lv_img_buf_set_px_color(&d, x, y, res_color);
}
diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h
index b8ab370d6..a75a6ea20 100644
--- a/src/lv_conf_internal.h
+++ b/src/lv_conf_internal.h
@@ -300,6 +300,36 @@
#endif
#endif /*LV_DRAW_COMPLEX*/
+/**
+ * "Simple layers" are used when a widget has `style_opa < 255` to buffer the widget into a layer
+ * and blend it as an image with the given opacity.
+ * Note that `bg_opa`, `text_opa` etc don't require buffering into layer)
+ * The widget can be buffered in smaller chunks to avoid using large buffers.
+ * `draw_area` (`lv_area_t` meaning the area to draw and `px_size` (size of a pixel in bytes)
+ * can be used the set the buffer size adaptively.
+ *
+ * - LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate it
+ * - LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.
+ *
+ * Both buffer sizes are in bytes.
+ * "Transformed layers" (where transform_angle/zoom properties are used) use larger buffers
+ * and can't be drawn in chunks. So these settings affects only widgets with opacity.
+ */
+#ifndef LV_LAYER_SIMPLE_BUF_SIZE
+ #ifdef CONFIG_LV_LAYER_SIMPLE_BUF_SIZE
+ #define LV_LAYER_SIMPLE_BUF_SIZE CONFIG_LV_LAYER_SIMPLE_BUF_SIZE
+ #else
+ #define LV_LAYER_SIMPLE_BUF_SIZE (24 * 1024)
+ #endif
+#endif
+#ifndef LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE
+ #ifdef CONFIG_LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE
+ #define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE CONFIG_LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE
+ #else
+ #define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE LV_MAX(lv_area_get_width(&draw_area) * px_size, 2048)
+ #endif
+#endif
+
/*Default image cache size. Image caching keeps the images opened.
*If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added)
*With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
diff --git a/src/misc/lv_area.c b/src/misc/lv_area.c
index 7c66a9b33..2edc4a226 100644
--- a/src/misc/lv_area.c
+++ b/src/misc/lv_area.c
@@ -456,6 +456,55 @@ void lv_area_align(const lv_area_t * base, lv_area_t * to_align, lv_align_t alig
to_align->y2 = to_align->y1 + h - 1;
}
+#define _LV_TRANSFORM_TRIGO_SHIFT 10
+void lv_point_transform(lv_point_t * p, int32_t angle, int32_t zoom, const lv_point_t * pivot)
+{
+ if(angle == 0 && zoom == 256) {
+ return;
+ }
+
+ p->x -= pivot->x;
+ p->y -= pivot->y;
+
+ if(angle == 0) {
+ p->x = (((int32_t)(p->x) * zoom) >> 8) + pivot->x;
+ p->y = (((int32_t)(p->y) * zoom) >> 8) + pivot->y;
+ return;
+ }
+
+ static int32_t angle_prev = INT32_MIN;
+ static int32_t sinma;
+ static int32_t cosma;
+ if(angle_prev != angle) {
+ int32_t angle_low = angle / 10;
+ int32_t angle_high = angle_low + 1;
+ int32_t angle_rem = angle - (angle_low * 10);
+
+ int32_t s1 = lv_trigo_sin(angle_low);
+ int32_t s2 = lv_trigo_sin(angle_high);
+
+ int32_t c1 = lv_trigo_sin(angle_low + 90);
+ int32_t c2 = lv_trigo_sin(angle_high + 90);
+
+ sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
+ cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
+ sinma = sinma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
+ cosma = cosma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
+ angle_prev = angle;
+ }
+ int32_t x = p->x;
+ int32_t y = p->y;
+ if(zoom == 256) {
+ p->x = ((cosma * x - sinma * y) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
+ p->y = ((sinma * x + cosma * y) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
+ }
+ else {
+ p->x = (((cosma * x - sinma * y) * zoom) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->x;
+ p->y = (((sinma * x + cosma * y) * zoom) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->y;
+ }
+}
+
+
/**********************
* STATIC FUNCTIONS
**********************/
diff --git a/src/misc/lv_area.h b/src/misc/lv_area.h
index 542d86bc5..137931a29 100644
--- a/src/misc/lv_area.h
+++ b/src/misc/lv_area.h
@@ -236,6 +236,8 @@ 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, lv_coord_t ofs_x, lv_coord_t ofs_y);
+void lv_point_transform(lv_point_t * p, int32_t angle, int32_t zoom, const lv_point_t * pivot);
+
/**********************
* MACROS
**********************/
diff --git a/src/misc/lv_color.h b/src/misc/lv_color.h
index b02660eb9..ab3447ed6 100644
--- a/src/misc/lv_color.h
+++ b/src/misc/lv_color.h
@@ -23,10 +23,6 @@ extern "C" {
#error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)"
#endif
-#if LV_COLOR_DEPTH != 32 && LV_COLOR_SCREEN_TRANSP != 0
-#error "LV_COLOR_SCREEN_TRANSP requires LV_COLOR_DEPTH == 32. Set it in lv_conf.h"
-#endif
-
#if LV_COLOR_DEPTH != 16 && LV_COLOR_16_SWAP != 0
#error "LV_COLOR_16_SWAP requires LV_COLOR_DEPTH == 16. Set it in lv_conf.h"
#endif
diff --git a/src/misc/lv_mem.c b/src/misc/lv_mem.c
index 91d50678b..b7c602f7a 100644
--- a/src/misc/lv_mem.c
+++ b/src/misc/lv_mem.c
@@ -55,6 +55,8 @@
**********************/
#if LV_MEM_CUSTOM == 0
static lv_tlsf_t tlsf;
+ static uint32_t cur_used;
+ static uint32_t max_used;
#endif
static uint32_t zero_mem = ZERO_MEM_SENTINEL; /*Give the address of this variable if 0 byte should be allocated*/
@@ -135,12 +137,14 @@ void * lv_mem_alloc(size_t size)
#endif
if(alloc == NULL) {
- LV_LOG_ERROR("couldn't allocate memory (%lu bytes)", (unsigned long)size);
+ LV_LOG_INFO("couldn't allocate memory (%lu bytes)", (unsigned long)size);
+#if LV_LOG_LEVEL <= LV_LOG_LEVEL_INFO
lv_mem_monitor_t mon;
lv_mem_monitor(&mon);
- LV_LOG_ERROR("used: %6d (%3d %%), frag: %3d %%, biggest free: %6d",
- (int)(mon.total_size - mon.free_size), mon.used_pct, mon.frag_pct,
- (int)mon.free_biggest_size);
+ LV_LOG_INFO("used: %6d (%3d %%), frag: %3d %%, biggest free: %6d",
+ (int)(mon.total_size - mon.free_size), mon.used_pct, mon.frag_pct,
+ (int)mon.free_biggest_size);
+#endif
}
#if LV_MEM_ADD_JUNK
else {
@@ -148,7 +152,13 @@ void * lv_mem_alloc(size_t size)
}
#endif
- MEM_TRACE("allocated at %p", alloc);
+ if(alloc) {
+#if LV_MEM_CUSTOM == 0
+ cur_used += size;
+ max_used = LV_MAX(cur_used, max_used);
+#endif
+ MEM_TRACE("allocated at %p", alloc);
+ }
return alloc;
}
@@ -166,7 +176,9 @@ void lv_mem_free(void * data)
# if LV_MEM_ADD_JUNK
lv_memset(data, 0xbb, lv_tlsf_block_size(data));
# endif
- lv_tlsf_free(tlsf, data);
+ size_t size = lv_tlsf_free(tlsf, data);
+ if(cur_used > size) cur_used -= size;
+ else cur_used = 0;
#else
LV_MEM_CUSTOM_FREE(data);
#endif
@@ -250,6 +262,8 @@ void lv_mem_monitor(lv_mem_monitor_t * mon_p)
mon_p->frag_pct = 0; /*no fragmentation if all the RAM is used*/
}
+ mon_p->max_used = max_used;
+
MEM_TRACE("finished");
#endif
}
diff --git a/src/misc/lv_style.c b/src/misc/lv_style.c
index 1a343d542..1e96b082c 100644
--- a/src/misc/lv_style.c
+++ b/src/misc/lv_style.c
@@ -110,7 +110,7 @@ const uint8_t _lv_style_builtin_prop_flag_lookup_table[_LV_STYLE_NUM_BUILT_IN_PR
[LV_STYLE_RADIUS] = 0,
[LV_STYLE_CLIP_CORNER] = 0,
- [LV_STYLE_OPA] = LV_STYLE_PROP_INHERIT,
+ [LV_STYLE_OPA] = 0,
[LV_STYLE_COLOR_FILTER_DSC] = LV_STYLE_PROP_INHERIT,
[LV_STYLE_COLOR_FILTER_OPA] = LV_STYLE_PROP_INHERIT,
[LV_STYLE_ANIM_TIME] = 0,
diff --git a/src/misc/lv_style.h b/src/misc/lv_style.h
index eee3a947e..8075d8f99 100644
--- a/src/misc/lv_style.h
+++ b/src/misc/lv_style.h
@@ -160,7 +160,7 @@ typedef union {
* Props are split into groups of 16. When adding a new prop to a group, ensure it does not overflow into the next one.
*/
typedef enum {
- LV_STYLE_PROP_INV,
+ LV_STYLE_PROP_INV = 0,
/*Group 0*/
LV_STYLE_WIDTH = 1,
@@ -172,12 +172,8 @@ typedef enum {
LV_STYLE_X = 7,
LV_STYLE_Y = 8,
LV_STYLE_ALIGN = 9,
- LV_STYLE_TRANSFORM_WIDTH = 10,
- LV_STYLE_TRANSFORM_HEIGHT = 11,
- LV_STYLE_TRANSLATE_X = 12,
- LV_STYLE_TRANSLATE_Y = 13,
- LV_STYLE_TRANSFORM_ZOOM = 14,
- LV_STYLE_TRANSFORM_ANGLE = 15,
+ LV_STYLE_LAYOUT = 10,
+ LV_STYLE_RADIUS = 11,
/*Group 1*/
LV_STYLE_PAD_TOP = 16,
@@ -186,6 +182,8 @@ typedef enum {
LV_STYLE_PAD_RIGHT = 19,
LV_STYLE_PAD_ROW = 20,
LV_STYLE_PAD_COLUMN = 21,
+ LV_STYLE_BASE_DIR = 22,
+ LV_STYLE_CLIP_CORNER = 23,
/*Group 2*/
LV_STYLE_BG_COLOR = 32,
@@ -245,18 +243,22 @@ typedef enum {
LV_STYLE_TEXT_ALIGN = 91,
/*Group 6*/
- LV_STYLE_RADIUS = 96,
- LV_STYLE_CLIP_CORNER = 97,
- LV_STYLE_OPA = 98,
- LV_STYLE_COLOR_FILTER_DSC = 99,
- LV_STYLE_COLOR_FILTER_OPA = 100,
- LV_STYLE_ANIM = 101,
- LV_STYLE_ANIM_TIME = 102,
- LV_STYLE_ANIM_SPEED = 103,
- LV_STYLE_TRANSITION = 104,
- LV_STYLE_BLEND_MODE = 105,
- LV_STYLE_LAYOUT = 106,
- LV_STYLE_BASE_DIR = 107,
+ LV_STYLE_OPA = 96,
+ LV_STYLE_COLOR_FILTER_DSC = 97,
+ LV_STYLE_COLOR_FILTER_OPA = 98,
+ LV_STYLE_ANIM = 99,
+ LV_STYLE_ANIM_TIME = 100,
+ LV_STYLE_ANIM_SPEED = 101,
+ LV_STYLE_TRANSITION = 102,
+ LV_STYLE_BLEND_MODE = 103,
+ LV_STYLE_TRANSFORM_WIDTH = 104,
+ LV_STYLE_TRANSFORM_HEIGHT = 105,
+ LV_STYLE_TRANSLATE_X = 106,
+ LV_STYLE_TRANSLATE_Y = 107,
+ LV_STYLE_TRANSFORM_ZOOM = 108,
+ LV_STYLE_TRANSFORM_ANGLE = 109,
+ LV_STYLE_TRANSFORM_PIVOT_X = 110,
+ LV_STYLE_TRANSFORM_PIVOT_Y = 111,
_LV_STYLE_LAST_BUILT_IN_PROP = 111,
_LV_STYLE_NUM_BUILT_IN_PROPS = _LV_STYLE_LAST_BUILT_IN_PROP + 1,
diff --git a/src/misc/lv_style_gen.c b/src/misc/lv_style_gen.c
index e4dfbf435..13d85607a 100644
--- a/src/misc/lv_style_gen.c
+++ b/src/misc/lv_style_gen.c
@@ -120,6 +120,22 @@ void lv_style_set_transform_angle(lv_style_t * style, lv_coord_t value)
lv_style_set_prop(style, LV_STYLE_TRANSFORM_ANGLE, v);
}
+void lv_style_set_transform_pivot_x(lv_style_t * style, lv_coord_t value)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_style_set_prop(style, LV_STYLE_TRANSFORM_PIVOT_X, v);
+}
+
+void lv_style_set_transform_pivot_y(lv_style_t * style, lv_coord_t value)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_style_set_prop(style, LV_STYLE_TRANSFORM_PIVOT_Y, v);
+}
+
void lv_style_set_pad_top(lv_style_t * style, lv_coord_t value)
{
lv_style_value_t v = {
diff --git a/src/misc/lv_style_gen.h b/src/misc/lv_style_gen.h
index f62206f83..8bf3b68f4 100644
--- a/src/misc/lv_style_gen.h
+++ b/src/misc/lv_style_gen.h
@@ -13,6 +13,8 @@ void lv_style_set_translate_x(lv_style_t * style, lv_coord_t value);
void lv_style_set_translate_y(lv_style_t * style, lv_coord_t value);
void lv_style_set_transform_zoom(lv_style_t * style, lv_coord_t value);
void lv_style_set_transform_angle(lv_style_t * style, lv_coord_t value);
+void lv_style_set_transform_pivot_x(lv_style_t * style, lv_coord_t value);
+void lv_style_set_transform_pivot_y(lv_style_t * style, lv_coord_t value);
void lv_style_set_pad_top(lv_style_t * style, lv_coord_t value);
void lv_style_set_pad_bottom(lv_style_t * style, lv_coord_t value);
void lv_style_set_pad_left(lv_style_t * style, lv_coord_t value);
@@ -156,6 +158,16 @@ void lv_style_set_base_dir(lv_style_t * style, lv_base_dir_t value);
.prop = LV_STYLE_TRANSFORM_ANGLE, .value = { .num = (int32_t)val } \
}
+#define LV_STYLE_CONST_TRANSFORM_PIVOT_X(val) \
+ { \
+ .prop = LV_STYLE_TRANSFORM_PIVOT_X, .value = { .num = (int32_t)val } \
+ }
+
+#define LV_STYLE_CONST_TRANSFORM_PIVOT_Y(val) \
+ { \
+ .prop = LV_STYLE_TRANSFORM_PIVOT_Y, .value = { .num = (int32_t)val } \
+ }
+
#define LV_STYLE_CONST_PAD_TOP(val) \
{ \
.prop = LV_STYLE_PAD_TOP, .value = { .num = (int32_t)val } \
diff --git a/src/misc/lv_tlsf.c b/src/misc/lv_tlsf.c
index 64197f977..069318aad 100644
--- a/src/misc/lv_tlsf.c
+++ b/src/misc/lv_tlsf.c
@@ -1157,18 +1157,22 @@ void * lv_tlsf_memalign(lv_tlsf_t tlsf, size_t align, size_t size)
return block_prepare_used(control, block, adjust);
}
-void lv_tlsf_free(lv_tlsf_t tlsf, const void * ptr)
+size_t lv_tlsf_free(lv_tlsf_t tlsf, const void * ptr)
{
+ size_t size = 0;
/* Don't attempt to free a NULL pointer. */
if(ptr) {
control_t * control = tlsf_cast(control_t *, tlsf);
block_header_t * block = block_from_ptr(ptr);
tlsf_assert(!block_is_free(block) && "block already marked as free");
+ size = block->size;
block_mark_as_free(block);
block = block_merge_prev(control, block);
block = block_merge_next(control, block);
block_insert(control, block);
}
+
+ return size;
}
/*
diff --git a/src/misc/lv_tlsf.h b/src/misc/lv_tlsf.h
index 9380ee8ca..f12590b60 100644
--- a/src/misc/lv_tlsf.h
+++ b/src/misc/lv_tlsf.h
@@ -66,7 +66,7 @@ void lv_tlsf_remove_pool(lv_tlsf_t tlsf, lv_pool_t pool);
void * lv_tlsf_malloc(lv_tlsf_t tlsf, size_t bytes);
void * lv_tlsf_memalign(lv_tlsf_t tlsf, size_t align, size_t bytes);
void * lv_tlsf_realloc(lv_tlsf_t tlsf, void * ptr, size_t size);
-void lv_tlsf_free(lv_tlsf_t tlsf, const void * ptr);
+size_t lv_tlsf_free(lv_tlsf_t tlsf, const void * ptr);
/* Returns internal block size, not original request size */
size_t lv_tlsf_block_size(void * ptr);
diff --git a/src/widgets/lv_canvas.c b/src/widgets/lv_canvas.c
index bde4b92b1..6b37069ab 100644
--- a/src/widgets/lv_canvas.c
+++ b/src/widgets/lv_canvas.c
@@ -158,98 +158,63 @@ void lv_canvas_copy_buf(lv_obj_t * obj, const void * to_copy, lv_coord_t x, lv_c
}
}
-void lv_canvas_transform(lv_obj_t * obj, lv_img_dsc_t * img, int16_t angle, uint16_t zoom, lv_coord_t offset_x,
+void lv_canvas_transform(lv_obj_t * obj, lv_img_dsc_t * src_img, int16_t angle, uint16_t zoom, lv_coord_t offset_x,
lv_coord_t offset_y,
int32_t pivot_x, int32_t pivot_y, bool antialias)
{
#if LV_DRAW_COMPLEX
LV_ASSERT_OBJ(obj, MY_CLASS);
- LV_ASSERT_NULL(img);
+ LV_ASSERT_NULL(src_img);
lv_canvas_t * canvas = (lv_canvas_t *)obj;
- lv_color_t color = lv_obj_get_style_img_recolor(obj, LV_PART_MAIN);
-
- int32_t dest_width = canvas->dsc.header.w;
- int32_t dest_height = canvas->dsc.header.h;
+ lv_img_dsc_t * dest_img = &canvas->dsc;
int32_t x;
int32_t y;
- bool ret;
- lv_img_transform_dsc_t dsc;
- dsc.cfg.angle = angle;
- dsc.cfg.zoom = zoom;
- dsc.cfg.src = img->data;
- dsc.cfg.src_w = img->header.w;
- dsc.cfg.src_h = img->header.h;
- dsc.cfg.cf = img->header.cf;
- dsc.cfg.pivot_x = pivot_x;
- dsc.cfg.pivot_y = pivot_y;
- dsc.cfg.color = color;
- dsc.cfg.antialias = antialias;
- _lv_img_buf_transform_init(&dsc);
+ lv_draw_img_dsc_t draw_dsc;
+ lv_draw_img_dsc_init(&draw_dsc);
+ draw_dsc.angle = angle;
+ draw_dsc.zoom = zoom;
+ draw_dsc.pivot.x = pivot_x;
+ draw_dsc.pivot.y = pivot_y;
+ draw_dsc.antialias = antialias;
- for(y = -offset_y; y < dest_height - offset_y; y++) {
- for(x = -offset_x; x < dest_width - offset_x; x++) {
+ lv_area_t dest_area;
+ dest_area.x1 = 0;
+ dest_area.x2 = dest_img->header.w - 1;
+ dest_area.y1 = 0;
+ dest_area.y2 = 0;
- ret = _lv_img_buf_transform(&dsc, x, y);
+ lv_color_t * cbuf = lv_mem_alloc(dest_img->header.w * sizeof(lv_color_t));
+ lv_opa_t * abuf = lv_mem_alloc(dest_img->header.w * sizeof(lv_opa_t));
+ for(y = 0; y < dest_img->header.h; y++) {
+ if(y + offset_y >= 0) {
+ lv_draw_sw_transform(NULL, &dest_area, src_img->data, src_img->header.w, src_img->header.h, src_img->header.w,
+ &draw_dsc, canvas->dsc.header.cf, cbuf, abuf);
- if(ret == false) continue;
-
- if(x + offset_x >= 0 && x + offset_x < dest_width && y + offset_y >= 0 && y + offset_y < dest_height) {
- /*If the image has no alpha channel just simple set the result color on the canvas*/
- if(lv_img_cf_has_alpha(img->header.cf) == false) {
- lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y, dsc.res.color);
- }
- else {
- lv_color_t bg_color = lv_img_buf_get_px_color(&canvas->dsc, x + offset_x, y + offset_y, dsc.cfg.color);
-
- /*If the canvas has no alpha but the image has mix the image's color with
- * canvas*/
- if(lv_img_cf_has_alpha(canvas->dsc.header.cf) == false) {
- if(dsc.res.opa < LV_OPA_MAX) dsc.res.color = lv_color_mix(dsc.res.color, bg_color, dsc.res.opa);
- lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y, dsc.res.color);
- }
- /*Both the image and canvas has alpha channel. Some extra calculation is
- required*/
- else {
- lv_opa_t bg_opa = lv_img_buf_get_px_alpha(&canvas->dsc, x + offset_x, y + offset_y);
- /*Pick the foreground if it's fully opaque or the Background is fully
- *transparent*/
- if(dsc.res.opa >= LV_OPA_MAX || bg_opa <= LV_OPA_MIN) {
- lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y, dsc.res.color);
- lv_img_buf_set_px_alpha(&canvas->dsc, x + offset_x, y + offset_y, dsc.res.opa);
- }
- /*Opaque background: use simple mix*/
- else if(bg_opa >= LV_OPA_MAX) {
- lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y,
- lv_color_mix(dsc.res.color, bg_color, dsc.res.opa));
- }
- /*Both colors have alpha. Expensive calculation need to be applied*/
- else {
-
- /*Info:
- * https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/
- lv_opa_t opa_res_2 = 255 - ((uint16_t)((uint16_t)(255 - dsc.res.opa) * (255 - bg_opa)) >> 8);
- if(opa_res_2 == 0) {
- opa_res_2 = 1; /*never happens, just to be sure*/
- }
- lv_opa_t ratio = (uint16_t)((uint16_t)dsc.res.opa * 255) / opa_res_2;
-
- lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y,
- lv_color_mix(dsc.res.color, bg_color, ratio));
- lv_img_buf_set_px_alpha(&canvas->dsc, x + offset_x, y + offset_y, opa_res_2);
- }
- }
+ for(x = 0; x < dest_img->header.w; x++) {
+ if(x + offset_x < 0) continue;
+ if(x + offset_x >= dest_img->header.w) break;
+ if(abuf[x]) {
+ lv_img_buf_set_px_color(dest_img, x + offset_x, y + offset_y, cbuf[x]);
+ lv_img_buf_set_px_alpha(dest_img, x + offset_x, y + offset_y, abuf[x]);
}
}
+
+ if(y + offset_y >= dest_img->header.h) break;
+ dest_area.y1++;
+ dest_area.y2++;
}
}
+ lv_mem_free(cbuf);
+ lv_mem_free(abuf);
lv_obj_invalidate(obj);
+
#else
LV_UNUSED(obj);
- LV_UNUSED(img);
+ LV_UNUSED(src_img);
LV_UNUSED(angle);
LV_UNUSED(zoom);
LV_UNUSED(offset_x);
@@ -857,6 +822,9 @@ static void init_fake_disp(lv_obj_t * canvas, lv_disp_t * disp, lv_disp_drv_t *
draw_ctx->buf = (void *)dsc->data;
lv_disp_drv_use_generic_set_px_cb(disp->driver, dsc->header.cf);
+ if(LV_COLOR_SCREEN_TRANSP && dsc->header.cf != LV_IMG_CF_TRUE_COLOR_ALPHA) {
+ drv->screen_transp = 0;
+ }
}
static void deinit_fake_disp(lv_obj_t * canvas, lv_disp_t * disp)
diff --git a/src/widgets/lv_img.c b/src/widgets/lv_img.c
index e9581095e..b6df70807 100644
--- a/src/widgets/lv_img.c
+++ b/src/widgets/lv_img.c
@@ -190,16 +190,11 @@ void lv_img_set_angle(lv_obj_t * obj, int16_t angle)
lv_img_t * img = (lv_img_t *)obj;
if(angle == img->angle) return;
- lv_coord_t transf_zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
- transf_zoom = ((int32_t)transf_zoom * img->zoom) >> 8;
-
- lv_coord_t transf_angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
-
lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t h = lv_obj_get_height(obj);
lv_area_t a;
- _lv_img_buf_get_transformed_area(&a, w, h, transf_angle + img->angle, transf_zoom, &img->pivot);
+ _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
a.x1 += obj->coords.x1;
a.y1 += obj->coords.y1;
a.x2 += obj->coords.x1;
@@ -209,7 +204,7 @@ void lv_img_set_angle(lv_obj_t * obj, int16_t angle)
img->angle = angle;
lv_obj_refresh_ext_draw_size(obj);
- _lv_img_buf_get_transformed_area(&a, w, h, transf_angle + img->angle, transf_zoom, &img->pivot);
+ _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
a.x1 += obj->coords.x1;
a.y1 += obj->coords.y1;
a.x2 += obj->coords.x1;
@@ -222,17 +217,11 @@ void lv_img_set_pivot(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
lv_img_t * img = (lv_img_t *)obj;
if(img->pivot.x == x && img->pivot.y == y) return;
- lv_coord_t transf_zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
- transf_zoom = ((int32_t)transf_zoom * img->zoom) >> 8;
-
- lv_coord_t transf_angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
- transf_angle += img->angle;
-
lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t h = lv_obj_get_height(obj);
lv_area_t a;
- _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, transf_zoom, &img->pivot);
+ _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
a.x1 += obj->coords.x1;
a.y1 += obj->coords.y1;
a.x2 += obj->coords.x1;
@@ -243,7 +232,7 @@ void lv_img_set_pivot(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
img->pivot.y = y;
lv_obj_refresh_ext_draw_size(obj);
- _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, transf_zoom, &img->pivot);
+ _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
a.x1 += obj->coords.x1;
a.y1 += obj->coords.y1;
a.x2 += obj->coords.x1;
@@ -258,16 +247,11 @@ void lv_img_set_zoom(lv_obj_t * obj, uint16_t zoom)
if(zoom == 0) zoom = 1;
- lv_coord_t transf_zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
-
- lv_coord_t transf_angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
- transf_angle += img->angle;
-
lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t h = lv_obj_get_height(obj);
lv_area_t a;
- _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, ((int32_t)transf_zoom * img->zoom) >> 8, &img->pivot);
+ _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom >> 8, &img->pivot);
a.x1 += obj->coords.x1 - 1;
a.y1 += obj->coords.y1 - 1;
a.x2 += obj->coords.x1 + 1;
@@ -277,7 +261,7 @@ void lv_img_set_zoom(lv_obj_t * obj, uint16_t zoom)
img->zoom = zoom;
lv_obj_refresh_ext_draw_size(obj);
- _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, ((int32_t)transf_zoom * img->zoom) >> 8, &img->pivot);
+ _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
a.x1 += obj->coords.x1 - 1;
a.y1 += obj->coords.y1 - 1;
a.x2 += obj->coords.x1 + 1;
@@ -424,14 +408,10 @@ static lv_point_t lv_img_get_transformed_size(lv_obj_t * obj)
{
lv_img_t * img = (lv_img_t *)obj;
- int32_t zoom_final = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
- zoom_final = (zoom_final * img->zoom) >> 8;
- int32_t angle_final = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
- angle_final += img->angle;
lv_area_t area_transform;
_lv_img_buf_get_transformed_area(&area_transform, img->w, img->h,
- angle_final, zoom_final, &img->pivot);
+ img->angle, img->zoom, &img->pivot);
return (lv_point_t) {
lv_area_get_width(&area_transform), lv_area_get_height(&area_transform)
@@ -467,42 +447,31 @@ static void lv_img_event(const lv_obj_class_t * class_p, lv_event_t * e)
else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
lv_coord_t * s = lv_event_get_param(e);
- lv_coord_t transf_zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
- transf_zoom = ((int32_t)transf_zoom * img->zoom) >> 8;
-
- lv_coord_t transf_angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
- transf_angle += img->angle;
/*If the image has angle provide enough room for the rotated corners*/
- if(transf_angle || transf_zoom != LV_IMG_ZOOM_NONE) {
+ if(img->angle || img->zoom != LV_IMG_ZOOM_NONE) {
lv_area_t a;
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t h = lv_obj_get_height(obj);
- _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, transf_zoom, &img->pivot);
- lv_coord_t pad_ori = *s;
- *s = LV_MAX(*s, pad_ori - a.x1);
- *s = LV_MAX(*s, pad_ori - a.y1);
- *s = LV_MAX(*s, pad_ori + a.x2 - w);
- *s = LV_MAX(*s, pad_ori + a.y2 - h);
+ _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
+ *s = LV_MAX(*s, -a.x1);
+ *s = LV_MAX(*s, -a.y1);
+ *s = LV_MAX(*s, a.x2 - w);
+ *s = LV_MAX(*s, a.y2 - h);
}
}
else if(code == LV_EVENT_HIT_TEST) {
lv_hit_test_info_t * info = lv_event_get_param(e);
- lv_coord_t zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
- zoom = (zoom * img->zoom) >> 8;
-
- lv_coord_t angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
- angle += img->angle;
/*If the object is exactly image sized (not cropped, not mosaic) and transformed
*perform hit test on its transformed area*/
if(img->w == lv_obj_get_width(obj) && img->h == lv_obj_get_height(obj) &&
- (zoom != LV_IMG_ZOOM_NONE || angle != 0 || img->pivot.x != img->w / 2 || img->pivot.y != img->h / 2)) {
+ (img->zoom != LV_IMG_ZOOM_NONE || img->angle != 0 || img->pivot.x != img->w / 2 || img->pivot.y != img->h / 2)) {
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t h = lv_obj_get_height(obj);
lv_area_t coords;
- _lv_img_buf_get_transformed_area(&coords, w, h, angle, zoom, &img->pivot);
+ _lv_img_buf_get_transformed_area(&coords, w, h, img->angle, img->zoom, &img->pivot);
coords.x1 += obj->coords.x1;
coords.y1 += obj->coords.y1;
coords.x2 += obj->coords.x1;
@@ -556,19 +525,13 @@ static void draw_img(lv_event_t * e)
return;
}
- int32_t angle_final = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
- angle_final += img->angle;
-
- if(angle_final != 0) {
+ if(img->angle != 0) {
info->res = LV_COVER_RES_NOT_COVER;
return;
}
- int32_t zoom_final = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
- zoom_final = (zoom_final * img->zoom) >> 8;
-
const lv_area_t * clip_area = lv_event_get_param(e);
- if(zoom_final == LV_IMG_ZOOM_NONE) {
+ if(img->zoom == LV_IMG_ZOOM_NONE) {
if(_lv_area_is_in(clip_area, &obj->coords, 0) == false) {
info->res = LV_COVER_RES_NOT_COVER;
return;
@@ -576,7 +539,7 @@ static void draw_img(lv_event_t * e)
}
else {
lv_area_t a;
- _lv_img_buf_get_transformed_area(&a, lv_obj_get_width(obj), lv_obj_get_height(obj), 0, zoom_final, &img->pivot);
+ _lv_img_buf_get_transformed_area(&a, lv_obj_get_width(obj), lv_obj_get_height(obj), 0, img->zoom, &img->pivot);
a.x1 += obj->coords.x1;
a.y1 += obj->coords.y1;
a.x2 += obj->coords.x1;
@@ -590,12 +553,6 @@ static void draw_img(lv_event_t * e)
}
else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST) {
- int32_t zoom_final = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
- zoom_final = (zoom_final * img->zoom) >> 8;
-
- int32_t angle_final = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
- angle_final += img->angle;
-
lv_coord_t obj_w = lv_obj_get_width(obj);
lv_coord_t obj_h = lv_obj_get_height(obj);
@@ -616,7 +573,7 @@ static void draw_img(lv_event_t * e)
}
else {
_lv_img_buf_get_transformed_area(&bg_coords, obj_w, obj_h,
- angle_final, zoom_final, &bg_pivot);
+ img->angle, img->zoom, &bg_pivot);
/*Modify the coordinates to draw the background for the rotated and scaled coordinates*/
bg_coords.x1 += obj->coords.x1;
@@ -636,7 +593,7 @@ static void draw_img(lv_event_t * e)
if(code == LV_EVENT_DRAW_MAIN) {
if(img->h == 0 || img->w == 0) return;
- if(zoom_final == 0) return;
+ if(img->zoom == 0) return;
lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
@@ -666,8 +623,8 @@ static void draw_img(lv_event_t * e)
lv_draw_img_dsc_init(&img_dsc);
lv_obj_init_draw_img_dsc(obj, LV_PART_MAIN, &img_dsc);
- img_dsc.zoom = zoom_final;
- img_dsc.angle = angle_final;
+ img_dsc.zoom = img->zoom;
+ img_dsc.angle = img->angle;
img_dsc.pivot.x = img->pivot.x;
img_dsc.pivot.y = img->pivot.y;
img_dsc.antialias = img->antialias;