1 /**
2 * @file lv_draw_sdl_rect.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9
10 #include "../../lv_conf_internal.h"
11
12 #if LV_USE_GPU_SDL
13
14 #include "../lv_draw_rect.h"
15 #include "../lv_draw_img.h"
16 #include "../lv_draw_label.h"
17 #include "../lv_draw_mask.h"
18 #include "../../core/lv_refr.h"
19 #include "lv_draw_sdl_utils.h"
20 #include "lv_draw_sdl_texture_cache.h"
21 #include "lv_draw_sdl_composite.h"
22 #include "lv_draw_sdl_mask.h"
23 #include "lv_draw_sdl_stack_blur.h"
24 #include "lv_draw_sdl_layer.h"
25
26 /*********************
27 * DEFINES
28 *********************/
29
30 #define FRAG_SPACING 3
31
32 /**********************
33 * TYPEDEFS
34 **********************/
35
36 typedef struct {
37 lv_sdl_cache_key_magic_t magic;
38 lv_coord_t radius;
39 lv_coord_t size;
40 } lv_draw_rect_bg_key_t;
41
42 typedef struct {
43 lv_sdl_cache_key_magic_t magic;
44 lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS];
45 uint8_t stops_count;
46 lv_grad_dir_t dir;
47 } lv_draw_rect_grad_strip_key_t;
48
49 typedef struct {
50 lv_sdl_cache_key_magic_t magic;
51 lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS];
52 uint8_t stops_count;
53 lv_grad_dir_t dir;
54 lv_coord_t w;
55 lv_coord_t h;
56 lv_coord_t radius;
57 } lv_draw_rect_grad_frag_key_t;
58
59 typedef struct {
60 lv_sdl_cache_key_magic_t magic;
61 lv_coord_t radius;
62 lv_coord_t size;
63 lv_coord_t blur;
64 } lv_draw_rect_shadow_key_t;
65
66 typedef struct {
67 lv_sdl_cache_key_magic_t magic;
68 lv_coord_t rout, rin;
69 lv_area_t offsets;
70 } lv_draw_rect_border_key_t;
71
72 /**********************
73 * STATIC PROTOTYPES
74 **********************/
75
76 static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
77 const lv_draw_rect_dsc_t * dsc);
78
79 static void draw_bg_grad_simple(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
80 const lv_grad_dsc_t * grad, bool blend_mod);
81
82 static void draw_bg_grad_radius(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
83 const lv_draw_rect_dsc_t * dsc);
84
85 static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
86 const lv_draw_rect_dsc_t * dsc);
87
88 static void draw_border(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
89 const lv_draw_rect_dsc_t * dsc);
90
91 static void draw_shadow(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * clip,
92 const lv_draw_rect_dsc_t * dsc);
93
94 static void draw_outline(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * clip,
95 const lv_draw_rect_dsc_t * dsc);
96
97 static void draw_border_generic(lv_draw_sdl_ctx_t * ctx, const lv_area_t * outer_area, const lv_area_t * inner_area,
98 const lv_area_t * clip, lv_coord_t rout, lv_coord_t rin, lv_color_t color, lv_opa_t opa,
99 lv_blend_mode_t blend_mode);
100
101 static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size,
102 const lv_area_t * coords, const lv_area_t * clipped, bool full);
103
104 static void frag_render_center(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size,
105 const lv_area_t * coords, const lv_area_t * clipped, bool full);
106
107 static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size);
108
109 static lv_draw_rect_grad_frag_key_t rect_grad_frag_key_create(const lv_grad_dsc_t * grad, lv_coord_t w, lv_coord_t h,
110 lv_coord_t radius);
111
112 static lv_draw_rect_grad_strip_key_t rect_grad_strip_key_create(const lv_grad_dsc_t * grad);
113
114 static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur);
115
116 static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, const lv_area_t * outer_area,
117 const lv_area_t * inner_area);
118
119 /**********************
120 * STATIC VARIABLES
121 **********************/
122
123 /**********************
124 * MACROS
125 **********************/
126 #define SKIP_BORDER(dsc) ((dsc)->border_opa <= LV_OPA_MIN || (dsc)->border_width == 0 || (dsc)->border_side == LV_BORDER_SIDE_NONE || (dsc)->border_post)
127 #define SKIP_SHADOW(dsc) ((dsc)->shadow_width == 0 || (dsc)->shadow_opa <= LV_OPA_MIN || ((dsc)->shadow_width == 1 && (dsc)->shadow_spread <= 0 && (dsc)->shadow_ofs_x == 0 && (dsc)->shadow_ofs_y == 0))
128 #define SKIP_IMAGE(dsc) ((dsc)->bg_img_src == NULL || (dsc)->bg_img_opa <= LV_OPA_MIN)
129 #define SKIP_OUTLINE(dsc) ((dsc)->outline_opa <= LV_OPA_MIN || (dsc)->outline_width == 0)
130
131 /**********************
132 * GLOBAL FUNCTIONS
133 **********************/
134
lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)135 void lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
136 {
137 const lv_area_t * clip = draw_ctx->clip_area;
138 lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
139
140 lv_area_t extension = {0, 0, 0, 0};
141 if(!SKIP_SHADOW(dsc)) {
142 lv_coord_t ext = (lv_coord_t)(dsc->shadow_spread - dsc->shadow_width / 2 + 1);
143 extension.x1 = LV_MAX(extension.x1, -dsc->shadow_ofs_x + ext);
144 extension.x2 = LV_MAX(extension.x2, dsc->shadow_ofs_x + ext);
145 extension.y1 = LV_MAX(extension.y1, -dsc->shadow_ofs_y + ext);
146 extension.y2 = LV_MAX(extension.y2, dsc->shadow_ofs_y + ext);
147 }
148 if(!SKIP_OUTLINE(dsc)) {
149 lv_coord_t ext = (lv_coord_t)(dsc->outline_pad - 1 + dsc->outline_width);
150 extension.x1 = LV_MAX(extension.x1, ext);
151 extension.x2 = LV_MAX(extension.x2, ext);
152 extension.y1 = LV_MAX(extension.y1, ext);
153 extension.y2 = LV_MAX(extension.y2, ext);
154 }
155 /* Coords will be translated so coords will start at (0,0) */
156 lv_area_t t_coords = *coords, t_clip = *clip, apply_area, t_area;
157 bool has_composite = lv_draw_sdl_composite_begin(ctx, coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip,
158 &apply_area);
159
160 lv_draw_sdl_transform_areas_offset(ctx, has_composite, &apply_area, &t_coords, &t_clip);
161
162 bool has_content = _lv_area_intersect(&t_area, &t_coords, &t_clip);
163
164 SDL_Rect clip_rect;
165 lv_area_to_sdl_rect(&t_clip, &clip_rect);
166 draw_shadow(ctx, &t_coords, &t_clip, dsc);
167 /* Shadows and outlines will also draw in extended area */
168 if(has_content) {
169 draw_bg_color(ctx, &t_coords, &t_area, dsc);
170 draw_bg_img(ctx, &t_coords, &t_area, dsc);
171 draw_border(ctx, &t_coords, &t_area, dsc);
172 }
173 draw_outline(ctx, &t_coords, &t_clip, dsc);
174
175 lv_draw_sdl_composite_end(ctx, &apply_area, dsc->blend_mode);
176 }
177
lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx,lv_coord_t radius,bool * in_cache)178 SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius, bool * in_cache)
179 {
180 lv_draw_rect_bg_key_t key = rect_bg_key_create(radius, radius);
181 SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL);
182 if(texture == NULL) {
183 lv_area_t coords = {0, 0, radius * 2 - 1, radius * 2 - 1};
184 lv_area_t coords_frag = {0, 0, radius - 1, radius - 1};
185 lv_draw_mask_radius_param_t mask_rout_param;
186 lv_draw_mask_radius_init(&mask_rout_param, &coords, radius, false);
187 int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL);
188 texture = lv_draw_sdl_mask_dump_texture(ctx->renderer, &coords_frag, &mask_id, 1);
189 SDL_assert(texture != NULL);
190 lv_draw_mask_remove_id(mask_id);
191 *in_cache = lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture);
192 }
193 else {
194 *in_cache = true;
195 }
196 return texture;
197 }
198
lv_draw_sdl_rect_grad_frag_obtain(lv_draw_sdl_ctx_t * ctx,const lv_grad_dsc_t * grad,lv_coord_t w,lv_coord_t h,lv_coord_t radius,bool * in_cache)199 SDL_Texture * lv_draw_sdl_rect_grad_frag_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad, lv_coord_t w,
200 lv_coord_t h, lv_coord_t radius, bool * in_cache)
201 {
202 lv_draw_rect_grad_frag_key_t key = rect_grad_frag_key_create(grad, w, h, radius);
203 SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL);
204 if(texture == NULL) {
205 lv_area_t coords = {0, 0, radius * 2 + FRAG_SPACING - 1, radius * 2 + FRAG_SPACING - 1};
206 texture = SDL_CreateTexture(ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET,
207 lv_area_get_width(&coords), lv_area_get_height(&coords));
208 SDL_assert(texture != NULL);
209
210 lv_draw_mask_radius_param_t mask_rout_param;
211 lv_draw_mask_radius_init(&mask_rout_param, &coords, radius, false);
212 int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL);
213 SDL_Texture * mask = lv_draw_sdl_mask_dump_texture(ctx->renderer, &coords, &mask_id, 1);
214 SDL_assert(mask != NULL);
215 SDL_SetTextureBlendMode(mask, SDL_BLENDMODE_NONE);
216 lv_draw_mask_remove_id(mask_id);
217
218 SDL_Texture * target_backup = SDL_GetRenderTarget(ctx->renderer);
219 SDL_SetRenderTarget(ctx->renderer, texture);
220 SDL_RenderCopy(ctx->renderer, mask, NULL, NULL);
221 SDL_DestroyTexture(mask);
222
223 lv_area_t blend_coords = {.x1 = 0, .y1 = 0, .x2 = w - 1, .y2 = h - 1};
224 lv_area_t draw_area = {.x1 = 0, .y1 = 0, .x2 = radius - 1, .y2 = radius - 1};
225 /* Align to top left */
226 lv_area_align(&coords, &draw_area, LV_ALIGN_TOP_LEFT, 0, 0);
227 lv_area_align(&coords, &blend_coords, LV_ALIGN_TOP_LEFT, 0, 0);
228 draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true);
229
230 /* Align to top right */
231 lv_area_align(&coords, &draw_area, LV_ALIGN_TOP_RIGHT, 0, 0);
232 lv_area_align(&coords, &blend_coords, LV_ALIGN_TOP_RIGHT, 0, 0);
233 draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true);
234
235 /* Align to bottom right */
236 lv_area_align(&coords, &draw_area, LV_ALIGN_BOTTOM_RIGHT, 0, 0);
237 lv_area_align(&coords, &blend_coords, LV_ALIGN_BOTTOM_RIGHT, 0, 0);
238 draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true);
239
240 /* Align to bottom left */
241 lv_area_align(&coords, &draw_area, LV_ALIGN_BOTTOM_LEFT, 0, 0);
242 lv_area_align(&coords, &blend_coords, LV_ALIGN_BOTTOM_LEFT, 0, 0);
243 draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true);
244
245 SDL_SetRenderTarget(ctx->renderer, target_backup);
246 *in_cache = lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture);
247 }
248 else {
249 *in_cache = true;
250 }
251 return texture;
252 }
253
lv_draw_sdl_rect_grad_strip_obtain(lv_draw_sdl_ctx_t * ctx,const lv_grad_dsc_t * grad,bool * in_cache)254 SDL_Texture * lv_draw_sdl_rect_grad_strip_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad, bool * in_cache)
255 {
256 lv_draw_rect_grad_strip_key_t key = rect_grad_strip_key_create(grad);
257 SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL);
258 if(texture == NULL) {
259 Uint32 amask = 0xFF000000;
260 Uint32 rmask = 0x00FF0000;
261 Uint32 gmask = 0x0000FF00;
262 Uint32 bmask = 0x000000FF;
263 lv_color_t pixels[256];
264 for(int i = 0; i < 256; i++) {
265 pixels[i] = lv_gradient_calculate(grad, 256, i);
266 }
267 int width = grad->dir == LV_GRAD_DIR_VER ? 1 : 256;
268 int height = grad->dir == LV_GRAD_DIR_VER ? 256 : 1;
269 SDL_Surface * surface = SDL_CreateRGBSurfaceFrom(pixels, width, height, LV_COLOR_DEPTH, width * LV_COLOR_DEPTH / 8,
270 rmask, gmask, bmask, amask);
271 texture = SDL_CreateTextureFromSurface(ctx->renderer, surface);
272 SDL_assert(texture != NULL);
273 SDL_FreeSurface(surface);
274 *in_cache = lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture);
275 }
276 else {
277 *in_cache = true;
278 }
279 return texture;
280 }
281
lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx,SDL_Texture * frag,lv_coord_t frag_size,const lv_area_t * coords,const lv_area_t * clip,bool full)282 void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture * frag, lv_coord_t frag_size,
283 const lv_area_t * coords, const lv_area_t * clip, bool full)
284 {
285 if(!clip) clip = coords;
286 lv_area_t corner_area, dst_area;
287 /* Upper left */
288 corner_area.x1 = coords->x1;
289 corner_area.y1 = coords->y1;
290 corner_area.x2 = coords->x1 + frag_size - 1;
291 corner_area.y2 = coords->y1 + frag_size - 1;
292 if(_lv_area_intersect(&dst_area, &corner_area, clip)) {
293 SDL_Rect dst_rect;
294 lv_area_to_sdl_rect(&dst_area, &dst_rect);
295
296 lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area);
297 lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1);
298 SDL_Rect src_rect = {sx, sy, dw, dh};
299 SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect);
300 }
301 /* Upper right, clip right edge if too big */
302 corner_area.x1 = LV_MAX(coords->x2 - frag_size + 1, coords->x1 + frag_size);
303 corner_area.x2 = coords->x2;
304 if(_lv_area_intersect(&dst_area, &corner_area, clip)) {
305 SDL_Rect dst_rect;
306 lv_area_to_sdl_rect(&dst_area, &dst_rect);
307
308 lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area);
309 if(full) {
310 lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1),
311 sy = (lv_coord_t)(dst_area.y1 - corner_area.y1);
312 SDL_Rect src_rect = {frag_size + FRAG_SPACING + sx, sy, dw, dh};
313 SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect);
314 }
315 else {
316 SDL_Rect src_rect = {corner_area.x2 - dst_area.x2, dst_area.y1 - corner_area.y1, dw, dh};
317 SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL);
318 }
319 }
320 /* Lower right, clip bottom edge if too big */
321 corner_area.y1 = LV_MAX(coords->y2 - frag_size + 1, coords->y1 + frag_size);
322 corner_area.y2 = coords->y2;
323 if(_lv_area_intersect(&dst_area, &corner_area, clip)) {
324 SDL_Rect dst_rect;
325 lv_area_to_sdl_rect(&dst_area, &dst_rect);
326
327 lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area);
328 if(full) {
329 lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1),
330 sy = (lv_coord_t)(dst_area.y1 - corner_area.y1);
331 SDL_Rect src_rect = {frag_size + FRAG_SPACING + sx, frag_size + FRAG_SPACING + sy, dw, dh};
332 SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect);
333 }
334 else {
335 SDL_Rect src_rect = {corner_area.x2 - dst_area.x2, corner_area.y2 - dst_area.y2, dw, dh};
336 SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL);
337 }
338 }
339 /* Lower left, right edge should not be clipped */
340 corner_area.x1 = coords->x1;
341 corner_area.x2 = coords->x1 + frag_size - 1;
342 if(_lv_area_intersect(&dst_area, &corner_area, clip)) {
343 SDL_Rect dst_rect;
344 lv_area_to_sdl_rect(&dst_area, &dst_rect);
345
346 lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area);
347 if(full) {
348 lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1),
349 sy = (lv_coord_t)(dst_area.y1 - corner_area.y1);
350 SDL_Rect src_rect = {sx, frag_size + FRAG_SPACING + sy, dw, dh};
351 SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect);
352 }
353 else {
354 SDL_Rect src_rect = {dst_area.x1 - corner_area.x1, corner_area.y2 - dst_area.y2, dw, dh};
355 SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_VERTICAL);
356 }
357 }
358 }
359
360 /**********************
361 * STATIC FUNCTIONS
362 **********************/
363
draw_bg_color(lv_draw_sdl_ctx_t * ctx,const lv_area_t * coords,const lv_area_t * draw_area,const lv_draw_rect_dsc_t * dsc)364 static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
365 const lv_draw_rect_dsc_t * dsc)
366 {
367 if(dsc->bg_opa == 0) {
368 return;
369 }
370 lv_coord_t radius = dsc->radius;
371 SDL_Color bg_color;
372 if(dsc->bg_grad.dir == LV_GRAD_DIR_NONE) {
373 lv_color_to_sdl_color(&dsc->bg_color, &bg_color);
374 }
375 else if(dsc->bg_grad.stops_count == 1) {
376 lv_color_to_sdl_color(&dsc->bg_grad.stops[0].color, &bg_color);
377 }
378 else {
379 if(radius <= 0) {
380 draw_bg_grad_simple(ctx, coords, draw_area, &dsc->bg_grad, false);
381 }
382 else {
383 draw_bg_grad_radius(ctx, coords, draw_area, dsc);
384 }
385 return;
386 }
387 if(radius <= 0) {
388 SDL_Rect rect;
389 lv_area_to_sdl_rect(draw_area, &rect);
390 SDL_SetRenderDrawColor(ctx->renderer, bg_color.r, bg_color.g, bg_color.b, dsc->bg_opa);
391 SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_BLEND);
392 SDL_RenderFillRect(ctx->renderer, &rect);
393 return;
394 }
395
396 /*A small texture with a quarter of the rect is enough*/
397 lv_coord_t bg_w = lv_area_get_width(coords), bg_h = lv_area_get_height(coords);
398 lv_coord_t real_radius = LV_MIN3(bg_w / 2, bg_h / 2, radius);
399 bool texture_in_cache = false;
400 SDL_Texture * texture = lv_draw_sdl_rect_bg_frag_obtain(ctx, real_radius, &texture_in_cache);
401
402 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
403 SDL_SetTextureAlphaMod(texture, dsc->bg_opa);
404 SDL_SetTextureColorMod(texture, bg_color.r, bg_color.g, bg_color.b);
405 lv_draw_sdl_rect_bg_frag_draw_corners(ctx, texture, real_radius, coords, draw_area, false);
406 frag_render_borders(ctx->renderer, texture, real_radius, coords, draw_area, false);
407 frag_render_center(ctx->renderer, texture, real_radius, coords, draw_area, false);
408
409 if(!texture_in_cache) {
410 LV_LOG_WARN("Texture is not cached, this will impact performance.");
411 SDL_DestroyTexture(texture);
412 }
413 }
414
draw_bg_grad_simple(lv_draw_sdl_ctx_t * ctx,const lv_area_t * coords,const lv_area_t * draw_area,const lv_grad_dsc_t * grad,bool blend_mod)415 static void draw_bg_grad_simple(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
416 const lv_grad_dsc_t * grad, bool blend_mod)
417 {
418 SDL_Rect dstrect;
419 lv_area_to_sdl_rect(draw_area, &dstrect);
420 SDL_Rect srcrect;
421 if(grad->dir == LV_GRAD_DIR_VER) {
422 lv_coord_t coords_h = lv_area_get_height(coords);
423 srcrect.x = 0;
424 srcrect.y = (draw_area->y1 - coords->y1) * 255 / coords_h;
425 srcrect.w = 1;
426 srcrect.h = dstrect.h * 256 / coords_h;
427
428 if(srcrect.y < 0 || srcrect.y > 255) {
429 return;
430 }
431 }
432 else {
433 lv_coord_t coords_w = lv_area_get_width(coords);
434 srcrect.x = (draw_area->x1 - coords->x1) * 255 / coords_w;
435 srcrect.y = 0;
436 srcrect.w = dstrect.w * 256 / coords_w;
437 srcrect.h = 1;
438
439 if(srcrect.x < 0 || srcrect.x > 255) {
440 return;
441 }
442 }
443
444 bool grad_texture_in_cache = false;
445 SDL_Texture * grad_texture = lv_draw_sdl_rect_grad_strip_obtain(ctx, grad, &grad_texture_in_cache);
446 if(blend_mod) {
447 SDL_SetTextureBlendMode(grad_texture, SDL_BLENDMODE_MOD);
448 }
449 else {
450 SDL_SetTextureBlendMode(grad_texture, SDL_BLENDMODE_BLEND);
451 }
452
453 SDL_RenderCopy(ctx->renderer, grad_texture, &srcrect, &dstrect);
454
455 if(!grad_texture_in_cache) {
456 LV_LOG_WARN("Texture is not cached, this will impact performance.");
457 SDL_DestroyTexture(grad_texture);
458 }
459 }
460
draw_bg_grad_radius(lv_draw_sdl_ctx_t * ctx,const lv_area_t * coords,const lv_area_t * draw_area,const lv_draw_rect_dsc_t * dsc)461 static void draw_bg_grad_radius(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
462 const lv_draw_rect_dsc_t * dsc)
463 {
464 lv_coord_t radius = dsc->radius;
465 /*A small texture with a quarter of the rect is enough*/
466 lv_coord_t bg_w = lv_area_get_width(coords), bg_h = lv_area_get_height(coords);
467 lv_coord_t real_radius = LV_MIN3(bg_w / 2, bg_h / 2, radius);
468 bool grad_texture_in_cache = false;
469 SDL_Texture * grad_texture = lv_draw_sdl_rect_grad_frag_obtain(ctx, &dsc->bg_grad, bg_w, bg_h, radius,
470 &grad_texture_in_cache);
471 SDL_SetTextureBlendMode(grad_texture, SDL_BLENDMODE_BLEND);
472
473 lv_draw_sdl_rect_bg_frag_draw_corners(ctx, grad_texture, real_radius, coords, draw_area, true);
474 lv_area_t part_coords;
475 lv_area_t part_area;
476 if(bg_w > radius * 2) {
477 /*Draw left, middle, right*/
478 part_coords.x1 = 0;
479 part_coords.x2 = radius - 1;
480 part_coords.y1 = radius;
481 part_coords.y2 = bg_h - radius - 1;
482
483 lv_area_align(coords, &part_coords, LV_ALIGN_LEFT_MID, 0, 0);
484 _lv_area_intersect(&part_area, &part_coords, draw_area);
485 draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false);
486
487 lv_area_align(coords, &part_coords, LV_ALIGN_RIGHT_MID, 0, 0);
488 _lv_area_intersect(&part_area, &part_coords, draw_area);
489 draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false);
490
491 part_coords.x1 = radius;
492 part_coords.x2 = bg_w - radius - 1;
493 part_coords.y1 = 0;
494 part_coords.y2 = bg_h - 1;
495 lv_area_align(coords, &part_coords, LV_ALIGN_CENTER, 0, 0);
496 _lv_area_intersect(&part_area, &part_coords, draw_area);
497 draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false);
498 }
499 else if(bg_h > radius * 2) {
500 /*Draw top, middle, bottom*/
501 part_coords.x1 = radius;
502 part_coords.x2 = bg_w - radius - 1;
503 part_coords.y1 = 0;
504 part_coords.y2 = radius - 1;
505
506 lv_area_align(coords, &part_coords, LV_ALIGN_TOP_MID, 0, 0);
507 _lv_area_intersect(&part_area, &part_coords, draw_area);
508 draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false);
509
510 lv_area_align(coords, &part_coords, LV_ALIGN_BOTTOM_MID, 0, 0);
511 _lv_area_intersect(&part_area, &part_coords, draw_area);
512 draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false);
513
514 part_coords.x1 = 0;
515 part_coords.x2 = bg_w - 1;
516 part_coords.y1 = radius;
517 part_coords.y2 = bg_h - radius - 1;
518 lv_area_align(coords, &part_coords, LV_ALIGN_CENTER, 0, 0);
519 _lv_area_intersect(&part_area, &part_coords, draw_area);
520 draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false);
521 }
522
523 if(!grad_texture_in_cache) {
524 LV_LOG_WARN("Texture is not cached, this will impact performance.");
525 SDL_DestroyTexture(grad_texture);
526 }
527 }
528
draw_bg_img(lv_draw_sdl_ctx_t * ctx,const lv_area_t * coords,const lv_area_t * draw_area,const lv_draw_rect_dsc_t * dsc)529 static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
530 const lv_draw_rect_dsc_t * dsc)
531 {
532 LV_UNUSED(draw_area);
533 if(SKIP_IMAGE(dsc)) return;
534
535 lv_img_src_t src_type = lv_img_src_get_type(dsc->bg_img_src);
536 if(src_type == LV_IMG_SRC_SYMBOL) {
537 lv_point_t size;
538 lv_txt_get_size(&size, dsc->bg_img_src, dsc->bg_img_symbol_font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
539 lv_area_t a;
540 a.x1 = coords->x1 + lv_area_get_width(coords) / 2 - size.x / 2;
541 a.x2 = a.x1 + size.x - 1;
542 a.y1 = coords->y1 + lv_area_get_height(coords) / 2 - size.y / 2;
543 a.y2 = a.y1 + size.y - 1;
544
545 lv_draw_label_dsc_t label_draw_dsc;
546 lv_draw_label_dsc_init(&label_draw_dsc);
547 label_draw_dsc.font = dsc->bg_img_symbol_font;
548 label_draw_dsc.color = dsc->bg_img_recolor;
549 label_draw_dsc.opa = dsc->bg_img_opa;
550 lv_draw_label((lv_draw_ctx_t *) ctx, &label_draw_dsc, &a, dsc->bg_img_src, NULL);
551 }
552 else {
553 lv_img_header_t header;
554 size_t key_size;
555 lv_draw_sdl_cache_key_head_img_t * key = lv_draw_sdl_texture_img_key_create(dsc->bg_img_src, 0, &key_size);
556 bool key_found;
557 lv_img_header_t * cache_header = NULL;
558 SDL_Texture * texture = lv_draw_sdl_texture_cache_get_with_userdata(ctx, key, key_size, &key_found,
559 (void **) &cache_header);
560 SDL_free(key);
561 if(texture) {
562 header = *cache_header;
563 }
564 else if(key_found || lv_img_decoder_get_info(dsc->bg_img_src, &header) != LV_RES_OK) {
565 /* When cache hit but with negative result, use default decoder. If still fail, return.*/
566 LV_LOG_WARN("Couldn't read the background image");
567 return;
568 }
569
570 lv_draw_img_dsc_t img_dsc;
571 lv_draw_img_dsc_init(&img_dsc);
572 img_dsc.blend_mode = dsc->blend_mode;
573 img_dsc.recolor = dsc->bg_img_recolor;
574 img_dsc.recolor_opa = dsc->bg_img_recolor_opa;
575 img_dsc.opa = dsc->bg_img_opa;
576 img_dsc.frame_id = 0;
577
578 int16_t radius_mask_id = LV_MASK_ID_INV;
579 lv_draw_mask_radius_param_t radius_param;
580 if(dsc->radius > 0) {
581 lv_draw_mask_radius_init(&radius_param, coords, dsc->radius, false);
582 radius_mask_id = lv_draw_mask_add(&radius_param, NULL);
583 }
584
585 /*Center align*/
586 if(dsc->bg_img_tiled == false) {
587 lv_area_t area;
588 area.x1 = coords->x1 + lv_area_get_width(coords) / 2 - header.w / 2;
589 area.y1 = coords->y1 + lv_area_get_height(coords) / 2 - header.h / 2;
590 area.x2 = area.x1 + header.w - 1;
591 area.y2 = area.y1 + header.h - 1;
592
593 lv_draw_img((lv_draw_ctx_t *) ctx, &img_dsc, &area, dsc->bg_img_src);
594 }
595 else {
596 lv_area_t area;
597 area.y1 = coords->y1;
598 area.y2 = area.y1 + header.h - 1;
599
600 for(; area.y1 <= coords->y2; area.y1 += header.h, area.y2 += header.h) {
601
602 area.x1 = coords->x1;
603 area.x2 = area.x1 + header.w - 1;
604 for(; area.x1 <= coords->x2; area.x1 += header.w, area.x2 += header.w) {
605 lv_draw_img((lv_draw_ctx_t *) ctx, &img_dsc, &area, dsc->bg_img_src);
606 }
607 }
608 }
609
610 if(radius_mask_id != LV_MASK_ID_INV) {
611 lv_draw_mask_remove_id(radius_mask_id);
612 lv_draw_mask_free_param(&radius_param);
613 }
614 }
615 }
616
draw_shadow(lv_draw_sdl_ctx_t * ctx,const lv_area_t * coords,const lv_area_t * clip,const lv_draw_rect_dsc_t * dsc)617 static void draw_shadow(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * clip,
618 const lv_draw_rect_dsc_t * dsc)
619 {
620 /*Check whether the shadow is visible*/
621 if(SKIP_SHADOW(dsc)) return;
622
623 lv_coord_t sw = dsc->shadow_width;
624
625 lv_area_t core_area;
626 core_area.x1 = coords->x1 + dsc->shadow_ofs_x - dsc->shadow_spread;
627 core_area.x2 = coords->x2 + dsc->shadow_ofs_x + dsc->shadow_spread;
628 core_area.y1 = coords->y1 + dsc->shadow_ofs_y - dsc->shadow_spread;
629 core_area.y2 = coords->y2 + dsc->shadow_ofs_y + dsc->shadow_spread;
630
631 lv_area_t shadow_area;
632 shadow_area.x1 = core_area.x1 - sw / 2 - 1;
633 shadow_area.x2 = core_area.x2 + sw / 2 + 1;
634 shadow_area.y1 = core_area.y1 - sw / 2 - 1;
635 shadow_area.y2 = core_area.y2 + sw / 2 + 1;
636
637 lv_opa_t opa = dsc->shadow_opa;
638
639 if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
640
641 /*Get clipped draw area which is the real draw area.
642 *It is always the same or inside `shadow_area`*/
643 lv_area_t draw_area;
644 if(!_lv_area_intersect(&draw_area, &shadow_area, clip)) return;
645
646 SDL_Rect core_area_rect;
647 lv_area_to_sdl_rect(&shadow_area, &core_area_rect);
648
649 lv_coord_t radius = dsc->radius;
650 /* No matter how big the shadow is, what we need is just a corner */
651 lv_coord_t frag_size = LV_MIN3(lv_area_get_width(&core_area) / 2, lv_area_get_height(&core_area) / 2,
652 LV_MAX(sw / 2, radius));
653
654 /* This is how big the corner is after blurring */
655 lv_coord_t blur_growth = (lv_coord_t)(sw / 2 + 1);
656
657 lv_coord_t blur_frag_size = (lv_coord_t)(frag_size + blur_growth);
658
659 lv_draw_rect_shadow_key_t key = rect_shadow_key_create(radius, frag_size, sw);
660
661 SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL);
662 bool texture_in_cache = false;
663 if(texture == NULL) {
664 lv_area_t mask_area = {blur_growth, blur_growth}, mask_area_blurred = {0, 0};
665 lv_area_set_width(&mask_area, frag_size * 2);
666 lv_area_set_height(&mask_area, frag_size * 2);
667 lv_area_set_width(&mask_area_blurred, blur_frag_size * 2);
668 lv_area_set_height(&mask_area_blurred, blur_frag_size * 2);
669
670 lv_draw_mask_radius_param_t mask_rout_param;
671 lv_draw_mask_radius_init(&mask_rout_param, &mask_area, radius, false);
672 int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL);
673 lv_opa_t * mask_buf = lv_draw_sdl_mask_dump_opa(&mask_area_blurred, &mask_id, 1);
674 lv_stack_blur_grayscale(mask_buf, lv_area_get_width(&mask_area_blurred), lv_area_get_height(&mask_area_blurred),
675 sw / 2 + sw % 2);
676 texture = lv_sdl_create_opa_texture(ctx->renderer, mask_buf, blur_frag_size, blur_frag_size,
677 lv_area_get_width(&mask_area_blurred));
678 lv_mem_buf_release(mask_buf);
679 lv_draw_mask_remove_id(mask_id);
680 SDL_assert(texture);
681 texture_in_cache = lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture);
682 }
683 else {
684 texture_in_cache = true;
685 }
686
687 SDL_Color shadow_color;
688 lv_color_to_sdl_color(&dsc->shadow_color, &shadow_color);
689 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
690 SDL_SetTextureAlphaMod(texture, opa);
691 SDL_SetTextureColorMod(texture, shadow_color.r, shadow_color.g, shadow_color.b);
692
693 lv_draw_sdl_rect_bg_frag_draw_corners(ctx, texture, blur_frag_size, &shadow_area, clip, false);
694 frag_render_borders(ctx->renderer, texture, blur_frag_size, &shadow_area, clip, false);
695 frag_render_center(ctx->renderer, texture, blur_frag_size, &shadow_area, clip, false);
696
697 if(!texture_in_cache) {
698 LV_LOG_WARN("Texture is not cached, this will impact performance.");
699 SDL_DestroyTexture(texture);
700 }
701 }
702
draw_border(lv_draw_sdl_ctx_t * ctx,const lv_area_t * coords,const lv_area_t * draw_area,const lv_draw_rect_dsc_t * dsc)703 static void draw_border(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area,
704 const lv_draw_rect_dsc_t * dsc)
705 {
706 if(SKIP_BORDER(dsc)) return;
707
708 SDL_Color border_color;
709 lv_color_to_sdl_color(&dsc->border_color, &border_color);
710
711 lv_coord_t coords_w = lv_area_get_width(coords), coords_h = lv_area_get_height(coords);
712 lv_coord_t short_side = LV_MIN(coords_w, coords_h);
713 lv_coord_t rout = LV_MIN(dsc->radius, short_side / 2);/*Get the inner area*/
714 lv_area_t area_inner;
715 lv_area_copy(&area_inner, coords);// lv_area_increase(&area_inner, 1, 1);
716 area_inner.x1 += ((dsc->border_side & LV_BORDER_SIDE_LEFT) ? dsc->border_width : -(dsc->border_width + rout));
717 area_inner.x2 -= ((dsc->border_side & LV_BORDER_SIDE_RIGHT) ? dsc->border_width : -(dsc->border_width + rout));
718 area_inner.y1 += ((dsc->border_side & LV_BORDER_SIDE_TOP) ? dsc->border_width : -(dsc->border_width + rout));
719 area_inner.y2 -= ((dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? dsc->border_width : -(dsc->border_width + rout));
720 lv_coord_t rin = LV_MAX(rout - dsc->border_width, 0);
721 draw_border_generic(ctx, coords, &area_inner, draw_area, rout, rin, dsc->border_color, dsc->border_opa,
722 dsc->blend_mode);
723 }
724
draw_outline(lv_draw_sdl_ctx_t * ctx,const lv_area_t * coords,const lv_area_t * clip,const lv_draw_rect_dsc_t * dsc)725 static void draw_outline(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * clip,
726 const lv_draw_rect_dsc_t * dsc)
727 {
728 if(SKIP_OUTLINE(dsc)) return;
729
730 lv_opa_t opa = dsc->outline_opa;
731
732 if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
733
734 /*Get the inner radius*/
735 lv_area_t area_inner;
736 lv_area_copy(&area_inner, coords);
737
738 /*Bring the outline closer to make sure there is no color bleeding with pad=0*/
739 lv_coord_t pad = dsc->outline_pad - 1;
740 area_inner.x1 -= pad;
741 area_inner.y1 -= pad;
742 area_inner.x2 += pad;
743 area_inner.y2 += pad;
744
745 lv_area_t area_outer;
746 lv_area_copy(&area_outer, &area_inner);
747
748 area_outer.x1 -= dsc->outline_width;
749 area_outer.x2 += dsc->outline_width;
750 area_outer.y1 -= dsc->outline_width;
751 area_outer.y2 += dsc->outline_width;
752
753 lv_area_t draw_area;
754 if(!_lv_area_intersect(&draw_area, &area_outer, clip)) return;
755
756 int32_t inner_w = lv_area_get_width(&area_inner);
757 int32_t inner_h = lv_area_get_height(&area_inner);
758 lv_coord_t rin = dsc->radius;
759 int32_t short_side = LV_MIN(inner_w, inner_h);
760 if(rin > short_side >> 1) rin = short_side >> 1;
761
762 lv_coord_t rout = rin + dsc->outline_width;
763
764 draw_border_generic(ctx, &area_outer, &area_inner, clip, rout, rin, dsc->outline_color, dsc->outline_opa,
765 dsc->blend_mode);
766 }
767
draw_border_generic(lv_draw_sdl_ctx_t * ctx,const lv_area_t * outer_area,const lv_area_t * inner_area,const lv_area_t * clip,lv_coord_t rout,lv_coord_t rin,lv_color_t color,lv_opa_t opa,lv_blend_mode_t blend_mode)768 static void draw_border_generic(lv_draw_sdl_ctx_t * ctx, const lv_area_t * outer_area, const lv_area_t * inner_area,
769 const lv_area_t * clip, lv_coord_t rout, lv_coord_t rin, lv_color_t color, lv_opa_t opa,
770 lv_blend_mode_t blend_mode)
771 {
772 opa = opa >= LV_OPA_COVER ? LV_OPA_COVER : opa;
773
774 SDL_Renderer * renderer = ctx->renderer;
775
776 lv_draw_rect_border_key_t key = rect_border_key_create(rout, rin, outer_area, inner_area);
777 lv_coord_t radius = LV_MIN3(rout, lv_area_get_width(outer_area) / 2, lv_area_get_height(outer_area) / 2);
778 lv_coord_t max_side = LV_MAX4(key.offsets.x1, key.offsets.y1, -key.offsets.x2, -key.offsets.y2);
779 lv_coord_t frag_size = LV_MAX(radius, max_side);
780 SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL);
781 bool texture_in_cache;
782 if(texture == NULL) {
783 /* Create a mask texture with size of (frag_size * 2 + FRAG_SPACING) */
784 const lv_area_t frag_area = {0, 0, frag_size * 2 + FRAG_SPACING - 1, frag_size * 2 + FRAG_SPACING - 1};
785
786 /*Create mask for the outer area*/
787 int16_t mask_ids[2] = {LV_MASK_ID_INV, LV_MASK_ID_INV};
788 lv_draw_mask_radius_param_t mask_rout_param;
789 if(rout > 0) {
790 lv_draw_mask_radius_init(&mask_rout_param, &frag_area, rout, false);
791 mask_ids[0] = lv_draw_mask_add(&mask_rout_param, NULL);
792 }
793
794 /*Create mask for the inner mask*/
795 if(rin < 0) rin = 0;
796 const lv_area_t frag_inner_area = {frag_area.x1 + key.offsets.x1, frag_area.y1 + key.offsets.y1,
797 frag_area.x2 + key.offsets.x2, frag_area.y2 + key.offsets.y2
798 };
799 lv_draw_mask_radius_param_t mask_rin_param;
800 lv_draw_mask_radius_init(&mask_rin_param, &frag_inner_area, rin, true);
801 mask_ids[1] = lv_draw_mask_add(&mask_rin_param, NULL);
802
803 texture = lv_draw_sdl_mask_dump_texture(renderer, &frag_area, mask_ids, 2);
804
805 lv_draw_mask_remove_id(mask_ids[1]);
806 lv_draw_mask_remove_id(mask_ids[0]);
807 SDL_assert(texture);
808 texture_in_cache = lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture);
809 }
810 else {
811 texture_in_cache = true;
812 }
813
814 SDL_Rect outer_rect;
815 lv_area_to_sdl_rect(outer_area, &outer_rect);
816 SDL_Color color_sdl;
817 lv_color_to_sdl_color(&color, &color_sdl);
818
819 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
820 SDL_SetTextureAlphaMod(texture, opa);
821 SDL_SetTextureColorMod(texture, color_sdl.r, color_sdl.g, color_sdl.b);
822
823 lv_draw_sdl_rect_bg_frag_draw_corners(ctx, texture, frag_size, outer_area, clip, true);
824 frag_render_borders(renderer, texture, frag_size, outer_area, clip, true);
825
826 if(!texture_in_cache) {
827 LV_LOG_WARN("Texture is not cached, this will impact performance.");
828 SDL_DestroyTexture(texture);
829 }
830 }
831
frag_render_borders(SDL_Renderer * renderer,SDL_Texture * frag,lv_coord_t frag_size,const lv_area_t * coords,const lv_area_t * clipped,bool full)832 static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size,
833 const lv_area_t * coords, const lv_area_t * clipped, bool full)
834 {
835 lv_area_t border_area, dst_area;
836 /* Top border */
837 border_area.x1 = coords->x1 + frag_size;
838 border_area.y1 = coords->y1;
839 border_area.x2 = coords->x2 - frag_size;
840 border_area.y2 = coords->y1 + frag_size - 1;
841 if(_lv_area_intersect(&dst_area, &border_area, clipped)) {
842 SDL_Rect dst_rect;
843 lv_area_to_sdl_rect(&dst_area, &dst_rect);
844
845 lv_coord_t sy = (lv_coord_t)(dst_area.y1 - border_area.y1);
846 if(full) {
847 SDL_Rect src_rect = {frag_size + 1, sy, 1, lv_area_get_height(&dst_area)};
848 SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
849 }
850 else {
851 SDL_Rect src_rect = {frag_size - 1, sy, 1, lv_area_get_height(&dst_area)};
852 SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
853 }
854 }
855 /* Bottom border */
856 border_area.y1 = LV_MAX(coords->y2 - frag_size + 1, coords->y1 + frag_size);
857 border_area.y2 = coords->y2;
858 if(_lv_area_intersect(&dst_area, &border_area, clipped)) {
859 SDL_Rect dst_rect;
860 lv_area_to_sdl_rect(&dst_area, &dst_rect);
861
862 lv_coord_t dh = lv_area_get_height(&dst_area);
863 if(full) {
864 lv_coord_t sy = (lv_coord_t)(dst_area.y1 - border_area.y1);
865 SDL_Rect src_rect = {frag_size + 1, frag_size + FRAG_SPACING + sy, 1, dh};
866 SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
867 }
868 else {
869 lv_coord_t sy = (lv_coord_t)(border_area.y2 - dst_area.y2);
870 SDL_Rect src_rect = {frag_size - 1, sy, 1, dh};
871 SDL_RenderCopyEx(renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_VERTICAL);
872 }
873 }
874 /* Left border */
875 border_area.x1 = coords->x1;
876 border_area.y1 = coords->y1 + frag_size;
877 border_area.x2 = coords->x1 + frag_size - 1;
878 border_area.y2 = coords->y2 - frag_size;
879 if(_lv_area_intersect(&dst_area, &border_area, clipped)) {
880 SDL_Rect dst_rect;
881 lv_area_to_sdl_rect(&dst_area, &dst_rect);
882
883 lv_coord_t dw = lv_area_get_width(&dst_area);
884 lv_coord_t sx = (lv_coord_t)(dst_area.x1 - border_area.x1);
885 if(full) {
886 SDL_Rect src_rect = {sx, frag_size + 1, dw, 1};
887 SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
888 }
889 else {
890 SDL_Rect src_rect = {sx, frag_size - 1, dw, 1};
891 SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
892 }
893 }
894 /* Right border */
895 border_area.x1 = LV_MAX(coords->x2 - frag_size + 1, coords->x1 + frag_size);
896 border_area.x2 = coords->x2;
897 if(_lv_area_intersect(&dst_area, &border_area, clipped)) {
898 SDL_Rect dst_rect;
899 lv_area_to_sdl_rect(&dst_area, &dst_rect);
900
901 lv_coord_t dw = lv_area_get_width(&dst_area);
902 if(full) {
903 lv_coord_t sx = (lv_coord_t)(dst_area.x1 - border_area.x1);
904 SDL_Rect src_rect = {frag_size + FRAG_SPACING + sx, frag_size + 1, dw, 1};
905 SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
906 }
907 else {
908 lv_coord_t sx = (lv_coord_t)(border_area.x2 - dst_area.x2);
909 SDL_Rect src_rect = {sx, frag_size - 1, dw, 1};
910 SDL_RenderCopyEx(renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL);
911 }
912 }
913 }
914
frag_render_center(SDL_Renderer * renderer,SDL_Texture * frag,lv_coord_t frag_size,const lv_area_t * coords,const lv_area_t * clipped,bool full)915 static void frag_render_center(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size,
916 const lv_area_t * coords,
917 const lv_area_t * clipped, bool full)
918 {
919 lv_area_t center_area = {
920 coords->x1 + frag_size,
921 coords->y1 + frag_size,
922 coords->x2 - frag_size,
923 coords->y2 - frag_size,
924 };
925 if(center_area.x2 < center_area.x1 || center_area.y2 < center_area.y1) return;
926 lv_area_t draw_area;
927 if(!_lv_area_intersect(&draw_area, ¢er_area, clipped)) {
928 return;
929 }
930 SDL_Rect dst_rect;
931 lv_area_to_sdl_rect(&draw_area, &dst_rect);
932 if(full) {
933 SDL_Rect src_rect = {frag_size, frag_size, 1, 1};
934 SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
935 }
936 else {
937 SDL_Rect src_rect = {frag_size - 1, frag_size - 1, 1, 1};
938 SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
939 }
940 }
941
rect_bg_key_create(lv_coord_t radius,lv_coord_t size)942 static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size)
943 {
944 lv_draw_rect_bg_key_t key;
945 SDL_memset(&key, 0, sizeof(key));
946 key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_BG;
947 key.radius = radius;
948 key.size = size;
949 return key;
950 }
951
rect_grad_frag_key_create(const lv_grad_dsc_t * grad,lv_coord_t w,lv_coord_t h,lv_coord_t radius)952 static lv_draw_rect_grad_frag_key_t rect_grad_frag_key_create(const lv_grad_dsc_t * grad, lv_coord_t w, lv_coord_t h,
953 lv_coord_t radius)
954 {
955 lv_draw_rect_grad_frag_key_t key;
956 SDL_memset(&key, 0, sizeof(key));
957 key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_GRAD;
958 key.stops_count = grad->stops_count;
959 key.dir = grad->dir;
960 for(uint8_t i = 0; i < grad->stops_count; i++) {
961 key.stops[i].frac = grad->stops[i].frac;
962 key.stops[i].color = grad->stops[i].color;
963 }
964 key.w = w;
965 key.h = h;
966 key.radius = radius;
967 return key;
968 }
969
rect_grad_strip_key_create(const lv_grad_dsc_t * grad)970 static lv_draw_rect_grad_strip_key_t rect_grad_strip_key_create(const lv_grad_dsc_t * grad)
971 {
972 lv_draw_rect_grad_strip_key_t key;
973 SDL_memset(&key, 0, sizeof(key));
974 key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_GRAD;
975 key.stops_count = grad->stops_count;
976 key.dir = grad->dir;
977 for(uint8_t i = 0; i < grad->stops_count; i++) {
978 key.stops[i].frac = grad->stops[i].frac;
979 key.stops[i].color = grad->stops[i].color;
980 }
981 return key;
982 }
983
rect_shadow_key_create(lv_coord_t radius,lv_coord_t size,lv_coord_t blur)984 static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur)
985 {
986 lv_draw_rect_shadow_key_t key;
987 SDL_memset(&key, 0, sizeof(key));
988 key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW;
989 key.radius = radius;
990 key.size = size;
991 key.blur = blur;
992 return key;
993 }
994
rect_border_key_create(lv_coord_t rout,lv_coord_t rin,const lv_area_t * outer_area,const lv_area_t * inner_area)995 static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, const lv_area_t * outer_area,
996 const lv_area_t * inner_area)
997 {
998 lv_draw_rect_border_key_t key;
999 /* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
1000 SDL_memset(&key, 0, sizeof(key));
1001 key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER;
1002 key.rout = rout;
1003 key.rin = rin;
1004 key.offsets.x1 = inner_area->x1 - outer_area->x1;
1005 key.offsets.x2 = inner_area->x2 - outer_area->x2;
1006 key.offsets.y1 = inner_area->y1 - outer_area->y1;
1007 key.offsets.y2 = inner_area->y2 - outer_area->y2;
1008 return key;
1009 }
1010
1011 #endif /*LV_USE_GPU_SDL*/
1012