doc: renamed project

This commit is contained in:
SylvanArnold
2025-04-29 13:52:54 +02:00
committed by Sylvan Arnold
parent 244e516bd8
commit 32618389d1
985 changed files with 1 additions and 1 deletions

View File

@@ -0,0 +1,28 @@
# SDL_Renderer Based Drawing Functions
In LVGL, drawing was performed by CPU. To improve drawing performance on platforms with GPU,
we should perform drawing operations on GPU if possible.
This implementation has moved most bitmap blending and drawing procedures to utilize SDL_Renderer,
which takes advantages of hardware acceleration APIs like DirectX or OpenGL.
This implementation can be also considered as a reference implementation, for contributors wants to
develop accelerated drawing functions with other APIs such as OpenGL/OpenGL ES.
## Caveats
`lv_draw_arc`, `lv_draw_line` is not enabled, due to incomplete implementation. So lines and arcs will
have significant impact to drawing performances.
Performance of this implementation still has room to improve. Or we should use more powerful APIs
such as OpenGL.
## Notices for files
### `lv_draw_sdl_stack_blur.c`
Contains modified code from [android-stackblur](https://github.com/kikoso/android-stackblur) project.
Apache License 2.0
### `lv_draw_sdl_lru.c`/`lv_draw_sdl_lru.h`
Contains modified code from [C-LRU-Cache](https://github.com/willcannings/C-LRU-Cache) project. No license defined.

View File

@@ -0,0 +1,103 @@
/**
* @file lv_draw_sdl.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "lv_draw_sdl.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
*********************/
void lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc,
const lv_area_t * coords, const void * src);
void lv_draw_sdl_draw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p,
uint32_t letter);
void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1,
const lv_point_t * point2);
void lv_draw_sdl_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
uint16_t radius, uint16_t start_angle, uint16_t end_angle);
void lv_draw_sdl_polygon(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t * points,
uint16_t point_cnt);
void lv_draw_sdl_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_init_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx)
{
_lv_draw_sdl_utils_init();
lv_memset_00(draw_ctx, sizeof(lv_draw_sdl_ctx_t));
draw_ctx->draw_rect = lv_draw_sdl_draw_rect;
draw_ctx->draw_img = lv_draw_sdl_img_core;
draw_ctx->draw_letter = lv_draw_sdl_draw_letter;
draw_ctx->draw_line = lv_draw_sdl_draw_line;
draw_ctx->draw_arc = lv_draw_sdl_draw_arc;
draw_ctx->draw_polygon = lv_draw_sdl_polygon;
draw_ctx->draw_bg = lv_draw_sdl_draw_bg;
draw_ctx->layer_init = lv_draw_sdl_layer_init;
draw_ctx->layer_blend = lv_draw_sdl_layer_blend;
draw_ctx->layer_destroy = lv_draw_sdl_layer_destroy;
draw_ctx->layer_instance_size = sizeof(lv_draw_sdl_layer_ctx_t);
lv_draw_sdl_ctx_t * draw_ctx_sdl = (lv_draw_sdl_ctx_t *) draw_ctx;
draw_ctx_sdl->renderer = ((lv_draw_sdl_drv_param_t *) disp_drv->user_data)->renderer;
draw_ctx_sdl->internals = lv_mem_alloc(sizeof(lv_draw_sdl_context_internals_t));
lv_memset_00(draw_ctx_sdl->internals, sizeof(lv_draw_sdl_context_internals_t));
lv_draw_sdl_texture_cache_init(draw_ctx_sdl);
}
void lv_draw_sdl_deinit_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx)
{
lv_draw_sdl_ctx_t * draw_ctx_sdl = (lv_draw_sdl_ctx_t *) draw_ctx;
lv_draw_sdl_texture_cache_deinit(draw_ctx_sdl);
lv_mem_free(draw_ctx_sdl->internals);
_lv_draw_sdl_utils_deinit();
}
SDL_Texture * lv_draw_sdl_create_screen_texture(SDL_Renderer * renderer, lv_coord_t hor, lv_coord_t ver)
{
SDL_Texture * texture = SDL_CreateTexture(renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET, hor, ver);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
return texture;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,96 @@
/**
* @file lv_draw_sdl.h
*
*/
#ifndef LV_DRAW_SDL_H
#define LV_DRAW_SDL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include LV_GPU_SDL_INCLUDE_PATH
#include "../lv_draw.h"
#include "../../core/lv_disp.h"
/*********************
* DEFINES
*********************/
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define LV_DRAW_SDL_TEXTURE_FORMAT SDL_PIXELFORMAT_ARGB8888
#else
#define LV_DRAW_SDL_TEXTURE_FORMAT SDL_PIXELFORMAT_RGBA8888
#endif
/**********************
* TYPEDEFS
**********************/
struct lv_draw_sdl_context_internals_t;
typedef struct {
/**
* Render for display driver
*/
SDL_Renderer * renderer;
void * user_data;
} lv_draw_sdl_drv_param_t;
typedef struct {
lv_draw_ctx_t base_draw;
SDL_Renderer * renderer;
struct lv_draw_sdl_context_internals_t * internals;
} lv_draw_sdl_ctx_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_draw_sdl_init_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx);
/**
* @brief Free caches
*
*/
void lv_draw_sdl_deinit_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx);
SDL_Texture * lv_draw_sdl_create_screen_texture(SDL_Renderer * renderer, lv_coord_t hor, lv_coord_t ver);
/*======================
* Add/remove functions
*=====================*/
/*=====================
* Setter functions
*====================*/
/*=====================
* Getter functions
*====================*/
/*=====================
* Other functions
*====================*/
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_SDL*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_SDL_H*/

View File

@@ -0,0 +1,19 @@
CSRCS += lv_draw_sdl.c
CSRCS += lv_draw_sdl_arc.c
CSRCS += lv_draw_sdl_bg.c
CSRCS += lv_draw_sdl_composite.c
CSRCS += lv_draw_sdl_img.c
CSRCS += lv_draw_sdl_label.c
CSRCS += lv_draw_sdl_line.c
CSRCS += lv_draw_sdl_mask.c
CSRCS += lv_draw_sdl_polygon.c
CSRCS += lv_draw_sdl_rect.c
CSRCS += lv_draw_sdl_stack_blur.c
CSRCS += lv_draw_sdl_texture_cache.c
CSRCS += lv_draw_sdl_utils.c
CSRCS += lv_draw_sdl_layer.c
DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/sdl
VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/sdl
CFLAGS += "-I$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/sdl"

View File

@@ -0,0 +1,238 @@
/**
* @file lv_draw_sdl_arc.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "lv_draw_sdl.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords, const int16_t * ids, int16_t ids_count,
const int16_t * caps);
static void get_cap_area(int16_t angle, lv_coord_t thickness, uint16_t radius, const lv_point_t * center,
lv_area_t * out);
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
uint16_t radius, uint16_t start_angle, uint16_t end_angle)
{
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
lv_area_t area_out;
area_out.x1 = center->x - radius;
area_out.y1 = center->y - radius;
area_out.x2 = center->x + radius - 1; /*-1 because the center already belongs to the left/bottom part*/
area_out.y2 = center->y + radius - 1;
lv_area_t draw_area;
if(!_lv_area_intersect(&draw_area, &area_out, draw_ctx->clip_area)) {
return;
}
lv_area_t area_in;
lv_area_copy(&area_in, &area_out);
area_in.x1 += dsc->width;
area_in.y1 += dsc->width;
area_in.x2 -= dsc->width;
area_in.y2 -= dsc->width;
while(start_angle >= 360) start_angle -= 360;
while(end_angle >= 360) end_angle -= 360;
int16_t mask_ids[3] = {LV_MASK_ID_INV, LV_MASK_ID_INV, LV_MASK_ID_INV}, mask_ids_count = 1;
int16_t cap_ids[2] = {LV_MASK_ID_INV, LV_MASK_ID_INV};
lv_draw_mask_radius_param_t mask_out_param;
lv_draw_mask_radius_init(&mask_out_param, &area_out, LV_RADIUS_CIRCLE, false);
mask_ids[0] = lv_draw_mask_add(&mask_out_param, NULL);
lv_draw_mask_radius_param_t mask_in_param;
if(lv_area_get_width(&area_in) > 0 && lv_area_get_height(&area_in) > 0) {
lv_draw_mask_radius_init(&mask_in_param, &area_in, LV_RADIUS_CIRCLE, true);
mask_ids[1] = lv_draw_mask_add(&mask_in_param, NULL);
mask_ids_count++;
}
lv_draw_mask_angle_param_t mask_angle_param;
if((start_angle - end_angle) % 360) {
lv_draw_mask_angle_init(&mask_angle_param, center->x, center->y, start_angle, end_angle);
mask_ids[2] = lv_draw_mask_add(&mask_angle_param, NULL);
mask_ids_count++;
}
lv_draw_mask_radius_param_t cap_start_param, cap_end_param;
if(mask_ids_count == 3 && dsc->rounded) {
lv_area_t start_area, end_area;
get_cap_area((int16_t) start_angle, dsc->width, radius, center, &start_area);
get_cap_area((int16_t) end_angle, dsc->width, radius, center, &end_area);
lv_draw_mask_radius_init(&cap_start_param, &start_area, dsc->width / 2, false);
cap_ids[0] = lv_draw_mask_add(&cap_start_param, NULL);
lv_draw_mask_radius_init(&cap_end_param, &end_area, dsc->width / 2, false);
cap_ids[1] = lv_draw_mask_add(&cap_end_param, NULL);
}
lv_coord_t w = lv_area_get_width(&draw_area), h = lv_area_get_height(&draw_area);
SDL_Texture * texture = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM1, w, h);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
dump_masks(texture, &draw_area, mask_ids, mask_ids_count, cap_ids[0] != LV_MASK_ID_INV ? cap_ids : NULL);
lv_draw_mask_remove_id(mask_ids[0]);
lv_draw_mask_free_param(&mask_out_param);
if(mask_ids_count > 1) {
lv_draw_mask_remove_id(mask_ids[1]);
lv_draw_mask_free_param(&mask_in_param);
}
if(mask_ids_count > 2) {
lv_draw_mask_remove_id(mask_ids[2]);
lv_draw_mask_free_param(&mask_angle_param);
}
if(cap_ids[0] != LV_MASK_ID_INV) {
lv_draw_mask_remove_id(cap_ids[0]);
lv_draw_mask_remove_id(cap_ids[1]);
lv_draw_mask_free_param(&cap_start_param);
lv_draw_mask_free_param(&cap_end_param);
}
SDL_Rect srcrect = {0, 0, w, h}, dstrect;
lv_area_to_sdl_rect(&draw_area, &dstrect);
SDL_Color color;
lv_color_to_sdl_color(&dsc->color, &color);
SDL_SetTextureColorMod(texture, color.r, color.g, color.b);
SDL_SetTextureAlphaMod(texture, dsc->opa);
SDL_RenderCopy(ctx->renderer, texture, &srcrect, &dstrect);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords, const int16_t * ids, int16_t ids_count,
const int16_t * caps)
{
lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords);
SDL_assert(w > 0 && h > 0);
SDL_Rect rect = {0, 0, w, h};
uint8_t * pixels;
int pitch;
if(SDL_LockTexture(texture, &rect, (void **) &pixels, &pitch) != 0) return;
lv_opa_t * line_buf = lv_mem_buf_get(rect.w);
for(lv_coord_t y = 0; y < rect.h; y++) {
lv_memset_ff(line_buf, rect.w);
lv_coord_t abs_x = (lv_coord_t) coords->x1, abs_y = (lv_coord_t)(y + coords->y1), len = (lv_coord_t) rect.w;
lv_draw_mask_res_t res;
res = lv_draw_mask_apply_ids(line_buf, abs_x, abs_y, len, ids, ids_count);
if(res == LV_DRAW_MASK_RES_TRANSP) {
lv_memset_00(&pixels[y * pitch], 4 * rect.w);
}
else if(res == LV_DRAW_MASK_RES_FULL_COVER) {
lv_memset_ff(&pixels[y * pitch], 4 * rect.w);
}
else {
for(int x = 0; x < rect.w; x++) {
uint8_t * pixel = &pixels[y * pitch + x * 4];
*pixel = line_buf[x];
pixel[1] = pixel[2] = pixel[3] = 0xFF;
}
}
if(caps) {
for(int i = 0; i < 2; i++) {
lv_memset_ff(line_buf, rect.w);
res = lv_draw_mask_apply_ids(line_buf, abs_x, abs_y, len, &caps[i], 1);
if(res == LV_DRAW_MASK_RES_TRANSP) {
/* Ignore */
}
else if(res == LV_DRAW_MASK_RES_FULL_COVER) {
lv_memset_ff(&pixels[y * pitch], 4 * rect.w);
}
else {
for(int x = 0; x < rect.w; x++) {
uint8_t * pixel = &pixels[y * pitch + x * 4];
uint16_t old_opa = line_buf[x] + *pixel;
*pixel = LV_MIN(old_opa, 0xFF);
pixel[1] = pixel[2] = pixel[3] = 0xFF;
}
}
}
}
}
lv_mem_buf_release(line_buf);
SDL_UnlockTexture(texture);
}
static void get_cap_area(int16_t angle, lv_coord_t thickness, uint16_t radius, const lv_point_t * center,
lv_area_t * out)
{
const uint8_t ps = 8;
const uint8_t pa = 127;
int32_t thick_half = thickness / 2;
uint8_t thick_corr = (thickness & 0x01) ? 0 : 1;
int32_t cir_x;
int32_t cir_y;
cir_x = ((radius - thick_half) * lv_trigo_sin((int16_t)(90 - angle))) >> (LV_TRIGO_SHIFT - ps);
cir_y = ((radius - thick_half) * lv_trigo_sin(angle)) >> (LV_TRIGO_SHIFT - ps);
/*Actually the center of the pixel need to be calculated so apply 1/2 px offset*/
if(cir_x > 0) {
cir_x = (cir_x - pa) >> ps;
out->x1 = cir_x - thick_half + thick_corr;
out->x2 = cir_x + thick_half;
}
else {
cir_x = (cir_x + pa) >> ps;
out->x1 = cir_x - thick_half;
out->x2 = cir_x + thick_half - thick_corr;
}
if(cir_y > 0) {
cir_y = (cir_y - pa) >> ps;
out->y1 = cir_y - thick_half + thick_corr;
out->y2 = cir_y + thick_half;
}
else {
cir_y = (cir_y + pa) >> ps;
out->y1 = cir_y - thick_half;
out->y2 = cir_y + thick_half - thick_corr;
}
lv_area_move(out, center->x, center->y);
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,106 @@
/**
* @file lv_draw_sdl_bg.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "../lv_draw_rect.h"
#include "../lv_draw_img.h"
#include "../lv_draw_label.h"
#include "../lv_draw_mask.h"
#include "../../core/lv_refr.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void 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);
static void 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);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
{
const lv_area_t * clip = draw_ctx->clip_area;
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
/* Coords will be translated so coords will start at (0,0) */
lv_area_t t_area;
bool has_content = _lv_area_intersect(&t_area, coords, clip);
/* Shadows and outlines will also draw in extended area */
if(has_content) {
if(dsc->bg_img_src) {
draw_bg_img(ctx, coords, &t_area, dsc);
}
else {
draw_bg_color(ctx, coords, &t_area, dsc);
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static void 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)
{
SDL_Color bg_color;
lv_color_to_sdl_color(&dsc->bg_color, &bg_color);
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(ctx->renderer, bg_color.r, bg_color.g, bg_color.b, dsc->bg_opa);
SDL_Rect rect;
lv_area_to_sdl_rect(draw_area, &rect);
SDL_RenderFillRect(ctx->renderer, &rect);
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_BLEND);
}
static void 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)
{
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 0);
SDL_Rect rect;
lv_area_to_sdl_rect(draw_area, &rect);
SDL_RenderFillRect(ctx->renderer, &rect);
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_BLEND);
lv_draw_rect((lv_draw_ctx_t *) ctx, dsc, coords);
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,262 @@
/**
* @file lv_draw_sdl_composite.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "../../misc/lv_gc.h"
#include "../../core/lv_refr.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_priv.h"
#include "lv_draw_sdl_texture_cache.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_sdl_cache_key_magic_t magic;
lv_draw_sdl_composite_texture_id_t type;
} composite_key_t;
/**********************
* STATIC PROTOTYPES
**********************/
static composite_key_t mask_key_create(lv_draw_sdl_composite_texture_id_t type);
static lv_coord_t next_pow_of_2(lv_coord_t num);
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
bool lv_draw_sdl_composite_begin(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords_in, const lv_area_t * clip_in,
const lv_area_t * extension, lv_blend_mode_t blend_mode, lv_area_t * coords_out,
lv_area_t * clip_out, lv_area_t * apply_area)
{
lv_area_t full_coords = *coords_in;
/* Normalize full_coords */
if(full_coords.x1 > full_coords.x2) {
lv_coord_t x2 = full_coords.x2;
full_coords.x2 = full_coords.x1;
full_coords.x1 = x2;
}
if(full_coords.y1 > full_coords.y2) {
lv_coord_t y2 = full_coords.y2;
full_coords.y2 = full_coords.y1;
full_coords.y1 = y2;
}
if(extension) {
full_coords.x1 -= extension->x1;
full_coords.x2 += extension->x2;
full_coords.y1 -= extension->y1;
full_coords.y2 += extension->y2;
}
if(!_lv_area_intersect(apply_area, &full_coords, clip_in)) return false;
bool has_mask = lv_draw_mask_is_any(apply_area);
const bool draw_mask = has_mask && LV_GPU_SDL_CUSTOM_BLEND_MODE;
const bool draw_blend = blend_mode != LV_BLEND_MODE_NORMAL;
if(draw_mask || draw_blend) {
lv_draw_sdl_context_internals_t * internals = ctx->internals;
LV_ASSERT(internals->mask == NULL && internals->composition == NULL && internals->target_backup == NULL);
lv_coord_t w = lv_area_get_width(apply_area), h = lv_area_get_height(apply_area);
internals->composition = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0, w, h);
/* Don't need to worry about integral overflow */
lv_coord_t ofs_x = (lv_coord_t) - apply_area->x1, ofs_y = (lv_coord_t) - apply_area->y1;
/* Offset draw area to start with (0,0) of coords */
lv_area_move(coords_out, ofs_x, ofs_y);
lv_area_move(clip_out, ofs_x, ofs_y);
internals->target_backup = SDL_GetRenderTarget(ctx->renderer);
SDL_SetRenderTarget(ctx->renderer, internals->composition);
SDL_SetRenderDrawColor(ctx->renderer, 255, 255, 255, 0);
/* SDL_RenderClear is not working properly, so we overwrite the target with solid color */
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_NONE);
SDL_RenderFillRect(ctx->renderer, NULL);
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_BLEND);
#if LV_GPU_SDL_CUSTOM_BLEND_MODE
internals->mask = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM0, w, h);
dump_masks(internals->mask, apply_area);
#endif
}
else if(has_mask) {
/* Fallback mask handling. This will at least make bars looks less bad */
for(uint8_t i = 0; i < _LV_MASK_MAX_NUM; i++) {
_lv_draw_mask_common_dsc_t * comm_param = LV_GC_ROOT(_lv_draw_mask_list[i]).param;
if(comm_param == NULL) continue;
switch(comm_param->type) {
case LV_DRAW_MASK_TYPE_RADIUS: {
const lv_draw_mask_radius_param_t * param = (const lv_draw_mask_radius_param_t *) comm_param;
if(param->cfg.outer) break;
_lv_area_intersect(clip_out, apply_area, &param->cfg.rect);
break;
}
default:
break;
}
}
}
return has_mask;
}
void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_area, lv_blend_mode_t blend_mode)
{
lv_draw_sdl_context_internals_t * internals = ctx->internals;
SDL_Rect src_rect = {0, 0, lv_area_get_width(apply_area), lv_area_get_height(apply_area)};
#if LV_GPU_SDL_CUSTOM_BLEND_MODE
if(internals->mask) {
SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE,
SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO,
SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
SDL_SetTextureBlendMode(internals->mask, mode);
SDL_RenderCopy(ctx->renderer, internals->mask, &src_rect, &src_rect);
}
#endif
/* Shapes are drawn on composite layer when mask or blend mode is present */
if(internals->composition) {
SDL_Rect dst_rect;
lv_area_to_sdl_rect(apply_area, &dst_rect);
SDL_SetRenderTarget(ctx->renderer, internals->target_backup);
switch(blend_mode) {
case LV_BLEND_MODE_NORMAL:
SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND);
break;
case LV_BLEND_MODE_ADDITIVE:
SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_ADD);
break;
#if LV_GPU_SDL_CUSTOM_BLEND_MODE
case LV_BLEND_MODE_SUBTRACTIVE: {
SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE,
SDL_BLENDOPERATION_SUBTRACT, SDL_BLENDFACTOR_ONE,
SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_SUBTRACT);
SDL_SetTextureBlendMode(internals->composition, mode);
break;
}
case LV_BLEND_MODE_MULTIPLY: {
SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_COLOR,
SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO,
SDL_BLENDFACTOR_DST_ALPHA, SDL_BLENDOPERATION_ADD);
SDL_SetTextureBlendMode(internals->composition, mode);
break;
}
#endif
default:
LV_LOG_WARN("Doesn't support blend mode %d", blend_mode);
SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND);
/* Unsupported yet */
break;
}
SDL_RenderCopy(ctx->renderer, internals->composition, &src_rect, &dst_rect);
}
internals->mask = internals->composition = internals->target_backup = NULL;
}
SDL_Texture * lv_draw_sdl_composite_texture_obtain(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_composite_texture_id_t id,
lv_coord_t w, lv_coord_t h)
{
lv_point_t * tex_size = NULL;
composite_key_t mask_key = mask_key_create(id);
SDL_Texture * result = lv_draw_sdl_texture_cache_get_with_userdata(ctx, &mask_key, sizeof(composite_key_t), NULL,
(void **) &tex_size);
if(!result || tex_size->x < w || tex_size->y < h) {
lv_coord_t size = next_pow_of_2(LV_MAX(w, h));
int access = SDL_TEXTUREACCESS_STREAMING;
if(id >= LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TRANSFORM0) {
access = SDL_TEXTUREACCESS_TARGET;
}
else if(id >= LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0) {
access = SDL_TEXTUREACCESS_TARGET;
}
result = SDL_CreateTexture(ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, access, size, size);
tex_size = lv_mem_alloc(sizeof(lv_point_t));
tex_size->x = tex_size->y = size;
lv_draw_sdl_texture_cache_put_advanced(ctx, &mask_key, sizeof(composite_key_t), result, tex_size, lv_mem_free, 0);
}
return result;
}
/**********************
* STATIC FUNCTIONS
**********************/
static composite_key_t mask_key_create(lv_draw_sdl_composite_texture_id_t type)
{
composite_key_t key;
/* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
SDL_memset(&key, 0, sizeof(key));
key.magic = LV_GPU_CACHE_KEY_MAGIC_MASK;
key.type = type;
return key;
}
static lv_coord_t next_pow_of_2(lv_coord_t num)
{
lv_coord_t n = 128;
while(n < num && n < 16384) {
n = n << 1;
}
return n;
}
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords)
{
lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords);
SDL_assert(w > 0 && h > 0);
SDL_Rect rect = {0, 0, w, h};
uint8_t * pixels;
int pitch;
if(SDL_LockTexture(texture, &rect, (void **) &pixels, &pitch) != 0) return;
lv_opa_t * line_buf = lv_mem_buf_get(rect.w);
for(lv_coord_t y = 0; y < rect.h; y++) {
lv_memset_ff(line_buf, rect.w);
lv_coord_t abs_x = (lv_coord_t) coords->x1, abs_y = (lv_coord_t)(y + coords->y1), len = (lv_coord_t) rect.w;
lv_draw_mask_res_t res;
res = lv_draw_mask_apply(line_buf, abs_x, abs_y, len);
if(res == LV_DRAW_MASK_RES_TRANSP) {
lv_memset_00(&pixels[y * pitch], 4 * rect.w);
}
else if(res == LV_DRAW_MASK_RES_FULL_COVER) {
lv_memset_ff(&pixels[y * pitch], 4 * rect.w);
}
else {
for(int x = 0; x < rect.w; x++) {
const size_t idx = y * pitch + x * 4;
pixels[idx] = line_buf[x];
pixels[idx + 1] = pixels[idx + 2] = pixels[idx + 3] = 0xFF;
}
}
}
lv_mem_buf_release(line_buf);
SDL_UnlockTexture(texture);
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,73 @@
/**
* @file lv_draw_sdl_composite.h
*
*/
#ifndef LV_DRAW_SDL_COMPOSITE_H
#define LV_DRAW_SDL_COMPOSITE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#include LV_GPU_SDL_INCLUDE_PATH
#include "lv_draw_sdl.h"
#include "../../misc/lv_area.h"
#include "../../misc/lv_color.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef enum lv_draw_sdl_composite_texture_id_t {
LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM0,
LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM1,
LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0,
LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET1,
LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TRANSFORM0,
} lv_draw_sdl_composite_texture_id_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Begin drawing with mask. Render target will be switched to a temporary texture,
* and drawing coordinates may get clipped or translated
* @param coords_in Original coordinates
* @param clip_in Original clip area
* @param extension Useful for shadows or outlines, can be NULL
* @param coords_out Translated coords
* @param clip_out Translated clip area
* @param apply_area Area of actual composited texture will be drawn
* @return true if there are any mask needs to be drawn, false otherwise
*/
bool lv_draw_sdl_composite_begin(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords_in, const lv_area_t * clip_in,
const lv_area_t * extension, lv_blend_mode_t blend_mode, lv_area_t * coords_out,
lv_area_t * clip_out, lv_area_t * apply_area);
void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_area, lv_blend_mode_t blend_mode);
SDL_Texture * lv_draw_sdl_composite_texture_obtain(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_composite_texture_id_t id,
lv_coord_t w, lv_coord_t h);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_SDL_COMPOSITE_H*/

View File

@@ -0,0 +1,467 @@
/**
* @file lv_draw_sdl_img.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "../lv_draw_img.h"
#include "../lv_img_cache.h"
#include "../lv_draw_mask.h"
#include "../../misc/lv_lru.h"
#include "../../misc/lv_gc.h"
#include "lv_draw_sdl_img.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_rect.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_sdl_cache_key_magic_t magic;
const SDL_Texture * texture;
lv_coord_t w, h, radius;
} lv_draw_img_rounded_key_t;
enum {
ROUNDED_IMG_PART_LEFT = 0,
ROUNDED_IMG_PART_HCENTER = 1,
ROUNDED_IMG_PART_RIGHT = 2,
ROUNDED_IMG_PART_TOP = 3,
ROUNDED_IMG_PART_VCENTER = 4,
ROUNDED_IMG_PART_BOTTOM = 5,
};
enum {
ROUNDED_IMG_CORNER_TOP_LEFT = 0,
ROUNDED_IMG_CORNER_TOP_RIGHT = 1,
ROUNDED_IMG_CORNER_BOTTOM_RIGHT = 2,
ROUNDED_IMG_CORNER_BOTTOM_LEFT = 3,
};
/**********************
* STATIC PROTOTYPES
**********************/
static SDL_Texture * upload_img_texture(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc);
static SDL_Texture * upload_img_texture_fallback(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc);
static bool check_mask_simple_radius(const lv_area_t * coords, lv_coord_t * radius);
static void draw_img_simple(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, const lv_draw_sdl_img_header_t * header,
const lv_draw_img_dsc_t * draw_dsc, const lv_area_t * coords, const lv_area_t * clip);
static void draw_img_rounded(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, const lv_draw_sdl_img_header_t * header,
const lv_draw_img_dsc_t * draw_dsc, const lv_area_t * coords, const lv_area_t * clip,
lv_coord_t radius);
static SDL_Texture * img_rounded_frag_obtain(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture,
const lv_draw_sdl_img_header_t * header, int w, int h, lv_coord_t radius);
static lv_draw_img_rounded_key_t rounded_key_create(const SDL_Texture * texture, lv_coord_t w, lv_coord_t h,
lv_coord_t radius);
static void calc_draw_part(SDL_Texture * texture, const lv_draw_sdl_img_header_t * header, const lv_area_t * coords,
const lv_area_t * clip, SDL_Rect * clipped_src, SDL_Rect * clipped_dst);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
static void apply_recolor_opa(SDL_Texture * texture, const lv_draw_img_dsc_t * draw_dsc);
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc,
const lv_area_t * coords, const void * src)
{
const lv_area_t * clip = draw_ctx->clip_area;
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
size_t key_size;
lv_draw_sdl_cache_key_head_img_t * key = lv_draw_sdl_texture_img_key_create(src, draw_dsc->frame_id, &key_size);
bool texture_found = false;
lv_draw_sdl_img_header_t * header = NULL;
SDL_Texture * texture = lv_draw_sdl_texture_cache_get_with_userdata(ctx, key, key_size, &texture_found,
(void **) &header);
if(!texture_found) {
lv_draw_sdl_img_load_texture(ctx, key, key_size, src, draw_dsc->frame_id, &texture, &header);
}
SDL_free(key);
if(!texture) {
return LV_RES_INV;
}
lv_area_t zoomed_cords;
_lv_img_buf_get_transformed_area(&zoomed_cords, lv_area_get_width(coords), lv_area_get_height(coords), 0,
draw_dsc->zoom, &draw_dsc->pivot);
lv_area_move(&zoomed_cords, coords->x1, coords->y1);
/* When in > 0, draw simple radius */
lv_coord_t radius = 0;
/* Coords will be translated so coords will start at (0,0) */
lv_area_t t_coords = zoomed_cords, t_clip = *clip, apply_area;
bool has_composite = false;
if(!check_mask_simple_radius(&t_coords, &radius)) {
has_composite = lv_draw_sdl_composite_begin(ctx, &zoomed_cords, clip, NULL, draw_dsc->blend_mode,
&t_coords, &t_clip, &apply_area);
}
lv_draw_sdl_transform_areas_offset(ctx, has_composite, &apply_area, &t_coords, &t_clip);
SDL_Rect clip_rect, coords_rect;
lv_area_to_sdl_rect(&t_clip, &clip_rect);
lv_area_to_sdl_rect(&t_coords, &coords_rect);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
if(radius > 0) {
draw_img_rounded(ctx, texture, header, draw_dsc, &t_coords, &t_clip, radius);
}
else {
draw_img_simple(ctx, texture, header, draw_dsc, &t_coords, &t_clip);
}
lv_draw_sdl_composite_end(ctx, &apply_area, draw_dsc->blend_mode);
return LV_RES_OK;
}
static void calc_draw_part(SDL_Texture * texture, const lv_draw_sdl_img_header_t * header, const lv_area_t * coords,
const lv_area_t * clip, SDL_Rect * clipped_src, SDL_Rect * clipped_dst)
{
double x = 0, y = 0, w, h;
if(SDL_RectEmpty(&header->rect)) {
Uint32 format = 0;
int access = 0, tw, th;
SDL_QueryTexture(texture, &format, &access, &tw, &th);
w = tw;
h = th;
}
else {
x = header->rect.x;
y = header->rect.y;
w = header->rect.w;
h = header->rect.h;
}
if(clip) {
lv_area_t clipped_area;
_lv_area_intersect(&clipped_area, coords, clip);
lv_area_to_sdl_rect(&clipped_area, clipped_dst);
}
else {
lv_area_to_sdl_rect(coords, clipped_dst);
}
lv_coord_t coords_w = lv_area_get_width(coords), coords_h = lv_area_get_height(coords);
clipped_src->x = (int)(x + (clipped_dst->x - coords->x1) * w / coords_w);
clipped_src->y = (int)(y + (clipped_dst->y - coords->y1) * h / coords_h);
clipped_src->w = (int)(w - (coords_w - clipped_dst->w) * w / coords_w);
clipped_src->h = (int)(h - (coords_h - clipped_dst->h) * h / coords_h);
}
bool lv_draw_sdl_img_load_texture(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_cache_key_head_img_t * key, size_t key_size,
const void * src, int32_t frame_id, SDL_Texture ** texture,
lv_draw_sdl_img_header_t ** header)
{
_lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, lv_color_white(), frame_id);
lv_draw_sdl_cache_flag_t tex_flags = 0;
SDL_Rect rect;
SDL_memset(&rect, 0, sizeof(SDL_Rect));
if(cdsc) {
lv_img_decoder_dsc_t * dsc = &cdsc->dec_dsc;
if(dsc->user_data && SDL_memcmp(dsc->user_data, LV_DRAW_SDL_DEC_DSC_TEXTURE_HEAD, 8) == 0) {
lv_draw_sdl_dec_dsc_userdata_t * ptr = (lv_draw_sdl_dec_dsc_userdata_t *) dsc->user_data;
*texture = ptr->texture;
rect = ptr->rect;
if(ptr->texture_managed) {
tex_flags |= LV_DRAW_SDL_CACHE_FLAG_MANAGED;
}
ptr->texture_referenced = true;
}
else {
*texture = upload_img_texture(ctx->renderer, dsc);
}
#if LV_IMG_CACHE_DEF_SIZE == 0
lv_img_decoder_close(dsc);
#endif
}
if(texture && cdsc) {
*header = SDL_malloc(sizeof(lv_draw_sdl_img_header_t));
SDL_memcpy(&(*header)->base, &cdsc->dec_dsc.header, sizeof(lv_img_header_t));
(*header)->rect = rect;
lv_draw_sdl_texture_cache_put_advanced(ctx, key, key_size, *texture, *header, SDL_free, tex_flags);
}
else {
lv_draw_sdl_texture_cache_put(ctx, key, key_size, NULL);
return false;
}
return true;
}
/**********************
* STATIC FUNCTIONS
**********************/
static SDL_Texture * upload_img_texture(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc)
{
if(!dsc->img_data) {
return upload_img_texture_fallback(renderer, dsc);
}
bool chroma_keyed = dsc->header.cf == (uint32_t) LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
int h = (int) dsc->header.h;
int w = (int) dsc->header.w;
void * data = (void *) dsc->img_data;
Uint32 rmask = 0x00FF0000;
Uint32 gmask = 0x0000FF00;
Uint32 bmask = 0x000000FF;
Uint32 amask = 0xFF000000;
if(chroma_keyed) {
amask = 0x00;
}
SDL_Surface * surface = SDL_CreateRGBSurfaceFrom(data, w, h, LV_COLOR_DEPTH, w * LV_COLOR_DEPTH / 8,
rmask, gmask, bmask, amask);
SDL_SetColorKey(surface, chroma_keyed, lv_color_to32(LV_COLOR_CHROMA_KEY));
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
return texture;
}
static SDL_Texture * upload_img_texture_fallback(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc)
{
lv_coord_t h = (lv_coord_t) dsc->header.h;
lv_coord_t w = (lv_coord_t) dsc->header.w;
uint8_t * data = lv_mem_buf_get(w * h * sizeof(lv_color_t));
for(lv_coord_t y = 0; y < h; y++) {
lv_img_decoder_read_line(dsc, 0, y, w, &data[y * w * sizeof(lv_color_t)]);
}
Uint32 rmask = 0x00FF0000;
Uint32 gmask = 0x0000FF00;
Uint32 bmask = 0x000000FF;
Uint32 amask = 0xFF000000;
SDL_Surface * surface = SDL_CreateRGBSurfaceFrom(data, w, h, LV_COLOR_DEPTH, w * LV_COLOR_DEPTH / 8,
rmask, gmask, bmask, amask);
SDL_SetColorKey(surface, SDL_TRUE, lv_color_to32(LV_COLOR_CHROMA_KEY));
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
lv_mem_buf_release(data);
return texture;
}
/**
* Check if there is only one radius mask
* @param radius Set to radius value if the only mask is a radius mask
* @return true if the only mask is a radius mask
*/
static bool check_mask_simple_radius(const lv_area_t * coords, lv_coord_t * radius)
{
if(lv_draw_mask_get_cnt() != 1) return false;
for(uint8_t i = 0; i < _LV_MASK_MAX_NUM; i++) {
_lv_draw_mask_common_dsc_t * param = LV_GC_ROOT(_lv_draw_mask_list[i]).param;
if(param->type == LV_DRAW_MASK_TYPE_RADIUS) {
lv_draw_mask_radius_param_t * rparam = (lv_draw_mask_radius_param_t *) param;
if(rparam->cfg.outer) return false;
if(!_lv_area_is_equal(&rparam->cfg.rect, coords)) return false;
*radius = rparam->cfg.radius;
return true;
}
}
return false;
}
static void draw_img_simple(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, const lv_draw_sdl_img_header_t * header,
const lv_draw_img_dsc_t * draw_dsc, const lv_area_t * coords, const lv_area_t * clip)
{
apply_recolor_opa(texture, draw_dsc);
SDL_Point pivot = {.x = draw_dsc->pivot.x, .y = draw_dsc->pivot.y};
/*Image needs to be rotated, so we have to use clip rect which is slower*/
if(draw_dsc->angle != 0) {
/* No radius, set clip here */
SDL_Rect clip_rect;
lv_area_to_sdl_rect(clip, &clip_rect);
SDL_RenderSetClipRect(ctx->renderer, &clip_rect);
}
SDL_Rect src_rect, dst_rect;
calc_draw_part(texture, header, coords, clip, &src_rect, &dst_rect);
SDL_RenderCopyEx(ctx->renderer, texture, &src_rect, &dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
if(draw_dsc->angle != 0) {
SDL_RenderSetClipRect(ctx->renderer, NULL);
}
}
static void draw_img_rounded(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, const lv_draw_sdl_img_header_t * header,
const lv_draw_img_dsc_t * draw_dsc, const lv_area_t * coords, const lv_area_t * clip,
lv_coord_t radius)
{
const int w = lv_area_get_width(coords), h = lv_area_get_height(coords);
lv_coord_t real_radius = LV_MIN3(radius, w, h);
SDL_Texture * frag = img_rounded_frag_obtain(ctx, texture, header, w, h, real_radius);
apply_recolor_opa(frag, draw_dsc);
lv_draw_sdl_rect_bg_frag_draw_corners(ctx, frag, real_radius, coords, clip, true);
apply_recolor_opa(texture, draw_dsc);
SDL_Rect src_rect, dst_rect;
/* Draw 3 parts */
lv_area_t clip_tmp, part;
calc_draw_part(texture, header, coords, NULL, &src_rect, &dst_rect);
for(int i = w > h ? ROUNDED_IMG_PART_LEFT : ROUNDED_IMG_PART_TOP, j = i + 3; i <= j; i++) {
switch(i) {
case ROUNDED_IMG_PART_LEFT:
lv_area_set(&part, coords->x1, coords->y1 + radius, coords->x1 + radius - 1, coords->y2 - radius);
break;
case ROUNDED_IMG_PART_HCENTER:
lv_area_set(&part, coords->x1 + radius, coords->y1, coords->x2 - radius, coords->y2);
break;
case ROUNDED_IMG_PART_RIGHT:
lv_area_set(&part, coords->x2 - radius + 1, coords->y1 + radius, coords->x2, coords->y2 - radius);
break;
case ROUNDED_IMG_PART_TOP:
lv_area_set(&part, coords->x1 + radius, coords->y1, coords->x2 - radius, coords->y1 + radius - 1);
break;
case ROUNDED_IMG_PART_VCENTER:
lv_area_set(&part, coords->x1 + radius, coords->y2 - radius + 1, coords->x2 - radius, coords->y2);
break;
case ROUNDED_IMG_PART_BOTTOM:
lv_area_set(&part, coords->x1, coords->y1 + radius, coords->x2, coords->y2 - radius);
break;
default:
break;
}
if(!_lv_area_intersect(&clip_tmp, &part, clip)) continue;
SDL_Rect clip_rect;
lv_area_to_sdl_rect(&clip_tmp, &clip_rect);
SDL_RenderSetClipRect(ctx->renderer, &clip_rect);
SDL_RenderCopy(ctx->renderer, texture, &src_rect, &dst_rect);
}
SDL_RenderSetClipRect(ctx->renderer, NULL);
}
static void apply_recolor_opa(SDL_Texture * texture, const lv_draw_img_dsc_t * draw_dsc)
{
if(draw_dsc->recolor_opa > LV_OPA_TRANSP) {
/* Draw with mixed recolor */
lv_color_t recolor = lv_color_mix(draw_dsc->recolor, lv_color_white(), draw_dsc->recolor_opa);
SDL_SetTextureColorMod(texture, recolor.ch.red, recolor.ch.green, recolor.ch.blue);
}
else {
/* Draw with no recolor */
SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF);
}
SDL_SetTextureAlphaMod(texture, draw_dsc->opa);
}
static SDL_Texture * img_rounded_frag_obtain(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture,
const lv_draw_sdl_img_header_t * header, int w, int h, lv_coord_t radius)
{
lv_draw_img_rounded_key_t key = rounded_key_create(texture, w, h, radius);
SDL_Texture * mask_frag = lv_draw_sdl_rect_bg_frag_obtain(ctx, radius);
SDL_Texture * img_frag = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL);
if(img_frag == NULL) {
const lv_coord_t full_frag_size = radius * 2 + 3;
img_frag = SDL_CreateTexture(ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET,
full_frag_size, full_frag_size);
SDL_SetTextureBlendMode(img_frag, SDL_BLENDMODE_BLEND);
SDL_Texture * old_target = SDL_GetRenderTarget(ctx->renderer);
SDL_SetRenderTarget(ctx->renderer, img_frag);
SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 0);
/* SDL_RenderClear is not working properly, so we overwrite the target with solid color */
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_NONE);
SDL_RenderFillRect(ctx->renderer, NULL);
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_BLEND);
lv_area_t coords = {0, 0, w - 1, h - 1}, clip;
lv_area_t frag_coords = {0, 0, full_frag_size - 1, full_frag_size - 1};
lv_draw_sdl_rect_bg_frag_draw_corners(ctx, mask_frag, radius, &frag_coords, NULL, false);
SDL_SetTextureAlphaMod(texture, 0xFF);
SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF);
#if LV_GPU_SDL_CUSTOM_BLEND_MODE
SDL_BlendMode blend_mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO,
SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_DST_ALPHA,
SDL_BLENDFACTOR_ZERO, SDL_BLENDOPERATION_ADD);
SDL_SetTextureBlendMode(texture, blend_mode);
#else
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD);
#endif
SDL_Rect srcrect, cliprect, dstrect = {0, 0, radius, radius};
cliprect.w = cliprect.h = radius;
for(int i = 0; i <= ROUNDED_IMG_CORNER_BOTTOM_LEFT; i++) {
switch(i) {
case ROUNDED_IMG_CORNER_TOP_LEFT:
cliprect.x = 0;
cliprect.y = 0;
lv_area_align(&frag_coords, &coords, LV_ALIGN_TOP_LEFT, 0, 0);
break;
case ROUNDED_IMG_CORNER_TOP_RIGHT:
cliprect.x = full_frag_size - radius;
cliprect.y = 0;
lv_area_align(&frag_coords, &coords, LV_ALIGN_TOP_RIGHT, 0, 0);
break;
case ROUNDED_IMG_CORNER_BOTTOM_RIGHT:
cliprect.x = full_frag_size - radius;
cliprect.y = full_frag_size - radius;
lv_area_align(&frag_coords, &coords, LV_ALIGN_BOTTOM_RIGHT, 0, 0);
break;
case ROUNDED_IMG_CORNER_BOTTOM_LEFT:
cliprect.x = 0;
cliprect.y = full_frag_size - radius;
lv_area_align(&frag_coords, &coords, LV_ALIGN_BOTTOM_LEFT, 0, 0);
break;
default:
break;
}
calc_draw_part(texture, header, &coords, NULL, &srcrect, &dstrect);
SDL_RenderSetClipRect(ctx->renderer, &cliprect);
SDL_RenderCopy(ctx->renderer, texture, &srcrect, &dstrect);
}
SDL_RenderSetClipRect(ctx->renderer, NULL);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(ctx->renderer, old_target);
lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), img_frag);
}
return img_frag;
}
static lv_draw_img_rounded_key_t rounded_key_create(const SDL_Texture * texture, lv_coord_t w, lv_coord_t h,
lv_coord_t radius)
{
lv_draw_img_rounded_key_t key;
SDL_memset(&key, 0, sizeof(key));
key.magic = LV_GPU_CACHE_KEY_MAGIC_IMG_ROUNDED_CORNERS;
key.texture = texture;
key.w = w;
key.h = h;
key.radius = radius;
return key;
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,72 @@
/**
* @file lv_draw_sdl_img.h
*
*/
#ifndef LV_DRAW_SDL_IMG_H
#define LV_DRAW_SDL_IMG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include LV_GPU_SDL_INCLUDE_PATH
#include "../lv_draw.h"
#include "lv_draw_sdl_texture_cache.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct lv_draw_sdl_img_header_t {
lv_img_header_t base;
SDL_Rect rect;
} lv_draw_sdl_img_header_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/*======================
* Add/remove functions
*=====================*/
/*=====================
* Setter functions
*====================*/
/*=====================
* Getter functions
*====================*/
/*=====================
* Other functions
*====================*/
bool lv_draw_sdl_img_load_texture(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_cache_key_head_img_t * key, size_t key_size,
const void * src, int32_t frame_id, SDL_Texture ** texture,
lv_draw_sdl_img_header_t ** header);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_SDL*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_SDL_IMG_H*/

View File

@@ -0,0 +1,176 @@
/**
* @file lv_draw_sdl_label.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include LV_GPU_SDL_INCLUDE_PATH
#include "../lv_draw_label.h"
#include "../../misc/lv_utils.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_sdl_cache_key_magic_t magic;
const lv_font_t * font_p;
uint32_t letter;
} lv_font_glyph_key_t;
/**********************
* STATIC PROTOTYPES
**********************/
static lv_font_glyph_key_t font_key_glyph_create(const lv_font_t * font_p, uint32_t letter);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_draw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p,
uint32_t letter)
{
const lv_area_t * clip_area = draw_ctx->clip_area;
const lv_font_t * font_p = dsc->font;
lv_opa_t opa = dsc->opa;
lv_color_t color = dsc->color;
if(opa < LV_OPA_MIN) return;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
if(font_p == NULL) {
LV_LOG_WARN("lv_draw_letter: font is NULL");
return;
}
lv_font_glyph_dsc_t g;
bool g_ret = lv_font_get_glyph_dsc(font_p, &g, letter, '\0');
if(g_ret == false) {
/*Add warning if the dsc is not found
*but do not print warning for non printable ASCII chars (e.g. '\n')*/
if(letter >= 0x20 &&
letter != 0xf8ff && /*LV_SYMBOL_DUMMY*/
letter != 0x200c) { /*ZERO WIDTH NON-JOINER*/
LV_LOG_WARN("lv_draw_letter: glyph dsc. not found for U+%X", letter);
/* draw placeholder */
lv_area_t glyph_coords;
lv_draw_rect_dsc_t glyph_dsc;
lv_coord_t begin_x = pos_p->x + g.ofs_x;
lv_coord_t begin_y = pos_p->y + g.ofs_y;
lv_area_set(&glyph_coords, begin_x, begin_y, begin_x + g.box_w, begin_y + g.box_h);
lv_draw_rect_dsc_init(&glyph_dsc);
glyph_dsc.bg_opa = LV_OPA_MIN;
glyph_dsc.outline_opa = LV_OPA_MIN;
glyph_dsc.shadow_opa = LV_OPA_MIN;
glyph_dsc.bg_img_opa = LV_OPA_MIN;
glyph_dsc.border_color = dsc->color;
glyph_dsc.border_width = 1;
draw_ctx->draw_rect(draw_ctx, &glyph_dsc, &glyph_coords);
}
return;
}
/*Don't draw anything if the character is empty. E.g. space*/
if((g.box_h == 0) || (g.box_w == 0)) return;
int32_t pos_x = pos_p->x + g.ofs_x;
int32_t pos_y = pos_p->y + (font_p->line_height - font_p->base_line) - g.box_h - g.ofs_y;
const lv_area_t letter_area = {pos_x, pos_y, pos_x + g.box_w - 1, pos_y + g.box_h - 1};
lv_area_t draw_area;
/*If the letter is completely out of mask don't draw it*/
if(!_lv_area_intersect(&draw_area, &letter_area, clip_area)) {
return;
}
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
SDL_Renderer * renderer = ctx->renderer;
lv_font_glyph_key_t glyph_key = font_key_glyph_create(font_p, letter);
bool glyph_found = false;
SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &glyph_key, sizeof(glyph_key), &glyph_found);
if(!glyph_found) {
if(g.resolved_font) {
font_p = g.resolved_font;
}
const uint8_t * bmp = lv_font_get_glyph_bitmap(font_p, letter);
uint8_t * buf = lv_mem_alloc(g.box_w * g.box_h);
lv_sdl_to_8bpp(buf, bmp, g.box_w, g.box_h, g.box_w, g.bpp);
SDL_Surface * mask = lv_sdl_create_opa_surface(buf, g.box_w, g.box_h, g.box_w);
texture = SDL_CreateTextureFromSurface(renderer, mask);
SDL_FreeSurface(mask);
lv_mem_free(buf);
lv_draw_sdl_texture_cache_put(ctx, &glyph_key, sizeof(glyph_key), texture);
}
if(!texture) {
return;
}
lv_area_t t_letter = letter_area, t_clip = *clip_area, apply_area;
bool has_composite = lv_draw_sdl_composite_begin(ctx, &letter_area, clip_area, NULL, dsc->blend_mode, &t_letter,
&t_clip, &apply_area);
lv_draw_sdl_transform_areas_offset(ctx, has_composite, &apply_area, &t_letter, &t_clip);
/*If the letter is completely out of mask don't draw it*/
if(!_lv_area_intersect(&draw_area, &t_letter, &t_clip)) {
return;
}
SDL_Rect srcrect, dstrect;
lv_area_to_sdl_rect(&draw_area, &dstrect);
srcrect.x = draw_area.x1 - t_letter.x1;
srcrect.y = draw_area.y1 - t_letter.y1;
srcrect.w = dstrect.w;
srcrect.h = dstrect.h;
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(texture, opa);
SDL_SetTextureColorMod(texture, color.ch.red, color.ch.green, color.ch.blue);
SDL_RenderCopy(renderer, texture, &srcrect, &dstrect);
lv_draw_sdl_composite_end(ctx, &apply_area, dsc->blend_mode);
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_font_glyph_key_t font_key_glyph_create(const lv_font_t * font_p, uint32_t letter)
{
lv_font_glyph_key_t key;
/* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
SDL_memset(&key, 0, sizeof(key));
key.magic = LV_GPU_CACHE_KEY_MAGIC_FONT_GLYPH;
key.font_p = font_p;
key.letter = letter;
return key;
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,141 @@
/**
* @file lv_draw_sdl_refr.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "../../core/lv_refr.h"
#include "lv_draw_sdl.h"
#include "lv_draw_sdl_priv.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_draw_layer_ctx_t * lv_draw_sdl_layer_init(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags)
{
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
SDL_Renderer * renderer = ctx->renderer;
lv_draw_sdl_layer_ctx_t * transform_ctx = (lv_draw_sdl_layer_ctx_t *) layer_ctx;
transform_ctx->flags = flags;
transform_ctx->orig_target = SDL_GetRenderTarget(renderer);
lv_coord_t target_w = lv_area_get_width(&layer_ctx->area_full);
lv_coord_t target_h = lv_area_get_height(&layer_ctx->area_full);
enum lv_draw_sdl_composite_texture_id_t texture_id = LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TRANSFORM0 +
ctx->internals->transform_count;
transform_ctx->target = lv_draw_sdl_composite_texture_obtain(ctx, texture_id, target_w, target_h);
transform_ctx->target_rect.x = 0;
transform_ctx->target_rect.y = 0;
transform_ctx->target_rect.w = target_w;
transform_ctx->target_rect.h = target_h;
layer_ctx->max_row_with_alpha = target_h;
layer_ctx->max_row_with_no_alpha = target_h;
SDL_SetTextureBlendMode(transform_ctx->target, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(renderer, transform_ctx->target);
/* SDL_RenderClear is not working properly, so we overwrite the target with solid color */
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderFillRect(renderer, NULL);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
/* Set proper drawing context for transform layer */
ctx->internals->transform_count += 1;
draw_ctx->buf_area = &layer_ctx->area_full;
draw_ctx->clip_area = &layer_ctx->area_full;
return layer_ctx;
}
void lv_draw_sdl_layer_blend(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx,
const lv_draw_img_dsc_t * draw_dsc)
{
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
lv_draw_sdl_layer_ctx_t * transform_ctx = (lv_draw_sdl_layer_ctx_t *) layer_ctx;
SDL_Renderer * renderer = ctx->renderer;
SDL_Rect trans_rect;
if(transform_ctx->flags & LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE) {
lv_area_zoom_to_sdl_rect(&layer_ctx->area_act, &trans_rect, draw_dsc->zoom, &draw_dsc->pivot);
}
else {
lv_area_zoom_to_sdl_rect(&layer_ctx->area_full, &trans_rect, draw_dsc->zoom, &draw_dsc->pivot);
}
SDL_SetRenderTarget(renderer, transform_ctx->orig_target);
/*Render off-screen texture, transformed*/
SDL_Rect clip_rect;
lv_area_to_sdl_rect(layer_ctx->original.clip_area, &clip_rect);
SDL_Point center = {.x = draw_dsc->pivot.x, .y = draw_dsc->pivot.y};
SDL_RenderSetClipRect(renderer, &clip_rect);
SDL_SetTextureAlphaMod(transform_ctx->target, draw_dsc->opa);
SDL_RenderCopyEx(renderer, transform_ctx->target, &transform_ctx->target_rect, &trans_rect,
draw_dsc->angle, &center, SDL_FLIP_NONE);
SDL_RenderSetClipRect(renderer, NULL);
}
void lv_draw_sdl_layer_destroy(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx)
{
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
ctx->internals->transform_count -= 1;
}
void lv_draw_sdl_transform_areas_offset(lv_draw_sdl_ctx_t * ctx, bool has_composite, lv_area_t * apply_area,
lv_area_t * coords, lv_area_t * clip)
{
if(ctx->internals->transform_count == 0) {
return;
}
lv_area_t * area = ctx->base_draw.buf_area;
lv_area_move(coords, -area->x1, -area->y1);
lv_area_move(clip, -area->x1, -area->y1);
if(has_composite) {
lv_area_move(apply_area, -area->x1, -area->y1);
}
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,55 @@
/**
* @file lv_draw_sdl_refr.h
*
*/
#ifndef LV_TEMPL_H
#define LV_TEMPL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_draw_sdl.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_draw_sdl_layer_ctx_t {
lv_draw_layer_ctx_t base;
SDL_Texture * orig_target;
SDL_Texture * target;
SDL_Rect target_rect;
lv_draw_layer_flags_t flags;
} lv_draw_sdl_layer_ctx_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_draw_layer_ctx_t * lv_draw_sdl_layer_init(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags);
void lv_draw_sdl_layer_blend(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * transform_ctx,
const lv_draw_img_dsc_t * draw_dsc);
void lv_draw_sdl_layer_destroy(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx);
void lv_draw_sdl_transform_areas_offset(lv_draw_sdl_ctx_t * ctx, bool has_composite, lv_area_t * apply_area,
lv_area_t * coords, lv_area_t * clip);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_TEMPL_H*/

View File

@@ -0,0 +1,157 @@
/**
* @file lv_draw_sdl_line.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "lv_draw_sdl.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_mask.h"
/*********************
* DEFINES
*********************/
#define ROUND_START 0x01
#define ROUND_END 0x02
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_sdl_cache_key_magic_t magic;
lv_coord_t length;
lv_coord_t width;
uint8_t round;
} lv_draw_line_key_t;
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
static lv_draw_line_key_t line_key_create(const lv_draw_line_dsc_t * dsc, lv_coord_t length);
static SDL_Texture * line_texture_create(lv_draw_sdl_ctx_t * sdl_ctx, const lv_draw_line_dsc_t * dsc,
lv_coord_t length);
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1,
const lv_point_t * point2)
{
lv_draw_sdl_ctx_t * sdl_ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
SDL_Renderer * renderer = sdl_ctx->renderer;
lv_coord_t x1 = point1->x, x2 = point2->x, y1 = point1->y, y2 = point2->y;
double length = SDL_sqrt(SDL_pow(x2 - x1, 2) + SDL_pow(y2 - y1, 2));
if(length - (long) length > 0.5) {
length = (long) length + 1;
}
double angle = SDL_atan2(y2 - y1, x2 - x1) * 180 / M_PI;
lv_draw_line_key_t key = line_key_create(dsc, (lv_coord_t) length);
SDL_Texture * texture = lv_draw_sdl_texture_cache_get(sdl_ctx, &key, sizeof(key), NULL);
if(!texture) {
texture = line_texture_create(sdl_ctx, dsc, (lv_coord_t) length);
lv_draw_sdl_texture_cache_put(sdl_ctx, &key, sizeof(key), texture);
}
lv_area_t coords = {x1, y1, x2, y2};
const lv_area_t * clip = draw_ctx->clip_area;
SDL_Rect coords_r, clip_r;
lv_area_to_sdl_rect(&coords, &coords_r);
lv_area_to_sdl_rect(clip, &clip_r);
lv_area_t t_coords = coords, t_clip = *clip, apply_area;
lv_area_t extension = {dsc->width / 2, dsc->width / 2, dsc->width / 2, dsc->width / 2};
lv_draw_sdl_composite_begin(sdl_ctx, &coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip,
&apply_area);
SDL_Color color;
lv_color_to_sdl_color(&dsc->color, &color);
SDL_SetTextureColorMod(texture, color.r, color.g, color.b);
SDL_SetTextureAlphaMod(texture, dsc->opa);
SDL_Rect srcrect = {0, 0, (int) length + dsc->width + 2, dsc->width + 2},
dstrect = {t_coords.x1 - 1 - dsc->width / 2, t_coords.y1 - 1, srcrect.w, srcrect.h};
SDL_Point center = {1 + dsc->width / 2, 1 + dsc->width / 2};
SDL_Rect clip_rect;
lv_area_to_sdl_rect(&t_clip, &clip_rect);
if(!SDL_RectEquals(&clip_rect, &dstrect) || angle != 0) {
SDL_RenderSetClipRect(renderer, &clip_rect);
}
SDL_RenderCopyEx(renderer, texture, &srcrect, &dstrect, angle, &center, 0);
SDL_RenderSetClipRect(renderer, NULL);
lv_draw_sdl_composite_end(sdl_ctx, &apply_area, dsc->blend_mode);
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_draw_line_key_t line_key_create(const lv_draw_line_dsc_t * dsc, lv_coord_t length)
{
lv_draw_line_key_t key;
lv_memset_00(&key, sizeof(lv_draw_line_key_t));
key.magic = LV_GPU_CACHE_KEY_MAGIC_LINE;
key.length = length;
key.width = dsc->width;
key.round = (dsc->round_start ? ROUND_START : 0) | (dsc->round_end ? ROUND_END : 0);
return key;
}
static SDL_Texture * line_texture_create(lv_draw_sdl_ctx_t * sdl_ctx, const lv_draw_line_dsc_t * dsc, lv_coord_t length)
{
SDL_Texture * texture = SDL_CreateTexture(sdl_ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET,
length + dsc->width + 2, dsc->width + 2);
SDL_Texture * target = SDL_GetRenderTarget(sdl_ctx->renderer);
SDL_SetRenderTarget(sdl_ctx->renderer, texture);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(sdl_ctx->renderer, 0xFF, 0xFF, 0xFF, 0x0);
/* SDL_RenderClear is not working properly, so we overwrite the target with solid color */
SDL_SetRenderDrawBlendMode(sdl_ctx->renderer, SDL_BLENDMODE_NONE);
SDL_RenderFillRect(sdl_ctx->renderer, NULL);
SDL_SetRenderDrawBlendMode(sdl_ctx->renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(sdl_ctx->renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_Rect line_rect = {1 + dsc->width / 2, 1, length, dsc->width};
SDL_RenderFillRect(sdl_ctx->renderer, &line_rect);
if(dsc->round_start || dsc->round_end) {
lv_draw_mask_radius_param_t param;
lv_area_t round_area = {0, 0, dsc->width - 1, dsc->width - 1};
lv_draw_mask_radius_init(&param, &round_area, LV_RADIUS_CIRCLE, false);
int16_t mask_id = lv_draw_mask_add(&param, NULL);
SDL_Texture * round_texture = lv_draw_sdl_mask_dump_texture(sdl_ctx->renderer, &round_area, &mask_id, 1);
lv_draw_mask_remove_id(mask_id);
SDL_Rect round_src = {0, 0, dsc->width, dsc->width};
SDL_Rect round_dst = {line_rect.x - dsc->width / 2, 1, dsc->width, dsc->width};
SDL_RenderCopy(sdl_ctx->renderer, round_texture, &round_src, &round_dst);
round_dst.x = line_rect.w + dsc->width / 2;
SDL_RenderCopy(sdl_ctx->renderer, round_texture, &round_src, &round_dst);
SDL_DestroyTexture(round_texture);
}
SDL_SetRenderTarget(sdl_ctx->renderer, target);
return texture;
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,84 @@
/**
* @file lv_draw_sdl_mask.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "../../misc/lv_gc.h"
#include "lv_draw_sdl_mask.h"
#include "lv_draw_sdl_utils.h"
/*********************
* DEFINES
*********************/
#ifndef HAVE_SDL_CUSTOM_BLEND_MODE
#define HAVE_SDL_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6))
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_opa_t * lv_draw_sdl_mask_dump_opa(const lv_area_t * coords, const int16_t * ids, int16_t ids_count)
{
SDL_assert(coords->x2 >= coords->x1);
SDL_assert(coords->y2 >= coords->y1);
lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords);
lv_opa_t * mask_buf = lv_mem_buf_get(w * h);
for(lv_coord_t y = 0; y < h; y++) {
lv_opa_t * line_buf = &mask_buf[y * w];
lv_memset_ff(line_buf, w);
lv_coord_t abs_x = (lv_coord_t) coords->x1, abs_y = (lv_coord_t)(y + coords->y1), len = (lv_coord_t) w;
lv_draw_mask_res_t res;
if(ids) {
res = lv_draw_mask_apply_ids(line_buf, abs_x, abs_y, len, ids, ids_count);
}
else {
res = lv_draw_mask_apply(line_buf, abs_x, abs_y, len);
}
if(res == LV_DRAW_MASK_RES_TRANSP) {
lv_memset_00(line_buf, w);
}
}
return mask_buf;
}
SDL_Texture * lv_draw_sdl_mask_dump_texture(SDL_Renderer * renderer, const lv_area_t * coords, const int16_t * ids,
int16_t ids_count)
{
lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords);
lv_opa_t * mask_buf = lv_draw_sdl_mask_dump_opa(coords, ids, ids_count);
SDL_Surface * surface = lv_sdl_create_opa_surface(mask_buf, w, h, w);
lv_mem_buf_release(mask_buf);
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
return texture;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,51 @@
/**
* @file lv_draw_sdl_mask.h
*
*/
#ifndef LV_DRAW_SDL_MASK_H
#define LV_DRAW_SDL_MASK_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#include LV_GPU_SDL_INCLUDE_PATH
#include "lv_draw_sdl.h"
#include "../../misc/lv_area.h"
#include "../../misc/lv_color.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_opa_t * lv_draw_sdl_mask_dump_opa(const lv_area_t * coords, const int16_t * ids, int16_t ids_count);
SDL_Texture * lv_draw_sdl_mask_dump_texture(SDL_Renderer * renderer, const lv_area_t * coords, const int16_t * ids,
int16_t ids_count);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_SDL_MASK_H*/

View File

@@ -0,0 +1,133 @@
/**
* @file lv_draw_sdl_polygon.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "lv_draw_sdl.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords);
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_polygon(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t * points,
uint16_t point_cnt)
{
if(point_cnt < 3) return;
if(points == NULL) return;
lv_draw_mask_polygon_param_t polygon_param;
lv_draw_mask_polygon_init(&polygon_param, points, point_cnt);
if(polygon_param.cfg.point_cnt < 3) {
lv_draw_mask_free_param(&polygon_param);
return;
}
lv_area_t poly_coords = {.x1 = LV_COORD_MAX, .y1 = LV_COORD_MAX, .x2 = LV_COORD_MIN, .y2 = LV_COORD_MIN};
uint16_t i;
for(i = 0; i < point_cnt; i++) {
poly_coords.x1 = LV_MIN(poly_coords.x1, polygon_param.cfg.points[i].x);
poly_coords.y1 = LV_MIN(poly_coords.y1, polygon_param.cfg.points[i].y);
poly_coords.x2 = LV_MAX(poly_coords.x2, polygon_param.cfg.points[i].x);
poly_coords.y2 = LV_MAX(poly_coords.y2, polygon_param.cfg.points[i].y);
}
bool is_common;
lv_area_t draw_area;
is_common = _lv_area_intersect(&draw_area, &poly_coords, draw_ctx->clip_area);
if(!is_common) {
lv_draw_mask_free_param(&polygon_param);
return;
}
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
int16_t mask_id = lv_draw_mask_add(&polygon_param, NULL);
lv_coord_t w = lv_area_get_width(&draw_area), h = lv_area_get_height(&draw_area);
SDL_Texture * texture = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM1, w, h);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
dump_masks(texture, &draw_area);
lv_draw_mask_remove_id(mask_id);
lv_draw_mask_free_param(&polygon_param);
SDL_Rect srcrect = {0, 0, w, h}, dstrect;
lv_area_to_sdl_rect(&draw_area, &dstrect);
SDL_Color color;
lv_color_to_sdl_color(&draw_dsc->bg_color, &color);
SDL_SetTextureColorMod(texture, color.r, color.g, color.b);
SDL_SetTextureAlphaMod(texture, draw_dsc->bg_opa);
SDL_RenderCopy(ctx->renderer, texture, &srcrect, &dstrect);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords)
{
lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords);
SDL_assert(w > 0 && h > 0);
SDL_Rect rect = {0, 0, w, h};
uint8_t * pixels;
int pitch;
if(SDL_LockTexture(texture, &rect, (void **) &pixels, &pitch) != 0) return;
lv_opa_t * line_buf = lv_mem_buf_get(rect.w);
for(lv_coord_t y = 0; y < rect.h; y++) {
lv_memset_ff(line_buf, rect.w);
lv_coord_t abs_x = (lv_coord_t) coords->x1, abs_y = (lv_coord_t)(y + coords->y1), len = (lv_coord_t) rect.w;
lv_draw_mask_res_t res;
res = lv_draw_mask_apply(line_buf, abs_x, abs_y, len);
if(res == LV_DRAW_MASK_RES_TRANSP) {
lv_memset_00(&pixels[y * pitch], 4 * rect.w);
}
else if(res == LV_DRAW_MASK_RES_FULL_COVER) {
lv_memset_ff(&pixels[y * pitch], 4 * rect.w);
}
else {
for(int x = 0; x < rect.w; x++) {
uint8_t * pixel = &pixels[y * pitch + x * 4];
*pixel = line_buf[x];
pixel[1] = pixel[2] = pixel[3] = 0xFF;
}
}
}
lv_mem_buf_release(line_buf);
SDL_UnlockTexture(texture);
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,72 @@
/**
* @file lv_draw_sdl_priv.h
*
*/
#ifndef LV_DRAW_SDL_PRIV_H
#define LV_DRAW_SDL_PRIV_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include LV_GPU_SDL_INCLUDE_PATH
#include "../lv_draw.h"
#include "../../misc/lv_lru.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct lv_draw_sdl_context_internals_t {
lv_lru_t * texture_cache;
SDL_Texture * mask;
SDL_Texture * composition;
SDL_Texture * target_backup;
uint8_t transform_count;
} lv_draw_sdl_context_internals_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/*======================
* Add/remove functions
*=====================*/
/*=====================
* Setter functions
*====================*/
/*=====================
* Getter functions
*====================*/
/*=====================
* Other functions
*====================*/
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_SDL*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_SDL_PRIV_H*/

View File

@@ -0,0 +1,712 @@
/**
* @file lv_draw_sdl_rect.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "../lv_draw_rect.h"
#include "../lv_draw_img.h"
#include "../lv_draw_label.h"
#include "../lv_draw_mask.h"
#include "../../core/lv_refr.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_mask.h"
#include "lv_draw_sdl_stack_blur.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_sdl_cache_key_magic_t magic;
lv_coord_t radius;
lv_coord_t size;
} lv_draw_rect_bg_key_t;
typedef struct {
lv_sdl_cache_key_magic_t magic;
lv_coord_t radius;
lv_coord_t size;
lv_coord_t blur;
} lv_draw_rect_shadow_key_t;
typedef struct {
lv_sdl_cache_key_magic_t magic;
lv_coord_t rout, rin;
lv_area_t offsets;
} lv_draw_rect_border_key_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void 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);
static void 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);
static void 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);
static void 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);
static void 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);
static void 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);
static void 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);
static void 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);
static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size);
static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur);
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,
const lv_area_t * inner_area);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
#define SKIP_BORDER(dsc) ((dsc)->border_opa <= LV_OPA_MIN || (dsc)->border_width == 0 || (dsc)->border_side == LV_BORDER_SIDE_NONE || (dsc)->border_post)
#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))
#define SKIP_IMAGE(dsc) ((dsc)->bg_img_src == NULL || (dsc)->bg_img_opa <= LV_OPA_MIN)
#define SKIP_OUTLINE(dsc) ((dsc)->outline_opa <= LV_OPA_MIN || (dsc)->outline_width == 0)
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
{
const lv_area_t * clip = draw_ctx->clip_area;
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
lv_area_t extension = {0, 0, 0, 0};
if(!SKIP_SHADOW(dsc)) {
lv_coord_t ext = (lv_coord_t)(dsc->shadow_spread - dsc->shadow_width / 2 + 1);
extension.x1 = LV_MAX(extension.x1, -dsc->shadow_ofs_x + ext);
extension.x2 = LV_MAX(extension.x2, dsc->shadow_ofs_x + ext);
extension.y1 = LV_MAX(extension.y1, -dsc->shadow_ofs_y + ext);
extension.y2 = LV_MAX(extension.y2, dsc->shadow_ofs_y + ext);
}
if(!SKIP_OUTLINE(dsc)) {
lv_coord_t ext = (lv_coord_t)(dsc->outline_pad - 1 + dsc->outline_width);
extension.x1 = LV_MAX(extension.x1, ext);
extension.x2 = LV_MAX(extension.x2, ext);
extension.y1 = LV_MAX(extension.y1, ext);
extension.y2 = LV_MAX(extension.y2, ext);
}
/* Coords will be translated so coords will start at (0,0) */
lv_area_t t_coords = *coords, t_clip = *clip, apply_area, t_area;
bool has_composite = lv_draw_sdl_composite_begin(ctx, coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip,
&apply_area);
lv_draw_sdl_transform_areas_offset(ctx, has_composite, &apply_area, &t_coords, &t_clip);
bool has_content = _lv_area_intersect(&t_area, &t_coords, &t_clip);
SDL_Rect clip_rect;
lv_area_to_sdl_rect(&t_clip, &clip_rect);
draw_shadow(ctx, &t_coords, &t_clip, dsc);
/* Shadows and outlines will also draw in extended area */
if(has_content) {
draw_bg_color(ctx, &t_coords, &t_area, dsc);
draw_bg_img(ctx, &t_coords, &t_area, dsc);
draw_border(ctx, &t_coords, &t_area, dsc);
}
draw_outline(ctx, &t_coords, &t_clip, dsc);
lv_draw_sdl_composite_end(ctx, &apply_area, dsc->blend_mode);
}
SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius)
{
lv_draw_rect_bg_key_t key = rect_bg_key_create(radius, radius);
lv_area_t coords = {0, 0, radius * 2 - 1, radius * 2 - 1};
lv_area_t coords_frag = {0, 0, radius - 1, radius - 1};
SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL);
if(texture == NULL) {
lv_draw_mask_radius_param_t mask_rout_param;
lv_draw_mask_radius_init(&mask_rout_param, &coords, radius, false);
int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL);
texture = lv_draw_sdl_mask_dump_texture(ctx->renderer, &coords_frag, &mask_id, 1);
lv_draw_mask_remove_id(mask_id);
SDL_assert(texture);
lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture);
}
return texture;
}
void 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)
{
if(!clip) clip = coords;
lv_area_t corner_area, dst_area;
/* Upper left */
corner_area.x1 = coords->x1;
corner_area.y1 = coords->y1;
corner_area.x2 = coords->x1 + frag_size - 1;
corner_area.y2 = coords->y1 + frag_size - 1;
if(_lv_area_intersect(&dst_area, &corner_area, clip)) {
SDL_Rect dst_rect;
lv_area_to_sdl_rect(&dst_area, &dst_rect);
lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area);
lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1);
SDL_Rect src_rect = {sx, sy, dw, dh};
SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect);
}
/* Upper right, clip right edge if too big */
corner_area.x1 = LV_MAX(coords->x2 - frag_size + 1, coords->x1 + frag_size);
corner_area.x2 = coords->x2;
if(_lv_area_intersect(&dst_area, &corner_area, clip)) {
SDL_Rect dst_rect;
lv_area_to_sdl_rect(&dst_area, &dst_rect);
lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area);
if(full) {
lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1),
sy = (lv_coord_t)(dst_area.y1 - corner_area.y1);
SDL_Rect src_rect = {frag_size + 3 + sx, sy, dw, dh};
SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect);
}
else {
SDL_Rect src_rect = {corner_area.x2 - dst_area.x2, dst_area.y1 - corner_area.y1, dw, dh};
SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL);
}
}
/* Lower right, clip bottom edge if too big */
corner_area.y1 = LV_MAX(coords->y2 - frag_size + 1, coords->y1 + frag_size);
corner_area.y2 = coords->y2;
if(_lv_area_intersect(&dst_area, &corner_area, clip)) {
SDL_Rect dst_rect;
lv_area_to_sdl_rect(&dst_area, &dst_rect);
lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area);
if(full) {
lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1),
sy = (lv_coord_t)(dst_area.y1 - corner_area.y1);
SDL_Rect src_rect = {frag_size + 3 + sx, frag_size + 3 + sy, dw, dh};
SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect);
}
else {
SDL_Rect src_rect = {corner_area.x2 - dst_area.x2, corner_area.y2 - dst_area.y2, dw, dh};
SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL);
}
}
/* Lower left, right edge should not be clip */
corner_area.x1 = coords->x1;
corner_area.x2 = coords->x1 + frag_size - 1;
if(_lv_area_intersect(&dst_area, &corner_area, clip)) {
SDL_Rect dst_rect;
lv_area_to_sdl_rect(&dst_area, &dst_rect);
lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area);
if(full) {
lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1),
sy = (lv_coord_t)(dst_area.y1 - corner_area.y1);
SDL_Rect src_rect = {sx, frag_size + 3 + sy, dw, dh};
SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect);
}
else {
SDL_Rect src_rect = {dst_area.x1 - corner_area.x1, corner_area.y2 - dst_area.y2, dw, dh};
SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_VERTICAL);
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static void 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)
{
if(dsc->bg_opa == 0) {
return;
}
SDL_Color bg_color;
lv_color_to_sdl_color(&dsc->bg_color, &bg_color);
lv_coord_t radius = dsc->radius;
if(radius <= 0) {
SDL_Rect rect;
lv_area_to_sdl_rect(draw_area, &rect);
SDL_SetRenderDrawColor(ctx->renderer, bg_color.r, bg_color.g, bg_color.b, dsc->bg_opa);
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_BLEND);
SDL_RenderFillRect(ctx->renderer, &rect);
return;
}
/*A small texture with a quarter of the rect is enough*/
lv_coord_t bg_w = lv_area_get_width(coords), bg_h = lv_area_get_height(coords);
lv_coord_t real_radius = LV_MIN3(bg_w / 2, bg_h / 2, radius);
SDL_Texture * texture = lv_draw_sdl_rect_bg_frag_obtain(ctx, real_radius);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(texture, dsc->bg_opa);
SDL_SetTextureColorMod(texture, bg_color.r, bg_color.g, bg_color.b);
lv_draw_sdl_rect_bg_frag_draw_corners(ctx, texture, real_radius, coords, draw_area, false);
frag_render_borders(ctx->renderer, texture, real_radius, coords, draw_area, false);
frag_render_center(ctx->renderer, texture, real_radius, coords, draw_area, false);
}
static void 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)
{
if(SKIP_IMAGE(dsc)) return;
lv_img_src_t src_type = lv_img_src_get_type(dsc->bg_img_src);
if(src_type == LV_IMG_SRC_SYMBOL) {
lv_point_t size;
lv_txt_get_size(&size, dsc->bg_img_src, dsc->bg_img_symbol_font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
lv_area_t a;
a.x1 = coords->x1 + lv_area_get_width(coords) / 2 - size.x / 2;
a.x2 = a.x1 + size.x - 1;
a.y1 = coords->y1 + lv_area_get_height(coords) / 2 - size.y / 2;
a.y2 = a.y1 + size.y - 1;
lv_draw_label_dsc_t label_draw_dsc;
lv_draw_label_dsc_init(&label_draw_dsc);
label_draw_dsc.font = dsc->bg_img_symbol_font;
label_draw_dsc.color = dsc->bg_img_recolor;
label_draw_dsc.opa = dsc->bg_img_opa;
lv_draw_label((lv_draw_ctx_t *) ctx, &label_draw_dsc, &a, dsc->bg_img_src, NULL);
}
else {
lv_img_header_t header;
size_t key_size;
lv_draw_sdl_cache_key_head_img_t * key = lv_draw_sdl_texture_img_key_create(dsc->bg_img_src, 0, &key_size);
bool key_found;
lv_img_header_t * cache_header = NULL;
SDL_Texture * texture = lv_draw_sdl_texture_cache_get_with_userdata(ctx, key, key_size, &key_found,
(void **) &cache_header);
SDL_free(key);
if(texture) {
header = *cache_header;
}
else if(key_found || lv_img_decoder_get_info(dsc->bg_img_src, &header) != LV_RES_OK) {
/* When cache hit but with negative result, use default decoder. If still fail, return.*/
LV_LOG_WARN("Couldn't read the background image");
return;
}
lv_draw_img_dsc_t img_dsc;
lv_draw_img_dsc_init(&img_dsc);
img_dsc.blend_mode = dsc->blend_mode;
img_dsc.recolor = dsc->bg_img_recolor;
img_dsc.recolor_opa = dsc->bg_img_recolor_opa;
img_dsc.opa = dsc->bg_img_opa;
img_dsc.frame_id = 0;
int16_t radius_mask_id = LV_MASK_ID_INV;
lv_draw_mask_radius_param_t radius_param;
if(dsc->radius > 0) {
lv_draw_mask_radius_init(&radius_param, coords, dsc->radius, false);
radius_mask_id = lv_draw_mask_add(&radius_param, NULL);
}
/*Center align*/
if(dsc->bg_img_tiled == false) {
lv_area_t area;
area.x1 = coords->x1 + lv_area_get_width(coords) / 2 - header.w / 2;
area.y1 = coords->y1 + lv_area_get_height(coords) / 2 - header.h / 2;
area.x2 = area.x1 + header.w - 1;
area.y2 = area.y1 + header.h - 1;
lv_draw_img((lv_draw_ctx_t *) ctx, &img_dsc, &area, dsc->bg_img_src);
}
else {
lv_area_t area;
area.y1 = coords->y1;
area.y2 = area.y1 + header.h - 1;
for(; area.y1 <= coords->y2; area.y1 += header.h, area.y2 += header.h) {
area.x1 = coords->x1;
area.x2 = area.x1 + header.w - 1;
for(; area.x1 <= coords->x2; area.x1 += header.w, area.x2 += header.w) {
lv_draw_img((lv_draw_ctx_t *) ctx, &img_dsc, &area, dsc->bg_img_src);
}
}
}
if(radius_mask_id != LV_MASK_ID_INV) {
lv_draw_mask_remove_id(radius_mask_id);
lv_draw_mask_free_param(&radius_param);
}
}
}
static void 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)
{
/*Check whether the shadow is visible*/
if(SKIP_SHADOW(dsc)) return;
lv_coord_t sw = dsc->shadow_width;
lv_area_t core_area;
core_area.x1 = coords->x1 + dsc->shadow_ofs_x - dsc->shadow_spread;
core_area.x2 = coords->x2 + dsc->shadow_ofs_x + dsc->shadow_spread;
core_area.y1 = coords->y1 + dsc->shadow_ofs_y - dsc->shadow_spread;
core_area.y2 = coords->y2 + dsc->shadow_ofs_y + dsc->shadow_spread;
lv_area_t shadow_area;
shadow_area.x1 = core_area.x1 - sw / 2 - 1;
shadow_area.x2 = core_area.x2 + sw / 2 + 1;
shadow_area.y1 = core_area.y1 - sw / 2 - 1;
shadow_area.y2 = core_area.y2 + sw / 2 + 1;
lv_opa_t opa = dsc->shadow_opa;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
/*Get clipped draw area which is the real draw area.
*It is always the same or inside `shadow_area`*/
lv_area_t draw_area;
if(!_lv_area_intersect(&draw_area, &shadow_area, clip)) return;
SDL_Rect core_area_rect;
lv_area_to_sdl_rect(&shadow_area, &core_area_rect);
lv_coord_t radius = dsc->radius;
/* No matter how big the shadow is, what we need is just a corner */
lv_coord_t frag_size = LV_MIN3(lv_area_get_width(&core_area) / 2, lv_area_get_height(&core_area) / 2,
LV_MAX(sw / 2, radius));
/* This is how big the corner is after blurring */
lv_coord_t blur_growth = (lv_coord_t)(sw / 2 + 1);
lv_coord_t blur_frag_size = (lv_coord_t)(frag_size + blur_growth);
lv_draw_rect_shadow_key_t key = rect_shadow_key_create(radius, frag_size, sw);
SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL);
if(texture == NULL) {
lv_area_t mask_area = {blur_growth, blur_growth}, mask_area_blurred = {0, 0};
lv_area_set_width(&mask_area, frag_size * 2);
lv_area_set_height(&mask_area, frag_size * 2);
lv_area_set_width(&mask_area_blurred, blur_frag_size * 2);
lv_area_set_height(&mask_area_blurred, blur_frag_size * 2);
lv_draw_mask_radius_param_t mask_rout_param;
lv_draw_mask_radius_init(&mask_rout_param, &mask_area, radius, false);
int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL);
lv_opa_t * mask_buf = lv_draw_sdl_mask_dump_opa(&mask_area_blurred, &mask_id, 1);
lv_stack_blur_grayscale(mask_buf, lv_area_get_width(&mask_area_blurred), lv_area_get_height(&mask_area_blurred),
sw / 2 + sw % 2);
texture = lv_sdl_create_opa_texture(ctx->renderer, mask_buf, blur_frag_size, blur_frag_size,
lv_area_get_width(&mask_area_blurred));
lv_mem_buf_release(mask_buf);
lv_draw_mask_remove_id(mask_id);
SDL_assert(texture);
lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture);
}
SDL_Color shadow_color;
lv_color_to_sdl_color(&dsc->shadow_color, &shadow_color);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(texture, opa);
SDL_SetTextureColorMod(texture, shadow_color.r, shadow_color.g, shadow_color.b);
lv_draw_sdl_rect_bg_frag_draw_corners(ctx, texture, blur_frag_size, &shadow_area, clip, false);
frag_render_borders(ctx->renderer, texture, blur_frag_size, &shadow_area, clip, false);
frag_render_center(ctx->renderer, texture, blur_frag_size, &shadow_area, clip, false);
}
static void 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)
{
if(SKIP_BORDER(dsc)) return;
SDL_Color border_color;
lv_color_to_sdl_color(&dsc->border_color, &border_color);
lv_coord_t coords_w = lv_area_get_width(coords), coords_h = lv_area_get_height(coords);
lv_coord_t short_side = LV_MIN(coords_w, coords_h);
lv_coord_t rout = LV_MIN(dsc->radius, short_side / 2);/*Get the inner area*/
lv_area_t area_inner;
lv_area_copy(&area_inner, coords);// lv_area_increase(&area_inner, 1, 1);
area_inner.x1 += ((dsc->border_side & LV_BORDER_SIDE_LEFT) ? dsc->border_width : -(dsc->border_width + rout));
area_inner.x2 -= ((dsc->border_side & LV_BORDER_SIDE_RIGHT) ? dsc->border_width : -(dsc->border_width + rout));
area_inner.y1 += ((dsc->border_side & LV_BORDER_SIDE_TOP) ? dsc->border_width : -(dsc->border_width + rout));
area_inner.y2 -= ((dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? dsc->border_width : -(dsc->border_width + rout));
lv_coord_t rin = LV_MAX(rout - dsc->border_width, 0);
draw_border_generic(ctx, coords, &area_inner, draw_area, rout, rin, dsc->border_color, dsc->border_opa,
dsc->blend_mode);
}
static void 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)
{
if(SKIP_OUTLINE(dsc)) return;
lv_opa_t opa = dsc->outline_opa;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
/*Get the inner radius*/
lv_area_t area_inner;
lv_area_copy(&area_inner, coords);
/*Bring the outline closer to make sure there is no color bleeding with pad=0*/
lv_coord_t pad = dsc->outline_pad - 1;
area_inner.x1 -= pad;
area_inner.y1 -= pad;
area_inner.x2 += pad;
area_inner.y2 += pad;
lv_area_t area_outer;
lv_area_copy(&area_outer, &area_inner);
area_outer.x1 -= dsc->outline_width;
area_outer.x2 += dsc->outline_width;
area_outer.y1 -= dsc->outline_width;
area_outer.y2 += dsc->outline_width;
lv_area_t draw_area;
if(!_lv_area_intersect(&draw_area, &area_outer, clip)) return;
int32_t inner_w = lv_area_get_width(&area_inner);
int32_t inner_h = lv_area_get_height(&area_inner);
lv_coord_t rin = dsc->radius;
int32_t short_side = LV_MIN(inner_w, inner_h);
if(rin > short_side >> 1) rin = short_side >> 1;
lv_coord_t rout = rin + dsc->outline_width;
draw_border_generic(ctx, &area_outer, &area_inner, clip, rout, rin, dsc->outline_color, dsc->outline_opa,
dsc->blend_mode);
}
static void 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)
{
opa = opa >= LV_OPA_COVER ? LV_OPA_COVER : opa;
SDL_Renderer * renderer = ctx->renderer;
lv_draw_rect_border_key_t key = rect_border_key_create(rout, rin, outer_area, inner_area);
lv_coord_t radius = LV_MIN3(rout, lv_area_get_width(outer_area) / 2, lv_area_get_height(outer_area) / 2);
lv_coord_t max_side = LV_MAX4(key.offsets.x1, key.offsets.y1, -key.offsets.x2, -key.offsets.y2);
lv_coord_t frag_size = LV_MAX(radius, max_side);
SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL);
if(texture == NULL) {
/* Create a mask texture with size of (frag_size * 2 + 3) */
const lv_area_t frag_area = {0, 0, frag_size * 2 + 2, frag_size * 2 + 2};
/*Create mask for the outer area*/
int16_t mask_ids[2] = {LV_MASK_ID_INV, LV_MASK_ID_INV};
lv_draw_mask_radius_param_t mask_rout_param;
if(rout > 0) {
lv_draw_mask_radius_init(&mask_rout_param, &frag_area, rout, false);
mask_ids[0] = lv_draw_mask_add(&mask_rout_param, NULL);
}
/*Create mask for the inner mask*/
if(rin < 0) rin = 0;
const lv_area_t frag_inner_area = {frag_area.x1 + key.offsets.x1, frag_area.y1 + key.offsets.y1,
frag_area.x2 + key.offsets.x2, frag_area.y2 + key.offsets.y2
};
lv_draw_mask_radius_param_t mask_rin_param;
lv_draw_mask_radius_init(&mask_rin_param, &frag_inner_area, rin, true);
mask_ids[1] = lv_draw_mask_add(&mask_rin_param, NULL);
texture = lv_draw_sdl_mask_dump_texture(renderer, &frag_area, mask_ids, 2);
lv_draw_mask_remove_id(mask_ids[1]);
lv_draw_mask_remove_id(mask_ids[0]);
SDL_assert(texture);
lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture);
}
SDL_Rect outer_rect;
lv_area_to_sdl_rect(outer_area, &outer_rect);
SDL_Color color_sdl;
lv_color_to_sdl_color(&color, &color_sdl);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(texture, opa);
SDL_SetTextureColorMod(texture, color_sdl.r, color_sdl.g, color_sdl.b);
lv_draw_sdl_rect_bg_frag_draw_corners(ctx, texture, frag_size, outer_area, clip, true);
frag_render_borders(renderer, texture, frag_size, outer_area, clip, true);
}
static void 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)
{
lv_area_t border_area, dst_area;
/* Top border */
border_area.x1 = coords->x1 + frag_size;
border_area.y1 = coords->y1;
border_area.x2 = coords->x2 - frag_size;
border_area.y2 = coords->y1 + frag_size - 1;
if(_lv_area_intersect(&dst_area, &border_area, clipped)) {
SDL_Rect dst_rect;
lv_area_to_sdl_rect(&dst_area, &dst_rect);
lv_coord_t sy = (lv_coord_t)(dst_area.y1 - border_area.y1);
if(full) {
SDL_Rect src_rect = {frag_size + 1, sy, 1, lv_area_get_height(&dst_area)};
SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
}
else {
SDL_Rect src_rect = {frag_size - 1, sy, 1, lv_area_get_height(&dst_area)};
SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
}
}
/* Bottom border */
border_area.y1 = LV_MAX(coords->y2 - frag_size + 1, coords->y1 + frag_size);
border_area.y2 = coords->y2;
if(_lv_area_intersect(&dst_area, &border_area, clipped)) {
SDL_Rect dst_rect;
lv_area_to_sdl_rect(&dst_area, &dst_rect);
lv_coord_t dh = lv_area_get_height(&dst_area);
if(full) {
lv_coord_t sy = (lv_coord_t)(dst_area.y1 - border_area.y1);
SDL_Rect src_rect = {frag_size + 1, frag_size + 3 + sy, 1, dh};
SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
}
else {
lv_coord_t sy = (lv_coord_t)(border_area.y2 - dst_area.y2);
SDL_Rect src_rect = {frag_size - 1, sy, 1, dh};
SDL_RenderCopyEx(renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_VERTICAL);
}
}
/* Left border */
border_area.x1 = coords->x1;
border_area.y1 = coords->y1 + frag_size;
border_area.x2 = coords->x1 + frag_size - 1;
border_area.y2 = coords->y2 - frag_size;
if(_lv_area_intersect(&dst_area, &border_area, clipped)) {
SDL_Rect dst_rect;
lv_area_to_sdl_rect(&dst_area, &dst_rect);
lv_coord_t dw = lv_area_get_width(&dst_area);
lv_coord_t sx = (lv_coord_t)(dst_area.x1 - border_area.x1);
if(full) {
SDL_Rect src_rect = {sx, frag_size + 1, dw, 1};
SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
}
else {
SDL_Rect src_rect = {sx, frag_size - 1, dw, 1};
SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
}
}
/* Right border */
border_area.x1 = LV_MAX(coords->x2 - frag_size + 1, coords->x1 + frag_size);
border_area.x2 = coords->x2;
if(_lv_area_intersect(&dst_area, &border_area, clipped)) {
SDL_Rect dst_rect;
lv_area_to_sdl_rect(&dst_area, &dst_rect);
lv_coord_t dw = lv_area_get_width(&dst_area);
if(full) {
lv_coord_t sx = (lv_coord_t)(dst_area.x1 - border_area.x1);
SDL_Rect src_rect = {frag_size + 3 + sx, frag_size + 1, dw, 1};
SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
}
else {
lv_coord_t sx = (lv_coord_t)(border_area.x2 - dst_area.x2);
SDL_Rect src_rect = {sx, frag_size - 1, dw, 1};
SDL_RenderCopyEx(renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL);
}
}
}
static void 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)
{
lv_area_t center_area = {
coords->x1 + frag_size,
coords->y1 + frag_size,
coords->x2 - frag_size,
coords->y2 - frag_size,
};
if(center_area.x2 < center_area.x1 || center_area.y2 < center_area.y1) return;
lv_area_t draw_area;
if(!_lv_area_intersect(&draw_area, &center_area, clipped)) {
return;
}
SDL_Rect dst_rect;
lv_area_to_sdl_rect(&draw_area, &dst_rect);
if(full) {
SDL_Rect src_rect = {frag_size, frag_size, 1, 1};
SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
}
else {
SDL_Rect src_rect = {frag_size - 1, frag_size - 1, 1, 1};
SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect);
}
}
static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size)
{
lv_draw_rect_bg_key_t key;
SDL_memset(&key, 0, sizeof(key));
key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_BG;
key.radius = radius;
key.size = size;
return key;
}
static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur)
{
lv_draw_rect_shadow_key_t key;
SDL_memset(&key, 0, sizeof(key));
key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW;
key.radius = radius;
key.size = size;
key.blur = blur;
return key;
}
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,
const lv_area_t * inner_area)
{
lv_draw_rect_border_key_t key;
/* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
SDL_memset(&key, 0, sizeof(key));
key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER;
key.rout = rout;
key.rin = rin;
key.offsets.x1 = inner_area->x1 - outer_area->x1;
key.offsets.x2 = inner_area->x2 - outer_area->x2;
key.offsets.y1 = inner_area->y1 - outer_area->y1;
key.offsets.y2 = inner_area->y2 - outer_area->y2;
return key;
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,75 @@
/**
* @file lv_draw_sdl_rect.h
*
*/
#ifndef LV_DRAW_SDL_RECT_H
#define LV_DRAW_SDL_RECT_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include LV_GPU_SDL_INCLUDE_PATH
#include "../lv_draw.h"
#include "lv_draw_sdl_texture_cache.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct lv_draw_sdl_rect_header_t {
lv_img_header_t base;
SDL_Rect rect;
} lv_draw_sdl_rect_header_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/*======================
* Add/remove functions
*=====================*/
/*=====================
* Setter functions
*====================*/
/*=====================
* Getter functions
*====================*/
/*=====================
* Other functions
*====================*/
SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius);
void 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);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_SDL*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_SDL_RECT_H*/

View File

@@ -0,0 +1,249 @@
/**
* @file lv_draw_sdl_stack_blur.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_sdl_stack_blur.h"
#if LV_USE_GPU_SDL
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void
stack_blur_job(lv_opa_t * src, unsigned int w, unsigned int h, unsigned int radius, int cores, int core, int step);
/**********************
* STATIC VARIABLES
**********************/
// Based heavily on http://vitiy.info/Code/stackblur.cpp
// See http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/
// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
static unsigned short const stackblur_mul[255] = {
512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259
};
static unsigned char const stackblur_shr[255] = {
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_stack_blur_grayscale(lv_opa_t * buf, uint16_t w, uint16_t h, uint16_t r)
{
stack_blur_job(buf, w, h, r, 1, 0, 1);
stack_blur_job(buf, w, h, r, 1, 0, 2);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void stack_blur_job(lv_opa_t * src, unsigned int w, unsigned int h, unsigned int radius, int cores, int core,
int step)
{
if(radius < 2 || radius > 254) {
/* Silently ignore bad radius */
return;
}
unsigned int x, y, xp, yp, i;
unsigned int sp;
unsigned int stack_start;
unsigned char * stack_ptr;
lv_opa_t * src_ptr;
lv_opa_t * dst_ptr;
unsigned long sum_r;
unsigned long sum_in_r;
unsigned long sum_out_r;
unsigned int wm = w - 1;
unsigned int hm = h - 1;
unsigned int stride = w;
unsigned int div = (radius * 2) + 1;
unsigned int mul_sum = stackblur_mul[radius];
unsigned char shr_sum = stackblur_shr[radius];
unsigned char stack[254 * 2 + 1];
if(step == 1) {
unsigned int minY = core * h / cores;
unsigned int maxY = (core + 1) * h / cores;
for(y = minY; y < maxY; y++) {
sum_r =
sum_in_r =
sum_out_r = 0;
src_ptr = src + stride * y; // start of line (0,y)
for(i = 0; i <= radius; i++) {
stack_ptr = &stack[i];
stack_ptr[0] = src_ptr[0];
sum_r += src_ptr[0] * (i + 1);
sum_out_r += src_ptr[0];
}
for(i = 1; i <= radius; i++) {
if(i <= wm) src_ptr += 1;
stack_ptr = &stack[i + radius];
stack_ptr[0] = src_ptr[0];
sum_r += src_ptr[0] * (radius + 1 - i);
sum_in_r += src_ptr[0];
}
sp = radius;
xp = radius;
if(xp > wm) xp = wm;
src_ptr = src + (xp + y * w); // img.pix_ptr(xp, y);
dst_ptr = src + y * stride; // img.pix_ptr(0, y);
for(x = 0; x < w; x++) {
dst_ptr[0] = LV_CLAMP((sum_r * mul_sum) >> shr_sum, 0, 255);
dst_ptr += 1;
sum_r -= sum_out_r;
stack_start = sp + div - radius;
if(stack_start >= div) stack_start -= div;
stack_ptr = &stack[stack_start];
sum_out_r -= stack_ptr[0];
if(xp < wm) {
src_ptr += 1;
++xp;
}
stack_ptr[0] = src_ptr[0];
sum_in_r += src_ptr[0];
sum_r += sum_in_r;
++sp;
if(sp >= div) sp = 0;
stack_ptr = &stack[sp];
sum_out_r += stack_ptr[0];
sum_in_r -= stack_ptr[0];
}
}
}
// step 2
if(step == 2) {
unsigned int minX = core * w / cores;
unsigned int maxX = (core + 1) * w / cores;
for(x = minX; x < maxX; x++) {
sum_r =
sum_in_r =
sum_out_r = 0;
src_ptr = src + x; // x,0
for(i = 0; i <= radius; i++) {
stack_ptr = &stack[i];
stack_ptr[0] = src_ptr[0];
sum_r += src_ptr[0] * (i + 1);
sum_out_r += src_ptr[0];
}
for(i = 1; i <= radius; i++) {
if(i <= hm) src_ptr += stride; // +stride
stack_ptr = &stack[i + radius];
stack_ptr[0] = src_ptr[0];
sum_r += src_ptr[0] * (radius + 1 - i);
sum_in_r += src_ptr[0];
}
sp = radius;
yp = radius;
if(yp > hm) yp = hm;
src_ptr = src + (x + yp * w); // img.pix_ptr(x, yp);
dst_ptr = src + x; // img.pix_ptr(x, 0);
for(y = 0; y < h; y++) {
dst_ptr[0] = LV_CLAMP((sum_r * mul_sum) >> shr_sum, 0, 255);
dst_ptr += stride;
sum_r -= sum_out_r;
stack_start = sp + div - radius;
if(stack_start >= div) stack_start -= div;
stack_ptr = &stack[stack_start];
sum_out_r -= stack_ptr[0];
if(yp < hm) {
src_ptr += stride; // stride
++yp;
}
stack_ptr[0] = src_ptr[0];
sum_in_r += src_ptr[0];
sum_r += sum_in_r;
++sp;
if(sp >= div) sp = 0;
stack_ptr = &stack[sp];
sum_out_r += stack_ptr[0];
sum_in_r -= stack_ptr[0];
}
}
}
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,46 @@
/**
* @file lv_draw_sdl_stack_blur.h
*
*/
#ifndef LV_DRAW_SDL_STACK_BLUR_H
#define LV_DRAW_SDL_STACK_BLUR_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "../../misc/lv_color.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_stack_blur_grayscale(lv_opa_t * buf, uint16_t w, uint16_t h, uint16_t r);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_SDL*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_SDL_STACK_BLUR_H*/

View File

@@ -0,0 +1,178 @@
/**
* @file lv_draw_sdl_texture_cache.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_utils.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
SDL_Texture * texture;
void * userdata;
lv_lru_free_t * userdata_free;
lv_draw_sdl_cache_flag_t flags;
} draw_cache_value_t;
typedef struct {
lv_sdl_cache_key_magic_t magic;
} temp_texture_key_t;
typedef struct {
lv_coord_t width, height;
} temp_texture_userdata_t;
static void draw_cache_free_value(draw_cache_value_t *);
static draw_cache_value_t * draw_cache_get_entry(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
bool * found);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_texture_cache_init(lv_draw_sdl_ctx_t * ctx)
{
ctx->internals->texture_cache = lv_lru_create(LV_GPU_SDL_LRU_SIZE, 65536,
(lv_lru_free_t *) draw_cache_free_value, NULL);
}
void lv_draw_sdl_texture_cache_deinit(lv_draw_sdl_ctx_t * ctx)
{
lv_lru_del(ctx->internals->texture_cache);
}
SDL_Texture * lv_draw_sdl_texture_cache_get(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, bool * found)
{
return lv_draw_sdl_texture_cache_get_with_userdata(ctx, key, key_length, found, NULL);
}
SDL_Texture * lv_draw_sdl_texture_cache_get_with_userdata(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
bool * found, void ** userdata)
{
draw_cache_value_t * value = draw_cache_get_entry(ctx, key, key_length, found);
if(!value) return NULL;
if(userdata) {
*userdata = value->userdata;
}
return value->texture;
}
void lv_draw_sdl_texture_cache_put(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, SDL_Texture * texture)
{
lv_draw_sdl_texture_cache_put_advanced(ctx, key, key_length, texture, NULL, NULL, 0);
}
void lv_draw_sdl_texture_cache_put_advanced(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
SDL_Texture * texture, void * userdata, void userdata_free(void *),
lv_draw_sdl_cache_flag_t flags)
{
lv_lru_t * lru = ctx->internals->texture_cache;
draw_cache_value_t * value = SDL_malloc(sizeof(draw_cache_value_t));
value->texture = texture;
value->userdata = userdata;
value->userdata_free = userdata_free;
value->flags = flags;
if(!texture) {
lv_lru_set(lru, key, key_length, value, 1);
return;
}
if(flags & LV_DRAW_SDL_CACHE_FLAG_MANAGED) {
/* Managed texture doesn't count into cache size */
LV_LOG_INFO("cache texture %p", texture);
lv_lru_set(lru, key, key_length, value, 1);
return;
}
Uint32 format;
int access, width, height;
if(SDL_QueryTexture(texture, &format, &access, &width, &height) != 0) {
return;
}
LV_LOG_INFO("cache texture %p, %d*%d@%dbpp", texture, width, height, SDL_BITSPERPIXEL(format));
lv_lru_set(lru, key, key_length, value, width * height * SDL_BITSPERPIXEL(format) / 8);
}
lv_draw_sdl_cache_key_head_img_t * lv_draw_sdl_texture_img_key_create(const void * src, int32_t frame_id, size_t * size)
{
lv_draw_sdl_cache_key_head_img_t header;
/* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
SDL_memset(&header, 0, sizeof(header));
header.magic = LV_GPU_CACHE_KEY_MAGIC_IMG;
header.type = lv_img_src_get_type(src);
header.frame_id = frame_id;
void * key;
size_t key_size;
if(header.type == LV_IMG_SRC_FILE || header.type == LV_IMG_SRC_SYMBOL) {
size_t srclen = SDL_strlen(src);
key_size = sizeof(header) + srclen;
key = SDL_malloc(key_size);
SDL_memcpy(key, &header, sizeof(header));
/*Copy string content as key value*/
SDL_memcpy(key + sizeof(header), src, srclen);
}
else {
key_size = sizeof(header) + sizeof(void *);
key = SDL_malloc(key_size);
SDL_memcpy(key, &header, sizeof(header));
/*Copy address number as key value*/
SDL_memcpy(key + sizeof(header), &src, sizeof(void *));
}
*size = key_size;
return (lv_draw_sdl_cache_key_head_img_t *) key;
}
static void draw_cache_free_value(draw_cache_value_t * value)
{
if(value->texture && !(value->flags & LV_DRAW_SDL_CACHE_FLAG_MANAGED)) {
LV_LOG_INFO("destroy texture %p", value->texture);
SDL_DestroyTexture(value->texture);
}
if(value->userdata_free) {
value->userdata_free(value->userdata);
}
SDL_free(value);
}
static draw_cache_value_t * draw_cache_get_entry(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
bool * found)
{
lv_lru_t * lru = ctx->internals->texture_cache;
draw_cache_value_t * value = NULL;
lv_lru_get(lru, key, key_length, (void **) &value);
if(!value) {
if(found) {
*found = false;
}
return NULL;
}
if(found) {
*found = true;
}
return value;
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,102 @@
/**
* @file lv_draw_sdl_texture_cache.h
*
*/
#ifndef LV_DRAW_SDL_TEXTURE_CACHE_H
#define LV_DRAW_SDL_TEXTURE_CACHE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include LV_GPU_SDL_INCLUDE_PATH
#include "lv_draw_sdl.h"
#include "lv_draw_sdl_priv.h"
#include "../../draw/lv_img_decoder.h"
#include "../../misc/lv_area.h"
/*********************
* DEFINES
*********************/
#define LV_DRAW_SDL_DEC_DSC_TEXTURE_HEAD "@LVSDLTex"
/**********************
* TYPEDEFS
**********************/
typedef struct {
char head[8];
SDL_Texture * texture;
SDL_Rect rect;
bool texture_managed;
bool texture_referenced;
} lv_draw_sdl_dec_dsc_userdata_t;
typedef enum {
LV_GPU_CACHE_KEY_MAGIC_ARC = 0x01,
LV_GPU_CACHE_KEY_MAGIC_IMG = 0x11,
LV_GPU_CACHE_KEY_MAGIC_IMG_ROUNDED_CORNERS = 0x12,
LV_GPU_CACHE_KEY_MAGIC_LINE = 0x21,
LV_GPU_CACHE_KEY_MAGIC_RECT_BG = 0x31,
LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW = 0x32,
LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER = 0x33,
LV_GPU_CACHE_KEY_MAGIC_FONT_GLYPH = 0x41,
LV_GPU_CACHE_KEY_MAGIC_MASK = 0x51,
} lv_sdl_cache_key_magic_t;
typedef enum {
LV_DRAW_SDL_CACHE_FLAG_NONE = 0,
LV_DRAW_SDL_CACHE_FLAG_MANAGED = 1,
} lv_draw_sdl_cache_flag_t;
typedef struct {
lv_sdl_cache_key_magic_t magic;
lv_img_src_t type;
int32_t frame_id;
} lv_draw_sdl_cache_key_head_img_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_draw_sdl_texture_cache_init(lv_draw_sdl_ctx_t * ctx);
void lv_draw_sdl_texture_cache_deinit(lv_draw_sdl_ctx_t * ctx);
/**
* Find cached texture by key. The texture can be destroyed during usage.
*/
SDL_Texture * lv_draw_sdl_texture_cache_get(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, bool * found);
SDL_Texture * lv_draw_sdl_texture_cache_get_with_userdata(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
bool * found, void ** userdata);
void lv_draw_sdl_texture_cache_put(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, SDL_Texture * texture);
void lv_draw_sdl_texture_cache_put_advanced(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
SDL_Texture * texture, void * userdata, void userdata_free(void *),
lv_draw_sdl_cache_flag_t flags);
lv_draw_sdl_cache_key_head_img_t * lv_draw_sdl_texture_img_key_create(const void * src, int32_t frame_id,
size_t * size);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_SDL*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_SDL_TEXTURE_CACHE_H*/

View File

@@ -0,0 +1,183 @@
/**
* @file lv_draw_sdl_utils.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "lv_draw_sdl_utils.h"
#include "../lv_draw.h"
#include "../lv_draw_label.h"
#include "../../core/lv_refr.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
extern const uint8_t _lv_bpp1_opa_table[2];
extern const uint8_t _lv_bpp2_opa_table[4];
extern const uint8_t _lv_bpp4_opa_table[16];
extern const uint8_t _lv_bpp8_opa_table[256];
static int utils_init_count = 0;
static SDL_Palette * lv_sdl_palette_grayscale8 = NULL;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void _lv_draw_sdl_utils_init()
{
utils_init_count++;
if(utils_init_count > 1) {
return;
}
lv_sdl_palette_grayscale8 = lv_sdl_alloc_palette_for_bpp(_lv_bpp8_opa_table, 8);
}
void _lv_draw_sdl_utils_deinit()
{
if(utils_init_count == 0) {
return;
}
utils_init_count--;
if(utils_init_count == 0) {
SDL_FreePalette(lv_sdl_palette_grayscale8);
lv_sdl_palette_grayscale8 = NULL;
}
}
void lv_area_to_sdl_rect(const lv_area_t * in, SDL_Rect * out)
{
out->x = in->x1;
out->y = in->y1;
out->w = in->x2 - in->x1 + 1;
out->h = in->y2 - in->y1 + 1;
}
void lv_color_to_sdl_color(const lv_color_t * in, SDL_Color * out)
{
#if LV_COLOR_DEPTH == 32
out->a = in->ch.alpha;
out->r = in->ch.red;
out->g = in->ch.green;
out->b = in->ch.blue;
#else
uint32_t color32 = lv_color_to32(*in);
lv_color32_t * color32_t = (lv_color32_t *) &color32;
out->a = color32_t->ch.alpha;
out->r = color32_t->ch.red;
out->g = color32_t->ch.green;
out->b = color32_t->ch.blue;
#endif
}
void lv_area_zoom_to_sdl_rect(const lv_area_t * in, SDL_Rect * out, uint16_t zoom, const lv_point_t * pivot)
{
if(zoom == LV_IMG_ZOOM_NONE) {
lv_area_to_sdl_rect(in, out);
return;
}
lv_area_t tmp;
_lv_img_buf_get_transformed_area(&tmp, lv_area_get_width(in), lv_area_get_height(in), 0, zoom, pivot);
lv_area_move(&tmp, in->x1, in->y1);
lv_area_to_sdl_rect(&tmp, out);
}
SDL_Palette * lv_sdl_alloc_palette_for_bpp(const uint8_t * mapping, uint8_t bpp)
{
SDL_assert(bpp >= 1 && bpp <= 8);
int color_cnt = 1 << bpp;
SDL_Palette * result = SDL_AllocPalette(color_cnt);
SDL_Color palette[256];
for(int i = 0; i < color_cnt; i++) {
palette[i].r = palette[i].g = palette[i].b = 0xFF;
palette[i].a = mapping ? mapping[i] : i;
}
SDL_SetPaletteColors(result, palette, 0, color_cnt);
return result;
}
SDL_Surface * lv_sdl_create_opa_surface(lv_opa_t * opa, lv_coord_t width, lv_coord_t height, lv_coord_t stride)
{
SDL_Surface * indexed = SDL_CreateRGBSurfaceFrom(opa, width, height, 8, stride, 0, 0, 0, 0);
SDL_SetSurfacePalette(indexed, lv_sdl_palette_grayscale8);
SDL_Surface * converted = SDL_ConvertSurfaceFormat(indexed, LV_DRAW_SDL_TEXTURE_FORMAT, 0);
SDL_FreeSurface(indexed);
return converted;
}
SDL_Texture * lv_sdl_create_opa_texture(SDL_Renderer * renderer, lv_opa_t * pixels, lv_coord_t width,
lv_coord_t height, lv_coord_t stride)
{
SDL_Surface * indexed = lv_sdl_create_opa_surface(pixels, width, height, stride);
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, indexed);
SDL_FreeSurface(indexed);
return texture;
}
void lv_sdl_to_8bpp(uint8_t * dest, const uint8_t * src, int width, int height, int stride, uint8_t bpp)
{
int src_len = width * height;
int cur = 0;
int curbit;
uint8_t opa_mask;
const uint8_t * opa_table;
switch(bpp) {
case 1:
opa_mask = 0x1;
opa_table = _lv_bpp1_opa_table;
break;
case 2:
opa_mask = 0x4;
opa_table = _lv_bpp2_opa_table;
break;
case 4:
opa_mask = 0xF;
opa_table = _lv_bpp4_opa_table;
break;
case 8:
opa_mask = 0xFF;
opa_table = _lv_bpp8_opa_table;
break;
default:
return;
}
/* Does this work well on big endian systems? */
while(cur < src_len) {
curbit = 8 - bpp;
uint8_t src_byte = src[cur * bpp / 8];
while(curbit >= 0 && cur < src_len) {
uint8_t src_bits = opa_mask & (src_byte >> curbit);
dest[(cur / width * stride) + (cur % width)] = opa_table[src_bits];
curbit -= bpp;
cur++;
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_GPU_SDL*/

View File

@@ -0,0 +1,65 @@
/**
* @file lv_draw_sdl_utils.h
*
*/
#ifndef LV_DRAW_SDL_UTILS_H
#define LV_DRAW_SDL_UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "lv_draw_sdl.h"
#include "../../misc/lv_color.h"
#include "../../misc/lv_area.h"
#include LV_GPU_SDL_INCLUDE_PATH
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void _lv_draw_sdl_utils_init();
void _lv_draw_sdl_utils_deinit();
void lv_area_to_sdl_rect(const lv_area_t * in, SDL_Rect * out);
void lv_color_to_sdl_color(const lv_color_t * in, SDL_Color * out);
void lv_area_zoom_to_sdl_rect(const lv_area_t * in, SDL_Rect * out, uint16_t zoom, const lv_point_t * pivot);
SDL_Palette * lv_sdl_alloc_palette_for_bpp(const uint8_t * mapping, uint8_t bpp);
SDL_Surface * lv_sdl_create_opa_surface(lv_opa_t * opa, lv_coord_t width, lv_coord_t height, lv_coord_t stride);
SDL_Texture * lv_sdl_create_opa_texture(SDL_Renderer * renderer, lv_opa_t * pixels, lv_coord_t width,
lv_coord_t height, lv_coord_t stride);
void lv_sdl_to_8bpp(uint8_t * dest, const uint8_t * src, int width, int height, int stride, uint8_t bpp);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_SDL*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_SDL_UTILS_H*/