1 /**
2  * @file lv_draw_sw_triangle.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_sw_mask_private.h"
10 #include "blend/lv_draw_sw_blend_private.h"
11 #include "../lv_draw_private.h"
12 #include "lv_draw_sw.h"
13 #if LV_USE_DRAW_SW
14 
15 #include "../../misc/lv_math.h"
16 #include "../../stdlib/lv_mem.h"
17 #include "../../misc/lv_area_private.h"
18 #include "../../misc/lv_color.h"
19 #include "../../stdlib/lv_string.h"
20 #include "../lv_draw_triangle_private.h"
21 #include "lv_draw_sw_gradient_private.h"
22 
23 /*********************
24  *      DEFINES
25  *********************/
26 
27 /**********************
28  *      TYPEDEFS
29  **********************/
30 
31 /**********************
32  *  STATIC PROTOTYPES
33  **********************/
34 
35 /**********************
36  *  STATIC VARIABLES
37  **********************/
38 
39 /**********************
40  *      MACROS
41  **********************/
42 
43 /**********************
44  *   GLOBAL FUNCTIONS
45  **********************/
46 
lv_draw_sw_triangle(lv_draw_unit_t * draw_unit,const lv_draw_triangle_dsc_t * dsc)47 void lv_draw_sw_triangle(lv_draw_unit_t * draw_unit, const lv_draw_triangle_dsc_t * dsc)
48 {
49 #if LV_DRAW_SW_COMPLEX
50     lv_area_t tri_area;
51     tri_area.x1 = (int32_t)LV_MIN3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
52     tri_area.y1 = (int32_t)LV_MIN3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
53     tri_area.x2 = (int32_t)LV_MAX3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
54     tri_area.y2 = (int32_t)LV_MAX3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
55 
56     bool is_common;
57     lv_area_t draw_area;
58     is_common = lv_area_intersect(&draw_area, &tri_area, draw_unit->clip_area);
59     if(!is_common) return;
60 
61     lv_point_t p[3];
62     /*If there is a vertical side use it as p[0] and p[1]*/
63     if(dsc->p[0].x == dsc->p[1].x) {
64         p[0] = lv_point_from_precise(&dsc->p[0]);
65         p[1] = lv_point_from_precise(&dsc->p[1]);
66         p[2] = lv_point_from_precise(&dsc->p[2]);
67     }
68     else if(dsc->p[0].x == dsc->p[2].x) {
69         p[0] = lv_point_from_precise(&dsc->p[0]);
70         p[1] = lv_point_from_precise(&dsc->p[2]);
71         p[2] = lv_point_from_precise(&dsc->p[1]);
72     }
73     else if(dsc->p[1].x == dsc->p[2].x) {
74         p[0] = lv_point_from_precise(&dsc->p[1]);
75         p[1] = lv_point_from_precise(&dsc->p[2]);
76         p[2] = lv_point_from_precise(&dsc->p[0]);
77     }
78     else {
79         p[0] = lv_point_from_precise(&dsc->p[0]);
80         p[1] = lv_point_from_precise(&dsc->p[1]);
81         p[2] = lv_point_from_precise(&dsc->p[2]);
82 
83         /*Set the smallest y as p[0]*/
84         if(p[0].y > p[1].y) lv_point_swap(&p[0], &p[1]);
85         if(p[0].y > p[2].y) lv_point_swap(&p[0], &p[2]);
86 
87         /*Set the greatest y as p[1]*/
88         if(p[1].y < p[2].y) lv_point_swap(&p[1], &p[2]);
89     }
90 
91     /*Be sure p[0] is on the top*/
92     if(p[0].y > p[1].y) lv_point_swap(&p[0], &p[1]);
93 
94     /*If right == true p[2] is on the right side of the p[0] p[1] line*/
95     bool right = ((p[1].x - p[0].x) * (p[2].y - p[0].y) - (p[1].y - p[0].y) * (p[2].x - p[0].x)) < 0;
96 
97     void * masks[4] = {0};
98     lv_draw_sw_mask_line_param_t mask_left;
99     lv_draw_sw_mask_line_param_t mask_right;
100     lv_draw_sw_mask_line_param_t mask_bottom;
101 
102     lv_draw_sw_mask_line_points_init(&mask_left, p[0].x, p[0].y,
103                                      p[1].x, p[1].y,
104                                      right ? LV_DRAW_SW_MASK_LINE_SIDE_RIGHT : LV_DRAW_SW_MASK_LINE_SIDE_LEFT);
105 
106     lv_draw_sw_mask_line_points_init(&mask_right, p[0].x, p[0].y,
107                                      p[2].x, p[2].y,
108                                      right ? LV_DRAW_SW_MASK_LINE_SIDE_LEFT : LV_DRAW_SW_MASK_LINE_SIDE_RIGHT);
109 
110     if(p[1].y == p[2].y) {
111         lv_draw_sw_mask_line_points_init(&mask_bottom, p[1].x, p[1].y,
112                                          p[2].x, p[2].y, LV_DRAW_SW_MASK_LINE_SIDE_TOP);
113     }
114     else {
115         lv_draw_sw_mask_line_points_init(&mask_bottom, p[1].x, p[1].y,
116                                          p[2].x, p[2].y,
117                                          right ? LV_DRAW_SW_MASK_LINE_SIDE_LEFT  : LV_DRAW_SW_MASK_LINE_SIDE_RIGHT);
118     }
119 
120     masks[0] = &mask_left;
121     masks[1] = &mask_right;
122     masks[2] = &mask_bottom;
123     int32_t area_w = lv_area_get_width(&draw_area);
124     lv_opa_t * mask_buf = lv_malloc(area_w);
125 
126     lv_area_t blend_area = draw_area;
127     blend_area.y2 = blend_area.y1;
128     lv_draw_sw_blend_dsc_t blend_dsc;
129     blend_dsc.color = dsc->bg_color;
130     blend_dsc.opa = dsc->bg_opa;
131     blend_dsc.mask_buf = mask_buf;
132     blend_dsc.blend_area = &blend_area;
133     blend_dsc.mask_area = &blend_area;
134     blend_dsc.blend_mode = LV_BLEND_MODE_NORMAL;
135     blend_dsc.src_buf = NULL;
136 
137     lv_grad_dir_t grad_dir = dsc->bg_grad.dir;
138 
139     lv_grad_t * grad = lv_gradient_get(&dsc->bg_grad, lv_area_get_width(&tri_area), lv_area_get_height(&tri_area));
140     lv_opa_t * grad_opa_map = NULL;
141     if(grad && grad_dir == LV_GRAD_DIR_HOR) {
142         blend_dsc.src_area = &blend_area;
143         blend_dsc.src_buf = grad->color_map + draw_area.x1 - tri_area.x1;
144         grad_opa_map = grad->opa_map + draw_area.x1 - tri_area.x1;
145         blend_dsc.src_color_format = LV_COLOR_FORMAT_RGB888;
146     }
147 
148     int32_t y;
149     for(y = draw_area.y1; y <= draw_area.y2; y++) {
150         blend_area.y1 = y;
151         blend_area.y2 = y;
152         lv_memset(mask_buf, 0xff, area_w);
153         blend_dsc.mask_res = lv_draw_sw_mask_apply(masks, mask_buf, draw_area.x1, y, area_w);
154         if(grad_dir == LV_GRAD_DIR_VER) {
155             LV_ASSERT_NULL(grad);
156             blend_dsc.color = grad->color_map[y - tri_area.y1];
157             blend_dsc.opa = grad->opa_map[y - tri_area.y1];
158             if(dsc->bg_opa < LV_OPA_MAX) blend_dsc.opa = LV_OPA_MIX2(blend_dsc.opa, dsc->bg_opa);
159         }
160         else if(grad_dir == LV_GRAD_DIR_HOR) {
161             if(grad_opa_map) {
162                 int32_t i;
163                 if(blend_dsc.mask_res == LV_DRAW_SW_MASK_RES_CHANGED) {
164                     blend_dsc.mask_buf = mask_buf;
165                     for(i = 0; i < area_w; i++) {
166                         if(grad_opa_map[i] < LV_OPA_MAX) mask_buf[i] = LV_OPA_MIX2(mask_buf[i], grad_opa_map[i]);
167                     }
168                 }
169                 else if(blend_dsc.mask_res == LV_DRAW_SW_MASK_RES_FULL_COVER) {
170                     blend_dsc.mask_buf = grad_opa_map;
171                     blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_CHANGED;
172                 }
173                 else if(blend_dsc.mask_res == LV_DRAW_SW_MASK_RES_TRANSP) {
174                     continue;
175                 }
176             }
177         }
178         lv_draw_sw_blend(draw_unit, &blend_dsc);
179     }
180 
181     lv_free(mask_buf);
182     lv_draw_sw_mask_free_param(&mask_bottom);
183     lv_draw_sw_mask_free_param(&mask_left);
184     lv_draw_sw_mask_free_param(&mask_right);
185 
186     if(grad) {
187         lv_gradient_cleanup(grad);
188     }
189 
190 #else
191     LV_UNUSED(draw_unit);
192     LV_UNUSED(dsc);
193     LV_LOG_WARN("Can't draw triangles with LV_DRAW_SW_COMPLEX == 0");
194 #endif /*LV_DRAW_SW_COMPLEX*/
195 }
196 
197 /**********************
198  *   STATIC FUNCTIONS
199  **********************/
200 
201 #endif /*LV_USE_DRAW_SW*/
202