Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/libs/lvgl/lv_draw/lv_draw_rect.c
1476 views
1
/**
2
* @file lv_draw_rect.c
3
*
4
*/
5
6
/*********************
7
* INCLUDES
8
*********************/
9
#include "lv_draw_rect.h"
10
#include "../lv_misc/lv_circ.h"
11
#include "../lv_misc/lv_math.h"
12
13
/*********************
14
* DEFINES
15
*********************/
16
#define CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD 5 /*Circle segment greater then this value will be anti-aliased by a non-linear (cos) opacity mapping*/
17
18
#define SHADOW_OPA_EXTRA_PRECISION 8 /*Calculate with 2^x bigger shadow opacity values to avoid rounding errors*/
19
#define SHADOW_BOTTOM_AA_EXTRA_RADIUS 3 /*Add extra radius with LV_SHADOW_BOTTOM to cover anti-aliased corners*/
20
21
/**********************
22
* TYPEDEFS
23
**********************/
24
25
/**********************
26
* STATIC PROTOTYPES
27
**********************/
28
static void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
29
static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
30
static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
31
static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
32
33
#if USE_LV_SHADOW && LV_VDB_SIZE
34
static void lv_draw_shadow(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
35
static void lv_draw_shadow_full(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
36
static void lv_draw_shadow_bottom(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
37
static void lv_draw_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map);
38
#endif
39
40
static uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h);
41
42
#if LV_ANTIALIAS
43
static lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa);
44
#endif
45
46
/**********************
47
* STATIC VARIABLES
48
**********************/
49
50
/**********************
51
* MACROS
52
**********************/
53
54
/**********************
55
* GLOBAL FUNCTIONS
56
**********************/
57
58
/**
59
* Draw a rectangle
60
* @param coords the coordinates of the rectangle
61
* @param mask the rectangle will be drawn only in this mask
62
* @param style pointer to a style
63
* @param opa_scale scale down all opacities by the factor
64
*/
65
void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
66
{
67
if(lv_area_get_height(coords) < 1 || lv_area_get_width(coords) < 1) return;
68
69
#if USE_LV_SHADOW && LV_VDB_SIZE
70
if(style->body.shadow.width != 0) {
71
lv_draw_shadow(coords, mask, style, opa_scale);
72
}
73
#endif
74
if(style->body.empty == 0 && style->body.opa >= LV_OPA_MIN) {
75
lv_draw_rect_main_mid(coords, mask, style, opa_scale);
76
77
if(style->body.radius != 0) {
78
lv_draw_rect_main_corner(coords, mask, style, opa_scale);
79
}
80
}
81
82
if(style->body.border.width != 0 && style->body.border.part != LV_BORDER_NONE && style->body.border.opa >= LV_OPA_MIN) {
83
lv_draw_rect_border_straight(coords, mask, style, opa_scale);
84
85
if(style->body.radius != 0) {
86
lv_draw_rect_border_corner(coords, mask, style, opa_scale);
87
}
88
}
89
}
90
91
/**********************
92
* STATIC FUNCTIONS
93
**********************/
94
95
/**
96
* Draw the middle part (rectangular) of a rectangle
97
* @param coords the coordinates of the original rectangle
98
* @param mask the rectangle will be drawn only on this area
99
* @param rects_p pointer to a rectangle style
100
* @param opa_scale scale down all opacities by the factor
101
*/
102
static void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
103
{
104
uint16_t radius = style->body.radius;
105
106
lv_color_t mcolor = style->body.main_color;
107
lv_color_t gcolor = style->body.grad_color;
108
uint8_t mix;
109
lv_coord_t height = lv_area_get_height(coords);
110
lv_coord_t width = lv_area_get_width(coords);
111
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;
112
113
radius = lv_draw_cont_radius_corr(radius, width, height);
114
115
/*If the radius is too big then there is no body*/
116
if(radius > height / 2) return;
117
118
lv_area_t work_area;
119
work_area.x1 = coords->x1;
120
work_area.x2 = coords->x2;
121
122
if(mcolor.full == gcolor.full) {
123
work_area.y1 = coords->y1 + radius;
124
work_area.y2 = coords->y2 - radius;
125
126
if(style->body.radius != 0) {
127
#if LV_ANTIALIAS
128
work_area.y1 += 2;
129
work_area.y2 -= 2;
130
#else
131
work_area.y1 += 1;
132
work_area.y2 -= 1;
133
#endif
134
}
135
136
fill_fp(&work_area, mask, mcolor, opa);
137
} else {
138
lv_coord_t row;
139
lv_coord_t row_start = coords->y1 + radius;
140
lv_coord_t row_end = coords->y2 - radius;
141
lv_color_t act_color;
142
143
if(style->body.radius != 0) {
144
#if LV_ANTIALIAS
145
row_start += 2;
146
row_end -= 2;
147
#else
148
row_start += 1;
149
row_end -= 1;
150
#endif
151
}
152
if(row_start < 0) row_start = 0;
153
154
for(row = row_start; row <= row_end; row ++) {
155
work_area.y1 = row;
156
work_area.y2 = row;
157
mix = (uint32_t)((uint32_t)(coords->y2 - work_area.y1) * 255) / height;
158
act_color = lv_color_mix(mcolor, gcolor, mix);
159
160
fill_fp(&work_area, mask, act_color, opa);
161
}
162
}
163
}
164
/**
165
* Draw the top and bottom parts (corners) of a rectangle
166
* @param coords the coordinates of the original rectangle
167
* @param mask the rectangle will be drawn only on this area
168
* @param rects_p pointer to a rectangle style
169
* @param opa_scale scale down all opacities by the factor
170
*/
171
static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
172
{
173
uint16_t radius = style->body.radius;
174
175
lv_color_t mcolor = style->body.main_color;
176
lv_color_t gcolor = style->body.grad_color;
177
lv_color_t act_color;
178
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;
179
uint8_t mix;
180
lv_coord_t height = lv_area_get_height(coords);
181
lv_coord_t width = lv_area_get_width(coords);
182
183
radius = lv_draw_cont_radius_corr(radius, width, height);
184
185
lv_point_t lt_origo; /*Left Top origo*/
186
lv_point_t lb_origo; /*Left Bottom origo*/
187
lv_point_t rt_origo; /*Right Top origo*/
188
lv_point_t rb_origo; /*Left Bottom origo*/
189
190
lt_origo.x = coords->x1 + radius + LV_ANTIALIAS;
191
lt_origo.y = coords->y1 + radius + LV_ANTIALIAS;
192
193
lb_origo.x = coords->x1 + radius + LV_ANTIALIAS;
194
lb_origo.y = coords->y2 - radius - LV_ANTIALIAS;
195
196
rt_origo.x = coords->x2 - radius - LV_ANTIALIAS;
197
rt_origo.y = coords->y1 + radius + LV_ANTIALIAS;
198
199
rb_origo.x = coords->x2 - radius - LV_ANTIALIAS;
200
rb_origo.y = coords->y2 - radius - LV_ANTIALIAS;
201
202
lv_area_t edge_top_area;
203
lv_area_t mid_top_area;
204
lv_area_t mid_bot_area;
205
lv_area_t edge_bot_area;
206
207
lv_point_t cir;
208
lv_coord_t cir_tmp;
209
lv_circ_init(&cir, &cir_tmp, radius);
210
211
/*Init the areas*/
212
lv_area_set(&mid_bot_area, lb_origo.x + LV_CIRC_OCT4_X(cir),
213
lb_origo.y + LV_CIRC_OCT4_Y(cir),
214
rb_origo.x + LV_CIRC_OCT1_X(cir),
215
rb_origo.y + LV_CIRC_OCT1_Y(cir));
216
217
lv_area_set(&edge_bot_area, lb_origo.x + LV_CIRC_OCT3_X(cir),
218
lb_origo.y + LV_CIRC_OCT3_Y(cir),
219
rb_origo.x + LV_CIRC_OCT2_X(cir),
220
rb_origo.y + LV_CIRC_OCT2_Y(cir));
221
222
lv_area_set(&mid_top_area, lt_origo.x + LV_CIRC_OCT5_X(cir),
223
lt_origo.y + LV_CIRC_OCT5_Y(cir),
224
rt_origo.x + LV_CIRC_OCT8_X(cir),
225
rt_origo.y + LV_CIRC_OCT8_Y(cir));
226
227
lv_area_set(&edge_top_area, lt_origo.x + LV_CIRC_OCT6_X(cir),
228
lt_origo.y + LV_CIRC_OCT6_Y(cir),
229
rt_origo.x + LV_CIRC_OCT7_X(cir),
230
rt_origo.y + LV_CIRC_OCT7_Y(cir));
231
#if LV_ANTIALIAS
232
/*Store some internal states for anti-aliasing*/
233
lv_coord_t out_y_seg_start = 0;
234
lv_coord_t out_y_seg_end = 0;
235
lv_coord_t out_x_last = radius;
236
237
lv_color_t aa_color_hor_top;
238
lv_color_t aa_color_hor_bottom;
239
lv_color_t aa_color_ver;
240
#endif
241
242
while(lv_circ_cont(&cir)) {
243
#if LV_ANTIALIAS != 0
244
/*New step in y on the outter circle*/
245
if(out_x_last != cir.x) {
246
out_y_seg_end = cir.y;
247
lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;
248
lv_point_t aa_p;
249
250
aa_p.x = out_x_last;
251
aa_p.y = out_y_seg_start;
252
253
mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height;
254
aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix);
255
aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix);
256
257
lv_coord_t i;
258
for(i = 0; i < seg_size; i++) {
259
lv_opa_t aa_opa;
260
if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/
261
aa_opa = antialias_get_opa_circ(seg_size, i, opa);
262
} else {
263
aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa);
264
}
265
266
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa);
267
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa);
268
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa);
269
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa);
270
271
mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height;
272
aa_color_ver = lv_color_mix(mcolor, gcolor, mix);
273
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa);
274
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa);
275
276
aa_color_ver = lv_color_mix(gcolor, mcolor, mix);
277
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa);
278
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa);
279
}
280
281
out_x_last = cir.x;
282
out_y_seg_start = out_y_seg_end;
283
}
284
#endif
285
uint8_t edge_top_refr = 0;
286
uint8_t mid_top_refr = 0;
287
uint8_t mid_bot_refr = 0;
288
uint8_t edge_bot_refr = 0;
289
290
/* If a new row coming draw the previous
291
* The y coordinate can remain the same so wait for a new*/
292
if(mid_bot_area.y1 != LV_CIRC_OCT4_Y(cir) + lb_origo.y) mid_bot_refr = 1;
293
294
if(edge_bot_area.y1 != LV_CIRC_OCT2_Y(cir) + lb_origo.y) edge_bot_refr = 1;
295
296
if(mid_top_area.y1 != LV_CIRC_OCT8_Y(cir) + lt_origo.y) mid_top_refr = 1;
297
298
if(edge_top_area.y1 != LV_CIRC_OCT7_Y(cir) + lt_origo.y) edge_top_refr = 1;
299
300
/*Draw the areas which are not disabled*/
301
if(edge_top_refr != 0) {
302
if(mcolor.full == gcolor.full) act_color = mcolor;
303
else {
304
mix = (uint32_t)((uint32_t)(coords->y2 - edge_top_area.y1) * 255) / height;
305
act_color = lv_color_mix(mcolor, gcolor, mix);
306
}
307
fill_fp(&edge_top_area, mask, act_color, opa);
308
}
309
310
if(mid_top_refr != 0) {
311
if(mcolor.full == gcolor.full) act_color = mcolor;
312
else {
313
mix = (uint32_t)((uint32_t)(coords->y2 - mid_top_area.y1) * 255) / height;
314
act_color = lv_color_mix(mcolor, gcolor, mix);
315
}
316
fill_fp(&mid_top_area, mask, act_color, opa);
317
}
318
319
if(mid_bot_refr != 0) {
320
if(mcolor.full == gcolor.full) act_color = mcolor;
321
else {
322
mix = (uint32_t)((uint32_t)(coords->y2 - mid_bot_area.y1) * 255) / height;
323
act_color = lv_color_mix(mcolor, gcolor, mix);
324
}
325
fill_fp(&mid_bot_area, mask, act_color, opa);
326
}
327
328
if(edge_bot_refr != 0) {
329
330
if(mcolor.full == gcolor.full) act_color = mcolor;
331
else {
332
mix = (uint32_t)((uint32_t)(coords->y2 - edge_bot_area.y1) * 255) / height;
333
act_color = lv_color_mix(mcolor, gcolor, mix);
334
}
335
fill_fp(&edge_bot_area, mask, act_color, opa);
336
}
337
338
/*Save the current coordinates*/
339
lv_area_set(&mid_bot_area, lb_origo.x + LV_CIRC_OCT4_X(cir),
340
lb_origo.y + LV_CIRC_OCT4_Y(cir),
341
rb_origo.x + LV_CIRC_OCT1_X(cir),
342
rb_origo.y + LV_CIRC_OCT1_Y(cir));
343
344
lv_area_set(&edge_bot_area, lb_origo.x + LV_CIRC_OCT3_X(cir),
345
lb_origo.y + LV_CIRC_OCT3_Y(cir),
346
rb_origo.x + LV_CIRC_OCT2_X(cir),
347
rb_origo.y + LV_CIRC_OCT2_Y(cir));
348
349
lv_area_set(&mid_top_area, lt_origo.x + LV_CIRC_OCT5_X(cir),
350
lt_origo.y + LV_CIRC_OCT5_Y(cir),
351
rt_origo.x + LV_CIRC_OCT8_X(cir),
352
rt_origo.y + LV_CIRC_OCT8_Y(cir));
353
354
lv_area_set(&edge_top_area, lt_origo.x + LV_CIRC_OCT6_X(cir),
355
lt_origo.y + LV_CIRC_OCT6_Y(cir),
356
rt_origo.x + LV_CIRC_OCT7_X(cir),
357
rt_origo.y + LV_CIRC_OCT7_Y(cir));
358
359
lv_circ_next(&cir, &cir_tmp);
360
}
361
362
if(mcolor.full == gcolor.full) act_color = mcolor;
363
else {
364
mix = (uint32_t)((uint32_t)(coords->y2 - edge_top_area.y1) * 255) / height;
365
act_color = lv_color_mix(mcolor, gcolor, mix);
366
}
367
fill_fp(&edge_top_area, mask, act_color, opa);
368
369
if(edge_top_area.y1 != mid_top_area.y1) {
370
371
if(mcolor.full == gcolor.full) act_color = mcolor;
372
else {
373
mix = (uint32_t)((uint32_t)(coords->y2 - mid_top_area.y1) * 255) / height;
374
act_color = lv_color_mix(mcolor, gcolor, mix);
375
}
376
fill_fp(&mid_top_area, mask, act_color, opa);
377
}
378
379
if(mcolor.full == gcolor.full) act_color = mcolor;
380
else {
381
mix = (uint32_t)((uint32_t)(coords->y2 - mid_bot_area.y1) * 255) / height;
382
act_color = lv_color_mix(mcolor, gcolor, mix);
383
}
384
fill_fp(&mid_bot_area, mask, act_color, opa);
385
386
if(edge_bot_area.y1 != mid_bot_area.y1) {
387
388
if(mcolor.full == gcolor.full) act_color = mcolor;
389
else {
390
mix = (uint32_t)((uint32_t)(coords->y2 - edge_bot_area.y1) * 255) / height;
391
act_color = lv_color_mix(mcolor, gcolor, mix);
392
}
393
fill_fp(&edge_bot_area, mask, act_color, opa);
394
}
395
396
397
#if LV_ANTIALIAS
398
/*The first and the last line is not drawn*/
399
edge_top_area.x1 = coords->x1 + radius + 2;
400
edge_top_area.x2 = coords->x2 - radius - 2;
401
edge_top_area.y1 = coords->y1;
402
edge_top_area.y2 = coords->y1;
403
fill_fp(&edge_top_area, mask, style->body.main_color, opa);
404
405
edge_top_area.y1 = coords->y2;
406
edge_top_area.y2 = coords->y2;
407
fill_fp(&edge_top_area, mask, style->body.grad_color, opa);
408
409
/*Last parts of the anti-alias*/
410
out_y_seg_end = cir.y;
411
lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;
412
lv_point_t aa_p;
413
414
aa_p.x = out_x_last;
415
aa_p.y = out_y_seg_start;
416
417
mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height;
418
aa_color_hor_bottom = lv_color_mix(gcolor, mcolor, mix);
419
aa_color_hor_top = lv_color_mix(mcolor, gcolor, mix);
420
421
lv_coord_t i;
422
for(i = 0; i < seg_size; i++) {
423
lv_opa_t aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa);
424
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa);
425
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa);
426
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa);
427
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa);
428
429
mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height;
430
aa_color_ver = lv_color_mix(mcolor, gcolor, mix);
431
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa);
432
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa);
433
434
aa_color_ver = lv_color_mix(gcolor, mcolor, mix);
435
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa);
436
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa);
437
}
438
439
/*In some cases the last pixel is not drawn*/
440
if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) {
441
aa_p.x = out_x_last;
442
aa_p.y = out_x_last;
443
444
mix = (uint32_t)((uint32_t)(out_x_last) * 255) / height;
445
aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix);
446
aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix);
447
448
lv_opa_t aa_opa = opa >> 1;
449
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, aa_color_hor_bottom, aa_opa);
450
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, aa_color_hor_bottom, aa_opa);
451
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, aa_color_hor_top, aa_opa);
452
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, aa_color_hor_top, aa_opa);
453
}
454
455
#endif
456
457
458
}
459
460
/**
461
* Draw the straight parts of a rectangle border
462
* @param coords the coordinates of the original rectangle
463
* @param mask_ the rectangle will be drawn only on this area
464
* @param rstyle pointer to a rectangle style
465
* @param opa_scale scale down all opacities by the factor
466
*/
467
static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
468
{
469
uint16_t radius = style->body.radius;
470
471
lv_coord_t width = lv_area_get_width(coords);
472
lv_coord_t height = lv_area_get_height(coords);
473
uint16_t bwidth = style->body.border.width;
474
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.border.opa : (uint16_t)((uint16_t) style->body.border.opa * opa_scale) >> 8;
475
lv_border_part_t part = style->body.border.part;
476
lv_color_t color = style->body.border.color;
477
lv_area_t work_area;
478
lv_coord_t length_corr = 0;
479
lv_coord_t corner_size = 0;
480
481
/*the 0 px border width drawn as 1 px, so decrement the b_width*/
482
bwidth--;
483
484
radius = lv_draw_cont_radius_corr(radius, width, height);
485
486
if(radius < bwidth) {
487
length_corr = bwidth - radius - LV_ANTIALIAS;
488
corner_size = bwidth;
489
} else {
490
corner_size = radius + LV_ANTIALIAS;
491
}
492
493
/*If radius == 0 is a special case*/
494
if(style->body.radius == 0) {
495
/*Left top corner*/
496
if(part & LV_BORDER_TOP) {
497
work_area.x1 = coords->x1;
498
work_area.x2 = coords->x2;
499
work_area.y1 = coords->y1;
500
work_area.y2 = coords->y1 + bwidth;
501
fill_fp(&work_area, mask, color, opa);
502
}
503
504
/*Right top corner*/
505
if(part & LV_BORDER_RIGHT) {
506
work_area.x1 = coords->x2 - bwidth;
507
work_area.x2 = coords->x2;
508
work_area.y1 = coords->y1 + (part & LV_BORDER_TOP ? bwidth + 1 : 0);
509
work_area.y2 = coords->y2 - (part & LV_BORDER_BOTTOM ? bwidth + 1 : 0);
510
fill_fp(&work_area, mask, color, opa);
511
}
512
513
/*Left bottom corner*/
514
if(part & LV_BORDER_LEFT) {
515
work_area.x1 = coords->x1;
516
work_area.x2 = coords->x1 + bwidth;
517
work_area.y1 = coords->y1 + (part & LV_BORDER_TOP ? bwidth + 1 : 0);
518
work_area.y2 = coords->y2 - (part & LV_BORDER_BOTTOM ? bwidth + 1 : 0);
519
fill_fp(&work_area, mask, color, opa);
520
}
521
522
/*Right bottom corner*/
523
if(part & LV_BORDER_BOTTOM) {
524
work_area.x1 = coords->x1;
525
work_area.x2 = coords->x2;
526
work_area.y1 = coords->y2 - bwidth;
527
work_area.y2 = coords->y2;
528
fill_fp(&work_area, mask, color, opa);
529
}
530
return;
531
}
532
533
/* Modify the corner_size if corner is drawn */
534
corner_size ++;
535
536
/*Depending one which part's are drawn modify the area lengths */
537
if(part & LV_BORDER_TOP) work_area.y1 = coords->y1 + corner_size;
538
else work_area.y1 = coords->y1 + radius;
539
540
if(part & LV_BORDER_BOTTOM) work_area.y2 = coords->y2 - corner_size;
541
else work_area.y2 = coords->y2 - radius;
542
543
/*Left border*/
544
if(part & LV_BORDER_LEFT) {
545
work_area.x1 = coords->x1;
546
work_area.x2 = work_area.x1 + bwidth;
547
fill_fp(&work_area, mask, color, opa);
548
}
549
550
/*Right border*/
551
if(part & LV_BORDER_RIGHT) {
552
work_area.x2 = coords->x2;
553
work_area.x1 = work_area.x2 - bwidth;
554
fill_fp(&work_area, mask, color, opa);
555
}
556
557
work_area.x1 = coords->x1 + corner_size - length_corr;
558
work_area.x2 = coords->x2 - corner_size + length_corr;
559
560
/*Upper border*/
561
if(part & LV_BORDER_TOP) {
562
work_area.y1 = coords->y1;
563
work_area.y2 = coords->y1 + bwidth;
564
fill_fp(&work_area, mask, color, opa);
565
}
566
567
/*Lower border*/
568
if(part & LV_BORDER_BOTTOM) {
569
work_area.y2 = coords->y2;
570
work_area.y1 = work_area.y2 - bwidth;
571
fill_fp(&work_area, mask, color, opa);
572
}
573
574
/*Draw the a remaining rectangles if the radius is smaller then bwidth */
575
if(length_corr != 0) {
576
/*Left top correction*/
577
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
578
work_area.x1 = coords->x1;
579
work_area.x2 = coords->x1 + radius + LV_ANTIALIAS;
580
work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS;
581
work_area.y2 = coords->y1 + bwidth;
582
fill_fp(&work_area, mask, color, opa);
583
}
584
585
/*Right top correction*/
586
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
587
work_area.x1 = coords->x2 - radius - LV_ANTIALIAS;
588
work_area.x2 = coords->x2;
589
work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS;
590
work_area.y2 = coords->y1 + bwidth;
591
fill_fp(&work_area, mask, color, opa);
592
}
593
594
/*Left bottom correction*/
595
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
596
work_area.x1 = coords->x1;
597
work_area.x2 = coords->x1 + radius + LV_ANTIALIAS;
598
work_area.y1 = coords->y2 - bwidth;
599
work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS;
600
fill_fp(&work_area, mask, color, opa);
601
}
602
603
/*Right bottom correction*/
604
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
605
work_area.x1 = coords->x2 - radius - LV_ANTIALIAS;
606
work_area.x2 = coords->x2;
607
work_area.y1 = coords->y2 - bwidth;
608
work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS;
609
fill_fp(&work_area, mask, color, opa);
610
}
611
}
612
613
/*If radius == 0 one px on the corners are not drawn by main drawer*/
614
if(style->body.radius == 0) {
615
/*Left top corner*/
616
if(part & (LV_BORDER_TOP | LV_BORDER_LEFT)) {
617
work_area.x1 = coords->x1;
618
work_area.x2 = coords->x1 + LV_ANTIALIAS;
619
work_area.y1 = coords->y1;
620
work_area.y2 = coords->y1 + LV_ANTIALIAS;
621
fill_fp(&work_area, mask, color, opa);
622
}
623
624
/*Right top corner*/
625
if(part & (LV_BORDER_TOP | LV_BORDER_RIGHT)) {
626
work_area.x1 = coords->x2 - LV_ANTIALIAS;
627
work_area.x2 = coords->x2;
628
work_area.y1 = coords->y1;
629
work_area.y2 = coords->y1 + LV_ANTIALIAS;
630
fill_fp(&work_area, mask, color, opa);
631
}
632
633
/*Left bottom corner*/
634
if(part & (LV_BORDER_BOTTOM | LV_BORDER_LEFT)) {
635
work_area.x1 = coords->x1;
636
work_area.x2 = coords->x1 + LV_ANTIALIAS;
637
work_area.y1 = coords->y2 - LV_ANTIALIAS;
638
work_area.y2 = coords->y2;
639
fill_fp(&work_area, mask, color, opa);
640
}
641
642
/*Right bottom corner*/
643
if(part & (LV_BORDER_BOTTOM | LV_BORDER_RIGHT)) {
644
work_area.x1 = coords->x2 - LV_ANTIALIAS;
645
work_area.x2 = coords->x2;
646
work_area.y1 = coords->y2 - LV_ANTIALIAS;
647
work_area.y2 = coords->y2;
648
fill_fp(&work_area, mask, color, opa);
649
}
650
}
651
}
652
653
654
/**
655
* Draw the corners of a rectangle border
656
* @param coords the coordinates of the original rectangle
657
* @param mask the rectangle will be drawn only on this area
658
* @param style pointer to a style
659
* @param opa_scale scale down all opacities by the factor
660
*/
661
static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
662
{
663
uint16_t radius = style->body.radius ;
664
uint16_t bwidth = style->body.border.width;
665
lv_color_t color = style->body.border.color;
666
lv_border_part_t part = style->body.border.part;
667
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.border.opa : (uint16_t)((uint16_t) style->body.border.opa * opa_scale) >> 8;
668
/*0 px border width drawn as 1 px, so decrement the bwidth*/
669
bwidth--;
670
671
#if LV_ANTIALIAS
672
bwidth--; /*Because of anti-aliasing the border seems one pixel ticker*/
673
#endif
674
675
lv_coord_t width = lv_area_get_width(coords);
676
lv_coord_t height = lv_area_get_height(coords);
677
678
radius = lv_draw_cont_radius_corr(radius, width, height);
679
680
lv_point_t lt_origo; /*Left Top origo*/
681
lv_point_t lb_origo; /*Left Bottom origo*/
682
lv_point_t rt_origo; /*Right Top origo*/
683
lv_point_t rb_origo; /*Left Bottom origo*/
684
685
lt_origo.x = coords->x1 + radius + LV_ANTIALIAS;
686
lt_origo.y = coords->y1 + radius + LV_ANTIALIAS;
687
688
lb_origo.x = coords->x1 + radius + LV_ANTIALIAS;
689
lb_origo.y = coords->y2 - radius - LV_ANTIALIAS;
690
691
rt_origo.x = coords->x2 - radius - LV_ANTIALIAS;
692
rt_origo.y = coords->y1 + radius + LV_ANTIALIAS;
693
694
rb_origo.x = coords->x2 - radius - LV_ANTIALIAS;
695
rb_origo.y = coords->y2 - radius - LV_ANTIALIAS;
696
697
lv_point_t cir_out;
698
lv_coord_t tmp_out;
699
lv_circ_init(&cir_out, &tmp_out, radius);
700
701
lv_point_t cir_in;
702
lv_coord_t tmp_in;
703
lv_coord_t radius_in = radius - bwidth;
704
705
if(radius_in < 0) {
706
radius_in = 0;
707
}
708
709
lv_circ_init(&cir_in, &tmp_in, radius_in);
710
711
lv_area_t circ_area;
712
lv_coord_t act_w1;
713
lv_coord_t act_w2;
714
715
#if LV_ANTIALIAS
716
/*Store some internal states for anti-aliasing*/
717
lv_coord_t out_y_seg_start = 0;
718
lv_coord_t out_y_seg_end = 0;
719
lv_coord_t out_x_last = radius;
720
721
722
lv_coord_t in_y_seg_start = 0;
723
lv_coord_t in_y_seg_end = 0;
724
lv_coord_t in_x_last = radius - bwidth;
725
#endif
726
727
while(cir_out.y <= cir_out.x) {
728
729
/*Calculate the actual width to avoid overwriting pixels*/
730
if(cir_in.y < cir_in.x) {
731
act_w1 = cir_out.x - cir_in.x;
732
act_w2 = act_w1;
733
} else {
734
act_w1 = cir_out.x - cir_out.y;
735
act_w2 = act_w1 - 1;
736
}
737
738
#if LV_ANTIALIAS != 0
739
/*New step in y on the outter circle*/
740
if(out_x_last != cir_out.x) {
741
out_y_seg_end = cir_out.y;
742
lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;
743
lv_point_t aa_p;
744
745
aa_p.x = out_x_last;
746
aa_p.y = out_y_seg_start;
747
748
lv_coord_t i;
749
for(i = 0; i < seg_size; i++) {
750
lv_opa_t aa_opa;
751
752
if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/
753
aa_opa = antialias_get_opa_circ(seg_size, i, opa);
754
} else {
755
aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa);
756
}
757
758
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
759
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
760
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
761
}
762
763
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
764
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
765
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
766
}
767
768
769
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
770
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
771
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
772
}
773
774
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
775
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
776
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
777
}
778
}
779
780
out_x_last = cir_out.x;
781
out_y_seg_start = out_y_seg_end;
782
}
783
784
/*New step in y on the inner circle*/
785
if(in_x_last != cir_in.x) {
786
in_y_seg_end = cir_out.y;
787
lv_coord_t seg_size = in_y_seg_end - in_y_seg_start;
788
lv_point_t aa_p;
789
790
aa_p.x = in_x_last;
791
aa_p.y = in_y_seg_start;
792
793
lv_coord_t i;
794
for(i = 0; i < seg_size; i++) {
795
lv_opa_t aa_opa;
796
797
if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/
798
aa_opa = opa - antialias_get_opa_circ(seg_size, i, opa);
799
} else {
800
aa_opa = lv_draw_aa_get_opa(seg_size, i, opa);
801
}
802
803
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
804
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
805
}
806
807
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
808
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
809
}
810
811
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
812
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
813
}
814
815
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
816
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
817
}
818
819
/*Be sure the pixels on the middle are not drawn twice*/
820
if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) {
821
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
822
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
823
}
824
825
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
826
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
827
}
828
829
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
830
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
831
}
832
833
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
834
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
835
}
836
}
837
838
}
839
840
in_x_last = cir_in.x;
841
in_y_seg_start = in_y_seg_end;
842
843
}
844
845
#endif
846
847
848
/*Draw the octets to the right bottom corner*/
849
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
850
circ_area.x1 = rb_origo.x + LV_CIRC_OCT1_X(cir_out) - act_w2;
851
circ_area.x2 = rb_origo.x + LV_CIRC_OCT1_X(cir_out);
852
circ_area.y1 = rb_origo.y + LV_CIRC_OCT1_Y(cir_out);
853
circ_area.y2 = rb_origo.y + LV_CIRC_OCT1_Y(cir_out);
854
fill_fp(&circ_area, mask, color, opa);
855
856
circ_area.x1 = rb_origo.x + LV_CIRC_OCT2_X(cir_out);
857
circ_area.x2 = rb_origo.x + LV_CIRC_OCT2_X(cir_out);
858
circ_area.y1 = rb_origo.y + LV_CIRC_OCT2_Y(cir_out) - act_w1;
859
circ_area.y2 = rb_origo.y + LV_CIRC_OCT2_Y(cir_out);
860
fill_fp(&circ_area, mask, color, opa);
861
}
862
863
/*Draw the octets to the left bottom corner*/
864
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
865
circ_area.x1 = lb_origo.x + LV_CIRC_OCT3_X(cir_out);
866
circ_area.x2 = lb_origo.x + LV_CIRC_OCT3_X(cir_out);
867
circ_area.y1 = lb_origo.y + LV_CIRC_OCT3_Y(cir_out) - act_w2;
868
circ_area.y2 = lb_origo.y + LV_CIRC_OCT3_Y(cir_out);
869
fill_fp(&circ_area, mask, color, opa);
870
871
circ_area.x1 = lb_origo.x + LV_CIRC_OCT4_X(cir_out);
872
circ_area.x2 = lb_origo.x + LV_CIRC_OCT4_X(cir_out) + act_w1;
873
circ_area.y1 = lb_origo.y + LV_CIRC_OCT4_Y(cir_out);
874
circ_area.y2 = lb_origo.y + LV_CIRC_OCT4_Y(cir_out);
875
fill_fp(&circ_area, mask, color, opa);
876
}
877
878
/*Draw the octets to the left top corner*/
879
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
880
if(lb_origo.y + LV_CIRC_OCT4_Y(cir_out) > lt_origo.y + LV_CIRC_OCT5_Y(cir_out)) {
881
/*Don't draw if the lines are common in the middle*/
882
circ_area.x1 = lt_origo.x + LV_CIRC_OCT5_X(cir_out);
883
circ_area.x2 = lt_origo.x + LV_CIRC_OCT5_X(cir_out) + act_w2;
884
circ_area.y1 = lt_origo.y + LV_CIRC_OCT5_Y(cir_out);
885
circ_area.y2 = lt_origo.y + LV_CIRC_OCT5_Y(cir_out);
886
fill_fp(&circ_area, mask, color, opa);
887
}
888
889
circ_area.x1 = lt_origo.x + LV_CIRC_OCT6_X(cir_out);
890
circ_area.x2 = lt_origo.x + LV_CIRC_OCT6_X(cir_out);
891
circ_area.y1 = lt_origo.y + LV_CIRC_OCT6_Y(cir_out);
892
circ_area.y2 = lt_origo.y + LV_CIRC_OCT6_Y(cir_out) + act_w1;
893
fill_fp(&circ_area, mask, color, opa);
894
}
895
896
/*Draw the octets to the right top corner*/
897
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
898
circ_area.x1 = rt_origo.x + LV_CIRC_OCT7_X(cir_out);
899
circ_area.x2 = rt_origo.x + LV_CIRC_OCT7_X(cir_out);
900
circ_area.y1 = rt_origo.y + LV_CIRC_OCT7_Y(cir_out);
901
circ_area.y2 = rt_origo.y + LV_CIRC_OCT7_Y(cir_out) + act_w2;
902
fill_fp(&circ_area, mask, color, opa);
903
904
/*Don't draw if the lines are common in the middle*/
905
if(rb_origo.y + LV_CIRC_OCT1_Y(cir_out) > rt_origo.y + LV_CIRC_OCT8_Y(cir_out)) {
906
circ_area.x1 = rt_origo.x + LV_CIRC_OCT8_X(cir_out) - act_w1;
907
circ_area.x2 = rt_origo.x + LV_CIRC_OCT8_X(cir_out);
908
circ_area.y1 = rt_origo.y + LV_CIRC_OCT8_Y(cir_out);
909
circ_area.y2 = rt_origo.y + LV_CIRC_OCT8_Y(cir_out);
910
fill_fp(&circ_area, mask, color, opa);
911
}
912
}
913
lv_circ_next(&cir_out, &tmp_out);
914
915
/*The internal circle will be ready faster
916
* so check it! */
917
if(cir_in.y < cir_in.x) {
918
lv_circ_next(&cir_in, &tmp_in);
919
}
920
}
921
922
923
#if LV_ANTIALIAS != 0
924
925
/*Last parts of the outer anti-alias*/
926
out_y_seg_end = cir_out.y;
927
lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;
928
lv_point_t aa_p;
929
930
aa_p.x = out_x_last;
931
aa_p.y = out_y_seg_start;
932
933
lv_coord_t i;
934
for(i = 0; i < seg_size; i++) {
935
lv_opa_t aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa);
936
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
937
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
938
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
939
}
940
941
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
942
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
943
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
944
}
945
946
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
947
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
948
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
949
}
950
951
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
952
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
953
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
954
}
955
}
956
957
/*In some cases the last pixel in the outer middle is not drawn*/
958
if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) {
959
aa_p.x = out_x_last;
960
aa_p.y = out_x_last;
961
962
lv_opa_t aa_opa = opa >> 1;
963
964
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
965
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, style->body.border.color, aa_opa);
966
}
967
968
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
969
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, style->body.border.color, aa_opa);
970
}
971
972
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
973
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, style->body.border.color, aa_opa);
974
}
975
976
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
977
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, style->body.border.color, aa_opa);
978
}
979
}
980
981
/*Last parts of the inner anti-alias*/
982
in_y_seg_end = cir_in.y;
983
aa_p.x = in_x_last;
984
aa_p.y = in_y_seg_start;
985
seg_size = in_y_seg_end - in_y_seg_start;
986
987
for(i = 0; i < seg_size; i++) {
988
lv_opa_t aa_opa = lv_draw_aa_get_opa(seg_size, i, opa);
989
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
990
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
991
}
992
993
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
994
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
995
}
996
997
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
998
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
999
}
1000
1001
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
1002
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
1003
}
1004
1005
if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) {
1006
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
1007
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
1008
}
1009
1010
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
1011
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
1012
}
1013
1014
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
1015
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
1016
}
1017
1018
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
1019
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
1020
}
1021
}
1022
}
1023
1024
#endif
1025
1026
}
1027
1028
#if USE_LV_SHADOW && LV_VDB_SIZE
1029
1030
/**
1031
* Draw a shadow
1032
* @param rect pointer to rectangle object
1033
* @param mask pointer to a mask area (from the design functions)
1034
* @param opa_scale scale down all opacities by the factor
1035
*/
1036
static void lv_draw_shadow(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
1037
{
1038
/* If mask is in the middle of cords do not draw shadow*/
1039
lv_coord_t radius = style->body.radius;
1040
lv_coord_t width = lv_area_get_width(coords);
1041
lv_coord_t height = lv_area_get_height(coords);
1042
radius = lv_draw_cont_radius_corr(radius, width, height);
1043
lv_area_t area_tmp;
1044
1045
/*Check horizontally without radius*/
1046
lv_area_copy(&area_tmp, coords);
1047
area_tmp.x1 += radius;
1048
area_tmp.x2 -= radius;
1049
if(lv_area_is_in(mask, &area_tmp) != false) return;
1050
1051
/*Check vertically without radius*/
1052
lv_area_copy(&area_tmp, coords);
1053
area_tmp.y1 += radius;
1054
area_tmp.y2 -= radius;
1055
if(lv_area_is_in(mask, &area_tmp) != false) return;
1056
1057
if(style->body.shadow.type == LV_SHADOW_FULL) {
1058
lv_draw_shadow_full(coords, mask, style, opa_scale);
1059
} else if(style->body.shadow.type == LV_SHADOW_BOTTOM) {
1060
lv_draw_shadow_bottom(coords, mask, style, opa_scale);
1061
}
1062
}
1063
1064
static void lv_draw_shadow_full(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
1065
{
1066
1067
/* KNOWN ISSUE
1068
* The algorithm calculates the shadow only above the middle point of the radius (speaking about the left top corner).
1069
* It causes an error because it doesn't consider how long the straight edge is which effects the value of bottom of the corner shadow.
1070
* In addition the straight shadow is drawn from the middles point of the radius however
1071
* the ends of the straight parts still should be effected by the corner shadow.
1072
* It also causes an issue in opacity. A smaller radius means smaller average shadow opacity.
1073
* The solution should be to start `line` from `- swidth` and handle if the straight part is short (or zero) and the value is taken from
1074
* the other corner. `col` also should start from `- swidth`
1075
*/
1076
1077
1078
lv_coord_t radius = style->body.radius;
1079
lv_coord_t swidth = style->body.shadow.width;
1080
1081
lv_coord_t width = lv_area_get_width(coords);
1082
lv_coord_t height = lv_area_get_height(coords);
1083
1084
radius = lv_draw_cont_radius_corr(radius, width, height);
1085
1086
radius += LV_ANTIALIAS;
1087
1088
#if LV_COMPILER_VLA_SUPPORTED
1089
lv_coord_t curve_x[radius + swidth + 1]; /*Stores the 'x' coordinates of a quarter circle.*/
1090
#else
1091
# if LV_HOR_RES > LV_VER_RES
1092
lv_coord_t curve_x[LV_HOR_RES];
1093
# else
1094
lv_coord_t curve_x[LV_VER_RES];
1095
# endif
1096
#endif
1097
memset(curve_x, 0, sizeof(curve_x));
1098
lv_point_t circ;
1099
lv_coord_t circ_tmp;
1100
lv_circ_init(&circ, &circ_tmp, radius);
1101
while(lv_circ_cont(&circ)) {
1102
curve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ);
1103
curve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ);
1104
lv_circ_next(&circ, &circ_tmp);
1105
}
1106
int16_t line;
1107
1108
int16_t filter_width = 2 * swidth + 1;
1109
#if LV_COMPILER_VLA_SUPPORTED
1110
uint32_t line_1d_blur[filter_width];
1111
#else
1112
# if LV_HOR_RES > LV_VER_RES
1113
uint32_t line_1d_blur[LV_HOR_RES];
1114
# else
1115
uint32_t line_1d_blur[LV_VER_RES];
1116
# endif
1117
#endif
1118
/*1D Blur horizontally*/
1119
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;
1120
for(line = 0; line < filter_width; line++) {
1121
line_1d_blur[line] = (uint32_t)((uint32_t)(filter_width - line) * (opa * 2) << SHADOW_OPA_EXTRA_PRECISION) / (filter_width * filter_width);
1122
}
1123
1124
uint16_t col;
1125
#if LV_COMPILER_VLA_SUPPORTED
1126
lv_opa_t line_2d_blur[radius + swidth + 1];
1127
#else
1128
# if LV_HOR_RES > LV_VER_RES
1129
lv_opa_t line_2d_blur[LV_HOR_RES];
1130
# else
1131
lv_opa_t line_2d_blur[LV_VER_RES];
1132
# endif
1133
#endif
1134
1135
lv_point_t point_rt;
1136
lv_point_t point_rb;
1137
lv_point_t point_lt;
1138
lv_point_t point_lb;
1139
lv_point_t ofs_rb;
1140
lv_point_t ofs_rt;
1141
lv_point_t ofs_lb;
1142
lv_point_t ofs_lt;
1143
ofs_rb.x = coords->x2 - radius - LV_ANTIALIAS;
1144
ofs_rb.y = coords->y2 - radius - LV_ANTIALIAS;
1145
1146
ofs_rt.x = coords->x2 - radius - LV_ANTIALIAS;
1147
ofs_rt.y = coords->y1 + radius + LV_ANTIALIAS;
1148
1149
ofs_lb.x = coords->x1 + radius + LV_ANTIALIAS;
1150
ofs_lb.y = coords->y2 - radius - LV_ANTIALIAS;
1151
1152
ofs_lt.x = coords->x1 + radius + LV_ANTIALIAS;
1153
ofs_lt.y = coords->y1 + radius + LV_ANTIALIAS;
1154
bool line_ready;
1155
for(line = 0; line <= radius + swidth; line++) { /*Check all rows and make the 1D blur to 2D*/
1156
line_ready = false;
1157
for(col = 0; col <= radius + swidth; col++) { /*Check all pixels in a 1D blur line (from the origo to last shadow pixel (radius + swidth))*/
1158
1159
/*Sum the opacities from the lines above and below this 'row'*/
1160
int16_t line_rel;
1161
uint32_t px_opa_sum = 0;
1162
for(line_rel = -swidth; line_rel <= swidth; line_rel ++) {
1163
/*Get the relative x position of the 'line_rel' to 'line'*/
1164
int16_t col_rel;
1165
if(line + line_rel < 0) { /*Below the radius, here is the blur of the edge */
1166
col_rel = radius - curve_x[line] - col;
1167
} else if(line + line_rel > radius) { /*Above the radius, here won't be more 1D blur*/
1168
break;
1169
} else { /*Blur from the curve*/
1170
col_rel = curve_x[line + line_rel] - curve_x[line] - col;
1171
}
1172
1173
/*Add the value of the 1D blur on 'col_rel' position*/
1174
if(col_rel < -swidth) { /*Outside of the blurred area. */
1175
if(line_rel == -swidth) line_ready = true; /*If no data even on the very first line then it wont't be anything else in this line*/
1176
break; /*Break anyway because only smaller 'col_rel' values will come */
1177
} else if(col_rel > swidth) px_opa_sum += line_1d_blur[0]; /*Inside the not blurred area*/
1178
else px_opa_sum += line_1d_blur[swidth - col_rel]; /*On the 1D blur (+ swidth to align to the center)*/
1179
}
1180
1181
line_2d_blur[col] = px_opa_sum >> SHADOW_OPA_EXTRA_PRECISION;
1182
if(line_ready) {
1183
col++; /*To make this line to the last one ( drawing will go to '< col')*/
1184
break;
1185
}
1186
1187
}
1188
1189
/*Flush the line*/
1190
point_rt.x = curve_x[line] + ofs_rt.x + 1;
1191
point_rt.y = ofs_rt.y - line;
1192
1193
point_rb.x = curve_x[line] + ofs_rb.x + 1;
1194
point_rb.y = ofs_rb.y + line;
1195
1196
point_lt.x = ofs_lt.x - curve_x[line] - 1;
1197
point_lt.y = ofs_lt.y - line;
1198
1199
point_lb.x = ofs_lb.x - curve_x[line] - 1;
1200
point_lb.y = ofs_lb.y + line;
1201
1202
uint16_t d;
1203
for(d = 1; d < col; d++) {
1204
1205
if(point_lt.x < ofs_lt.x && point_lt.y < ofs_lt.y) {
1206
px_fp(point_lt.x, point_lt.y, mask, style->body.shadow.color, line_2d_blur[d]);
1207
}
1208
1209
if(point_lb.x < ofs_lb.x && point_lb.y > ofs_lb.y) {
1210
px_fp(point_lb.x, point_lb.y, mask, style->body.shadow.color, line_2d_blur[d]);
1211
}
1212
1213
if(point_rt.x > ofs_rt.x && point_rt.y < ofs_rt.y) {
1214
px_fp(point_rt.x, point_rt.y, mask, style->body.shadow.color, line_2d_blur[d]);
1215
}
1216
1217
if(point_rb.x > ofs_rb.x && point_rb.y > ofs_rb.y) {
1218
px_fp(point_rb.x, point_rb.y, mask, style->body.shadow.color, line_2d_blur[d]);
1219
}
1220
1221
point_rb.x++;
1222
point_lb.x--;
1223
1224
point_rt.x++;
1225
point_lt.x--;
1226
}
1227
1228
/* Put the first line to the edges too.
1229
* It is not correct because blur should be done below the corner too
1230
* but is is simple, fast and gives a good enough result*/
1231
if(line == 0) lv_draw_shadow_full_straight(coords, mask, style, line_2d_blur);
1232
}
1233
}
1234
1235
1236
static void lv_draw_shadow_bottom(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
1237
{
1238
lv_coord_t radius = style->body.radius;
1239
lv_coord_t swidth = style->body.shadow.width;
1240
lv_coord_t width = lv_area_get_width(coords);
1241
lv_coord_t height = lv_area_get_height(coords);
1242
1243
radius = lv_draw_cont_radius_corr(radius, width, height);
1244
radius += LV_ANTIALIAS * SHADOW_BOTTOM_AA_EXTRA_RADIUS;
1245
swidth += LV_ANTIALIAS;
1246
#if LV_COMPILER_VLA_SUPPORTED
1247
lv_coord_t curve_x[radius + 1]; /*Stores the 'x' coordinates of a quarter circle.*/
1248
#else
1249
# if LV_HOR_RES > LV_VER_RES
1250
lv_coord_t curve_x[LV_HOR_RES];
1251
# else
1252
lv_coord_t curve_x[LV_VER_RES];
1253
# endif
1254
#endif
1255
lv_point_t circ;
1256
lv_coord_t circ_tmp;
1257
lv_circ_init(&circ, &circ_tmp, radius);
1258
while(lv_circ_cont(&circ)) {
1259
curve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ);
1260
curve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ);
1261
lv_circ_next(&circ, &circ_tmp);
1262
}
1263
1264
int16_t col;
1265
#if LV_COMPILER_VLA_SUPPORTED
1266
lv_opa_t line_1d_blur[swidth];
1267
#else
1268
# if LV_HOR_RES > LV_VER_RES
1269
lv_opa_t line_1d_blur[LV_HOR_RES];
1270
# else
1271
lv_opa_t line_1d_blur[LV_VER_RES];
1272
# endif
1273
#endif
1274
1275
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;
1276
for(col = 0; col < swidth; col++) {
1277
line_1d_blur[col] = (uint32_t)((uint32_t)(swidth - col) * opa / 2) / (swidth);
1278
}
1279
1280
lv_point_t point_l;
1281
lv_point_t point_r;
1282
lv_area_t area_mid;
1283
lv_point_t ofs_l;
1284
lv_point_t ofs_r;
1285
1286
ofs_l.x = coords->x1 + radius;
1287
ofs_l.y = coords->y2 - radius + 1 - LV_ANTIALIAS;
1288
1289
ofs_r.x = coords->x2 - radius;
1290
ofs_r.y = coords->y2 - radius + 1 - LV_ANTIALIAS;
1291
1292
for(col = 0; col <= radius; col++) {
1293
point_l.x = ofs_l.x - col ;
1294
point_l.y = ofs_l.y + curve_x[col];
1295
1296
point_r.x = ofs_r.x + col;
1297
point_r.y = ofs_r.y + curve_x[col];
1298
1299
lv_opa_t px_opa;
1300
int16_t diff = col == 0 ? 0 : curve_x[col - 1] - curve_x[col];
1301
uint16_t d;
1302
for(d = 0; d < swidth; d++) {
1303
/*When stepping a pixel in y calculate the average with the pixel from the prev. column to make a blur */
1304
if(diff == 0) {
1305
px_opa = line_1d_blur[d];
1306
} else {
1307
px_opa = (uint16_t)((uint16_t)line_1d_blur[d] + line_1d_blur[d - diff]) >> 1;
1308
}
1309
px_fp(point_l.x, point_l.y, mask, style->body.shadow.color, px_opa);
1310
point_l.y ++;
1311
1312
/*Don't overdraw the pixel on the middle*/
1313
if(point_r.x > ofs_l.x) {
1314
px_fp(point_r.x, point_r.y, mask, style->body.shadow.color, px_opa);
1315
}
1316
point_r.y ++;
1317
}
1318
1319
}
1320
1321
area_mid.x1 = ofs_l.x + 1;
1322
area_mid.y1 = ofs_l.y + radius;
1323
area_mid.x2 = ofs_r.x - 1;
1324
area_mid.y2 = area_mid.y1;
1325
1326
uint16_t d;
1327
for(d = 0; d < swidth; d++) {
1328
fill_fp(&area_mid, mask, style->body.shadow.color, line_1d_blur[d]);
1329
area_mid.y1 ++;
1330
area_mid.y2 ++;
1331
}
1332
}
1333
1334
static void lv_draw_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map)
1335
{
1336
lv_coord_t radius = style->body.radius;
1337
lv_coord_t swidth = style->body.shadow.width;// + LV_ANTIALIAS;
1338
lv_coord_t width = lv_area_get_width(coords);
1339
lv_coord_t height = lv_area_get_height(coords);
1340
1341
radius = lv_draw_cont_radius_corr(radius, width, height);
1342
radius += LV_ANTIALIAS;
1343
1344
lv_area_t right_area;
1345
right_area.x1 = coords->x2 + 1 - LV_ANTIALIAS;
1346
right_area.y1 = coords->y1 + radius + LV_ANTIALIAS;
1347
right_area.x2 = right_area.x1;
1348
right_area.y2 = coords->y2 - radius - LV_ANTIALIAS;
1349
1350
lv_area_t left_area;
1351
left_area.x1 = coords->x1 - 1 + LV_ANTIALIAS;
1352
left_area.y1 = coords->y1 + radius + LV_ANTIALIAS;
1353
left_area.x2 = left_area.x1;
1354
left_area.y2 = coords->y2 - radius - LV_ANTIALIAS;
1355
1356
lv_area_t top_area;
1357
top_area.x1 = coords->x1 + radius + LV_ANTIALIAS;
1358
top_area.y1 = coords->y1 - 1 + LV_ANTIALIAS;
1359
top_area.x2 = coords->x2 - radius - LV_ANTIALIAS;
1360
top_area.y2 = top_area.y1;
1361
1362
lv_area_t bottom_area;
1363
bottom_area.x1 = coords->x1 + radius + LV_ANTIALIAS;
1364
bottom_area.y1 = coords->y2 + 1 - LV_ANTIALIAS;
1365
bottom_area.x2 = coords->x2 - radius - LV_ANTIALIAS;
1366
bottom_area.y2 = bottom_area.y1;
1367
1368
lv_opa_t opa_act;
1369
int16_t d;
1370
for(d = 1 /*+ LV_ANTIALIAS*/; d <= swidth/* - LV_ANTIALIAS*/; d++) {
1371
opa_act = map[d];
1372
1373
fill_fp(&right_area, mask, style->body.shadow.color, opa_act);
1374
right_area.x1++;
1375
right_area.x2++;
1376
1377
fill_fp(&left_area, mask, style->body.shadow.color, opa_act);
1378
left_area.x1--;
1379
left_area.x2--;
1380
1381
fill_fp(&top_area, mask, style->body.shadow.color, opa_act);
1382
top_area.y1--;
1383
top_area.y2--;
1384
1385
fill_fp(&bottom_area, mask, style->body.shadow.color, opa_act);
1386
bottom_area.y1++;
1387
bottom_area.y2++;
1388
}
1389
}
1390
1391
#endif
1392
1393
1394
static uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h)
1395
{
1396
if(r >= (w >> 1)) {
1397
r = (w >> 1);
1398
if(r != 0) r--;
1399
}
1400
if(r >= (h >> 1)) {
1401
r = (h >> 1);
1402
if(r != 0) r--;
1403
}
1404
1405
if(r > 0) r -= LV_ANTIALIAS;
1406
1407
return r;
1408
}
1409
1410
#if LV_ANTIALIAS
1411
1412
/**
1413
* Approximate the opacity for anti-aliasing.
1414
* Used the first segment of a circle which is the longest and have the most non-linearity (cos)
1415
* @param seg length of the line segment
1416
* @param px_id index of pixel on the line segment
1417
* @param line_opa opacity of the lien (it will be the max opacity)
1418
* @return the desired opacity of the pixel
1419
*/
1420
static lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa)
1421
{
1422
static const lv_opa_t opa_map[8] = {250, 242, 221, 196, 163, 122, 74, 18};
1423
1424
if(seg == 0) return LV_OPA_TRANSP;
1425
else if(seg == 1) return LV_OPA_80;
1426
else {
1427
1428
uint8_t id = (uint32_t)((uint32_t)px_id * (sizeof(opa_map) - 1)) / (seg - 1);
1429
return (uint32_t)((uint32_t) opa_map[id] * opa) >> 8;
1430
1431
}
1432
1433
}
1434
1435
#endif
1436
1437