小忍者项目相关文件上传
This commit is contained in:
59
MXC-A36/xrz/lvgl/src/draw/lv_draw.h
Normal file
59
MXC-A36/xrz/lvgl/src/draw/lv_draw.h
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file lv_draw.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_H
|
||||
#define LV_DRAW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#include "../misc/lv_style.h"
|
||||
#include "../misc/lv_txt.h"
|
||||
#include "lv_img_decoder.h"
|
||||
|
||||
#include "lv_draw_rect.h"
|
||||
#include "lv_draw_label.h"
|
||||
#include "lv_draw_img.h"
|
||||
#include "lv_draw_line.h"
|
||||
#include "lv_draw_triangle.h"
|
||||
#include "lv_draw_arc.h"
|
||||
#include "lv_draw_blend.h"
|
||||
#include "lv_draw_mask.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* POST INCLUDES
|
||||
*********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_H*/
|
16
MXC-A36/xrz/lvgl/src/draw/lv_draw.mk
Normal file
16
MXC-A36/xrz/lvgl/src/draw/lv_draw.mk
Normal file
@ -0,0 +1,16 @@
|
||||
CSRCS += lv_draw_arc.c
|
||||
CSRCS += lv_draw_blend.c
|
||||
CSRCS += lv_draw_img.c
|
||||
CSRCS += lv_draw_label.c
|
||||
CSRCS += lv_draw_line.c
|
||||
CSRCS += lv_draw_mask.c
|
||||
CSRCS += lv_draw_rect.c
|
||||
CSRCS += lv_draw_triangle.c
|
||||
CSRCS += lv_img_buf.c
|
||||
CSRCS += lv_img_cache.c
|
||||
CSRCS += lv_img_decoder.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw
|
||||
VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw
|
||||
|
||||
CFLAGS += "-I$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw"
|
542
MXC-A36/xrz/lvgl/src/draw/lv_draw_arc.c
Normal file
542
MXC-A36/xrz/lvgl/src/draw/lv_draw_arc.c
Normal file
@ -0,0 +1,542 @@
|
||||
/**
|
||||
* @file lv_draw_arc.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_arc.h"
|
||||
#include "lv_draw_rect.h"
|
||||
#include "lv_draw_mask.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_log.h"
|
||||
#include "../misc/lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define SPLIT_RADIUS_LIMIT 10 /*With radius greater then this the arc will drawn in quarters. A quarter is drawn only if there is arc in it*/
|
||||
#define SPLIT_ANGLE_GAP_LIMIT 60 /*With small gaps in the arc don't bother with splitting because there is nothing to skip.*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct {
|
||||
lv_coord_t center_x;
|
||||
lv_coord_t center_y;
|
||||
lv_coord_t radius;
|
||||
uint16_t start_angle;
|
||||
uint16_t end_angle;
|
||||
uint16_t start_quarter;
|
||||
uint16_t end_quarter;
|
||||
lv_coord_t width;
|
||||
lv_draw_rect_dsc_t * draw_dsc;
|
||||
const lv_area_t * draw_area;
|
||||
const lv_area_t * clip_area;
|
||||
} quarter_draw_dsc_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
#if LV_DRAW_COMPLEX
|
||||
static void draw_quarter_0(quarter_draw_dsc_t * q);
|
||||
static void draw_quarter_1(quarter_draw_dsc_t * q);
|
||||
static void draw_quarter_2(quarter_draw_dsc_t * q);
|
||||
static void draw_quarter_3(quarter_draw_dsc_t * q);
|
||||
static void get_rounded_area(int16_t angle, lv_coord_t radius, uint8_t thickness, lv_area_t * res_area);
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_arc_dsc_init(lv_draw_arc_dsc_t * dsc)
|
||||
{
|
||||
lv_memset_00(dsc, sizeof(lv_draw_arc_dsc_t));
|
||||
dsc->width = 1;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
}
|
||||
|
||||
void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uint16_t start_angle, uint16_t end_angle,
|
||||
const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc)
|
||||
{
|
||||
#if LV_DRAW_COMPLEX
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->width == 0) return;
|
||||
if(start_angle == end_angle) return;
|
||||
|
||||
lv_coord_t width = dsc->width;
|
||||
if(width > radius) width = radius;
|
||||
|
||||
lv_draw_rect_dsc_t cir_dsc;
|
||||
lv_draw_rect_dsc_init(&cir_dsc);
|
||||
cir_dsc.blend_mode = dsc->blend_mode;
|
||||
if(dsc->img_src) {
|
||||
cir_dsc.bg_opa = LV_OPA_TRANSP;
|
||||
cir_dsc.bg_img_src = dsc->img_src;
|
||||
cir_dsc.bg_img_opa = dsc->opa;
|
||||
} else {
|
||||
cir_dsc.bg_opa = dsc->opa;
|
||||
cir_dsc.bg_color = dsc->color;
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
/*Draw a full ring*/
|
||||
if(start_angle + 360 == end_angle || start_angle == end_angle + 360) {
|
||||
cir_dsc.border_width = dsc->width;
|
||||
cir_dsc.border_color = dsc->color;
|
||||
cir_dsc.border_opa = dsc->opa;
|
||||
cir_dsc.bg_opa = LV_OPA_TRANSP;
|
||||
cir_dsc.radius = LV_RADIUS_CIRCLE;
|
||||
lv_draw_rect(&area_out, clip_area, &cir_dsc);
|
||||
return;
|
||||
}
|
||||
|
||||
while(start_angle >= 360) start_angle -= 360;
|
||||
while(end_angle >= 360) end_angle -= 360;
|
||||
|
||||
lv_draw_mask_angle_param_t mask_angle_param;
|
||||
lv_draw_mask_angle_init(&mask_angle_param, center_x, center_y, start_angle, end_angle);
|
||||
int16_t mask_angle_id = lv_draw_mask_add(&mask_angle_param, NULL);
|
||||
|
||||
/*Create inner the mask*/
|
||||
lv_draw_mask_radius_param_t mask_in_param;
|
||||
lv_draw_mask_radius_init(&mask_in_param, &area_in, LV_RADIUS_CIRCLE, true);
|
||||
int16_t mask_in_id = lv_draw_mask_add(&mask_in_param, NULL);
|
||||
|
||||
lv_draw_mask_radius_param_t mask_out_param;
|
||||
lv_draw_mask_radius_init(&mask_out_param, &area_out, LV_RADIUS_CIRCLE, false);
|
||||
int16_t mask_out_id = lv_draw_mask_add(&mask_out_param, NULL);
|
||||
|
||||
int32_t angle_gap;
|
||||
if(end_angle > start_angle) {
|
||||
angle_gap = 360 - (end_angle - start_angle);
|
||||
}
|
||||
else {
|
||||
angle_gap = start_angle - end_angle;
|
||||
}
|
||||
if(angle_gap > SPLIT_ANGLE_GAP_LIMIT && radius > SPLIT_RADIUS_LIMIT) {
|
||||
/*Handle each quarter individually and skip which is empty*/
|
||||
quarter_draw_dsc_t q_dsc;
|
||||
q_dsc.center_x = center_x;
|
||||
q_dsc.center_y = center_y;
|
||||
q_dsc.radius = radius;
|
||||
q_dsc.start_angle = start_angle;
|
||||
q_dsc.end_angle = end_angle;
|
||||
q_dsc.start_quarter = (start_angle / 90) & 0x3;
|
||||
q_dsc.end_quarter = (end_angle / 90) & 0x3;
|
||||
q_dsc.width = width;
|
||||
q_dsc.draw_dsc = &cir_dsc;
|
||||
q_dsc.draw_area = &area_out;
|
||||
q_dsc.clip_area = clip_area;
|
||||
|
||||
draw_quarter_0(&q_dsc);
|
||||
draw_quarter_1(&q_dsc);
|
||||
draw_quarter_2(&q_dsc);
|
||||
draw_quarter_3(&q_dsc);
|
||||
}
|
||||
else {
|
||||
lv_draw_rect(&area_out, clip_area, &cir_dsc);
|
||||
}
|
||||
lv_draw_mask_remove_id(mask_angle_id);
|
||||
lv_draw_mask_remove_id(mask_out_id);
|
||||
lv_draw_mask_remove_id(mask_in_id);
|
||||
|
||||
if(dsc->rounded) {
|
||||
|
||||
lv_draw_mask_radius_param_t mask_end_param;
|
||||
|
||||
lv_area_t round_area;
|
||||
get_rounded_area(start_angle, radius, width, &round_area);
|
||||
round_area.x1 += center_x;
|
||||
round_area.x2 += center_x;
|
||||
round_area.y1 += center_y;
|
||||
round_area.y2 += center_y;
|
||||
lv_area_t clip_area2;
|
||||
if(_lv_area_intersect(&clip_area2, clip_area, &round_area)) {
|
||||
lv_draw_mask_radius_init(&mask_end_param, &round_area, LV_RADIUS_CIRCLE, false);
|
||||
int16_t mask_end_id = lv_draw_mask_add(&mask_end_param, NULL);
|
||||
|
||||
lv_draw_rect(&area_out, &clip_area2, &cir_dsc);
|
||||
lv_draw_mask_remove_id(mask_end_id);
|
||||
}
|
||||
|
||||
get_rounded_area(end_angle, radius, width, &round_area);
|
||||
round_area.x1 += center_x;
|
||||
round_area.x2 += center_x;
|
||||
round_area.y1 += center_y;
|
||||
round_area.y2 += center_y;
|
||||
if(_lv_area_intersect(&clip_area2, clip_area, &round_area)) {
|
||||
lv_draw_mask_radius_init(&mask_end_param, &round_area, LV_RADIUS_CIRCLE, false);
|
||||
int16_t mask_end_id = lv_draw_mask_add(&mask_end_param, NULL);
|
||||
|
||||
lv_draw_rect(&area_out, &clip_area2, &cir_dsc);
|
||||
lv_draw_mask_remove_id(mask_end_id);
|
||||
}
|
||||
}
|
||||
#else
|
||||
LV_LOG_WARN("Can't draw arc with LV_DRAW_COMPLEX == 0");
|
||||
LV_UNUSED(center_x);
|
||||
LV_UNUSED(center_y);
|
||||
LV_UNUSED(radius);
|
||||
LV_UNUSED(start_angle);
|
||||
LV_UNUSED(end_angle);
|
||||
LV_UNUSED(clip_area);
|
||||
LV_UNUSED(dsc);
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
}
|
||||
|
||||
void lv_draw_arc_get_area(lv_coord_t x, lv_coord_t y, uint16_t radius, uint16_t start_angle, uint16_t end_angle, lv_coord_t w, bool rounded, lv_area_t * area)
|
||||
{
|
||||
lv_coord_t rout = radius;
|
||||
lv_coord_t rin = radius - w;
|
||||
lv_coord_t extra_area = rounded ? w : 0;
|
||||
uint8_t start_quarter = start_angle / 90;
|
||||
uint8_t end_quarter = end_angle / 90;
|
||||
|
||||
|
||||
if(start_quarter == end_quarter && start_angle <= end_angle) {
|
||||
if(start_quarter == 0) {
|
||||
area->y1 = y + ((lv_trigo_sin(start_angle) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(start_angle + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
area->y2 = y + ((lv_trigo_sin(end_angle) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->x1 = x + ((lv_trigo_sin(end_angle + 90) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
}
|
||||
else if(start_quarter == 1) {
|
||||
area->y2 = y + ((lv_trigo_sin(start_angle) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(start_angle + 90) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
area->y1 = y + ((lv_trigo_sin(end_angle) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x1 = x + ((lv_trigo_sin(end_angle + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
}
|
||||
else if(start_quarter == 2) {
|
||||
area->x1 = x + ((lv_trigo_sin(start_angle + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(start_angle) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
area->y1 = y + ((lv_trigo_sin(end_angle) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(end_angle + 90) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
else if(start_quarter == 3) {
|
||||
area->x1 = x + ((lv_trigo_sin(start_angle + 90) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y + ((lv_trigo_sin(start_angle) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
|
||||
area->x2 = x + ((lv_trigo_sin(end_angle + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(end_angle) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
}
|
||||
else if(start_quarter == 0 && end_quarter == 1) {
|
||||
area->x1 = x + ((lv_trigo_sin(end_angle + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y + ((LV_MIN(lv_trigo_sin(end_angle),
|
||||
lv_trigo_sin(start_angle)) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(start_angle + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + rout + extra_area;
|
||||
}
|
||||
else if(start_quarter == 1 && end_quarter == 2) {
|
||||
area->x1 = x - rout - extra_area;
|
||||
area->y1 = y + ((lv_trigo_sin(end_angle) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((LV_MAX(lv_trigo_sin(start_angle + 90),
|
||||
lv_trigo_sin(end_angle + 90)) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(start_angle) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
else if(start_quarter == 2 && end_quarter == 3) {
|
||||
area->x1 = x + ((lv_trigo_sin(start_angle + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y - rout - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(end_angle + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + (LV_MAX(lv_trigo_sin(end_angle) * rin,
|
||||
lv_trigo_sin(start_angle) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
else if(start_quarter == 3 && end_quarter == 0) {
|
||||
area->x1 = x + ((LV_MIN(lv_trigo_sin(end_angle + 90),
|
||||
lv_trigo_sin(start_angle + 90)) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y + ((lv_trigo_sin(start_angle) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + rout + extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(end_angle) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
}
|
||||
else {
|
||||
area->x1 = x - rout;
|
||||
area->y1 = y - rout;
|
||||
area->x2 = x + rout;
|
||||
area->y2 = y + rout;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
static void draw_quarter_0(quarter_draw_dsc_t * q)
|
||||
{
|
||||
lv_area_t quarter_area;
|
||||
|
||||
if(q->start_quarter == 0 && q->end_quarter == 0 && q->start_angle < q->end_angle) {
|
||||
/*Small arc here*/
|
||||
quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->end_angle) * q->radius) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
else if(q->start_quarter == 0 || q->end_quarter == 0) {
|
||||
/*Start and/or end arcs here*/
|
||||
if(q->start_quarter == 0) {
|
||||
quarter_area.x1 = q->center_x;
|
||||
quarter_area.y2 = q->center_y + q->radius;
|
||||
|
||||
quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
if(q->end_quarter == 0) {
|
||||
quarter_area.x2 = q->center_x + q->radius;
|
||||
quarter_area.y1 = q->center_y;
|
||||
|
||||
quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->end_angle) * q->radius) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
}
|
||||
else if((q->start_quarter == q->end_quarter && q->start_quarter != 0 && q->end_angle < q->start_angle) ||
|
||||
(q->start_quarter == 2 && q->end_quarter == 1) ||
|
||||
(q->start_quarter == 3 && q->end_quarter == 2) ||
|
||||
(q->start_quarter == 3 && q->end_quarter == 1)) {
|
||||
/*Arc crosses here*/
|
||||
quarter_area.x1 = q->center_x;
|
||||
quarter_area.y1 = q->center_y;
|
||||
quarter_area.x2 = q->center_x + q->radius;
|
||||
quarter_area.y2 = q->center_y + q->radius;
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_quarter_1(quarter_draw_dsc_t * q)
|
||||
{
|
||||
lv_area_t quarter_area;
|
||||
|
||||
if(q->start_quarter == 1 && q->end_quarter == 1 && q->start_angle < q->end_angle) {
|
||||
/*Small arc here*/
|
||||
quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
else if(q->start_quarter == 1 || q->end_quarter == 1) {
|
||||
/*Start and/or end arcs here*/
|
||||
if(q->start_quarter == 1) {
|
||||
quarter_area.x1 = q->center_x - q->radius;
|
||||
quarter_area.y1 = q->center_y;
|
||||
|
||||
quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
if(q->end_quarter == 1) {
|
||||
quarter_area.x2 = q->center_x - 1;
|
||||
quarter_area.y2 = q->center_y + q->radius;
|
||||
|
||||
quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
}
|
||||
else if((q->start_quarter == q->end_quarter && q->start_quarter != 1 && q->end_angle < q->start_angle) ||
|
||||
(q->start_quarter == 0 && q->end_quarter == 2) ||
|
||||
(q->start_quarter == 0 && q->end_quarter == 3) ||
|
||||
(q->start_quarter == 3 && q->end_quarter == 2)) {
|
||||
/*Arc crosses here*/
|
||||
quarter_area.x1 = q->center_x - q->radius;
|
||||
quarter_area.y1 = q->center_y;
|
||||
quarter_area.x2 = q->center_x - 1;
|
||||
quarter_area.y2 = q->center_y + q->radius;
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_quarter_2(quarter_draw_dsc_t * q)
|
||||
{
|
||||
lv_area_t quarter_area;
|
||||
|
||||
if(q->start_quarter == 2 && q->end_quarter == 2 && q->start_angle < q->end_angle) {
|
||||
/*Small arc here*/
|
||||
quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->end_angle) * q->radius) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
else if(q->start_quarter == 2 || q->end_quarter == 2) {
|
||||
/*Start and/or end arcs here*/
|
||||
if(q->start_quarter == 2) {
|
||||
quarter_area.x2 = q->center_x - 1;
|
||||
quarter_area.y1 = q->center_y - q->radius;
|
||||
|
||||
quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
if(q->end_quarter == 2) {
|
||||
quarter_area.x1 = q->center_x - q->radius;
|
||||
quarter_area.y2 = q->center_y - 1;
|
||||
|
||||
quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
}
|
||||
else if((q->start_quarter == q->end_quarter && q->start_quarter != 2 && q->end_angle < q->start_angle) ||
|
||||
(q->start_quarter == 0 && q->end_quarter == 3) ||
|
||||
(q->start_quarter == 1 && q->end_quarter == 3) ||
|
||||
(q->start_quarter == 1 && q->end_quarter == 0)) {
|
||||
/*Arc crosses here*/
|
||||
quarter_area.x1 = q->center_x - q->radius;
|
||||
quarter_area.y1 = q->center_y - q->radius;
|
||||
quarter_area.x2 = q->center_x - 1;
|
||||
quarter_area.y2 = q->center_y - 1;
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_quarter_3(quarter_draw_dsc_t * q)
|
||||
{
|
||||
lv_area_t quarter_area;
|
||||
|
||||
if(q->start_quarter == 3 && q->end_quarter == 3 && q->start_angle < q->end_angle) {
|
||||
/*Small arc here*/
|
||||
quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
else if(q->start_quarter == 3 || q->end_quarter == 3) {
|
||||
/*Start and/or end arcs here*/
|
||||
if(q->start_quarter == 3) {
|
||||
quarter_area.x2 = q->center_x + q->radius;
|
||||
quarter_area.y2 = q->center_y - 1;
|
||||
|
||||
quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
if(q->end_quarter == 3) {
|
||||
quarter_area.x1 = q->center_x;
|
||||
quarter_area.y1 = q->center_y - q->radius;
|
||||
|
||||
quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT);
|
||||
quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT);
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
}
|
||||
else if((q->start_quarter == q->end_quarter && q->start_quarter != 3 && q->end_angle < q->start_angle) ||
|
||||
(q->start_quarter == 2 && q->end_quarter == 0) ||
|
||||
(q->start_quarter == 1 && q->end_quarter == 0) ||
|
||||
(q->start_quarter == 2 && q->end_quarter == 1)) {
|
||||
/*Arc crosses here*/
|
||||
quarter_area.x1 = q->center_x;
|
||||
quarter_area.y1 = q->center_y - q->radius;
|
||||
quarter_area.x2 = q->center_x + q->radius;
|
||||
quarter_area.y2 = q->center_y - 1;
|
||||
|
||||
bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area);
|
||||
if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_rounded_area(int16_t angle, lv_coord_t radius, uint8_t thickness, lv_area_t * res_area)
|
||||
{
|
||||
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(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;
|
||||
res_area->x1 = cir_x - thick_half + thick_corr;
|
||||
res_area->x2 = cir_x + thick_half;
|
||||
}
|
||||
else {
|
||||
cir_x = (cir_x + pa) >> ps;
|
||||
res_area->x1 = cir_x - thick_half;
|
||||
res_area->x2 = cir_x + thick_half - thick_corr;
|
||||
}
|
||||
|
||||
if(cir_y > 0) {
|
||||
cir_y = (cir_y - pa) >> ps;
|
||||
res_area->y1 = cir_y - thick_half + thick_corr;
|
||||
res_area->y2 = cir_y + thick_half;
|
||||
}
|
||||
else {
|
||||
cir_y = (cir_y + pa) >> ps;
|
||||
res_area->y1 = cir_y - thick_half;
|
||||
res_area->y2 = cir_y + thick_half - thick_corr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
75
MXC-A36/xrz/lvgl/src/draw/lv_draw_arc.h
Normal file
75
MXC-A36/xrz/lvgl/src/draw/lv_draw_arc.h
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file lv_draw_arc.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_ARC_H
|
||||
#define LV_DRAW_ARC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_line.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct {
|
||||
lv_color_t color;
|
||||
lv_coord_t width;
|
||||
const void * img_src;
|
||||
lv_opa_t opa;
|
||||
lv_blend_mode_t blend_mode : 2;
|
||||
uint8_t rounded : 1;
|
||||
} lv_draw_arc_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_arc_dsc_init(lv_draw_arc_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Draw an arc. (Can draw pie too with great thickness.)
|
||||
* @param center_x the x coordinate of the center of the arc
|
||||
* @param center_y the y coordinate of the center of the arc
|
||||
* @param radius the radius of the arc
|
||||
* @param mask the arc will be drawn only in this mask
|
||||
* @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)
|
||||
* @param end_angle the end angle of the arc
|
||||
* @param clip_area the arc will be drawn only in this area
|
||||
* @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uint16_t start_angle, uint16_t end_angle,
|
||||
const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Get an area the should be invalidated when the arcs angle changed between start_angle and end_ange
|
||||
* @param x the x coordinate of the center of the arc
|
||||
* @param y the y coordinate of the center of the arc
|
||||
* @param radius the radius of the arc
|
||||
* @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)
|
||||
* @param end_angle the end angle of the arc
|
||||
* @param w width of the arc
|
||||
* @param rounded true: the arc is rounded
|
||||
* @param area store the area to invalidate here
|
||||
*/
|
||||
void lv_draw_arc_get_area(lv_coord_t x, lv_coord_t y, uint16_t radius, uint16_t start_angle, uint16_t end_angle, lv_coord_t w, bool rounded, lv_area_t * area);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_ARC*/
|
1040
MXC-A36/xrz/lvgl/src/draw/lv_draw_blend.c
Normal file
1040
MXC-A36/xrz/lvgl/src/draw/lv_draw_blend.c
Normal file
File diff suppressed because it is too large
Load Diff
50
MXC-A36/xrz/lvgl/src/draw/lv_draw_blend.h
Normal file
50
MXC-A36/xrz/lvgl/src/draw/lv_draw_blend.h
Normal file
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @file lv_draw_blend.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_BLEND_H
|
||||
#define LV_DRAW_BLEND_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_style.h"
|
||||
#include "lv_draw_mask.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
LV_ATTRIBUTE_FAST_MEM void _lv_blend_fill(const lv_area_t * clip_area, const lv_area_t * fill_area, lv_color_t color,
|
||||
lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode);
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void _lv_blend_map(const lv_area_t * clip_area, const lv_area_t * map_area,
|
||||
const lv_color_t * map_buf,
|
||||
lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode);
|
||||
|
||||
//! @endcond
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_BLEND_H*/
|
660
MXC-A36/xrz/lvgl/src/draw/lv_draw_img.c
Normal file
660
MXC-A36/xrz/lvgl/src/draw/lv_draw_img.c
Normal file
@ -0,0 +1,660 @@
|
||||
/**
|
||||
* @file lv_draw_img.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_img.h"
|
||||
#include "lv_img_cache.h"
|
||||
#include "../hal/lv_hal_disp.h"
|
||||
#include "../misc/lv_log.h"
|
||||
#include "../core/lv_refr.h"
|
||||
#include "../misc/lv_mem.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#if LV_USE_GPU_STM32_DMA2D
|
||||
#include "../gpu/lv_gpu_stm32_dma2d.h"
|
||||
#elif LV_USE_GPU_NXP_PXP
|
||||
#include "../gpu/lv_gpu_nxp_pxp.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * clip_area,
|
||||
const void * src,
|
||||
const lv_draw_img_dsc_t * draw_dsc);
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area,
|
||||
const uint8_t * map_p,
|
||||
const lv_draw_img_dsc_t * draw_dsc,
|
||||
bool chroma_key, bool alpha_byte);
|
||||
|
||||
static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, const char * msg);
|
||||
static void draw_cleanup(_lv_img_cache_entry_t * cache);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc)
|
||||
{
|
||||
lv_memset_00(dsc, sizeof(lv_draw_img_dsc_t));
|
||||
dsc->recolor = lv_color_black();
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->zoom = LV_IMG_ZOOM_NONE;
|
||||
dsc->antialias = LV_COLOR_DEPTH > 8 ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw an image
|
||||
* @param coords the coordinates of the image
|
||||
* @param mask the image will be drawn only in this area
|
||||
* @param src pointer to a lv_color_t array which contains the pixels of the image
|
||||
* @param dsc pointer to an initialized `lv_draw_img_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_draw_img_dsc_t * dsc)
|
||||
{
|
||||
if(src == NULL) {
|
||||
LV_LOG_WARN("Image draw: src is NULL");
|
||||
show_error(coords, mask, "No\ndata");
|
||||
return;
|
||||
}
|
||||
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
lv_res_t res;
|
||||
res = lv_img_draw_core(coords, mask, src, dsc);
|
||||
|
||||
if(res == LV_RES_INV) {
|
||||
LV_LOG_WARN("Image draw error");
|
||||
show_error(coords, mask, "No\ndata");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pixel size of a color format in bits
|
||||
* @param cf a color format (`LV_IMG_CF_...`)
|
||||
* @return the pixel size in bits
|
||||
*/
|
||||
uint8_t lv_img_cf_get_px_size(lv_img_cf_t cf)
|
||||
{
|
||||
uint8_t px_size = 0;
|
||||
|
||||
switch(cf) {
|
||||
case LV_IMG_CF_UNKNOWN:
|
||||
case LV_IMG_CF_RAW:
|
||||
px_size = 0;
|
||||
break;
|
||||
case LV_IMG_CF_TRUE_COLOR:
|
||||
case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
|
||||
px_size = LV_COLOR_SIZE;
|
||||
break;
|
||||
case LV_IMG_CF_TRUE_COLOR_ALPHA:
|
||||
px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
case LV_IMG_CF_ALPHA_1BIT:
|
||||
px_size = 1;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
case LV_IMG_CF_ALPHA_2BIT:
|
||||
px_size = 2;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
case LV_IMG_CF_ALPHA_4BIT:
|
||||
px_size = 4;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
case LV_IMG_CF_ALPHA_8BIT:
|
||||
px_size = 8;
|
||||
break;
|
||||
default:
|
||||
px_size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return px_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a color format is chroma keyed or not
|
||||
* @param cf a color format (`LV_IMG_CF_...`)
|
||||
* @return true: chroma keyed; false: not chroma keyed
|
||||
*/
|
||||
bool lv_img_cf_is_chroma_keyed(lv_img_cf_t cf)
|
||||
{
|
||||
bool is_chroma_keyed = false;
|
||||
|
||||
switch(cf) {
|
||||
case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
|
||||
case LV_IMG_CF_RAW_CHROMA_KEYED:
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
is_chroma_keyed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
is_chroma_keyed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return is_chroma_keyed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a color format has alpha channel or not
|
||||
* @param cf a color format (`LV_IMG_CF_...`)
|
||||
* @return true: has alpha channel; false: doesn't have alpha channel
|
||||
*/
|
||||
bool lv_img_cf_has_alpha(lv_img_cf_t cf)
|
||||
{
|
||||
bool has_alpha = false;
|
||||
|
||||
switch(cf) {
|
||||
case LV_IMG_CF_TRUE_COLOR_ALPHA:
|
||||
case LV_IMG_CF_RAW_ALPHA:
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
case LV_IMG_CF_ALPHA_1BIT:
|
||||
case LV_IMG_CF_ALPHA_2BIT:
|
||||
case LV_IMG_CF_ALPHA_4BIT:
|
||||
case LV_IMG_CF_ALPHA_8BIT:
|
||||
has_alpha = true;
|
||||
break;
|
||||
default:
|
||||
has_alpha = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return has_alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of an image source
|
||||
* @param src pointer to an image source:
|
||||
* - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)
|
||||
* - a path to a file (e.g. "S:/folder/image.bin")
|
||||
* - or a symbol (e.g. LV_SYMBOL_CLOSE)
|
||||
* @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN
|
||||
*/
|
||||
lv_img_src_t lv_img_src_get_type(const void * src)
|
||||
{
|
||||
lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN;
|
||||
|
||||
if(src == NULL) return img_src_type;
|
||||
const uint8_t * u8_p = src;
|
||||
|
||||
/*The first byte shows the type of the image source*/
|
||||
if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) {
|
||||
img_src_type = LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/
|
||||
}
|
||||
else if(u8_p[0] >= 0x80) {
|
||||
img_src_type = LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/
|
||||
}
|
||||
else {
|
||||
img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is draw to the first byte < 0x20*/
|
||||
}
|
||||
|
||||
if(LV_IMG_SRC_UNKNOWN == img_src_type) {
|
||||
LV_LOG_WARN("lv_img_src_get_type: unknown image type");
|
||||
}
|
||||
|
||||
return img_src_type;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * clip_area,
|
||||
const void * src,
|
||||
const lv_draw_img_dsc_t * draw_dsc)
|
||||
{
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) return LV_RES_OK;
|
||||
|
||||
_lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, draw_dsc->recolor, draw_dsc->frame_id);
|
||||
|
||||
if(cdsc == NULL) return LV_RES_INV;
|
||||
|
||||
bool chroma_keyed = lv_img_cf_is_chroma_keyed(cdsc->dec_dsc.header.cf);
|
||||
bool alpha_byte = lv_img_cf_has_alpha(cdsc->dec_dsc.header.cf);
|
||||
|
||||
if(cdsc->dec_dsc.error_msg != NULL) {
|
||||
LV_LOG_WARN("Image draw error");
|
||||
|
||||
show_error(coords, clip_area, cdsc->dec_dsc.error_msg);
|
||||
}
|
||||
/*The decoder could open the image and gave the entire uncompressed image.
|
||||
*Just draw it!*/
|
||||
else if(cdsc->dec_dsc.img_data) {
|
||||
lv_area_t map_area_rot;
|
||||
lv_area_copy(&map_area_rot, coords);
|
||||
if(draw_dsc->angle || draw_dsc->zoom != LV_IMG_ZOOM_NONE) {
|
||||
int32_t w = lv_area_get_width(coords);
|
||||
int32_t h = lv_area_get_height(coords);
|
||||
|
||||
_lv_img_buf_get_transformed_area(&map_area_rot, w, h, draw_dsc->angle, draw_dsc->zoom, &draw_dsc->pivot);
|
||||
|
||||
map_area_rot.x1 += coords->x1;
|
||||
map_area_rot.y1 += coords->y1;
|
||||
map_area_rot.x2 += coords->x1;
|
||||
map_area_rot.y2 += coords->y1;
|
||||
}
|
||||
|
||||
lv_area_t mask_com; /*Common area of mask and coords*/
|
||||
bool union_ok;
|
||||
union_ok = _lv_area_intersect(&mask_com, clip_area, &map_area_rot);
|
||||
/*Out of mask. There is nothing to draw so the image is drawn successfully.*/
|
||||
if(union_ok == false) {
|
||||
draw_cleanup(cdsc);
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
lv_draw_map(coords, &mask_com, cdsc->dec_dsc.img_data, draw_dsc, chroma_keyed, alpha_byte);
|
||||
}
|
||||
/*The whole uncompressed image is not available. Try to read it line-by-line*/
|
||||
else {
|
||||
lv_area_t mask_com; /*Common area of mask and coords*/
|
||||
bool union_ok;
|
||||
union_ok = _lv_area_intersect(&mask_com, clip_area, coords);
|
||||
/*Out of mask. There is nothing to draw so the image is drawn successfully.*/
|
||||
if(union_ok == false) {
|
||||
draw_cleanup(cdsc);
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
int32_t width = lv_area_get_width(&mask_com);
|
||||
|
||||
uint8_t * buf = lv_mem_buf_get(lv_area_get_width(&mask_com) *
|
||||
LV_IMG_PX_SIZE_ALPHA_BYTE); /*+1 because of the possible alpha byte*/
|
||||
|
||||
lv_area_t line;
|
||||
lv_area_copy(&line, &mask_com);
|
||||
lv_area_set_height(&line, 1);
|
||||
int32_t x = mask_com.x1 - coords->x1;
|
||||
int32_t y = mask_com.y1 - coords->y1;
|
||||
int32_t row;
|
||||
lv_res_t read_res;
|
||||
for(row = mask_com.y1; row <= mask_com.y2; row++) {
|
||||
lv_area_t mask_line;
|
||||
union_ok = _lv_area_intersect(&mask_line, clip_area, &line);
|
||||
if(union_ok == false) continue;
|
||||
|
||||
read_res = lv_img_decoder_read_line(&cdsc->dec_dsc, x, y, width, buf);
|
||||
if(read_res != LV_RES_OK) {
|
||||
lv_img_decoder_close(&cdsc->dec_dsc);
|
||||
LV_LOG_WARN("Image draw can't read the line");
|
||||
lv_mem_buf_release(buf);
|
||||
draw_cleanup(cdsc);
|
||||
return LV_RES_INV;
|
||||
}
|
||||
|
||||
lv_draw_map(&line, &mask_line, buf, draw_dsc, chroma_keyed, alpha_byte);
|
||||
line.y1++;
|
||||
line.y2++;
|
||||
y++;
|
||||
}
|
||||
lv_mem_buf_release(buf);
|
||||
}
|
||||
|
||||
draw_cleanup(cdsc);
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a color map to the display (image)
|
||||
* @param cords_p coordinates the color map
|
||||
* @param mask_p the map will drawn only on this area (truncated to draw_buf area)
|
||||
* @param map_p pointer to a lv_color_t array
|
||||
* @param draw_dsc pointer to an initialized `lv_draw_img_dsc_t` variable
|
||||
* @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels
|
||||
* @param alpha_byte true: extra alpha byte is inserted for every pixel
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area,
|
||||
const uint8_t * map_p,
|
||||
const lv_draw_img_dsc_t * draw_dsc,
|
||||
bool chroma_key, bool alpha_byte)
|
||||
{
|
||||
/*Use the clip area as draw area*/
|
||||
lv_area_t draw_area;
|
||||
lv_area_copy(&draw_area, clip_area);
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp);
|
||||
const lv_area_t * disp_area = &draw_buf->area;
|
||||
|
||||
/*Now `draw_area` has absolute coordinates.
|
||||
*Make it relative to `disp_area` to simplify draw to `disp_buf`*/
|
||||
draw_area.x1 -= disp_area->x1;
|
||||
draw_area.y1 -= disp_area->y1;
|
||||
draw_area.x2 -= disp_area->x1;
|
||||
draw_area.y2 -= disp_area->y1;
|
||||
|
||||
uint8_t other_mask_cnt = lv_draw_mask_get_cnt();
|
||||
|
||||
/*The simplest case just copy the pixels into the draw_buf*/
|
||||
if(other_mask_cnt == 0 && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE &&
|
||||
chroma_key == false && alpha_byte == false && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
|
||||
_lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, draw_dsc->opa,
|
||||
draw_dsc->blend_mode);
|
||||
}
|
||||
|
||||
#if LV_USE_GPU_NXP_PXP
|
||||
/*Simple case without masking and transformations*/
|
||||
else if(other_mask_cnt == 0 && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE && alpha_byte == false &&
|
||||
chroma_key == true && draw_dsc->recolor_opa == LV_OPA_TRANSP) { /*copy with color keying (+ alpha)*/
|
||||
lv_gpu_nxp_pxp_enable_color_key();
|
||||
_lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, draw_dsc->opa,
|
||||
draw_dsc->blend_mode);
|
||||
lv_gpu_nxp_pxp_disable_color_key();
|
||||
}
|
||||
else if(other_mask_cnt == 0 && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE && alpha_byte == false &&
|
||||
chroma_key == false && draw_dsc->recolor_opa != LV_OPA_TRANSP) { /*copy with recolor (+ alpha)*/
|
||||
lv_gpu_nxp_pxp_enable_recolor(draw_dsc->recolor, draw_dsc->recolor_opa);
|
||||
_lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, draw_dsc->opa,
|
||||
draw_dsc->blend_mode);
|
||||
lv_gpu_nxp_pxp_disable_recolor();
|
||||
}
|
||||
#endif
|
||||
/*In the other cases every pixel need to be checked one-by-one*/
|
||||
else {
|
||||
//#if LV_DRAW_COMPLEX
|
||||
/*The pixel size in byte is different if an alpha byte is added too*/
|
||||
uint8_t px_size_byte = alpha_byte ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
|
||||
|
||||
/*Go to the first displayed pixel of the map*/
|
||||
int32_t map_w = lv_area_get_width(map_area);
|
||||
const uint8_t * map_buf_tmp = map_p;
|
||||
map_buf_tmp += map_w * (draw_area.y1 - (map_area->y1 - disp_area->y1)) * px_size_byte;
|
||||
map_buf_tmp += (draw_area.x1 - (map_area->x1 - disp_area->x1)) * px_size_byte;
|
||||
|
||||
lv_color_t c;
|
||||
lv_color_t chroma_keyed_color = LV_COLOR_CHROMA_KEY;
|
||||
uint32_t px_i = 0;
|
||||
|
||||
const uint8_t * map_px;
|
||||
|
||||
lv_area_t blend_area;
|
||||
blend_area.x1 = draw_area.x1 + disp_area->x1;
|
||||
blend_area.x2 = blend_area.x1 + lv_area_get_width(&draw_area) - 1;
|
||||
blend_area.y1 = disp_area->y1 + draw_area.y1;
|
||||
blend_area.y2 = blend_area.y1;
|
||||
|
||||
lv_coord_t draw_area_h = lv_area_get_height(&draw_area);
|
||||
lv_coord_t draw_area_w = lv_area_get_width(&draw_area);
|
||||
|
||||
bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false;
|
||||
/*Simple ARGB image. Handle it as special case because it's very common*/
|
||||
if(other_mask_cnt == 0 && !transform && !chroma_key && draw_dsc->recolor_opa == LV_OPA_TRANSP && alpha_byte) {
|
||||
#if LV_USE_GPU_STM32_DMA2D && LV_COLOR_DEPTH == 32
|
||||
/*Blend ARGB images directly*/
|
||||
if(lv_area_get_size(&draw_area) > 240) {
|
||||
int32_t disp_w = lv_area_get_width(disp_area);
|
||||
lv_color_t * disp_buf = draw_buf->buf_act;
|
||||
lv_color_t * disp_buf_first = disp_buf + disp_w * draw_area.y1 + draw_area.x1;
|
||||
lv_gpu_stm32_dma2d_blend(disp_buf_first, disp_w, (const lv_color_t *)map_buf_tmp, draw_dsc->opa, map_w, draw_area_w,
|
||||
draw_area_h);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(disp);
|
||||
uint32_t mask_buf_size = lv_area_get_size(&draw_area) > (uint32_t) hor_res ? hor_res : lv_area_get_size(&draw_area);
|
||||
lv_color_t * map2 = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
for(y = 0; y < draw_area_h; y++) {
|
||||
map_px = map_buf_tmp;
|
||||
for(x = 0; x < draw_area_w; x++, map_px += px_size_byte, px_i++) {
|
||||
lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
||||
mask_buf[px_i] = px_opa;
|
||||
if(px_opa) {
|
||||
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
||||
map2[px_i].full = map_px[0];
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
map2[px_i].full = map_px[0] + (map_px[1] << 8);
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
map2[px_i].full = *((uint32_t *)map_px);
|
||||
#endif
|
||||
}
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
map2[px_i].ch.alpha = 0xFF;
|
||||
#endif
|
||||
}
|
||||
|
||||
map_buf_tmp += map_w * px_size_byte;
|
||||
if(px_i + lv_area_get_width(&draw_area) < mask_buf_size) {
|
||||
blend_area.y2 ++;
|
||||
}
|
||||
else {
|
||||
_lv_blend_map(clip_area, &blend_area, map2, mask_buf, LV_DRAW_MASK_RES_CHANGED, draw_dsc->opa, draw_dsc->blend_mode);
|
||||
|
||||
blend_area.y1 = blend_area.y2 + 1;
|
||||
blend_area.y2 = blend_area.y1;
|
||||
|
||||
px_i = 0;
|
||||
}
|
||||
}
|
||||
/*Flush the last part*/
|
||||
if(blend_area.y1 != blend_area.y2) {
|
||||
blend_area.y2--;
|
||||
_lv_blend_map(clip_area, &blend_area, map2, mask_buf, LV_DRAW_MASK_RES_CHANGED, draw_dsc->opa, draw_dsc->blend_mode);
|
||||
}
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
lv_mem_buf_release(map2);
|
||||
}
|
||||
/*Most complicated case: transform or other mask or chroma keyed*/
|
||||
else {
|
||||
/*Build the image and a mask line-by-line*/
|
||||
uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(disp);
|
||||
uint32_t mask_buf_size = lv_area_get_size(&draw_area) > hor_res ? hor_res : lv_area_get_size(&draw_area);
|
||||
lv_color_t * map2 = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
lv_img_transform_dsc_t trans_dsc;
|
||||
lv_memset_00(&trans_dsc, sizeof(lv_img_transform_dsc_t));
|
||||
if(transform) {
|
||||
lv_img_cf_t cf = LV_IMG_CF_TRUE_COLOR;
|
||||
if(alpha_byte) cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
|
||||
else if(chroma_key) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
|
||||
|
||||
trans_dsc.cfg.angle = draw_dsc->angle;
|
||||
trans_dsc.cfg.zoom = draw_dsc->zoom;
|
||||
trans_dsc.cfg.src = map_p;
|
||||
trans_dsc.cfg.src_w = map_w;
|
||||
trans_dsc.cfg.src_h = lv_area_get_height(map_area);;
|
||||
trans_dsc.cfg.cf = cf;
|
||||
trans_dsc.cfg.pivot_x = draw_dsc->pivot.x;
|
||||
trans_dsc.cfg.pivot_y = draw_dsc->pivot.y;
|
||||
trans_dsc.cfg.color = draw_dsc->recolor;
|
||||
trans_dsc.cfg.antialias = draw_dsc->antialias;
|
||||
|
||||
_lv_img_buf_transform_init(&trans_dsc);
|
||||
}
|
||||
#endif
|
||||
uint16_t recolor_premult[3] = {0};
|
||||
lv_opa_t recolor_opa_inv = 255 - draw_dsc->recolor_opa;
|
||||
if(draw_dsc->recolor_opa != 0) {
|
||||
lv_color_premult(draw_dsc->recolor, draw_dsc->recolor_opa, recolor_premult);
|
||||
}
|
||||
|
||||
lv_draw_mask_res_t mask_res;
|
||||
mask_res = (alpha_byte || chroma_key || draw_dsc->angle ||
|
||||
draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
|
||||
|
||||
/*Prepare the `mask_buf`if there are other masks*/
|
||||
if(other_mask_cnt) {
|
||||
lv_memset_ff(mask_buf, mask_buf_size);
|
||||
}
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
#if LV_DRAW_COMPLEX
|
||||
int32_t rot_y = disp_area->y1 + draw_area.y1 - map_area->y1;
|
||||
#endif
|
||||
for(y = 0; y < draw_area_h; y++) {
|
||||
map_px = map_buf_tmp;
|
||||
#if LV_DRAW_COMPLEX
|
||||
uint32_t px_i_start = px_i;
|
||||
int32_t rot_x = disp_area->x1 + draw_area.x1 - map_area->x1;
|
||||
#endif
|
||||
|
||||
for(x = 0; x < draw_area_w; x++, map_px += px_size_byte, px_i++) {
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
if(transform) {
|
||||
|
||||
/*Transform*/
|
||||
bool ret;
|
||||
ret = _lv_img_buf_transform(&trans_dsc, rot_x + x, rot_y + y);
|
||||
if(ret == false) {
|
||||
mask_buf[px_i] = LV_OPA_TRANSP;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
mask_buf[px_i] = trans_dsc.res.opa;
|
||||
c.full = trans_dsc.res.color.full;
|
||||
}
|
||||
}
|
||||
/*No transform*/
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if(alpha_byte) {
|
||||
lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
||||
mask_buf[px_i] = px_opa;
|
||||
if(px_opa == 0) {
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
map2[px_i].full = 0;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mask_buf[px_i] = 0xFF;
|
||||
}
|
||||
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
c.full = map_px[0];
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
c.full = map_px[0];
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
c.full = map_px[0] + (map_px[1] << 8);
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
c.full = *((uint32_t *)map_px);
|
||||
c.ch.alpha = 0xFF;
|
||||
#endif
|
||||
if(chroma_key) {
|
||||
if(c.full == chroma_keyed_color.full) {
|
||||
mask_buf[px_i] = LV_OPA_TRANSP;
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
map2[px_i].full = 0;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(draw_dsc->recolor_opa != 0) {
|
||||
c = lv_color_mix_premult(recolor_premult, c, recolor_opa_inv);
|
||||
}
|
||||
|
||||
map2[px_i].full = c.full;
|
||||
}
|
||||
#if LV_DRAW_COMPLEX
|
||||
/*Apply the masks if any*/
|
||||
if(other_mask_cnt) {
|
||||
lv_draw_mask_res_t mask_res_sub;
|
||||
mask_res_sub = lv_draw_mask_apply(mask_buf + px_i_start, draw_area.x1 + draw_buf->area.x1, y + draw_area.y1 + draw_buf->area.y1,
|
||||
lv_area_get_width(&draw_area));
|
||||
if(mask_res_sub == LV_DRAW_MASK_RES_TRANSP) {
|
||||
lv_memset_00(mask_buf + px_i_start, lv_area_get_width(&draw_area));
|
||||
mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
}
|
||||
else if(mask_res_sub == LV_DRAW_MASK_RES_CHANGED) {
|
||||
mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
map_buf_tmp += map_w * px_size_byte;
|
||||
if(px_i + lv_area_get_width(&draw_area) < mask_buf_size) {
|
||||
blend_area.y2 ++;
|
||||
}
|
||||
else {
|
||||
|
||||
_lv_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, draw_dsc->opa, draw_dsc->blend_mode);
|
||||
|
||||
blend_area.y1 = blend_area.y2 + 1;
|
||||
blend_area.y2 = blend_area.y1;
|
||||
|
||||
px_i = 0;
|
||||
mask_res = (alpha_byte || chroma_key || draw_dsc->angle ||
|
||||
draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
|
||||
|
||||
/*Prepare the `mask_buf`if there are other masks*/
|
||||
if(other_mask_cnt) {
|
||||
lv_memset_ff(mask_buf, mask_buf_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Flush the last part*/
|
||||
if(blend_area.y1 != blend_area.y2) {
|
||||
blend_area.y2--;
|
||||
_lv_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, draw_dsc->opa, draw_dsc->blend_mode);
|
||||
}
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
lv_mem_buf_release(map2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, const char * msg)
|
||||
{
|
||||
lv_draw_rect_dsc_t rect_dsc;
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.bg_color = lv_color_white();
|
||||
lv_draw_rect(coords, clip_area, &rect_dsc);
|
||||
|
||||
lv_draw_label_dsc_t label_dsc;
|
||||
lv_draw_label_dsc_init(&label_dsc);
|
||||
lv_draw_label(coords, clip_area, &label_dsc, msg, NULL);
|
||||
}
|
||||
|
||||
static void draw_cleanup(_lv_img_cache_entry_t * cache)
|
||||
{
|
||||
/*Automatically close images with no caching*/
|
||||
#if LV_IMG_CACHE_DEF_SIZE == 0
|
||||
lv_img_decoder_close(&cache->dec_dsc);
|
||||
#else
|
||||
LV_UNUSED(cache);
|
||||
#endif
|
||||
}
|
97
MXC-A36/xrz/lvgl/src/draw/lv_draw_img.h
Normal file
97
MXC-A36/xrz/lvgl/src/draw/lv_draw_img.h
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file lv_draw_img.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_IMG_H
|
||||
#define LV_DRAW_IMG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_img_decoder.h"
|
||||
#include "lv_img_buf.h"
|
||||
#include "lv_draw_blend.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
|
||||
uint16_t angle;
|
||||
uint16_t zoom;
|
||||
lv_point_t pivot;
|
||||
|
||||
lv_color_t recolor;
|
||||
lv_opa_t recolor_opa;
|
||||
|
||||
lv_opa_t opa;
|
||||
lv_blend_mode_t blend_mode : 4;
|
||||
|
||||
int32_t frame_id;
|
||||
uint8_t antialias : 1;
|
||||
} lv_draw_img_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc);
|
||||
/**
|
||||
* Draw an image
|
||||
* @param coords the coordinates of the image
|
||||
* @param mask the image will be drawn only in this area
|
||||
* @param src pointer to a lv_color_t array which contains the pixels of the image
|
||||
* @param dsc pointer to an initialized `lv_draw_img_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_draw_img_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Get the type of an image source
|
||||
* @param src pointer to an image source:
|
||||
* - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)
|
||||
* - a path to a file (e.g. "S:/folder/image.bin")
|
||||
* - or a symbol (e.g. LV_SYMBOL_CLOSE)
|
||||
* @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN
|
||||
*/
|
||||
lv_img_src_t lv_img_src_get_type(const void * src);
|
||||
|
||||
/**
|
||||
* Get the pixel size of a color format in bits
|
||||
* @param cf a color format (`LV_IMG_CF_...`)
|
||||
* @return the pixel size in bits
|
||||
*/
|
||||
uint8_t lv_img_cf_get_px_size(lv_img_cf_t cf);
|
||||
|
||||
/**
|
||||
* Check if a color format is chroma keyed or not
|
||||
* @param cf a color format (`LV_IMG_CF_...`)
|
||||
* @return true: chroma keyed; false: not chroma keyed
|
||||
*/
|
||||
bool lv_img_cf_is_chroma_keyed(lv_img_cf_t cf);
|
||||
|
||||
/**
|
||||
* Check if a color format has alpha channel or not
|
||||
* @param cf a color format (`LV_IMG_CF_...`)
|
||||
* @return true: has alpha channel; false: doesn't have alpha channel
|
||||
*/
|
||||
bool lv_img_cf_has_alpha(lv_img_cf_t cf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_IMG_H*/
|
860
MXC-A36/xrz/lvgl/src/draw/lv_draw_label.c
Normal file
860
MXC-A36/xrz/lvgl/src/draw/lv_draw_label.c
Normal file
@ -0,0 +1,860 @@
|
||||
/**
|
||||
* @file lv_draw_label.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_label.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../hal/lv_hal_disp.h"
|
||||
#include "../core/lv_refr.h"
|
||||
#include "../misc/lv_bidi.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LABEL_RECOLOR_PAR_LENGTH 6
|
||||
#define LV_LABEL_HINT_UPDATE_TH 1024 /*Update the "hint" if the label's y coordinates have changed more then this*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum {
|
||||
CMD_STATE_WAIT,
|
||||
CMD_STATE_PAR,
|
||||
CMD_STATE_IN,
|
||||
};
|
||||
typedef uint8_t cmd_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g,
|
||||
const lv_area_t * clip_area,
|
||||
const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode);
|
||||
#if LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX
|
||||
static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area,
|
||||
const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode);
|
||||
#endif
|
||||
static uint8_t hex_char_to_num(char hex);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
const uint8_t _lv_bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
|
||||
const uint8_t _lv_bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
|
||||
|
||||
const uint8_t _lv_bpp3_opa_table[8] = {0, 36, 73, 109, /*Opacity mapping with bpp = 3*/
|
||||
146, 182, 219, 255
|
||||
};
|
||||
|
||||
const uint8_t _lv_bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
|
||||
68, 85, 102, 119,
|
||||
136, 153, 170, 187,
|
||||
204, 221, 238, 255
|
||||
};
|
||||
|
||||
const uint8_t _lv_bpp8_opa_table[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
|
||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
|
||||
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
|
||||
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
|
||||
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
|
||||
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
|
||||
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
|
||||
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
|
||||
};
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc)
|
||||
{
|
||||
lv_memset_00(dsc, sizeof(lv_draw_label_dsc_t));
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
dsc->font = LV_FONT_DEFAULT;
|
||||
dsc->sel_start = LV_DRAW_LABEL_NO_TXT_SEL;
|
||||
dsc->sel_end = LV_DRAW_LABEL_NO_TXT_SEL;
|
||||
dsc->sel_color = lv_color_black();
|
||||
dsc->sel_bg_color = lv_palette_main(LV_PALETTE_BLUE);
|
||||
dsc->bidi_dir = LV_BASE_DIR_LTR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a text
|
||||
* @param coords coordinates of the label
|
||||
* @param mask the label will be drawn only in this area
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param txt `\0` terminated text to write
|
||||
* @param hint pointer to a `lv_draw_label_hint_t` variable.
|
||||
* It is managed by the draw to speed up the drawing of very long texts (thousands of lines).
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask,
|
||||
const lv_draw_label_dsc_t * dsc,
|
||||
const char * txt,
|
||||
lv_draw_label_hint_t * hint)
|
||||
{
|
||||
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
const lv_font_t * font = dsc->font;
|
||||
int32_t w;
|
||||
|
||||
/*No need to waste processor time if string is empty*/
|
||||
if (txt == NULL || txt[0] == '\0')
|
||||
return;
|
||||
|
||||
lv_area_t clipped_area;
|
||||
bool clip_ok = _lv_area_intersect(&clipped_area, coords, mask);
|
||||
if(!clip_ok) return;
|
||||
|
||||
if((dsc->flag & LV_TEXT_FLAG_EXPAND) == 0) {
|
||||
/*Normally use the label's width as width*/
|
||||
w = lv_area_get_width(coords);
|
||||
}
|
||||
else {
|
||||
/*If EXAPND is enabled then not limit the text's width to the object's width*/
|
||||
lv_point_t p;
|
||||
lv_txt_get_size(&p, txt, dsc->font, dsc->letter_space, dsc->line_space, LV_COORD_MAX,
|
||||
dsc->flag);
|
||||
w = p.x;
|
||||
}
|
||||
|
||||
int32_t line_height_font = lv_font_get_line_height(font);
|
||||
int32_t line_height = line_height_font + dsc->line_space;
|
||||
|
||||
/*Init variables for the first line*/
|
||||
int32_t line_width = 0;
|
||||
lv_point_t pos;
|
||||
pos.x = coords->x1;
|
||||
pos.y = coords->y1;
|
||||
|
||||
int32_t x_ofs = 0;
|
||||
int32_t y_ofs = 0;
|
||||
x_ofs = dsc->ofs_x;
|
||||
y_ofs = dsc->ofs_y;
|
||||
pos.y += y_ofs;
|
||||
|
||||
uint32_t line_start = 0;
|
||||
int32_t last_line_start = -1;
|
||||
|
||||
/*Check the hint to use the cached info*/
|
||||
if(hint && y_ofs == 0 && coords->y1 < 0) {
|
||||
/*If the label changed too much recalculate the hint.*/
|
||||
if(LV_ABS(hint->coord_y - coords->y1) > LV_LABEL_HINT_UPDATE_TH - 2 * line_height) {
|
||||
hint->line_start = -1;
|
||||
}
|
||||
last_line_start = hint->line_start;
|
||||
}
|
||||
|
||||
/*Use the hint if it's valid*/
|
||||
if(hint && last_line_start >= 0) {
|
||||
line_start = last_line_start;
|
||||
pos.y += hint->y;
|
||||
}
|
||||
|
||||
uint32_t line_end = line_start + _lv_txt_get_next_line(&txt[line_start], font, dsc->letter_space, w, dsc->flag);
|
||||
|
||||
/*Go the first visible line*/
|
||||
while(pos.y + line_height_font < mask->y1) {
|
||||
/*Go to next line*/
|
||||
line_start = line_end;
|
||||
line_end += _lv_txt_get_next_line(&txt[line_start], font, dsc->letter_space, w, dsc->flag);
|
||||
pos.y += line_height;
|
||||
|
||||
/*Save at the threshold coordinate*/
|
||||
if(hint && pos.y >= -LV_LABEL_HINT_UPDATE_TH && hint->line_start < 0) {
|
||||
hint->line_start = line_start;
|
||||
hint->y = pos.y - coords->y1;
|
||||
hint->coord_y = coords->y1;
|
||||
}
|
||||
|
||||
if(txt[line_start] == '\0') return;
|
||||
}
|
||||
|
||||
/*Align to middle*/
|
||||
if(dsc->align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(dsc->align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
lv_opa_t opa = dsc->opa;
|
||||
|
||||
uint32_t sel_start = dsc->sel_start;
|
||||
uint32_t sel_end = dsc->sel_end;
|
||||
if(sel_start > sel_end) {
|
||||
uint32_t tmp = sel_start;
|
||||
sel_start = sel_end;
|
||||
sel_end = tmp;
|
||||
}
|
||||
lv_draw_line_dsc_t line_dsc;
|
||||
|
||||
if((dsc->decor & LV_TEXT_DECOR_UNDERLINE) || (dsc->decor & LV_TEXT_DECOR_STRIKETHROUGH)) {
|
||||
lv_draw_line_dsc_init(&line_dsc);
|
||||
line_dsc.color = dsc->color;
|
||||
line_dsc.width = font->underline_thickness ? font->underline_thickness : 1;
|
||||
line_dsc.opa = dsc->opa;
|
||||
line_dsc.blend_mode = dsc->blend_mode;
|
||||
}
|
||||
|
||||
cmd_state_t cmd_state = CMD_STATE_WAIT;
|
||||
uint32_t i;
|
||||
uint32_t par_start = 0;
|
||||
lv_color_t recolor;
|
||||
int32_t letter_w;
|
||||
|
||||
lv_draw_rect_dsc_t draw_dsc_sel;
|
||||
lv_draw_rect_dsc_init(&draw_dsc_sel);
|
||||
draw_dsc_sel.bg_color = dsc->sel_bg_color;
|
||||
|
||||
int32_t pos_x_start = pos.x;
|
||||
/*Write out all lines*/
|
||||
while(txt[line_start] != '\0') {
|
||||
pos.x += x_ofs;
|
||||
|
||||
/*Write all letter of a line*/
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
i = 0;
|
||||
#if LV_USE_BIDI
|
||||
char * bidi_txt = lv_mem_buf_get(line_end - line_start + 1);
|
||||
_lv_bidi_process_paragraph(txt + line_start, bidi_txt, line_end - line_start, dsc->bidi_dir, NULL, 0);
|
||||
#else
|
||||
const char * bidi_txt = txt + line_start;
|
||||
#endif
|
||||
|
||||
while(i < line_end - line_start) {
|
||||
uint32_t logical_char_pos = 0;
|
||||
if(sel_start != 0xFFFF && sel_end != 0xFFFF) {
|
||||
#if LV_USE_BIDI
|
||||
logical_char_pos = _lv_txt_encoded_get_char_id(txt, line_start);
|
||||
uint32_t t = _lv_txt_encoded_get_char_id(bidi_txt, i);
|
||||
logical_char_pos += _lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, dsc->bidi_dir, t, NULL);
|
||||
#else
|
||||
logical_char_pos = _lv_txt_encoded_get_char_id(txt, line_start + i);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
_lv_txt_encoded_letter_next_2(bidi_txt, &letter, &letter_next, &i);
|
||||
/*Handle the re-color command*/
|
||||
if((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) {
|
||||
if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) {
|
||||
if(cmd_state == CMD_STATE_WAIT) { /*Start char*/
|
||||
par_start = i;
|
||||
cmd_state = CMD_STATE_PAR;
|
||||
continue;
|
||||
}
|
||||
else if(cmd_state == CMD_STATE_PAR) { /*Other start char in parameter escaped cmd. char*/
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
}
|
||||
else if(cmd_state == CMD_STATE_IN) { /*Command end*/
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*Skip the color parameter and wait the space after it*/
|
||||
if(cmd_state == CMD_STATE_PAR) {
|
||||
if(letter == ' ') {
|
||||
/*Get the parameter*/
|
||||
if(i - par_start == LABEL_RECOLOR_PAR_LENGTH + 1) {
|
||||
char buf[LABEL_RECOLOR_PAR_LENGTH + 1];
|
||||
lv_memcpy_small(buf, &bidi_txt[par_start], LABEL_RECOLOR_PAR_LENGTH);
|
||||
buf[LABEL_RECOLOR_PAR_LENGTH] = '\0';
|
||||
int r, g, b;
|
||||
r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]);
|
||||
g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]);
|
||||
b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]);
|
||||
recolor = lv_color_make(r, g, b);
|
||||
}
|
||||
else {
|
||||
recolor.full = dsc->color.full;
|
||||
}
|
||||
cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
lv_color_t color = dsc->color;
|
||||
|
||||
if(cmd_state == CMD_STATE_IN) color = recolor;
|
||||
|
||||
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
if(sel_start != 0xFFFF && sel_end != 0xFFFF) {
|
||||
if(logical_char_pos >= sel_start && logical_char_pos < sel_end) {
|
||||
lv_area_t sel_coords;
|
||||
sel_coords.x1 = pos.x;
|
||||
sel_coords.y1 = pos.y;
|
||||
sel_coords.x2 = pos.x + letter_w + dsc->letter_space - 1;
|
||||
sel_coords.y2 = pos.y + line_height - 1;
|
||||
lv_draw_rect(&sel_coords, mask, &draw_dsc_sel);
|
||||
color = dsc->sel_color;
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_letter(&pos, mask, font, letter, color, opa, dsc->blend_mode);
|
||||
|
||||
if(letter_w > 0) {
|
||||
pos.x += letter_w + dsc->letter_space;
|
||||
}
|
||||
}
|
||||
|
||||
if(dsc->decor & LV_TEXT_DECOR_STRIKETHROUGH) {
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
p1.x = pos_x_start;
|
||||
p1.y = pos.y + (dsc->font->line_height / 2) + line_dsc.width / 2;
|
||||
p2.x = pos.x;
|
||||
p2.y = p1.y;
|
||||
lv_draw_line(&p1, &p2, mask, &line_dsc);
|
||||
}
|
||||
|
||||
if(dsc->decor & LV_TEXT_DECOR_UNDERLINE) {
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
p1.x = pos_x_start;
|
||||
p1.y = pos.y + dsc->font->line_height - dsc->font->base_line - font->underline_position;
|
||||
p2.x = pos.x;
|
||||
p2.y = p1.y;
|
||||
lv_draw_line(&p1, &p2, mask, &line_dsc);
|
||||
}
|
||||
|
||||
#if LV_USE_BIDI
|
||||
lv_mem_buf_release(bidi_txt);
|
||||
bidi_txt = NULL;
|
||||
#endif
|
||||
/*Go to next line*/
|
||||
line_start = line_end;
|
||||
line_end += _lv_txt_get_next_line(&txt[line_start], font, dsc->letter_space, w, dsc->flag);
|
||||
|
||||
pos.x = coords->x1;
|
||||
/*Align to middle*/
|
||||
if(dsc->align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width =
|
||||
lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(dsc->align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width =
|
||||
lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
/*Go the next line position*/
|
||||
pos.y += line_height;
|
||||
|
||||
if(pos.y > mask->y2) return;
|
||||
}
|
||||
|
||||
LV_ASSERT_MEM_INTEGRITY();
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw a letter in the Virtual Display Buffer
|
||||
* @param pos_p left-top coordinate of the latter
|
||||
* @param mask_p the letter will be drawn only on this area (truncated to draw_buf area)
|
||||
* @param font_p pointer to font
|
||||
* @param letter a letter to draw
|
||||
* @param color color of letter
|
||||
* @param opa opacity of letter (0..255)
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area,
|
||||
const lv_font_t * font_p,
|
||||
uint32_t letter,
|
||||
lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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;
|
||||
|
||||
/*If the letter is completely out of mask don't draw it*/
|
||||
if(pos_x + g.box_w < clip_area->x1 ||
|
||||
pos_x > clip_area->x2 ||
|
||||
pos_y + g.box_h < clip_area->y1 ||
|
||||
pos_y > clip_area->y2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t * map_p = lv_font_get_glyph_bitmap(font_p, letter);
|
||||
if(map_p == NULL) {
|
||||
LV_LOG_WARN("lv_draw_letter: character's bitmap not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if(font_p->subpx) {
|
||||
#if LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX
|
||||
draw_letter_subpx(pos_x, pos_y, &g, clip_area, map_p, color, opa, blend_mode);
|
||||
#else
|
||||
LV_LOG_WARN("Can't draw sub-pixel rendered letter because LV_USE_FONT_SUBPX == 0 in lv_conf.h");
|
||||
#endif
|
||||
} else {
|
||||
draw_letter_normal(pos_x, pos_y, &g, clip_area, map_p, color, opa, blend_mode);
|
||||
}
|
||||
}
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g,
|
||||
const lv_area_t * clip_area,
|
||||
const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode)
|
||||
{
|
||||
const uint8_t * bpp_opa_table_p;
|
||||
uint32_t bitmask_init;
|
||||
uint32_t bitmask;
|
||||
uint32_t bpp = g->bpp;
|
||||
uint32_t shades;
|
||||
if(bpp == 3) bpp = 4;
|
||||
|
||||
switch(bpp) {
|
||||
case 1:
|
||||
bpp_opa_table_p = _lv_bpp1_opa_table;
|
||||
bitmask_init = 0x80;
|
||||
shades = 2;
|
||||
break;
|
||||
case 2:
|
||||
bpp_opa_table_p = _lv_bpp2_opa_table;
|
||||
bitmask_init = 0xC0;
|
||||
shades = 4;
|
||||
break;
|
||||
case 4:
|
||||
bpp_opa_table_p = _lv_bpp4_opa_table;
|
||||
bitmask_init = 0xF0;
|
||||
shades = 16;
|
||||
break;
|
||||
case 8:
|
||||
bpp_opa_table_p = _lv_bpp8_opa_table;
|
||||
bitmask_init = 0xFF;
|
||||
shades = 256;
|
||||
break; /*No opa table, pixel value will be used directly*/
|
||||
default:
|
||||
LV_LOG_WARN("lv_draw_letter: invalid bpp");
|
||||
return; /*Invalid bpp. Can't render the letter*/
|
||||
}
|
||||
|
||||
static lv_opa_t opa_table[256];
|
||||
static lv_opa_t prev_opa = LV_OPA_TRANSP;
|
||||
static uint32_t prev_bpp = 0;
|
||||
if(opa < LV_OPA_MAX) {
|
||||
if(prev_opa != opa || prev_bpp != bpp) {
|
||||
uint32_t i;
|
||||
for(i = 0; i < shades; i++) {
|
||||
opa_table[i] = bpp_opa_table_p[i] == LV_OPA_COVER ? opa : ((bpp_opa_table_p[i] * opa) >> 8);
|
||||
}
|
||||
}
|
||||
bpp_opa_table_p = opa_table;
|
||||
prev_opa = opa;
|
||||
prev_bpp = bpp;
|
||||
}
|
||||
|
||||
int32_t col, row;
|
||||
int32_t box_w = g->box_w;
|
||||
int32_t box_h = g->box_h;
|
||||
int32_t width_bit = box_w * bpp; /*Letter width in bits*/
|
||||
|
||||
/*Calculate the col/row start/end on the map*/
|
||||
int32_t col_start = pos_x >= clip_area->x1 ? 0 : clip_area->x1 - pos_x;
|
||||
int32_t col_end = pos_x + box_w <= clip_area->x2 ? box_w : clip_area->x2 - pos_x + 1;
|
||||
int32_t row_start = pos_y >= clip_area->y1 ? 0 : clip_area->y1 - pos_y;
|
||||
int32_t row_end = pos_y + box_h <= clip_area->y2 ? box_h : clip_area->y2 - pos_y + 1;
|
||||
|
||||
/*Move on the map too*/
|
||||
uint32_t bit_ofs = (row_start * width_bit) + (col_start * bpp);
|
||||
map_p += bit_ofs >> 3;
|
||||
|
||||
uint8_t letter_px;
|
||||
uint32_t col_bit;
|
||||
col_bit = bit_ofs & 0x7; /*"& 0x7" equals to "% 8" just faster*/
|
||||
|
||||
lv_coord_t hor_res = lv_disp_get_hor_res(_lv_refr_get_disp_refreshing());
|
||||
uint32_t mask_buf_size = box_w * box_h > hor_res ? hor_res : box_w * box_h;
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||
int32_t mask_p = 0;
|
||||
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = col_start + pos_x;
|
||||
fill_area.x2 = col_end + pos_x - 1;
|
||||
fill_area.y1 = row_start + pos_y;
|
||||
fill_area.y2 = fill_area.y1;
|
||||
#if LV_DRAW_COMPLEX
|
||||
uint8_t other_mask_cnt = lv_draw_mask_get_cnt();
|
||||
#endif
|
||||
|
||||
uint32_t col_bit_max = 8 - bpp;
|
||||
uint32_t col_bit_row_ofs = (box_w + col_start - col_end) * bpp;
|
||||
|
||||
for(row = row_start ; row < row_end; row++) {
|
||||
#if LV_DRAW_COMPLEX
|
||||
int32_t mask_p_start = mask_p;
|
||||
#endif
|
||||
bitmask = bitmask_init >> col_bit;
|
||||
for(col = col_start; col < col_end; col++) {
|
||||
/*Load the pixel's opacity into the mask*/
|
||||
letter_px = (*map_p & bitmask) >> (col_bit_max - col_bit);
|
||||
if(letter_px) {
|
||||
mask_buf[mask_p] = bpp_opa_table_p[letter_px];
|
||||
}
|
||||
else {
|
||||
mask_buf[mask_p] = 0;
|
||||
}
|
||||
|
||||
/*Go to the next column*/
|
||||
if(col_bit < col_bit_max) {
|
||||
col_bit += bpp;
|
||||
bitmask = bitmask >> bpp;
|
||||
}
|
||||
else {
|
||||
col_bit = 0;
|
||||
bitmask = bitmask_init;
|
||||
map_p++;
|
||||
}
|
||||
|
||||
/*Next mask byte*/
|
||||
mask_p++;
|
||||
}
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
/*Apply masks if any*/
|
||||
if(other_mask_cnt) {
|
||||
lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, fill_area.x1, fill_area.y2,
|
||||
lv_area_get_width(&fill_area));
|
||||
if(mask_res == LV_DRAW_MASK_RES_TRANSP) {
|
||||
lv_memset_00(mask_buf + mask_p_start, lv_area_get_width(&fill_area));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if((uint32_t) mask_p + (col_end - col_start) < mask_buf_size) {
|
||||
fill_area.y2 ++;
|
||||
}
|
||||
else {
|
||||
_lv_blend_fill(clip_area, &fill_area,
|
||||
color, mask_buf, LV_DRAW_MASK_RES_CHANGED, LV_OPA_COVER,
|
||||
blend_mode);
|
||||
|
||||
fill_area.y1 = fill_area.y2 + 1;
|
||||
fill_area.y2 = fill_area.y1;
|
||||
mask_p = 0;
|
||||
}
|
||||
|
||||
col_bit += col_bit_row_ofs;
|
||||
map_p += (col_bit >> 3);
|
||||
col_bit = col_bit & 0x7;
|
||||
}
|
||||
|
||||
/*Flush the last part*/
|
||||
if(fill_area.y1 != fill_area.y2) {
|
||||
fill_area.y2--;
|
||||
_lv_blend_fill(clip_area, &fill_area,
|
||||
color, mask_buf, LV_DRAW_MASK_RES_CHANGED, LV_OPA_COVER,
|
||||
blend_mode);
|
||||
mask_p = 0;
|
||||
}
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
}
|
||||
|
||||
#if LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX
|
||||
static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area,
|
||||
const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode)
|
||||
{
|
||||
const uint8_t * bpp_opa_table;
|
||||
uint32_t bitmask_init;
|
||||
uint32_t bitmask;
|
||||
uint32_t bpp = g->bpp;
|
||||
if(bpp == 3) bpp = 4;
|
||||
|
||||
switch(bpp) {
|
||||
case 1:
|
||||
bpp_opa_table = _lv_bpp1_opa_table;
|
||||
bitmask_init = 0x80;
|
||||
break;
|
||||
case 2:
|
||||
bpp_opa_table = _lv_bpp2_opa_table;
|
||||
bitmask_init = 0xC0;
|
||||
break;
|
||||
case 4:
|
||||
bpp_opa_table = _lv_bpp4_opa_table;
|
||||
bitmask_init = 0xF0;
|
||||
break;
|
||||
case 8:
|
||||
bpp_opa_table = _lv_bpp8_opa_table;
|
||||
bitmask_init = 0xFF;
|
||||
break; /*No opa table, pixel value will be used directly*/
|
||||
default:
|
||||
LV_LOG_WARN("lv_draw_letter: invalid bpp not found");
|
||||
return; /*Invalid bpp. Can't render the letter*/
|
||||
}
|
||||
|
||||
int32_t col, row;
|
||||
|
||||
int32_t box_w = g->box_w;
|
||||
int32_t box_h = g->box_h;
|
||||
int32_t width_bit = box_w * bpp; /*Letter width in bits*/
|
||||
|
||||
/*Calculate the col/row start/end on the map*/
|
||||
int32_t col_start = pos_x >= clip_area->x1 ? 0 : (clip_area->x1 - pos_x) * 3;
|
||||
int32_t col_end = pos_x + box_w / 3 <= clip_area->x2 ? box_w : (clip_area->x2 - pos_x + 1) * 3;
|
||||
int32_t row_start = pos_y >= clip_area->y1 ? 0 : clip_area->y1 - pos_y;
|
||||
int32_t row_end = pos_y + box_h <= clip_area->y2 ? box_h : clip_area->y2 - pos_y + 1;
|
||||
|
||||
/*Move on the map too*/
|
||||
int32_t bit_ofs = (row_start * width_bit) + (col_start * bpp);
|
||||
map_p += bit_ofs >> 3;
|
||||
|
||||
uint8_t letter_px;
|
||||
lv_opa_t px_opa;
|
||||
int32_t col_bit;
|
||||
col_bit = bit_ofs & 0x7; /*"& 0x7" equals to "% 8" just faster*/
|
||||
|
||||
int32_t mask_buf_size = box_w * box_h > _LV_MASK_BUF_MAX_SIZE ? _LV_MASK_BUF_MAX_SIZE : g->box_w * g->box_h;
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||
int32_t mask_p = 0;
|
||||
|
||||
lv_color_t * color_buf = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp);
|
||||
|
||||
int32_t disp_buf_width = lv_area_get_width(&draw_buf->area);
|
||||
lv_color_t * disp_buf_buf_tmp = draw_buf->buf_act;
|
||||
|
||||
/*Set a pointer on draw_buf to the first pixel of the letter*/
|
||||
disp_buf_buf_tmp += ((pos_y - draw_buf->area.y1) * disp_buf_width) + pos_x - draw_buf->area.x1;
|
||||
|
||||
/*If the letter is partially out of mask the move there on draw_buf*/
|
||||
disp_buf_buf_tmp += (row_start * disp_buf_width) + col_start / 3;
|
||||
|
||||
lv_area_t map_area;
|
||||
map_area.x1 = col_start / 3 + pos_x;
|
||||
map_area.x2 = col_end / 3 + pos_x - 1;
|
||||
map_area.y1 = row_start + pos_y;
|
||||
map_area.y2 = map_area.y1;
|
||||
|
||||
uint8_t other_mask_cnt = lv_draw_mask_get_cnt();
|
||||
|
||||
uint8_t font_rgb[3];
|
||||
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
uint8_t txt_rgb[3] = {color.ch.red, color.ch.green, color.ch.blue};
|
||||
#else
|
||||
uint8_t txt_rgb[3] = {color.ch.red, (color.ch.green_h << 3) + color.ch.green_l, color.ch.blue};
|
||||
#endif
|
||||
|
||||
for(row = row_start ; row < row_end; row++) {
|
||||
uint32_t subpx_cnt = 0;
|
||||
bitmask = bitmask_init >> col_bit;
|
||||
int32_t mask_p_start = mask_p;
|
||||
|
||||
for(col = col_start; col < col_end; col++) {
|
||||
/*Load the pixel's opacity into the mask*/
|
||||
letter_px = (*map_p & bitmask) >> (8 - col_bit - bpp);
|
||||
if(letter_px != 0) {
|
||||
if(opa == LV_OPA_COVER) {
|
||||
px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px];
|
||||
}
|
||||
else {
|
||||
px_opa = bpp == 8 ? (uint32_t)((uint32_t)letter_px * opa) >> 8
|
||||
: (uint32_t)((uint32_t)bpp_opa_table[letter_px] * opa) >> 8;
|
||||
}
|
||||
}
|
||||
else {
|
||||
px_opa = 0;
|
||||
}
|
||||
|
||||
font_rgb[subpx_cnt] = px_opa;
|
||||
|
||||
subpx_cnt ++;
|
||||
if(subpx_cnt == 3) {
|
||||
subpx_cnt = 0;
|
||||
|
||||
lv_color_t res_color;
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
uint8_t bg_rgb[3] = {disp_buf_buf_tmp->ch.red, disp_buf_buf_tmp->ch.green, disp_buf_buf_tmp->ch.blue};
|
||||
#else
|
||||
uint8_t bg_rgb[3] = {disp_buf_buf_tmp->ch.red,
|
||||
(disp_buf_buf_tmp->ch.green_h << 3) + disp_buf_buf_tmp->ch.green_l,
|
||||
disp_buf_buf_tmp->ch.blue
|
||||
};
|
||||
#endif
|
||||
|
||||
#if LV_FONT_SUBPX_BGR
|
||||
res_color.ch.blue = (uint32_t)((uint32_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8;
|
||||
res_color.ch.red = (uint32_t)((uint32_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8;
|
||||
#else
|
||||
res_color.ch.red = (uint32_t)((uint16_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8;
|
||||
res_color.ch.blue = (uint32_t)((uint16_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8;
|
||||
#endif
|
||||
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
res_color.ch.green = (uint32_t)((uint32_t)txt_rgb[1] * font_rgb[1] + (bg_rgb[1] * (255 - font_rgb[1]))) >> 8;
|
||||
#else
|
||||
uint8_t green = (uint32_t)((uint32_t)txt_rgb[1] * font_rgb[1] + (bg_rgb[1] * (255 - font_rgb[1]))) >> 8;
|
||||
res_color.ch.green_h = green >> 3;
|
||||
res_color.ch.green_l = green & 0x7;
|
||||
#endif
|
||||
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
res_color.ch.alpha = 0xff;
|
||||
#endif
|
||||
|
||||
if(font_rgb[0] == 0 && font_rgb[1] == 0 && font_rgb[2] == 0) mask_buf[mask_p] = LV_OPA_TRANSP;
|
||||
else mask_buf[mask_p] = LV_OPA_COVER;
|
||||
color_buf[mask_p] = res_color;
|
||||
|
||||
/*Next mask byte*/
|
||||
mask_p++;
|
||||
disp_buf_buf_tmp++;
|
||||
}
|
||||
|
||||
/*Go to the next column*/
|
||||
if(col_bit < (int32_t)(8 - bpp)) {
|
||||
col_bit += bpp;
|
||||
bitmask = bitmask >> bpp;
|
||||
}
|
||||
else {
|
||||
col_bit = 0;
|
||||
bitmask = bitmask_init;
|
||||
map_p++;
|
||||
}
|
||||
}
|
||||
|
||||
/*Apply masks if any*/
|
||||
if(other_mask_cnt) {
|
||||
lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, map_area.x1, map_area.y2,
|
||||
lv_area_get_width(&map_area));
|
||||
if(mask_res == LV_DRAW_MASK_RES_TRANSP) {
|
||||
lv_memset_00(mask_buf + mask_p_start, lv_area_get_width(&map_area));
|
||||
}
|
||||
}
|
||||
|
||||
if((int32_t) mask_p + (col_end - col_start) < mask_buf_size) {
|
||||
map_area.y2 ++;
|
||||
}
|
||||
else {
|
||||
_lv_blend_map(clip_area, &map_area, color_buf, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, blend_mode);
|
||||
|
||||
map_area.y1 = map_area.y2 + 1;
|
||||
map_area.y2 = map_area.y1;
|
||||
mask_p = 0;
|
||||
}
|
||||
|
||||
col_bit += ((box_w - col_end) + col_start) * bpp;
|
||||
|
||||
map_p += (col_bit >> 3);
|
||||
col_bit = col_bit & 0x7;
|
||||
|
||||
/*Next row in draw_buf*/
|
||||
disp_buf_buf_tmp += disp_buf_width - (col_end - col_start) / 3;
|
||||
}
|
||||
|
||||
/*Flush the last part*/
|
||||
if(map_area.y1 != map_area.y2) {
|
||||
map_area.y2--;
|
||||
_lv_blend_map(clip_area, &map_area, color_buf, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, blend_mode);
|
||||
}
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
lv_mem_buf_release(color_buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Convert a hexadecimal characters to a number (0..15)
|
||||
* @param hex Pointer to a hexadecimal character (0..9, A..F)
|
||||
* @return the numerical value of `hex` or 0 on error
|
||||
*/
|
||||
static uint8_t hex_char_to_num(char hex)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
if(hex >= '0' && hex <= '9') {
|
||||
result = hex - '0';
|
||||
}
|
||||
else {
|
||||
if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/
|
||||
|
||||
switch(hex) {
|
||||
case 'A':
|
||||
result = 10;
|
||||
break;
|
||||
case 'B':
|
||||
result = 11;
|
||||
break;
|
||||
case 'C':
|
||||
result = 12;
|
||||
break;
|
||||
case 'D':
|
||||
result = 13;
|
||||
break;
|
||||
case 'E':
|
||||
result = 14;
|
||||
break;
|
||||
case 'F':
|
||||
result = 15;
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
108
MXC-A36/xrz/lvgl/src/draw/lv_draw_label.h
Normal file
108
MXC-A36/xrz/lvgl/src/draw/lv_draw_label.h
Normal file
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @file lv_draw_label.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LABEL_H
|
||||
#define LV_DRAW_LABEL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_blend.h"
|
||||
#include "../misc/lv_bidi.h"
|
||||
#include "../misc/lv_txt.h"
|
||||
#include "../misc/lv_color.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_DRAW_LABEL_NO_TXT_SEL (0xFFFF)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
const lv_font_t * font;
|
||||
uint32_t sel_start;
|
||||
uint32_t sel_end;
|
||||
lv_color_t color;
|
||||
lv_color_t sel_color;
|
||||
lv_color_t sel_bg_color;
|
||||
lv_coord_t line_space;
|
||||
lv_coord_t letter_space;
|
||||
lv_coord_t ofs_x;
|
||||
lv_coord_t ofs_y;
|
||||
lv_opa_t opa;
|
||||
lv_base_dir_t bidi_dir;
|
||||
lv_text_flag_t flag;
|
||||
lv_text_align_t align :2;
|
||||
lv_text_decor_t decor : 3;
|
||||
lv_blend_mode_t blend_mode: 3;
|
||||
} lv_draw_label_dsc_t;
|
||||
|
||||
/** Store some info to speed up drawing of very large texts
|
||||
* It takes a lot of time to get the first visible character because
|
||||
* all the previous characters needs to be checked to calculate the positions.
|
||||
* This structure stores an earlier (e.g. at -1000 px) coordinate and the index of that line.
|
||||
* Therefore the calculations can start from here.*/
|
||||
typedef struct _lv_draw_label_hint_t {
|
||||
/** Index of the line at `y` coordinate*/
|
||||
int32_t line_start;
|
||||
|
||||
/** Give the `y` coordinate of the first letter at `line start` index. Relative to the label's coordinates*/
|
||||
int32_t y;
|
||||
|
||||
/** The 'y1' coordinate of the label when the hint was saved.
|
||||
* Used to invalidate the hint if the label has moved too much.*/
|
||||
int32_t coord_y;
|
||||
} lv_draw_label_hint_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Write a text
|
||||
* @param coords coordinates of the label
|
||||
* @param mask the label will be drawn only in this area
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param txt `\0` terminated text to write
|
||||
* @param hint pointer to a `lv_draw_label_hint_t` variable.
|
||||
* It is managed by the draw to speed up the drawing of very long texts (thousands of lines).
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask,
|
||||
const lv_draw_label_dsc_t * dsc,
|
||||
const char * txt, lv_draw_label_hint_t * hint);
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area,
|
||||
const lv_font_t * font_p,
|
||||
uint32_t letter, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode);
|
||||
//! @endcond
|
||||
/***********************
|
||||
* GLOBAL VARIABLES
|
||||
***********************/
|
||||
extern const uint8_t _lv_bpp2_opa_table[];
|
||||
extern const uint8_t _lv_bpp3_opa_table[];
|
||||
extern const uint8_t _lv_bpp1_opa_table[];
|
||||
extern const uint8_t _lv_bpp4_opa_table[];
|
||||
extern const uint8_t _lv_bpp8_opa_table[];
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LABEL_H*/
|
489
MXC-A36/xrz/lvgl/src/draw/lv_draw_line.c
Normal file
489
MXC-A36/xrz/lvgl/src/draw/lv_draw_line.c
Normal file
@ -0,0 +1,489 @@
|
||||
/**
|
||||
* @file lv_draw_line.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdbool.h>
|
||||
#include "lv_draw_mask.h"
|
||||
#include "lv_draw_blend.h"
|
||||
#include "../core/lv_refr.h"
|
||||
#include "../misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc);
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc);
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
lv_memset_00(dsc, sizeof(lv_draw_line_dsc_t));
|
||||
dsc->width = 1;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a line
|
||||
* @param point1 first point of the line
|
||||
* @param point2 second point of the line
|
||||
* @param clip the line will be drawn only in this area
|
||||
* @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->width == 0) return;
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
if(point1->x == point2->x && point1->y == point2->y) return;
|
||||
|
||||
lv_area_t clip_line;
|
||||
clip_line.x1 = LV_MIN(point1->x, point2->x) - dsc->width / 2;
|
||||
clip_line.x2 = LV_MAX(point1->x, point2->x) + dsc->width / 2;
|
||||
clip_line.y1 = LV_MIN(point1->y, point2->y) - dsc->width / 2;
|
||||
clip_line.y2 = LV_MAX(point1->y, point2->y) + dsc->width / 2;
|
||||
|
||||
bool is_common;
|
||||
is_common = _lv_area_intersect(&clip_line, &clip_line, clip);
|
||||
if(!is_common) return;
|
||||
|
||||
if(point1->y == point2->y) draw_line_hor(point1, point2, &clip_line, dsc);
|
||||
else if(point1->x == point2->x) draw_line_ver(point1, point2, &clip_line, dsc);
|
||||
else draw_line_skew(point1, point2, &clip_line, dsc);
|
||||
|
||||
if(dsc->round_end || dsc->round_start) {
|
||||
lv_draw_rect_dsc_t cir_dsc;
|
||||
lv_draw_rect_dsc_init(&cir_dsc);
|
||||
cir_dsc.bg_color = dsc->color;
|
||||
cir_dsc.radius = LV_RADIUS_CIRCLE;
|
||||
cir_dsc.bg_opa = dsc->opa;
|
||||
|
||||
int32_t r = (dsc->width >> 1);
|
||||
int32_t r_corr = (dsc->width & 1) ? 0 : 1;
|
||||
lv_area_t cir_area;
|
||||
|
||||
if(dsc->round_start) {
|
||||
cir_area.x1 = point1->x - r;
|
||||
cir_area.y1 = point1->y - r;
|
||||
cir_area.x2 = point1->x + r - r_corr;
|
||||
cir_area.y2 = point1->y + r - r_corr ;
|
||||
lv_draw_rect(&cir_area, clip, &cir_dsc);
|
||||
}
|
||||
|
||||
if(dsc->round_end) {
|
||||
cir_area.x1 = point2->x - r;
|
||||
cir_area.y1 = point2->y - r;
|
||||
cir_area.x2 = point2->x + r - r_corr;
|
||||
cir_area.y2 = point2->y + r - r_corr ;
|
||||
lv_draw_rect(&cir_area, clip, &cir_dsc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
lv_opa_t opa = dsc->opa;
|
||||
|
||||
int32_t w = dsc->width - 1;
|
||||
int32_t w_half0 = w >> 1;
|
||||
int32_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/
|
||||
|
||||
bool dashed = dsc->dash_gap && dsc->dash_width ? true : false;
|
||||
|
||||
bool simple_mode = true;
|
||||
if(lv_draw_mask_get_cnt()) simple_mode = false;
|
||||
else if(dashed) simple_mode = false;
|
||||
|
||||
lv_area_t draw_area;
|
||||
draw_area.x1 = LV_MIN(point1->x, point2->x);
|
||||
draw_area.x2 = LV_MAX(point1->x, point2->x) - 1;
|
||||
draw_area.y1 = point1->y - w_half1;
|
||||
draw_area.y2 = point1->y + w_half0;
|
||||
|
||||
/*If there is no mask then simply draw a rectangle*/
|
||||
if(simple_mode) {
|
||||
_lv_blend_fill(clip, &draw_area,
|
||||
dsc->color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa,
|
||||
dsc->blend_mode);
|
||||
}
|
||||
#if LV_DRAW_COMPLEX
|
||||
/*If there other mask apply it*/
|
||||
else {
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp);
|
||||
const lv_area_t * disp_area = &draw_buf->area;
|
||||
/*Get clipped fill area which is the real draw area.
|
||||
*It is always the same or inside `fill_area`*/
|
||||
bool is_common;
|
||||
is_common = _lv_area_intersect(&draw_area, clip, &draw_area);
|
||||
if(!is_common) return;
|
||||
|
||||
/*Now `draw_area` has absolute coordinates.
|
||||
*Make it relative to `disp_area` to simplify draw to `disp_buf`*/
|
||||
draw_area.x1 -= disp_area->x1;
|
||||
draw_area.y1 -= disp_area->y1;
|
||||
draw_area.x2 -= disp_area->x1;
|
||||
draw_area.y2 -= disp_area->y1;
|
||||
|
||||
int32_t draw_area_w = lv_area_get_width(&draw_area);
|
||||
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = draw_area.x1 + disp_area->x1;
|
||||
fill_area.x2 = draw_area.x2 + disp_area->x1;
|
||||
fill_area.y1 = draw_area.y1 + disp_area->y1;
|
||||
fill_area.y2 = fill_area.y1;
|
||||
|
||||
lv_coord_t dash_start = 0;
|
||||
if(dashed) {
|
||||
dash_start = (draw_buf->area.x1 + draw_area.x1) % (dsc->dash_gap + dsc->dash_width);
|
||||
}
|
||||
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(draw_area_w);
|
||||
int32_t h;
|
||||
for(h = draw_area.y1; h <= draw_area.y2; h++) {
|
||||
lv_memset_ff(mask_buf, draw_area_w);
|
||||
lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf, draw_buf->area.x1 + draw_area.x1, draw_buf->area.y1 + h, draw_area_w);
|
||||
|
||||
if(dashed) {
|
||||
if(mask_res != LV_DRAW_MASK_RES_TRANSP) {
|
||||
lv_coord_t dash_cnt = dash_start;
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < draw_area_w; i++, dash_cnt++) {
|
||||
if(dash_cnt <= dsc->dash_width) {
|
||||
int16_t diff = dsc->dash_width - dash_cnt;
|
||||
i += diff;
|
||||
dash_cnt += diff;
|
||||
}
|
||||
else if(dash_cnt >= dsc->dash_gap + dsc->dash_width) {
|
||||
dash_cnt = 0;
|
||||
}
|
||||
else {
|
||||
mask_buf[i] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
_lv_blend_fill(clip, &fill_area,
|
||||
dsc->color, mask_buf, mask_res, dsc->opa,
|
||||
dsc->blend_mode);
|
||||
|
||||
fill_area.y1++;
|
||||
fill_area.y2++;
|
||||
}
|
||||
lv_mem_buf_release(mask_buf);
|
||||
}
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
}
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
lv_opa_t opa = dsc->opa;
|
||||
|
||||
int32_t w = dsc->width - 1;
|
||||
int32_t w_half0 = w >> 1;
|
||||
int32_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/
|
||||
|
||||
bool dashed = dsc->dash_gap && dsc->dash_width ? true : false;
|
||||
|
||||
bool simple_mode = true;
|
||||
if(lv_draw_mask_get_cnt()) simple_mode = false;
|
||||
else if(dashed) simple_mode = false;
|
||||
|
||||
lv_area_t draw_area;
|
||||
draw_area.x1 = point1->x - w_half1;
|
||||
draw_area.x2 = point1->x + w_half0;
|
||||
draw_area.y1 = LV_MIN(point1->y, point2->y);
|
||||
draw_area.y2 = LV_MAX(point1->y, point2->y) - 1;
|
||||
|
||||
/*If there is no mask then simply draw a rectangle*/
|
||||
if(simple_mode) {
|
||||
_lv_blend_fill(clip, &draw_area,
|
||||
dsc->color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa,
|
||||
dsc->blend_mode);
|
||||
}
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
/*If there other mask apply it*/
|
||||
else {
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp);
|
||||
const lv_area_t * disp_area = &draw_buf->area;
|
||||
/*Get clipped fill area which is the real draw area.
|
||||
*It is always the same or inside `fill_area`*/
|
||||
bool is_common;
|
||||
is_common = _lv_area_intersect(&draw_area, clip, &draw_area);
|
||||
if(!is_common) return;
|
||||
|
||||
/*Now `draw_area` has absolute coordinates.
|
||||
*Make it relative to `disp_area` to simplify draw to `disp_buf`*/
|
||||
draw_area.x1 -= draw_buf->area.x1;
|
||||
draw_area.y1 -= draw_buf->area.y1;
|
||||
draw_area.x2 -= draw_buf->area.x1;
|
||||
draw_area.y2 -= draw_buf->area.y1;
|
||||
|
||||
int32_t draw_area_w = lv_area_get_width(&draw_area);
|
||||
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = draw_area.x1 + disp_area->x1;
|
||||
fill_area.x2 = draw_area.x2 + disp_area->x1;
|
||||
fill_area.y1 = draw_area.y1 + disp_area->y1;
|
||||
fill_area.y2 = fill_area.y1;
|
||||
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(draw_area_w);
|
||||
|
||||
lv_coord_t dash_start = 0;
|
||||
if(dashed) {
|
||||
dash_start = (draw_buf->area.y1 + draw_area.y1) % (dsc->dash_gap + dsc->dash_width);
|
||||
}
|
||||
|
||||
lv_coord_t dash_cnt = dash_start;
|
||||
|
||||
int32_t h;
|
||||
for(h = draw_area.y1; h <= draw_area.y2; h++) {
|
||||
lv_memset_ff(mask_buf, draw_area_w);
|
||||
lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf, draw_buf->area.x1 + draw_area.x1, draw_buf->area.y1 + h, draw_area_w);
|
||||
|
||||
if(dashed) {
|
||||
if(mask_res != LV_DRAW_MASK_RES_TRANSP) {
|
||||
if(dash_cnt > dsc->dash_width) {
|
||||
mask_res = LV_DRAW_MASK_RES_TRANSP;
|
||||
}
|
||||
|
||||
if(dash_cnt >= dsc->dash_gap + dsc->dash_width) {
|
||||
dash_cnt = 0;
|
||||
}
|
||||
}
|
||||
dash_cnt ++;
|
||||
}
|
||||
|
||||
_lv_blend_fill(clip, &fill_area,
|
||||
dsc->color, mask_buf, mask_res, dsc->opa,
|
||||
LV_BLEND_MODE_NORMAL);
|
||||
|
||||
fill_area.y1++;
|
||||
fill_area.y2++;
|
||||
}
|
||||
lv_mem_buf_release(mask_buf);
|
||||
}
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
}
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
#if LV_DRAW_COMPLEX
|
||||
/*Keep the great y in p1*/
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
if(point1->y < point2->y) {
|
||||
p1.y = point1->y;
|
||||
p2.y = point2->y;
|
||||
p1.x = point1->x;
|
||||
p2.x = point2->x;
|
||||
}
|
||||
else {
|
||||
p1.y = point2->y;
|
||||
p2.y = point1->y;
|
||||
p1.x = point2->x;
|
||||
p2.x = point1->x;
|
||||
}
|
||||
|
||||
int32_t xdiff = p2.x - p1.x;
|
||||
int32_t ydiff = p2.y - p1.y;
|
||||
bool flat = LV_ABS(xdiff) > LV_ABS(ydiff) ? true : false;
|
||||
|
||||
static const uint8_t wcorr[] = {
|
||||
128, 128, 128, 129, 129, 130, 130, 131,
|
||||
132, 133, 134, 135, 137, 138, 140, 141,
|
||||
143, 145, 147, 149, 151, 153, 155, 158,
|
||||
160, 162, 165, 167, 170, 173, 175, 178,
|
||||
181,
|
||||
};
|
||||
|
||||
int32_t w = dsc->width;
|
||||
int32_t wcorr_i = 0;
|
||||
if(flat) wcorr_i = (LV_ABS(ydiff) << 5) / LV_ABS(xdiff);
|
||||
else wcorr_i = (LV_ABS(xdiff) << 5) / LV_ABS(ydiff);
|
||||
|
||||
w = (w * wcorr[wcorr_i] + 63) >> 7; /*+ 63 for rounding*/
|
||||
int32_t w_half0 = w >> 1;
|
||||
int32_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/
|
||||
|
||||
lv_area_t draw_area;
|
||||
draw_area.x1 = LV_MIN(p1.x, p2.x) - w;
|
||||
draw_area.x2 = LV_MAX(p1.x, p2.x) + w;
|
||||
draw_area.y1 = LV_MIN(p1.y, p2.y) - w;
|
||||
draw_area.y2 = LV_MAX(p1.y, p2.y) + w;
|
||||
|
||||
/*Get the union of `coords` and `clip`*/
|
||||
/*`clip` is already truncated to the `draw_buf` size
|
||||
*in 'lv_refr_area' function*/
|
||||
bool is_common = _lv_area_intersect(&draw_area, &draw_area, clip);
|
||||
if(is_common == false) return;
|
||||
|
||||
lv_draw_mask_line_param_t mask_left_param;
|
||||
lv_draw_mask_line_param_t mask_right_param;
|
||||
lv_draw_mask_line_param_t mask_top_param;
|
||||
lv_draw_mask_line_param_t mask_bottom_param;
|
||||
|
||||
if(flat) {
|
||||
if(xdiff > 0) {
|
||||
lv_draw_mask_line_points_init(&mask_left_param, p1.x, p1.y - w_half0, p2.x, p2.y - w_half0,
|
||||
LV_DRAW_MASK_LINE_SIDE_LEFT);
|
||||
lv_draw_mask_line_points_init(&mask_right_param, p1.x, p1.y + w_half1, p2.x, p2.y + w_half1,
|
||||
LV_DRAW_MASK_LINE_SIDE_RIGHT);
|
||||
}
|
||||
else {
|
||||
lv_draw_mask_line_points_init(&mask_left_param, p1.x, p1.y + w_half1, p2.x, p2.y + w_half1,
|
||||
LV_DRAW_MASK_LINE_SIDE_LEFT);
|
||||
lv_draw_mask_line_points_init(&mask_right_param, p1.x, p1.y - w_half0, p2.x, p2.y - w_half0,
|
||||
LV_DRAW_MASK_LINE_SIDE_RIGHT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
lv_draw_mask_line_points_init(&mask_left_param, p1.x + w_half1, p1.y, p2.x + w_half1, p2.y,
|
||||
LV_DRAW_MASK_LINE_SIDE_LEFT);
|
||||
lv_draw_mask_line_points_init(&mask_right_param, p1.x - w_half0, p1.y, p2.x - w_half0, p2.y,
|
||||
LV_DRAW_MASK_LINE_SIDE_RIGHT);
|
||||
}
|
||||
|
||||
/*Use the normal vector for the endings*/
|
||||
|
||||
int16_t mask_left_id = lv_draw_mask_add(&mask_left_param, NULL);
|
||||
int16_t mask_right_id = lv_draw_mask_add(&mask_right_param, NULL);
|
||||
int16_t mask_top_id = LV_MASK_ID_INV;
|
||||
int16_t mask_bottom_id = LV_MASK_ID_INV;
|
||||
|
||||
if(!dsc->raw_end) {
|
||||
lv_draw_mask_line_points_init(&mask_top_param, p1.x, p1.y, p1.x - ydiff, p1.y + xdiff, LV_DRAW_MASK_LINE_SIDE_BOTTOM);
|
||||
lv_draw_mask_line_points_init(&mask_bottom_param, p2.x, p2.y, p2.x - ydiff, p2.y + xdiff, LV_DRAW_MASK_LINE_SIDE_TOP);
|
||||
mask_top_id = lv_draw_mask_add(&mask_top_param, NULL);
|
||||
mask_bottom_id = lv_draw_mask_add(&mask_bottom_param, NULL);
|
||||
}
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp);
|
||||
|
||||
const lv_area_t * disp_area = &draw_buf->area;
|
||||
|
||||
/*Store the coordinates of the `draw_a` relative to the draw_buf*/
|
||||
draw_area.x1 -= disp_area->x1;
|
||||
draw_area.y1 -= disp_area->y1;
|
||||
draw_area.x2 -= disp_area->x1;
|
||||
draw_area.y2 -= disp_area->y1;
|
||||
|
||||
/*The real draw area is around the line.
|
||||
*It's easy to calculate with steep lines, but the area can be very wide with very flat lines.
|
||||
*So deal with it only with steep lines.*/
|
||||
int32_t draw_area_w = lv_area_get_width(&draw_area);
|
||||
|
||||
/*Draw the background line by line*/
|
||||
int32_t h;
|
||||
uint32_t hor_res = (uint32_t)lv_disp_get_hor_res(disp);
|
||||
size_t mask_buf_size = LV_MIN(lv_area_get_size(&draw_area), hor_res);
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = draw_area.x1 + disp_area->x1;
|
||||
fill_area.x2 = draw_area.x2 + disp_area->x1;
|
||||
fill_area.y1 = draw_area.y1 + disp_area->y1;
|
||||
fill_area.y2 = fill_area.y1;
|
||||
|
||||
int32_t x = draw_buf->area.x1 + draw_area.x1;
|
||||
|
||||
uint32_t mask_p = 0;
|
||||
|
||||
lv_memset_ff(mask_buf, mask_buf_size);
|
||||
/*Fill the first row with 'color'*/
|
||||
for(h = draw_area.y1 + disp_area->y1; h <= draw_area.y2 + disp_area->y1; h++) {
|
||||
|
||||
lv_draw_mask_res_t mask_res = lv_draw_mask_apply(&mask_buf[mask_p], x, h, draw_area_w);
|
||||
if(mask_res == LV_DRAW_MASK_RES_TRANSP) {
|
||||
lv_memset_00(&mask_buf[mask_p], draw_area_w);
|
||||
}
|
||||
|
||||
mask_p += draw_area_w;
|
||||
if((uint32_t) mask_p + draw_area_w < mask_buf_size) {
|
||||
fill_area.y2 ++;
|
||||
}
|
||||
else {
|
||||
_lv_blend_fill(&fill_area, clip,
|
||||
dsc->color, mask_buf, LV_DRAW_MASK_RES_CHANGED, dsc->opa,
|
||||
dsc->blend_mode);
|
||||
|
||||
fill_area.y1 = fill_area.y2 + 1;
|
||||
fill_area.y2 = fill_area.y1;
|
||||
mask_p = 0;
|
||||
lv_memset_ff(mask_buf, mask_buf_size);
|
||||
}
|
||||
}
|
||||
|
||||
/*Flush the last part*/
|
||||
if(fill_area.y1 != fill_area.y2) {
|
||||
fill_area.y2--;
|
||||
_lv_blend_fill(&fill_area, clip,
|
||||
dsc->color, mask_buf, LV_DRAW_MASK_RES_CHANGED, dsc->opa,
|
||||
dsc->blend_mode);
|
||||
|
||||
}
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
|
||||
lv_draw_mask_remove_id(mask_left_id);
|
||||
lv_draw_mask_remove_id(mask_right_id);
|
||||
lv_draw_mask_remove_id(mask_top_id);
|
||||
lv_draw_mask_remove_id(mask_bottom_id);
|
||||
#else
|
||||
LV_UNUSED(point1);
|
||||
LV_UNUSED(point2);
|
||||
LV_UNUSED(clip);
|
||||
LV_UNUSED(dsc);
|
||||
LV_LOG_WARN("Can't draw skewed line with LV_DRAW_COMPLEX == 0");
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
}
|
||||
|
64
MXC-A36/xrz/lvgl/src/draw/lv_draw_line.h
Normal file
64
MXC-A36/xrz/lvgl/src/draw/lv_draw_line.h
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @file lv_draw_line.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LINE_H
|
||||
#define LV_DRAW_LINE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_blend.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct {
|
||||
lv_color_t color;
|
||||
lv_coord_t width;
|
||||
lv_coord_t dash_width;
|
||||
lv_coord_t dash_gap;
|
||||
lv_opa_t opa;
|
||||
lv_blend_mode_t blend_mode : 2;
|
||||
uint8_t round_start : 1;
|
||||
uint8_t round_end : 1;
|
||||
uint8_t raw_end : 1; /*Do not bother with perpendicular line ending is it's not visible for any reason*/
|
||||
} lv_draw_line_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
/**
|
||||
* Draw a line
|
||||
* @param point1 first point of the line
|
||||
* @param point2 second point of the line
|
||||
* @param clip the line will be drawn only in this area
|
||||
* @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc);
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc);
|
||||
|
||||
//! @endcond
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LINE_H*/
|
1243
MXC-A36/xrz/lvgl/src/draw/lv_draw_mask.c
Normal file
1243
MXC-A36/xrz/lvgl/src/draw/lv_draw_mask.c
Normal file
File diff suppressed because it is too large
Load Diff
326
MXC-A36/xrz/lvgl/src/draw/lv_draw_mask.h
Normal file
326
MXC-A36/xrz/lvgl/src/draw/lv_draw_mask.h
Normal file
@ -0,0 +1,326 @@
|
||||
/**
|
||||
* @file lv_draw_mask.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_MASK_H
|
||||
#define LV_DRAW_MASK_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdbool.h>
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_MASK_ID_INV (-1)
|
||||
#if LV_DRAW_COMPLEX
|
||||
# define _LV_MASK_MAX_NUM 16
|
||||
# ifndef _LV_MASK_BUF_MAX_SIZE
|
||||
# define _LV_MASK_BUF_MAX_SIZE 2048 /*Should be >= than the max hor res*/
|
||||
# endif
|
||||
#else
|
||||
# define _LV_MASK_MAX_NUM 1
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
enum {
|
||||
LV_DRAW_MASK_RES_TRANSP,
|
||||
LV_DRAW_MASK_RES_FULL_COVER,
|
||||
LV_DRAW_MASK_RES_CHANGED,
|
||||
LV_DRAW_MASK_RES_UNKNOWN
|
||||
};
|
||||
|
||||
typedef uint8_t lv_draw_mask_res_t;
|
||||
|
||||
typedef struct {
|
||||
void * param;
|
||||
void * custom_id;
|
||||
} _lv_draw_mask_saved_t;
|
||||
|
||||
typedef _lv_draw_mask_saved_t _lv_draw_mask_saved_arr_t[_LV_MASK_MAX_NUM];
|
||||
|
||||
|
||||
|
||||
#if LV_DRAW_COMPLEX == 0
|
||||
static inline uint8_t lv_draw_mask_get_cnt(void) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
|
||||
enum {
|
||||
LV_DRAW_MASK_TYPE_LINE,
|
||||
LV_DRAW_MASK_TYPE_ANGLE,
|
||||
LV_DRAW_MASK_TYPE_RADIUS,
|
||||
LV_DRAW_MASK_TYPE_FADE,
|
||||
LV_DRAW_MASK_TYPE_MAP,
|
||||
};
|
||||
|
||||
typedef uint8_t lv_draw_mask_type_t;
|
||||
|
||||
enum {
|
||||
LV_DRAW_MASK_LINE_SIDE_LEFT = 0,
|
||||
LV_DRAW_MASK_LINE_SIDE_RIGHT,
|
||||
LV_DRAW_MASK_LINE_SIDE_TOP,
|
||||
LV_DRAW_MASK_LINE_SIDE_BOTTOM,
|
||||
};
|
||||
|
||||
/**
|
||||
* A common callback type for every mask type.
|
||||
* Used internally by the library.
|
||||
*/
|
||||
typedef lv_draw_mask_res_t (*lv_draw_mask_xcb_t)(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
|
||||
lv_coord_t len,
|
||||
void * p);
|
||||
|
||||
typedef uint8_t lv_draw_mask_line_side_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_mask_xcb_t cb;
|
||||
lv_draw_mask_type_t type;
|
||||
} _lv_draw_mask_common_dsc_t;
|
||||
|
||||
typedef struct {
|
||||
/*The first element must be the common descriptor*/
|
||||
_lv_draw_mask_common_dsc_t dsc;
|
||||
|
||||
struct {
|
||||
/*First point*/
|
||||
lv_point_t p1;
|
||||
|
||||
/*Second point*/
|
||||
lv_point_t p2;
|
||||
|
||||
/*Which side to keep?*/
|
||||
lv_draw_mask_line_side_t side : 2;
|
||||
} cfg;
|
||||
|
||||
/*A point of the line*/
|
||||
lv_point_t origo;
|
||||
|
||||
/*X / (1024*Y) steepness (X is 0..1023 range). What is the change of X in 1024 Y?*/
|
||||
int32_t xy_steep;
|
||||
|
||||
/*Y / (1024*X) steepness (Y is 0..1023 range). What is the change of Y in 1024 X?*/
|
||||
int32_t yx_steep;
|
||||
|
||||
/*Helper which stores yx_steep for flat lines and xy_steep for steep (non flat) lines*/
|
||||
int32_t steep;
|
||||
|
||||
/*Steepness in 1 px in 0..255 range. Used only by flat lines.*/
|
||||
int32_t spx;
|
||||
|
||||
/*1: It's a flat line? (Near to horizontal)*/
|
||||
uint8_t flat : 1;
|
||||
|
||||
/*Invert the mask. The default is: Keep the left part.
|
||||
*It is used to select left/right/top/bottom*/
|
||||
uint8_t inv: 1;
|
||||
} lv_draw_mask_line_param_t;
|
||||
|
||||
typedef struct {
|
||||
/*The first element must be the common descriptor*/
|
||||
_lv_draw_mask_common_dsc_t dsc;
|
||||
|
||||
struct {
|
||||
lv_point_t vertex_p;
|
||||
lv_coord_t start_angle;
|
||||
lv_coord_t end_angle;
|
||||
} cfg;
|
||||
|
||||
lv_draw_mask_line_param_t start_line;
|
||||
lv_draw_mask_line_param_t end_line;
|
||||
uint16_t delta_deg;
|
||||
} lv_draw_mask_angle_param_t;
|
||||
|
||||
typedef struct {
|
||||
/*The first element must be the common descriptor*/
|
||||
_lv_draw_mask_common_dsc_t dsc;
|
||||
|
||||
struct {
|
||||
lv_area_t rect;
|
||||
lv_coord_t radius;
|
||||
/*Invert the mask. 0: Keep the pixels inside.*/
|
||||
uint8_t outer: 1;
|
||||
} cfg;
|
||||
int32_t y_prev;
|
||||
lv_sqrt_res_t y_prev_x;
|
||||
|
||||
} lv_draw_mask_radius_param_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
/*The first element must be the common descriptor*/
|
||||
_lv_draw_mask_common_dsc_t dsc;
|
||||
|
||||
struct {
|
||||
lv_area_t coords;
|
||||
lv_coord_t y_top;
|
||||
lv_coord_t y_bottom;
|
||||
lv_opa_t opa_top;
|
||||
lv_opa_t opa_bottom;
|
||||
} cfg;
|
||||
|
||||
} lv_draw_mask_fade_param_t;
|
||||
|
||||
|
||||
typedef struct _lv_draw_mask_map_param_t {
|
||||
/*The first element must be the common descriptor*/
|
||||
_lv_draw_mask_common_dsc_t dsc;
|
||||
|
||||
struct {
|
||||
lv_area_t coords;
|
||||
const lv_opa_t * map;
|
||||
} cfg;
|
||||
} lv_draw_mask_map_param_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Add a draw mask. Everything drawn after it (until removing the mask) will be affected by the mask.
|
||||
* @param param an initialized mask parameter. Only the pointer is saved.
|
||||
* @param custom_id a custom pointer to identify the mask. Used in `lv_draw_mask_remove_custom`.
|
||||
* @return the an integer, the ID of the mask. Can be used in `lv_draw_mask_remove_id`.
|
||||
*/
|
||||
int16_t lv_draw_mask_add(void * param, void * custom_id);
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
|
||||
/**
|
||||
* Apply the added buffers on a line. Used internally by the library's drawing routines.
|
||||
* @param mask_buf store the result mask here. Has to be `len` byte long. Should be initialized with `0xFF`.
|
||||
* @param abs_x absolute X coordinate where the line to calculate start
|
||||
* @param abs_y absolute Y coordinate where the line to calculate start
|
||||
* @param len length of the line to calculate (in pixel count)
|
||||
* @return One of these values:
|
||||
* - `LV_DRAW_MASK_RES_FULL_TRANSP`: the whole line is transparent. `mask_buf` is not set to zero
|
||||
* - `LV_DRAW_MASK_RES_FULL_COVER`: the whole line is fully visible. `mask_buf` is unchanged
|
||||
* - `LV_DRAW_MASK_RES_CHANGED`: `mask_buf` has changed, it shows the desired opacity of each pixel in the given line
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM lv_draw_mask_res_t lv_draw_mask_apply(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
|
||||
lv_coord_t len);
|
||||
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
* Remove a mask with a given ID
|
||||
* @param id the ID of the mask. Returned by `lv_draw_mask_add`
|
||||
* @return the parameter of the removed mask.
|
||||
* If more masks have `custom_id` ID then the last mask's parameter will be returned
|
||||
*/
|
||||
void * lv_draw_mask_remove_id(int16_t id);
|
||||
|
||||
/**
|
||||
* Remove all mask with a given custom ID
|
||||
* @param custom_id a pointer used in `lv_draw_mask_add`
|
||||
* @return return the parameter of the removed mask.
|
||||
* If more masks have `custom_id` ID then the last mask's parameter will be returned
|
||||
*/
|
||||
void * lv_draw_mask_remove_custom(void * custom_id);
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
|
||||
/**
|
||||
* Count the currently added masks
|
||||
* @return number of active masks
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM uint8_t lv_draw_mask_get_cnt(void);
|
||||
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
*Initialize a line mask from two points.
|
||||
* @param param pointer to a `lv_draw_mask_param_t` to initialize
|
||||
* @param p1x X coordinate of the first point of the line
|
||||
* @param p1y Y coordinate of the first point of the line
|
||||
* @param p2x X coordinate of the second point of the line
|
||||
* @param p2y y coordinate of the second point of the line
|
||||
* @param side and element of `lv_draw_mask_line_side_t` to describe which side to keep.
|
||||
* With `LV_DRAW_MASK_LINE_SIDE_LEFT/RIGHT` and horizontal line all pixels are kept
|
||||
* With `LV_DRAW_MASK_LINE_SIDE_TOP/BOTTOM` and vertical line all pixels are kept
|
||||
*/
|
||||
void lv_draw_mask_line_points_init(lv_draw_mask_line_param_t * param, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x,
|
||||
lv_coord_t p2y, lv_draw_mask_line_side_t side);
|
||||
|
||||
/**
|
||||
*Initialize a line mask from a point and an angle.
|
||||
* @param param pointer to a `lv_draw_mask_param_t` to initialize
|
||||
* @param px X coordinate of a point of the line
|
||||
* @param py X coordinate of a point of the line
|
||||
* @param angle right 0 deg, bottom: 90
|
||||
* @param side and element of `lv_draw_mask_line_side_t` to describe which side to keep.
|
||||
* With `LV_DRAW_MASK_LINE_SIDE_LEFT/RIGHT` and horizontal line all pixels are kept
|
||||
* With `LV_DRAW_MASK_LINE_SIDE_TOP/BOTTOM` and vertical line all pixels are kept
|
||||
*/
|
||||
void lv_draw_mask_line_angle_init(lv_draw_mask_line_param_t * param, lv_coord_t p1x, lv_coord_t py, int16_t angle,
|
||||
lv_draw_mask_line_side_t side);
|
||||
|
||||
/**
|
||||
* Initialize an angle mask.
|
||||
* @param param pointer to a `lv_draw_mask_param_t` to initialize
|
||||
* @param vertex_x X coordinate of the angle vertex (absolute coordinates)
|
||||
* @param vertex_y Y coordinate of the angle vertex (absolute coordinates)
|
||||
* @param start_angle start angle in degrees. 0 deg on the right, 90 deg, on the bottom
|
||||
* @param end_angle end angle
|
||||
*/
|
||||
void lv_draw_mask_angle_init(lv_draw_mask_angle_param_t * param, lv_coord_t vertex_x, lv_coord_t vertex_y,
|
||||
lv_coord_t start_angle, lv_coord_t end_angle);
|
||||
|
||||
/**
|
||||
* Initialize a fade mask.
|
||||
* @param param param pointer to a `lv_draw_mask_param_t` to initialize
|
||||
* @param rect coordinates of the rectangle to affect (absolute coordinates)
|
||||
* @param radius radius of the rectangle
|
||||
* @param inv true: keep the pixels inside the rectangle; keep the pixels outside of the rectangle
|
||||
*/
|
||||
void lv_draw_mask_radius_init(lv_draw_mask_radius_param_t * param, const lv_area_t * rect, lv_coord_t radius, bool inv);
|
||||
|
||||
/**
|
||||
* Initialize a fade mask.
|
||||
* @param param pointer to a `lv_draw_mask_param_t` to initialize
|
||||
* @param coords coordinates of the area to affect (absolute coordinates)
|
||||
* @param opa_top opacity on the top
|
||||
* @param y_top at which coordinate start to change to opacity to `opa_bottom`
|
||||
* @param opa_bottom opacity at the bottom
|
||||
* @param y_bottom at which coordinate reach `opa_bottom`.
|
||||
*/
|
||||
void lv_draw_mask_fade_init(lv_draw_mask_fade_param_t * param, const lv_area_t * coords, lv_opa_t opa_top,
|
||||
lv_coord_t y_top,
|
||||
lv_opa_t opa_bottom, lv_coord_t y_bottom);
|
||||
|
||||
/**
|
||||
* Initialize a map mask.
|
||||
* @param param pointer to a `lv_draw_mask_param_t` to initialize
|
||||
* @param coords coordinates of the map (absolute coordinates)
|
||||
* @param map array of bytes with the mask values
|
||||
*/
|
||||
void lv_draw_mask_map_init(lv_draw_mask_map_param_t * param, const lv_area_t * coords, const lv_opa_t * map);
|
||||
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_MASK_H*/
|
1441
MXC-A36/xrz/lvgl/src/draw/lv_draw_rect.c
Normal file
1441
MXC-A36/xrz/lvgl/src/draw/lv_draw_rect.c
Normal file
File diff suppressed because it is too large
Load Diff
104
MXC-A36/xrz/lvgl/src/draw/lv_draw_rect.h
Normal file
104
MXC-A36/xrz/lvgl/src/draw/lv_draw_rect.h
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file lv_draw_rect.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_RECT_H
|
||||
#define LV_DRAW_RECT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_blend.h"
|
||||
#include "../font/lv_font.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_RADIUS_CIRCLE 0x7FFF /**< A very big radius to always draw as circle*/
|
||||
LV_EXPORT_CONST_INT(LV_RADIUS_CIRCLE);
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_coord_t radius;
|
||||
lv_blend_mode_t blend_mode;
|
||||
|
||||
/*Background*/
|
||||
lv_color_t bg_color;
|
||||
lv_color_t bg_grad_color;
|
||||
uint8_t bg_main_color_stop;
|
||||
uint8_t bg_grad_color_stop;
|
||||
lv_opa_t bg_opa;
|
||||
lv_grad_dir_t bg_grad_dir :3;
|
||||
|
||||
/*Background img*/
|
||||
const void * bg_img_src;
|
||||
const void * bg_img_symbol_font;
|
||||
lv_color_t bg_img_recolor;
|
||||
lv_opa_t bg_img_opa;
|
||||
lv_opa_t bg_img_recolor_opa;
|
||||
uint8_t bg_img_tiled;
|
||||
|
||||
/*Border*/
|
||||
lv_color_t border_color;
|
||||
lv_coord_t border_width;
|
||||
lv_opa_t border_opa;
|
||||
uint8_t border_post : 1; /*There is a border it will be drawn later.*/
|
||||
lv_border_side_t border_side :5;
|
||||
|
||||
/*Outline*/
|
||||
lv_color_t outline_color;
|
||||
lv_coord_t outline_width;
|
||||
lv_coord_t outline_pad;
|
||||
lv_opa_t outline_opa;
|
||||
|
||||
/*Shadow*/
|
||||
lv_color_t shadow_color;
|
||||
lv_coord_t shadow_width;
|
||||
lv_coord_t shadow_ofs_x;
|
||||
lv_coord_t shadow_ofs_y;
|
||||
lv_coord_t shadow_spread;
|
||||
lv_opa_t shadow_opa;
|
||||
} lv_draw_rect_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
* Draw a rectangle
|
||||
* @param coords the coordinates of the rectangle
|
||||
* @param mask the rectangle will be drawn only in this mask
|
||||
* @param dsc pointer to an initialized `lv_draw_rect_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Draw a pixel
|
||||
* @param point the coordinates of the point to draw
|
||||
* @param mask the pixel will be drawn only in this mask
|
||||
* @param style pointer to a style
|
||||
*/
|
||||
//void lv_draw_px(const lv_point_t * point, const lv_area_t * clip_area, const lv_style_t * style);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_RECT_H*/
|
216
MXC-A36/xrz/lvgl/src/draw/lv_draw_triangle.c
Normal file
216
MXC-A36/xrz/lvgl/src/draw/lv_draw_triangle.c
Normal file
@ -0,0 +1,216 @@
|
||||
/**
|
||||
* @file lv_draw_triangle.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_triangle.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw a triangle
|
||||
* @param points pointer to an array with 3 points
|
||||
* @param clip_area the triangle will be drawn only in this area
|
||||
* @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_triangle(const lv_point_t points[], const lv_area_t * clip_area, const lv_draw_rect_dsc_t * draw_dsc)
|
||||
{
|
||||
#if LV_DRAW_COMPLEX
|
||||
lv_draw_polygon(points, 3, clip_area, draw_dsc);
|
||||
#else
|
||||
LV_UNUSED(points);
|
||||
LV_UNUSED(clip_area);
|
||||
LV_UNUSED(draw_dsc);
|
||||
LV_LOG_WARN("Can't draw triangle with LV_DRAW_COMPLEX == 0");
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a polygon. Only convex polygons are supported
|
||||
* @param points an array of points
|
||||
* @param point_cnt number of points
|
||||
* @param clip_area polygon will be drawn only in this area
|
||||
* @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_polygon(const lv_point_t points[], uint16_t point_cnt, const lv_area_t * clip_area,
|
||||
const lv_draw_rect_dsc_t * draw_dsc)
|
||||
{
|
||||
#if LV_DRAW_COMPLEX
|
||||
if(point_cnt < 3) return;
|
||||
if(points == NULL) return;
|
||||
|
||||
/*Join adjacent points if they are on the same coordinate*/
|
||||
lv_point_t * p = lv_mem_buf_get(point_cnt * sizeof(lv_point_t));
|
||||
if(p == NULL) return;
|
||||
uint16_t i;
|
||||
uint16_t pcnt = 0;
|
||||
p[0] = points[0];
|
||||
for(i = 0; i < point_cnt - 1; i++) {
|
||||
if(points[i].x != points[i + 1].x || points[i].y != points[i + 1].y) {
|
||||
p[pcnt] = points[i];
|
||||
pcnt++;
|
||||
}
|
||||
}
|
||||
/*The first and the last points are also adjacent*/
|
||||
if(points[0].x != points[point_cnt - 1].x || points[0].y != points[point_cnt - 1].y) {
|
||||
p[pcnt] = points[point_cnt - 1];
|
||||
pcnt++;
|
||||
}
|
||||
|
||||
point_cnt = pcnt;
|
||||
if(point_cnt < 3) {
|
||||
lv_mem_buf_release(p);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t poly_coords = {.x1 = LV_COORD_MAX, .y1 = LV_COORD_MAX, .x2 = LV_COORD_MIN, .y2 = LV_COORD_MIN};
|
||||
|
||||
for(i = 0; i < point_cnt; i++) {
|
||||
poly_coords.x1 = LV_MIN(poly_coords.x1, p[i].x);
|
||||
poly_coords.y1 = LV_MIN(poly_coords.y1, p[i].y);
|
||||
poly_coords.x2 = LV_MAX(poly_coords.x2, p[i].x);
|
||||
poly_coords.y2 = LV_MAX(poly_coords.y2, p[i].y);
|
||||
}
|
||||
|
||||
bool is_common;
|
||||
lv_area_t poly_mask;
|
||||
is_common = _lv_area_intersect(&poly_mask, &poly_coords, clip_area);
|
||||
if(!is_common) {
|
||||
lv_mem_buf_release(p);
|
||||
return;
|
||||
}
|
||||
/*Find the lowest point*/
|
||||
lv_coord_t y_min = p[0].y;
|
||||
int16_t y_min_i = 0;
|
||||
|
||||
for(i = 1; i < point_cnt; i++) {
|
||||
if(p[i].y < y_min) {
|
||||
y_min = p[i].y;
|
||||
y_min_i = i;
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_mask_line_param_t * mp = lv_mem_buf_get(sizeof(lv_draw_mask_line_param_t) * point_cnt);
|
||||
lv_draw_mask_line_param_t * mp_next = mp;
|
||||
|
||||
int32_t i_prev_left = y_min_i;
|
||||
int32_t i_prev_right = y_min_i;
|
||||
int32_t i_next_left;
|
||||
int32_t i_next_right;
|
||||
uint32_t mask_cnt = 0;
|
||||
|
||||
/*Get the index of the left and right points*/
|
||||
i_next_left = y_min_i - 1;
|
||||
if(i_next_left < 0) i_next_left = point_cnt + i_next_left;
|
||||
|
||||
i_next_right = y_min_i + 1;
|
||||
if(i_next_right > point_cnt - 1) i_next_right = 0;
|
||||
|
||||
/**
|
||||
* Check if the order of points is inverted or not.
|
||||
* The normal case is when the left point is on `y_min_i - 1`
|
||||
* Explanation:
|
||||
* if angle(p_left) < angle(p_right) -> inverted
|
||||
* dy_left/dx_left < dy_right/dx_right
|
||||
* dy_left * dx_right < dy_right * dx_left
|
||||
*/
|
||||
lv_coord_t dxl = p[i_next_left].x - p[y_min_i].x;
|
||||
lv_coord_t dxr = p[i_next_right].x - p[y_min_i].x;
|
||||
lv_coord_t dyl = p[i_next_left].y - p[y_min_i].y;
|
||||
lv_coord_t dyr = p[i_next_right].y - p[y_min_i].y;
|
||||
|
||||
bool inv = false;
|
||||
if(dyl * dxr < dyr * dxl) inv = true;
|
||||
|
||||
do {
|
||||
if(!inv) {
|
||||
i_next_left = i_prev_left - 1;
|
||||
if(i_next_left < 0) i_next_left = point_cnt + i_next_left;
|
||||
|
||||
i_next_right = i_prev_right + 1;
|
||||
if(i_next_right > point_cnt - 1) i_next_right = 0;
|
||||
}
|
||||
else {
|
||||
i_next_left = i_prev_left + 1;
|
||||
if(i_next_left > point_cnt - 1) i_next_left = 0;
|
||||
|
||||
i_next_right = i_prev_right - 1;
|
||||
if(i_next_right < 0) i_next_right = point_cnt + i_next_right;
|
||||
}
|
||||
|
||||
if(p[i_next_left].y >= p[i_prev_left].y) {
|
||||
if(p[i_next_left].y != p[i_prev_left].y &&
|
||||
p[i_next_left].x != p[i_prev_left].x) {
|
||||
lv_draw_mask_line_points_init(mp_next, p[i_prev_left].x, p[i_prev_left].y,
|
||||
p[i_next_left].x, p[i_next_left].y,
|
||||
LV_DRAW_MASK_LINE_SIDE_RIGHT);
|
||||
lv_draw_mask_add(mp_next, mp);
|
||||
mp_next++;
|
||||
}
|
||||
mask_cnt++;
|
||||
i_prev_left = i_next_left;
|
||||
}
|
||||
|
||||
if(mask_cnt == point_cnt) break;
|
||||
|
||||
if(p[i_next_right].y >= p[i_prev_right].y) {
|
||||
if(p[i_next_right].y != p[i_prev_right].y &&
|
||||
p[i_next_right].x != p[i_prev_right].x) {
|
||||
|
||||
lv_draw_mask_line_points_init(mp_next, p[i_prev_right].x, p[i_prev_right].y,
|
||||
p[i_next_right].x, p[i_next_right].y,
|
||||
LV_DRAW_MASK_LINE_SIDE_LEFT);
|
||||
lv_draw_mask_add(mp_next, mp);
|
||||
mp_next++;
|
||||
}
|
||||
mask_cnt++;
|
||||
i_prev_right = i_next_right;
|
||||
}
|
||||
|
||||
} while(mask_cnt < point_cnt);
|
||||
|
||||
lv_draw_rect(&poly_coords, clip_area, draw_dsc);
|
||||
|
||||
lv_draw_mask_remove_custom(mp);
|
||||
|
||||
lv_mem_buf_release(mp);
|
||||
lv_mem_buf_release(p);
|
||||
#else
|
||||
LV_UNUSED(points);
|
||||
LV_UNUSED(point_cnt);
|
||||
LV_UNUSED(clip_area);
|
||||
LV_UNUSED(draw_dsc);
|
||||
LV_LOG_WARN("Can't draw polygon with LV_DRAW_COMPLEX == 0");
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
56
MXC-A36/xrz/lvgl/src/draw/lv_draw_triangle.h
Normal file
56
MXC-A36/xrz/lvgl/src/draw/lv_draw_triangle.h
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @file lv_draw_triangle.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_TRIANGLE_H
|
||||
#define LV_DRAW_TRIANGLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_rect.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw a triangle
|
||||
* @param points pointer to an array with 3 points
|
||||
* @param clip_area the triangle will be drawn only in this area
|
||||
* @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_triangle(const lv_point_t points[], const lv_area_t * clip, const lv_draw_rect_dsc_t * draw_dsc);
|
||||
|
||||
/**
|
||||
* Draw a polygon. Only convex polygons are supported.
|
||||
* @param points an array of points
|
||||
* @param point_cnt number of points
|
||||
* @param clip_area polygon will be drawn only in this area
|
||||
* @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_polygon(const lv_point_t points[], uint16_t point_cnt, const lv_area_t * mask,
|
||||
const lv_draw_rect_dsc_t * draw_dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_TRIANGLE_H*/
|
772
MXC-A36/xrz/lvgl/src/draw/lv_img_buf.c
Normal file
772
MXC-A36/xrz/lvgl/src/draw/lv_img_buf.c
Normal file
@ -0,0 +1,772 @@
|
||||
/**
|
||||
* @file lv_img_buf.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "lv_img_buf.h"
|
||||
#include "lv_draw_img.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_log.h"
|
||||
#include "../misc/lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Get the color of an image's pixel
|
||||
* @param dsc an image descriptor
|
||||
* @param x x coordinate of the point to get
|
||||
* @param y x coordinate of the point to get
|
||||
* @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used.
|
||||
* Not used in other cases.
|
||||
* @param safe true: check out of bounds
|
||||
* @return color of the point
|
||||
*/
|
||||
lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color)
|
||||
{
|
||||
lv_color_t p_color = lv_color_black();
|
||||
uint8_t * buf_u8 = (uint8_t *)dsc->data;
|
||||
|
||||
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED ||
|
||||
dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
|
||||
uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
|
||||
uint32_t px = dsc->header.w * y * px_size + x * px_size;
|
||||
lv_memcpy_small(&p_color, &buf_u8[px], sizeof(lv_color_t));
|
||||
#if LV_COLOR_SIZE == 32
|
||||
p_color.ch.alpha = 0xFF; /*Only the color should be get so use a default alpha value*/
|
||||
#endif
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) {
|
||||
buf_u8 += 4 * 2;
|
||||
uint8_t bit = x & 0x7;
|
||||
x = x >> 3;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
|
||||
*so the possible real width are 8, 16, 24 ...*/
|
||||
uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
|
||||
p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
|
||||
buf_u8 += 4 * 4;
|
||||
uint8_t bit = (x & 0x3) * 2;
|
||||
x = x >> 2;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
|
||||
*so the possible real width are 4, 8, 12 ...*/
|
||||
uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
|
||||
p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) {
|
||||
buf_u8 += 4 * 16;
|
||||
uint8_t bit = (x & 0x1) * 4;
|
||||
x = x >> 1;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
|
||||
*so the possible real width are 2, 4, 6 ...*/
|
||||
uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
|
||||
p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
|
||||
buf_u8 += 4 * 256;
|
||||
uint32_t px = dsc->header.w * y + x;
|
||||
p_color.full = buf_u8[px];
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
|
||||
dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
p_color = color;
|
||||
}
|
||||
return p_color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the alpha value of an image's pixel
|
||||
* @param dsc pointer to an image descriptor
|
||||
* @param x x coordinate of the point to set
|
||||
* @param y x coordinate of the point to set
|
||||
* @param safe true: check out of bounds
|
||||
* @return alpha value of the point
|
||||
*/
|
||||
lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
|
||||
{
|
||||
uint8_t * buf_u8 = (uint8_t *)dsc->data;
|
||||
|
||||
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
|
||||
uint32_t px = dsc->header.w * y * LV_IMG_PX_SIZE_ALPHA_BYTE + x * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
return buf_u8[px + LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) {
|
||||
uint8_t bit = x & 0x7;
|
||||
x = x >> 3;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
|
||||
*so the possible real width are 8 ,16, 24 ...*/
|
||||
uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
|
||||
uint8_t px_opa = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
|
||||
return px_opa ? LV_OPA_TRANSP : LV_OPA_COVER;
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
|
||||
const uint8_t opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
|
||||
|
||||
uint8_t bit = (x & 0x3) * 2;
|
||||
x = x >> 2;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
|
||||
*so the possible real width are 4 ,8, 12 ...*/
|
||||
uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
|
||||
uint8_t px_opa = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
|
||||
return opa_table[px_opa];
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
|
||||
const uint8_t opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
|
||||
68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
|
||||
};
|
||||
|
||||
uint8_t bit = (x & 0x1) * 4;
|
||||
x = x >> 1;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
|
||||
*so the possible real width are 2 ,4, 6 ...*/
|
||||
uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
|
||||
uint8_t px_opa = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
|
||||
return opa_table[px_opa];
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
uint32_t px = dsc->header.w * y + x;
|
||||
return buf_u8[px];
|
||||
}
|
||||
|
||||
return LV_OPA_COVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the alpha value of a pixel of an image. The color won't be affected
|
||||
* @param dsc pointer to an image descriptor
|
||||
* @param x x coordinate of the point to set
|
||||
* @param y x coordinate of the point to set
|
||||
* @param opa the desired opacity
|
||||
* @param safe true: check out of bounds
|
||||
*/
|
||||
void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa)
|
||||
{
|
||||
uint8_t * buf_u8 = (uint8_t *)dsc->data;
|
||||
|
||||
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
|
||||
uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
|
||||
uint32_t px = dsc->header.w * y * px_size + x * px_size;
|
||||
buf_u8[px + px_size - 1] = opa;
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) {
|
||||
opa = opa >> 7; /*opa -> [0,1]*/
|
||||
uint8_t bit = x & 0x7;
|
||||
x = x >> 3;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
|
||||
*so the possible real width are 8 ,16, 24 ...*/
|
||||
uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((opa & 0x1) << (7 - bit));
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
|
||||
opa = opa >> 6; /*opa -> [0,3]*/
|
||||
uint8_t bit = (x & 0x3) * 2;
|
||||
x = x >> 2;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
|
||||
*so the possible real width are 4 ,8, 12 ...*/
|
||||
uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((opa & 0x3) << (6 - bit));
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
|
||||
opa = opa >> 4; /*opa -> [0,15]*/
|
||||
uint8_t bit = (x & 0x1) * 4;
|
||||
x = x >> 1;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
|
||||
*so the possible real width are 2 ,4, 6 ...*/
|
||||
uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((opa & 0xF) << (4 - bit));
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
uint32_t px = dsc->header.w * y + x;
|
||||
buf_u8[px] = opa;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color of a pixel of an image. The alpha channel won't be affected.
|
||||
* @param dsc pointer to an image descriptor
|
||||
* @param x x coordinate of the point to set
|
||||
* @param y x coordinate of the point to set
|
||||
* @param c color of the point
|
||||
* @param safe true: check out of bounds
|
||||
*/
|
||||
void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c)
|
||||
{
|
||||
uint8_t * buf_u8 = (uint8_t *)dsc->data;
|
||||
|
||||
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
||||
uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
|
||||
uint32_t px = dsc->header.w * y * px_size + x * px_size;
|
||||
lv_memcpy_small(&buf_u8[px], &c, px_size);
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
|
||||
uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
|
||||
uint32_t px = dsc->header.w * y * px_size + x * px_size;
|
||||
lv_memcpy_small(&buf_u8[px], &c, px_size - 1); /*-1 to not overwrite the alpha value*/
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) {
|
||||
buf_u8 += sizeof(lv_color32_t) * 2; /*Skip the palette*/
|
||||
|
||||
uint8_t bit = x & 0x7;
|
||||
x = x >> 3;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
|
||||
*so the possible real width are 8 ,16, 24 ...*/
|
||||
uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit));
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
|
||||
buf_u8 += sizeof(lv_color32_t) * 4; /*Skip the palette*/
|
||||
uint8_t bit = (x & 0x3) * 2;
|
||||
x = x >> 2;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
|
||||
*so the possible real width are 4, 8 ,12 ...*/
|
||||
uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
|
||||
|
||||
buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit));
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) {
|
||||
buf_u8 += sizeof(lv_color32_t) * 16; /*Skip the palette*/
|
||||
uint8_t bit = (x & 0x1) * 4;
|
||||
x = x >> 1;
|
||||
|
||||
/*Get the current pixel.
|
||||
*dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
|
||||
*so the possible real width are 2 ,4, 6 ...*/
|
||||
uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit));
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
|
||||
buf_u8 += sizeof(lv_color32_t) * 256; /*Skip the palette*/
|
||||
uint32_t px = dsc->header.w * y + x;
|
||||
buf_u8[px] = c.full;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8`
|
||||
* @param dsc pointer to an image descriptor
|
||||
* @param id the palette color to set:
|
||||
* - for `LV_IMG_CF_INDEXED1`: 0..1
|
||||
* - for `LV_IMG_CF_INDEXED2`: 0..3
|
||||
* - for `LV_IMG_CF_INDEXED4`: 0..15
|
||||
* - for `LV_IMG_CF_INDEXED8`: 0..255
|
||||
* @param c the color to set
|
||||
*/
|
||||
void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c)
|
||||
{
|
||||
if((dsc->header.cf == LV_IMG_CF_ALPHA_1BIT && id > 1) || (dsc->header.cf == LV_IMG_CF_ALPHA_2BIT && id > 3) ||
|
||||
(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT && id > 15) || (dsc->header.cf == LV_IMG_CF_ALPHA_8BIT)) {
|
||||
LV_LOG_WARN("lv_img_buf_set_px_alpha: invalid 'id'");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_color32_t c32;
|
||||
c32.full = lv_color_to32(c);
|
||||
uint8_t * buf = (uint8_t *)dsc->data;
|
||||
lv_memcpy_small(&buf[id * sizeof(c32)], &c32, sizeof(c32));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate an image buffer in RAM
|
||||
* @param w width of image
|
||||
* @param h height of image
|
||||
* @param cf a color format (`LV_IMG_CF_...`)
|
||||
* @return an allocated image, or NULL on failure
|
||||
*/
|
||||
lv_img_dsc_t * lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
|
||||
{
|
||||
/*Allocate image descriptor*/
|
||||
lv_img_dsc_t * dsc = lv_mem_alloc(sizeof(lv_img_dsc_t));
|
||||
if(dsc == NULL)
|
||||
return NULL;
|
||||
|
||||
lv_memset_00(dsc, sizeof(lv_img_dsc_t));
|
||||
|
||||
/*Get image data size*/
|
||||
dsc->data_size = lv_img_buf_get_img_size(w, h, cf);
|
||||
if(dsc->data_size == 0) {
|
||||
lv_mem_free(dsc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*Allocate raw buffer*/
|
||||
dsc->data = lv_mem_alloc(dsc->data_size);
|
||||
if(dsc->data == NULL) {
|
||||
lv_mem_free(dsc);
|
||||
return NULL;
|
||||
}
|
||||
lv_memset_00((uint8_t *)dsc->data, dsc->data_size);
|
||||
|
||||
/*Fill in header*/
|
||||
dsc->header.always_zero = 0;
|
||||
dsc->header.w = w;
|
||||
dsc->header.h = h;
|
||||
dsc->header.cf = cf;
|
||||
return dsc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an allocated image buffer
|
||||
* @param dsc image buffer to free
|
||||
*/
|
||||
void lv_img_buf_free(lv_img_dsc_t * dsc)
|
||||
{
|
||||
if(dsc != NULL) {
|
||||
if(dsc->data != NULL)
|
||||
lv_mem_free((void*)dsc->data);
|
||||
|
||||
lv_mem_free(dsc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the memory consumption of a raw bitmap, given color format and dimensions.
|
||||
* @param w width
|
||||
* @param h height
|
||||
* @param cf color format
|
||||
* @return size in bytes
|
||||
*/
|
||||
uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_IMG_CF_TRUE_COLOR:
|
||||
return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h);
|
||||
case LV_IMG_CF_TRUE_COLOR_ALPHA:
|
||||
return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h);
|
||||
case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
|
||||
return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h);
|
||||
case LV_IMG_CF_ALPHA_1BIT:
|
||||
return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h);
|
||||
case LV_IMG_CF_ALPHA_2BIT:
|
||||
return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h);
|
||||
case LV_IMG_CF_ALPHA_4BIT:
|
||||
return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h);
|
||||
case LV_IMG_CF_ALPHA_8BIT:
|
||||
return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h);
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h);
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h);
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h);
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
/**
|
||||
* Initialize a descriptor to transform an image
|
||||
* @param dsc pointer to an `lv_img_transform_dsc_t` variable whose `cfg` field is initialized
|
||||
*/
|
||||
void _lv_img_buf_transform_init(lv_img_transform_dsc_t * dsc)
|
||||
{
|
||||
dsc->tmp.pivot_x_256 = dsc->cfg.pivot_x * 256;
|
||||
dsc->tmp.pivot_y_256 = dsc->cfg.pivot_y * 256;
|
||||
|
||||
int32_t angle_low = dsc->cfg.angle / 10;
|
||||
int32_t angle_high = angle_low + 1;
|
||||
int32_t angle_rem = dsc->cfg.angle - (angle_low * 10);
|
||||
|
||||
int32_t s1 = lv_trigo_sin(-angle_low);
|
||||
int32_t s2 = lv_trigo_sin(-angle_high);
|
||||
|
||||
int32_t c1 = lv_trigo_sin(-angle_low + 90);
|
||||
int32_t c2 = lv_trigo_sin(-angle_high + 90);
|
||||
|
||||
dsc->tmp.sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
|
||||
dsc->tmp.cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
|
||||
|
||||
/*Use smaller value to avoid overflow*/
|
||||
dsc->tmp.sinma = dsc->tmp.sinma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
|
||||
dsc->tmp.cosma = dsc->tmp.cosma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
|
||||
|
||||
dsc->tmp.chroma_keyed = lv_img_cf_is_chroma_keyed(dsc->cfg.cf) ? 1 : 0;
|
||||
dsc->tmp.has_alpha = lv_img_cf_has_alpha(dsc->cfg.cf) ? 1 : 0;
|
||||
if(dsc->cfg.cf == LV_IMG_CF_TRUE_COLOR || dsc->cfg.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
|
||||
dsc->cfg.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
||||
dsc->tmp.native_color = 1;
|
||||
}
|
||||
else {
|
||||
dsc->tmp.native_color = 0;
|
||||
}
|
||||
|
||||
dsc->tmp.img_dsc.data = dsc->cfg.src;
|
||||
dsc->tmp.img_dsc.header.always_zero = 0;
|
||||
dsc->tmp.img_dsc.header.cf = dsc->cfg.cf;
|
||||
dsc->tmp.img_dsc.header.w = dsc->cfg.src_w;
|
||||
dsc->tmp.img_dsc.header.h = dsc->cfg.src_h;
|
||||
|
||||
/*The inverse of the zoom will be sued during the transformation
|
||||
* + dsc->cfg.zoom / 2 for rounding*/
|
||||
dsc->tmp.zoom_inv = (((256 * 256) << _LV_ZOOM_INV_UPSCALE) + dsc->cfg.zoom / 2) / dsc->cfg.zoom;
|
||||
|
||||
dsc->res.opa = LV_OPA_COVER;
|
||||
dsc->res.color = dsc->cfg.color;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the area of a rectangle if its rotated and scaled
|
||||
* @param res store the coordinates here
|
||||
* @param w width of the rectangle to transform
|
||||
* @param h height of the rectangle to transform
|
||||
* @param angle angle of rotation
|
||||
* @param zoom zoom, (256 no zoom)
|
||||
* @param pivot x,y pivot coordinates of rotation
|
||||
*/
|
||||
void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t h, int16_t angle, uint16_t zoom,
|
||||
const lv_point_t * pivot)
|
||||
{
|
||||
#if LV_DRAW_COMPLEX
|
||||
if(angle == 0 && zoom == LV_IMG_ZOOM_NONE) {
|
||||
res->x1 = 0;
|
||||
res->y1 = 0;
|
||||
res->x2 = w - 1;
|
||||
res->y2 = h - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
res->x1 = (((-pivot->x) * zoom) >> 8) - 1;
|
||||
res->y1 = (((-pivot->y) * zoom) >> 8) - 1;
|
||||
res->x2 = (((w - pivot->x) * zoom) >> 8) + 2;
|
||||
res->y2 = (((h - pivot->y) * zoom) >> 8) + 2;
|
||||
|
||||
if(angle == 0) {
|
||||
res->x1 += pivot->x;
|
||||
res->y1 += pivot->y;
|
||||
res->x2 += pivot->x;
|
||||
res->y2 += pivot->y;
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t angle_low = angle / 10;
|
||||
int32_t angle_high = angle_low + 1;
|
||||
int32_t angle_rem = angle - (angle_low * 10);
|
||||
|
||||
int32_t s1 = lv_trigo_sin(angle_low);
|
||||
int32_t s2 = lv_trigo_sin(angle_high);
|
||||
|
||||
int32_t c1 = lv_trigo_sin(angle_low + 90);
|
||||
int32_t c2 = lv_trigo_sin(angle_high + 90);
|
||||
|
||||
int32_t sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
|
||||
int32_t cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
|
||||
|
||||
/*Use smaller value to avoid overflow*/
|
||||
sinma = sinma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
|
||||
cosma = cosma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
|
||||
|
||||
lv_point_t lt;
|
||||
lv_point_t rt;
|
||||
lv_point_t lb;
|
||||
lv_point_t rb;
|
||||
|
||||
lv_coord_t xt;
|
||||
lv_coord_t yt;
|
||||
|
||||
xt = res->x1;
|
||||
yt = res->y1;
|
||||
lt.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
|
||||
lt.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
|
||||
|
||||
xt = res->x2;
|
||||
yt = res->y1;
|
||||
rt.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
|
||||
rt.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
|
||||
|
||||
xt = res->x1;
|
||||
yt = res->y2;
|
||||
lb.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
|
||||
lb.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
|
||||
|
||||
xt = res->x2;
|
||||
yt = res->y2;
|
||||
rb.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
|
||||
rb.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
|
||||
|
||||
res->x1 = LV_MIN4(lb.x, lt.x, rb.x, rt.x);
|
||||
res->x2 = LV_MAX4(lb.x, lt.x, rb.x, rt.x);
|
||||
res->y1 = LV_MIN4(lb.y, lt.y, rb.y, rt.y);
|
||||
res->y2 = LV_MAX4(lb.y, lt.y, rb.y, rt.y);
|
||||
#else
|
||||
LV_UNUSED(angle);
|
||||
LV_UNUSED(zoom);
|
||||
LV_UNUSED(pivot);
|
||||
res->x1 = 0;
|
||||
res->y1 = 0;
|
||||
res->x2 = w - 1;
|
||||
res->y2 = h - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
/**
|
||||
* Get which color and opa would come to a pixel if it were rotated
|
||||
* @param dsc a descriptor initialized by `lv_img_buf_rotate_init`
|
||||
* @param x the coordinate which color and opa should be get
|
||||
* @param y the coordinate which color and opa should be get
|
||||
* @return true: there is valid pixel on these x/y coordinates; false: the rotated pixel was out of the image
|
||||
* @note the result is written back to `dsc->res_color` and `dsc->res_opa`
|
||||
*/
|
||||
bool _lv_img_buf_transform(lv_img_transform_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
|
||||
{
|
||||
const uint8_t * src_u8 = (const uint8_t *)dsc->cfg.src;
|
||||
|
||||
/*Get the target point relative coordinates to the pivot*/
|
||||
int32_t xt = x - dsc->cfg.pivot_x;
|
||||
int32_t yt = y - dsc->cfg.pivot_y;
|
||||
|
||||
int32_t xs;
|
||||
int32_t ys;
|
||||
if(dsc->cfg.zoom == LV_IMG_ZOOM_NONE) {
|
||||
/*Get the source pixel from the upscaled image*/
|
||||
xs = ((dsc->tmp.cosma * xt - dsc->tmp.sinma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT - 8)) + dsc->tmp.pivot_x_256;
|
||||
ys = ((dsc->tmp.sinma * xt + dsc->tmp.cosma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT - 8)) + dsc->tmp.pivot_y_256;
|
||||
}
|
||||
else if(dsc->cfg.angle == 0) {
|
||||
xt = (int32_t)((int32_t)xt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
|
||||
yt = (int32_t)((int32_t)yt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
|
||||
xs = xt + dsc->tmp.pivot_x_256;
|
||||
ys = yt + dsc->tmp.pivot_y_256;
|
||||
}
|
||||
else {
|
||||
xt = (int32_t)((int32_t)xt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
|
||||
yt = (int32_t)((int32_t)yt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
|
||||
xs = ((dsc->tmp.cosma * xt - dsc->tmp.sinma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT)) + dsc->tmp.pivot_x_256;
|
||||
ys = ((dsc->tmp.sinma * xt + dsc->tmp.cosma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT)) + dsc->tmp.pivot_y_256;
|
||||
}
|
||||
|
||||
/*Get the integer part of the source pixel*/
|
||||
int32_t xs_int = xs >> 8;
|
||||
int32_t ys_int = ys >> 8;
|
||||
|
||||
if(xs_int >= dsc->cfg.src_w) return false;
|
||||
else if(xs_int < 0) return false;
|
||||
|
||||
if(ys_int >= dsc->cfg.src_h) return false;
|
||||
else if(ys_int < 0) return false;
|
||||
|
||||
uint8_t px_size;
|
||||
uint32_t pxi;
|
||||
if(dsc->tmp.native_color) {
|
||||
if(dsc->tmp.has_alpha == 0) {
|
||||
px_size = LV_COLOR_SIZE >> 3;
|
||||
|
||||
pxi = dsc->cfg.src_w * ys_int * px_size + xs_int * px_size;
|
||||
lv_memcpy_small(&dsc->res.color, &src_u8[pxi], px_size);
|
||||
}
|
||||
else {
|
||||
px_size = LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
pxi = dsc->cfg.src_w * ys_int * px_size + xs_int * px_size;
|
||||
lv_memcpy_small(&dsc->res.color, &src_u8[pxi], px_size - 1);
|
||||
dsc->res.opa = src_u8[pxi + px_size - 1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
pxi = 0; /*unused*/
|
||||
px_size = 0; /*unused*/
|
||||
dsc->res.color = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, xs_int, ys_int, dsc->cfg.color);
|
||||
dsc->res.opa = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, xs_int, ys_int);
|
||||
}
|
||||
|
||||
if(dsc->tmp.chroma_keyed) {
|
||||
lv_color_t ct = LV_COLOR_CHROMA_KEY;
|
||||
if(dsc->res.color.full == ct.full) return false;
|
||||
}
|
||||
|
||||
if(dsc->cfg.antialias == false) return true;
|
||||
|
||||
dsc->tmp.xs = xs;
|
||||
dsc->tmp.ys = ys;
|
||||
dsc->tmp.xs_int = xs_int;
|
||||
dsc->tmp.ys_int = ys_int;
|
||||
dsc->tmp.pxi = pxi;
|
||||
dsc->tmp.px_size = px_size;
|
||||
|
||||
bool ret;
|
||||
ret = _lv_img_buf_transform_anti_alias(dsc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue transformation by taking the neighbors into account
|
||||
* @param dsc pointer to the transformation descriptor
|
||||
*/
|
||||
bool _lv_img_buf_transform_anti_alias(lv_img_transform_dsc_t * dsc)
|
||||
{
|
||||
const uint8_t * src_u8 = dsc->cfg.src;
|
||||
|
||||
/*Get the fractional part of the source pixel*/
|
||||
int xs_fract = dsc->tmp.xs & 0xff;
|
||||
int ys_fract = dsc->tmp.ys & 0xff;
|
||||
int32_t xn; /*x neighbor*/
|
||||
lv_opa_t xr; /*x mix ratio*/
|
||||
|
||||
if(xs_fract < 0x70) {
|
||||
xn = - 1;
|
||||
if(dsc->tmp.xs_int + xn < 0) xn = 0;
|
||||
xr = xs_fract + 0x80;
|
||||
}
|
||||
else if(xs_fract > 0x90) {
|
||||
xn = 1;
|
||||
if(dsc->tmp.xs_int + xn >= dsc->cfg.src_w) xn = 0;
|
||||
xr = (0xFF - xs_fract) + 0x80;
|
||||
}
|
||||
else {
|
||||
xn = 0;
|
||||
xr = 0xFF;
|
||||
}
|
||||
|
||||
int32_t yn; /*x neighbor*/
|
||||
lv_opa_t yr; /*x mix ratio*/
|
||||
|
||||
if(ys_fract < 0x70) {
|
||||
yn = - 1;
|
||||
if(dsc->tmp.ys_int + yn < 0) yn = 0;
|
||||
|
||||
yr = ys_fract + 0x80;
|
||||
}
|
||||
else if(ys_fract > 0x90) {
|
||||
yn = 1;
|
||||
if(dsc->tmp.ys_int + yn >= dsc->cfg.src_h) yn = 0;
|
||||
|
||||
yr = (0xFF - ys_fract) + 0x80;
|
||||
}
|
||||
else {
|
||||
yn = 0;
|
||||
yr = 0xFF;
|
||||
}
|
||||
|
||||
lv_color_t c00 = dsc->res.color;
|
||||
lv_color_t c01;
|
||||
lv_color_t c10;
|
||||
lv_color_t c11;
|
||||
|
||||
lv_opa_t a00 = dsc->res.opa;
|
||||
lv_opa_t a10 = 0;
|
||||
lv_opa_t a01 = 0;
|
||||
lv_opa_t a11 = 0;
|
||||
|
||||
if(dsc->tmp.native_color) {
|
||||
lv_memcpy_small(&c01, &src_u8[dsc->tmp.pxi + dsc->tmp.px_size * xn], sizeof(lv_color_t));
|
||||
lv_memcpy_small(&c10, &src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn], sizeof(lv_color_t));
|
||||
lv_memcpy_small(&c11, &src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn + dsc->tmp.px_size * xn],
|
||||
sizeof(lv_color_t));
|
||||
if(dsc->tmp.has_alpha) {
|
||||
a10 = src_u8[dsc->tmp.pxi + dsc->tmp.px_size * xn + dsc->tmp.px_size - 1];
|
||||
a01 = src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn + dsc->tmp.px_size - 1];
|
||||
a11 = src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn + dsc->tmp.px_size * xn + dsc->tmp.px_size - 1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
c01 = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int, dsc->cfg.color);
|
||||
c10 = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, dsc->tmp.xs_int, dsc->tmp.ys_int + yn, dsc->cfg.color);
|
||||
c11 = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int + yn, dsc->cfg.color);
|
||||
|
||||
if(dsc->tmp.has_alpha) {
|
||||
a10 = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int);
|
||||
a01 = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, dsc->tmp.xs_int, dsc->tmp.ys_int + yn);
|
||||
a11 = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int + yn);
|
||||
}
|
||||
}
|
||||
|
||||
lv_opa_t xr0 = xr;
|
||||
lv_opa_t xr1 = xr;
|
||||
if(dsc->tmp.has_alpha) {
|
||||
lv_opa_t a0 = (a00 * xr + (a10 * (255 - xr))) >> 8;
|
||||
lv_opa_t a1 = (a01 * xr + (a11 * (255 - xr))) >> 8;
|
||||
dsc->res.opa = (a0 * yr + (a1 * (255 - yr))) >> 8;
|
||||
|
||||
if(a0 <= LV_OPA_MIN && a1 <= LV_OPA_MIN) return false;
|
||||
if(a0 <= LV_OPA_MIN) yr = LV_OPA_TRANSP;
|
||||
if(a1 <= LV_OPA_MIN) yr = LV_OPA_COVER;
|
||||
if(a00 <= LV_OPA_MIN) xr0 = LV_OPA_TRANSP;
|
||||
if(a10 <= LV_OPA_MIN) xr0 = LV_OPA_COVER;
|
||||
if(a01 <= LV_OPA_MIN) xr1 = LV_OPA_TRANSP;
|
||||
if(a11 <= LV_OPA_MIN) xr1 = LV_OPA_COVER;
|
||||
}
|
||||
else {
|
||||
xr0 = xr;
|
||||
xr1 = xr;
|
||||
dsc->res.opa = LV_OPA_COVER;
|
||||
}
|
||||
|
||||
lv_color_t c0;
|
||||
if(xr0 == LV_OPA_TRANSP) c0 = c01;
|
||||
else if(xr0 == LV_OPA_COVER) c0 = c00;
|
||||
else c0 = lv_color_mix(c00, c01, xr0);
|
||||
|
||||
lv_color_t c1;
|
||||
if(xr1 == LV_OPA_TRANSP) c1 = c11;
|
||||
else if(xr1 == LV_OPA_COVER) c1 = c10;
|
||||
else c1 = lv_color_mix(c10, c11, xr1);
|
||||
|
||||
if(yr == LV_OPA_TRANSP) dsc->res.color = c1;
|
||||
else if(yr == LV_OPA_COVER) dsc->res.color = c0;
|
||||
else dsc->res.color = lv_color_mix(c0, c1, yr);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
310
MXC-A36/xrz/lvgl/src/draw/lv_img_buf.h
Normal file
310
MXC-A36/xrz/lvgl/src/draw/lv_img_buf.h
Normal file
@ -0,0 +1,310 @@
|
||||
/**
|
||||
* @file lv_img_buf.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_IMG_BUF_H
|
||||
#define LV_IMG_BUF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdbool.h>
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
/*If image pixels contains alpha we need to know how much byte is a pixel*/
|
||||
#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
|
||||
#define LV_IMG_PX_SIZE_ALPHA_BYTE 2
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
#define LV_IMG_PX_SIZE_ALPHA_BYTE 3
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
#define LV_IMG_PX_SIZE_ALPHA_BYTE 4
|
||||
#endif
|
||||
|
||||
#define LV_IMG_BUF_SIZE_TRUE_COLOR(w, h) ((LV_COLOR_SIZE / 8) * w * h)
|
||||
#define LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) ((LV_COLOR_SIZE / 8) * w * h)
|
||||
#define LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) (LV_IMG_PX_SIZE_ALPHA_BYTE * w * h)
|
||||
|
||||
/*+ 1: to be sure no fractional row*/
|
||||
#define LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) ((((w / 8) + 1) * h))
|
||||
#define LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) ((((w / 4) + 1) * h))
|
||||
#define LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) ((((w / 2) + 1) * h))
|
||||
#define LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) ((w * h))
|
||||
|
||||
/*4 * X: for palette*/
|
||||
#define LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) + 4 * 2)
|
||||
#define LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) + 4 * 4)
|
||||
#define LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) + 4 * 16)
|
||||
#define LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) + 4 * 256)
|
||||
|
||||
#define _LV_TRANSFORM_TRIGO_SHIFT 10
|
||||
#define _LV_ZOOM_INV_UPSCALE 5
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/*Image color format*/
|
||||
enum {
|
||||
LV_IMG_CF_UNKNOWN = 0,
|
||||
|
||||
LV_IMG_CF_RAW, /**< Contains the file as it is. Needs custom decoder function*/
|
||||
LV_IMG_CF_RAW_ALPHA, /**< Contains the file as it is. The image has alpha. Needs custom decoder
|
||||
function*/
|
||||
LV_IMG_CF_RAW_CHROMA_KEYED, /**< Contains the file as it is. The image is chroma keyed. Needs
|
||||
custom decoder function*/
|
||||
|
||||
LV_IMG_CF_TRUE_COLOR, /**< Color format and depth should match with LV_COLOR settings*/
|
||||
LV_IMG_CF_TRUE_COLOR_ALPHA, /**< Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/
|
||||
LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /**< Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels
|
||||
will be transparent*/
|
||||
|
||||
LV_IMG_CF_INDEXED_1BIT, /**< Can have 2 different colors in a palette (always chroma keyed)*/
|
||||
LV_IMG_CF_INDEXED_2BIT, /**< Can have 4 different colors in a palette (always chroma keyed)*/
|
||||
LV_IMG_CF_INDEXED_4BIT, /**< Can have 16 different colors in a palette (always chroma keyed)*/
|
||||
LV_IMG_CF_INDEXED_8BIT, /**< Can have 256 different colors in a palette (always chroma keyed)*/
|
||||
|
||||
LV_IMG_CF_ALPHA_1BIT, /**< Can have one color and it can be drawn or not*/
|
||||
LV_IMG_CF_ALPHA_2BIT, /**< Can have one color but 4 different alpha value*/
|
||||
LV_IMG_CF_ALPHA_4BIT, /**< Can have one color but 16 different alpha value*/
|
||||
LV_IMG_CF_ALPHA_8BIT, /**< Can have one color but 256 different alpha value*/
|
||||
|
||||
LV_IMG_CF_RESERVED_15, /**< Reserved for further use.*/
|
||||
LV_IMG_CF_RESERVED_16, /**< Reserved for further use.*/
|
||||
LV_IMG_CF_RESERVED_17, /**< Reserved for further use.*/
|
||||
LV_IMG_CF_RESERVED_18, /**< Reserved for further use.*/
|
||||
LV_IMG_CF_RESERVED_19, /**< Reserved for further use.*/
|
||||
LV_IMG_CF_RESERVED_20, /**< Reserved for further use.*/
|
||||
LV_IMG_CF_RESERVED_21, /**< Reserved for further use.*/
|
||||
LV_IMG_CF_RESERVED_22, /**< Reserved for further use.*/
|
||||
LV_IMG_CF_RESERVED_23, /**< Reserved for further use.*/
|
||||
|
||||
LV_IMG_CF_USER_ENCODED_0, /**< User holder encoding format.*/
|
||||
LV_IMG_CF_USER_ENCODED_1, /**< User holder encoding format.*/
|
||||
LV_IMG_CF_USER_ENCODED_2, /**< User holder encoding format.*/
|
||||
LV_IMG_CF_USER_ENCODED_3, /**< User holder encoding format.*/
|
||||
LV_IMG_CF_USER_ENCODED_4, /**< User holder encoding format.*/
|
||||
LV_IMG_CF_USER_ENCODED_5, /**< User holder encoding format.*/
|
||||
LV_IMG_CF_USER_ENCODED_6, /**< User holder encoding format.*/
|
||||
LV_IMG_CF_USER_ENCODED_7, /**< User holder encoding format.*/
|
||||
};
|
||||
typedef uint8_t lv_img_cf_t;
|
||||
|
||||
|
||||
/**
|
||||
* The first 8 bit is very important to distinguish the different source types.
|
||||
* For more info see `lv_img_get_src_type()` in lv_img.c
|
||||
* On big endian systems the order is reversed so cf and always_zero must be at
|
||||
* the end of the struct.
|
||||
*/
|
||||
#if LV_BIG_ENDIAN_SYSTEM
|
||||
typedef struct {
|
||||
|
||||
uint32_t h : 11; /*Height of the image map*/
|
||||
uint32_t w : 11; /*Width of the image map*/
|
||||
uint32_t reserved : 2; /*Reserved to be used later*/
|
||||
uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a
|
||||
non-printable character*/
|
||||
uint32_t cf : 5; /*Color format: See `lv_img_color_format_t`*/
|
||||
|
||||
} lv_img_header_t;
|
||||
#else
|
||||
typedef struct {
|
||||
|
||||
uint32_t cf : 5; /*Color format: See `lv_img_color_format_t`*/
|
||||
uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a
|
||||
non-printable character*/
|
||||
|
||||
uint32_t reserved : 2; /*Reserved to be used later*/
|
||||
|
||||
uint32_t w : 11; /*Width of the image map*/
|
||||
uint32_t h : 11; /*Height of the image map*/
|
||||
} lv_img_header_t;
|
||||
#endif
|
||||
|
||||
/** Image header it is compatible with
|
||||
* the result from image converter utility*/
|
||||
typedef struct {
|
||||
lv_img_header_t header; /**< A header describing the basics of the image*/
|
||||
uint32_t data_size; /**< Size of the image in bytes*/
|
||||
const uint8_t * data; /**< Pointer to the data of the image*/
|
||||
} lv_img_dsc_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
const void * src; /*image source (array of pixels)*/
|
||||
lv_coord_t src_w; /*width of the image source*/
|
||||
lv_coord_t src_h; /*height of the image source*/
|
||||
lv_coord_t pivot_x; /*pivot x*/
|
||||
lv_coord_t pivot_y; /*pivot y*/
|
||||
int16_t angle; /*angle to rotate*/
|
||||
uint16_t zoom; /*256 no zoom, 128 half size, 512 double size*/
|
||||
lv_color_t color; /*a color used for `LV_IMG_CF_INDEXED_1/2/4/8BIT` color formats*/
|
||||
lv_img_cf_t cf; /*color format of the image to rotate*/
|
||||
bool antialias;
|
||||
} cfg;
|
||||
|
||||
struct {
|
||||
lv_color_t color;
|
||||
lv_opa_t opa;
|
||||
} res;
|
||||
|
||||
struct {
|
||||
lv_img_dsc_t img_dsc;
|
||||
int32_t pivot_x_256;
|
||||
int32_t pivot_y_256;
|
||||
int32_t sinma;
|
||||
int32_t cosma;
|
||||
|
||||
uint8_t chroma_keyed : 1;
|
||||
uint8_t has_alpha : 1;
|
||||
uint8_t native_color : 1;
|
||||
|
||||
uint32_t zoom_inv;
|
||||
|
||||
/*Runtime data*/
|
||||
lv_coord_t xs;
|
||||
lv_coord_t ys;
|
||||
lv_coord_t xs_int;
|
||||
lv_coord_t ys_int;
|
||||
uint32_t pxi;
|
||||
uint8_t px_size;
|
||||
} tmp;
|
||||
} lv_img_transform_dsc_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Allocate an image buffer in RAM
|
||||
* @param w width of image
|
||||
* @param h height of image
|
||||
* @param cf a color format (`LV_IMG_CF_...`)
|
||||
* @return an allocated image, or NULL on failure
|
||||
*/
|
||||
lv_img_dsc_t * lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf);
|
||||
|
||||
/**
|
||||
* Get the color of an image's pixel
|
||||
* @param dsc an image descriptor
|
||||
* @param x x coordinate of the point to get
|
||||
* @param y x coordinate of the point to get
|
||||
* @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used.
|
||||
* Not used in other cases.
|
||||
* @param safe true: check out of bounds
|
||||
* @return color of the point
|
||||
*/
|
||||
lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color);
|
||||
|
||||
/**
|
||||
* Get the alpha value of an image's pixel
|
||||
* @param dsc pointer to an image descriptor
|
||||
* @param x x coordinate of the point to set
|
||||
* @param y x coordinate of the point to set
|
||||
* @param safe true: check out of bounds
|
||||
* @return alpha value of the point
|
||||
*/
|
||||
lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y);
|
||||
|
||||
/**
|
||||
* Set the color of a pixel of an image. The alpha channel won't be affected.
|
||||
* @param dsc pointer to an image descriptor
|
||||
* @param x x coordinate of the point to set
|
||||
* @param y x coordinate of the point to set
|
||||
* @param c color of the point
|
||||
* @param safe true: check out of bounds
|
||||
*/
|
||||
void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c);
|
||||
|
||||
/**
|
||||
* Set the alpha value of a pixel of an image. The color won't be affected
|
||||
* @param dsc pointer to an image descriptor
|
||||
* @param x x coordinate of the point to set
|
||||
* @param y x coordinate of the point to set
|
||||
* @param opa the desired opacity
|
||||
* @param safe true: check out of bounds
|
||||
*/
|
||||
void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa);
|
||||
|
||||
/**
|
||||
* Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8`
|
||||
* @param dsc pointer to an image descriptor
|
||||
* @param id the palette color to set:
|
||||
* - for `LV_IMG_CF_INDEXED1`: 0..1
|
||||
* - for `LV_IMG_CF_INDEXED2`: 0..3
|
||||
* - for `LV_IMG_CF_INDEXED4`: 0..15
|
||||
* - for `LV_IMG_CF_INDEXED8`: 0..255
|
||||
* @param c the color to set
|
||||
*/
|
||||
void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c);
|
||||
|
||||
/**
|
||||
* Free an allocated image buffer
|
||||
* @param dsc image buffer to free
|
||||
*/
|
||||
void lv_img_buf_free(lv_img_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Get the memory consumption of a raw bitmap, given color format and dimensions.
|
||||
* @param w width
|
||||
* @param h height
|
||||
* @param cf color format
|
||||
* @return size in bytes
|
||||
*/
|
||||
uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf);
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
/**
|
||||
* Initialize a descriptor to rotate an image
|
||||
* @param dsc pointer to an `lv_img_transform_dsc_t` variable whose `cfg` field is initialized
|
||||
*/
|
||||
void _lv_img_buf_transform_init(lv_img_transform_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Continue transformation by taking the neighbors into account
|
||||
* @param dsc pointer to the transformation descriptor
|
||||
*/
|
||||
bool _lv_img_buf_transform_anti_alias(lv_img_transform_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Get which color and opa would come to a pixel if it were rotated
|
||||
* @param dsc a descriptor initialized by `lv_img_buf_rotate_init`
|
||||
* @param x the coordinate which color and opa should be get
|
||||
* @param y the coordinate which color and opa should be get
|
||||
* @return true: there is valid pixel on these x/y coordinates; false: the rotated pixel was out of the image
|
||||
* @note the result is written back to `dsc->res_color` and `dsc->res_opa`
|
||||
*/
|
||||
bool _lv_img_buf_transform(lv_img_transform_dsc_t * dsc, lv_coord_t x, lv_coord_t y);
|
||||
|
||||
#endif
|
||||
/**
|
||||
* Get the area of a rectangle if its rotated and scaled
|
||||
* @param res store the coordinates here
|
||||
* @param w width of the rectangle to transform
|
||||
* @param h height of the rectangle to transform
|
||||
* @param angle angle of rotation
|
||||
* @param zoom zoom, (256 no zoom)
|
||||
* @param pivot x,y pivot coordinates of rotation
|
||||
*/
|
||||
void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t h, int16_t angle, uint16_t zoom,
|
||||
const lv_point_t * pivot);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_IMG_BUF_H*/
|
215
MXC-A36/xrz/lvgl/src/draw/lv_img_cache.c
Normal file
215
MXC-A36/xrz/lvgl/src/draw/lv_img_cache.c
Normal file
@ -0,0 +1,215 @@
|
||||
/**
|
||||
* @file lv_img_cache.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "lv_img_cache.h"
|
||||
#include "lv_img_decoder.h"
|
||||
#include "lv_draw_img.h"
|
||||
#include "../hal/lv_hal_tick.h"
|
||||
#include "../misc/lv_gc.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
/*Decrement life with this value on every open*/
|
||||
#define LV_IMG_CACHE_AGING 1
|
||||
|
||||
/*Boost life by this factor (multiply time_to_open with this value)*/
|
||||
#define LV_IMG_CACHE_LIFE_GAIN 1
|
||||
|
||||
/*Don't let life to be greater than this limit because it would require a lot of time to
|
||||
* "die" from very high values*/
|
||||
#define LV_IMG_CACHE_LIFE_LIMIT 1000
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
#if LV_IMG_CACHE_DEF_SIZE
|
||||
static bool lv_img_cache_match(const void * src1, const void * src2);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
#if LV_IMG_CACHE_DEF_SIZE
|
||||
static uint16_t entry_cnt;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Open an image using the image decoder interface and cache it.
|
||||
* The image will be left open meaning if the image decoder open callback allocated memory then it will remain.
|
||||
* The image is closed if a new image is opened and the new image takes its place in the cache.
|
||||
* @param src source of the image. Path to file or pointer to an `lv_img_dsc_t` variable
|
||||
* @param color color The color of the image with `LV_IMG_CF_ALPHA_...`
|
||||
* @return pointer to the cache entry or NULL if can open the image
|
||||
*/
|
||||
_lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color, int32_t frame_id)
|
||||
{
|
||||
/*Is the image cached?*/
|
||||
_lv_img_cache_entry_t * cached_src = NULL;
|
||||
|
||||
#if LV_IMG_CACHE_DEF_SIZE
|
||||
if(entry_cnt == 0) {
|
||||
LV_LOG_WARN("lv_img_cache_open: the cache size is 0");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_lv_img_cache_entry_t * cache = LV_GC_ROOT(_lv_img_cache_array);
|
||||
|
||||
/*Decrement all lifes. Make the entries older*/
|
||||
uint16_t i;
|
||||
for(i = 0; i < entry_cnt; i++) {
|
||||
if(cache[i].life > INT32_MIN + LV_IMG_CACHE_AGING) {
|
||||
cache[i].life -= LV_IMG_CACHE_AGING;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < entry_cnt; i++) {
|
||||
if(color.full == cache[i].dec_dsc.color.full &&
|
||||
frame_id == cache[i].dec_dsc.frame_id &&
|
||||
lv_img_cache_match(src, cache[i].dec_dsc.src)) {
|
||||
/*If opened increment its life.
|
||||
*Image difficult to open should live longer to keep avoid frequent their recaching.
|
||||
*Therefore increase `life` with `time_to_open`*/
|
||||
cached_src = &cache[i];
|
||||
cached_src->life += cached_src->dec_dsc.time_to_open * LV_IMG_CACHE_LIFE_GAIN;
|
||||
if(cached_src->life > LV_IMG_CACHE_LIFE_LIMIT) cached_src->life = LV_IMG_CACHE_LIFE_LIMIT;
|
||||
LV_LOG_TRACE("image source found in the cache");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*The image is not cached then cache it now*/
|
||||
if(cached_src) return cached_src;
|
||||
|
||||
/*Find an entry to reuse. Select the entry with the least life*/
|
||||
cached_src = &cache[0];
|
||||
for(i = 1; i < entry_cnt; i++) {
|
||||
if(cache[i].life < cached_src->life) {
|
||||
cached_src = &cache[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*Close the decoder to reuse if it was opened (has a valid source)*/
|
||||
if(cached_src->dec_dsc.src) {
|
||||
lv_img_decoder_close(&cached_src->dec_dsc);
|
||||
LV_LOG_INFO("image draw: cache miss, close and reuse an entry");
|
||||
}
|
||||
else {
|
||||
LV_LOG_INFO("image draw: cache miss, cached to an empty entry");
|
||||
}
|
||||
#else
|
||||
cached_src = &LV_GC_ROOT(_lv_img_cache_single);
|
||||
#endif
|
||||
/*Open the image and measure the time to open*/
|
||||
uint32_t t_start = lv_tick_get();
|
||||
lv_res_t open_res = lv_img_decoder_open(&cached_src->dec_dsc, src, color, frame_id);
|
||||
if(open_res == LV_RES_INV) {
|
||||
LV_LOG_WARN("Image draw cannot open the image resource");
|
||||
lv_memset_00(cached_src, sizeof(_lv_img_cache_entry_t));
|
||||
cached_src->life = INT32_MIN; /*Make the empty entry very "weak" to force its us*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cached_src->life = 0;
|
||||
|
||||
/*If `time_to_open` was not set in the open function set it here*/
|
||||
if(cached_src->dec_dsc.time_to_open == 0) {
|
||||
cached_src->dec_dsc.time_to_open = lv_tick_elaps(t_start);
|
||||
}
|
||||
|
||||
if(cached_src->dec_dsc.time_to_open == 0) cached_src->dec_dsc.time_to_open = 1;
|
||||
|
||||
return cached_src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of images to be cached.
|
||||
* More cached images mean more opened image at same time which might mean more memory usage.
|
||||
* E.g. if 20 PNG or JPG images are open in the RAM they consume memory while opened in the cache.
|
||||
* @param new_entry_cnt number of image to cache
|
||||
*/
|
||||
void lv_img_cache_set_size(uint16_t new_entry_cnt)
|
||||
{
|
||||
#if LV_IMG_CACHE_DEF_SIZE == 0
|
||||
LV_UNUSED(new_entry_cnt);
|
||||
LV_LOG_WARN("Can't change cache size because it's disabled by LV_IMG_CACHE_DEF_SIZE = 0");
|
||||
#else
|
||||
if(LV_GC_ROOT(_lv_img_cache_array) != NULL) {
|
||||
/*Clean the cache before free it*/
|
||||
lv_img_cache_invalidate_src(NULL);
|
||||
lv_mem_free(LV_GC_ROOT(_lv_img_cache_array));
|
||||
}
|
||||
|
||||
/*Reallocate the cache*/
|
||||
LV_GC_ROOT(_lv_img_cache_array) = lv_mem_alloc(sizeof(_lv_img_cache_entry_t) * new_entry_cnt);
|
||||
LV_ASSERT_MALLOC(LV_GC_ROOT(_lv_img_cache_array));
|
||||
if(LV_GC_ROOT(_lv_img_cache_array) == NULL) {
|
||||
entry_cnt = 0;
|
||||
return;
|
||||
}
|
||||
entry_cnt = new_entry_cnt;
|
||||
|
||||
/*Clean the cache*/
|
||||
lv_memset_00(LV_GC_ROOT(_lv_img_cache_array), entry_cnt * sizeof(_lv_img_cache_entry_t));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate an image source in the cache.
|
||||
* Useful if the image source is updated therefore it needs to be cached again.
|
||||
* @param src an image source path to a file or pointer to an `lv_img_dsc_t` variable.
|
||||
*/
|
||||
void lv_img_cache_invalidate_src(const void * src)
|
||||
{
|
||||
LV_UNUSED(src);
|
||||
#if LV_IMG_CACHE_DEF_SIZE
|
||||
_lv_img_cache_entry_t * cache = LV_GC_ROOT(_lv_img_cache_array);
|
||||
|
||||
uint16_t i;
|
||||
for(i = 0; i < entry_cnt; i++) {
|
||||
if(src == NULL || lv_img_cache_match(src, cache[i].dec_dsc.src)) {
|
||||
if(cache[i].dec_dsc.src != NULL) {
|
||||
lv_img_decoder_close(&cache[i].dec_dsc);
|
||||
}
|
||||
|
||||
lv_memset_00(&cache[i], sizeof(_lv_img_cache_entry_t));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_IMG_CACHE_DEF_SIZE
|
||||
static bool lv_img_cache_match(const void * src1, const void * src2)
|
||||
{
|
||||
lv_img_src_t src_type = lv_img_src_get_type(src1);
|
||||
if(src_type == LV_IMG_SRC_VARIABLE)
|
||||
return src1 == src2;
|
||||
if(src_type != LV_IMG_SRC_FILE)
|
||||
return false;
|
||||
if(lv_img_src_get_type(src2) != LV_IMG_SRC_FILE)
|
||||
return false;
|
||||
return strcmp(src1, src2) == 0;
|
||||
}
|
||||
#endif
|
78
MXC-A36/xrz/lvgl/src/draw/lv_img_cache.h
Normal file
78
MXC-A36/xrz/lvgl/src/draw/lv_img_cache.h
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @file lv_img_cache.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_IMG_CACHE_H
|
||||
#define LV_IMG_CACHE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_img_decoder.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* When loading images from the network it can take a long time to download and decode the image.
|
||||
*
|
||||
* To avoid repeating this heavy load images can be cached.
|
||||
*/
|
||||
typedef struct {
|
||||
lv_img_decoder_dsc_t dec_dsc; /**< Image information*/
|
||||
|
||||
/** Count the cache entries's life. Add `time_to_open` to `life` when the entry is used.
|
||||
* Decrement all lifes by one every in every ::lv_img_cache_open.
|
||||
* If life == 0 the entry can be reused*/
|
||||
int32_t life;
|
||||
} _lv_img_cache_entry_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Open an image using the image decoder interface and cache it.
|
||||
* The image will be left open meaning if the image decoder open callback allocated memory then it will remain.
|
||||
* The image is closed if a new image is opened and the new image takes its place in the cache.
|
||||
* @param src source of the image. Path to file or pointer to an `lv_img_dsc_t` variable
|
||||
* @param color The color of the image with `LV_IMG_CF_ALPHA_...`
|
||||
* @param frame_id the index of the frame. Used only with animated images, set 0 for normal images
|
||||
* @return pointer to the cache entry or NULL if can open the image
|
||||
*/
|
||||
_lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color, int32_t frame_id);
|
||||
|
||||
/**
|
||||
* Set the number of images to be cached.
|
||||
* More cached images mean more opened image at same time which might mean more memory usage.
|
||||
* E.g. if 20 PNG or JPG images are open in the RAM they consume memory while opened in the cache.
|
||||
* @param new_entry_cnt number of image to cache
|
||||
*/
|
||||
void lv_img_cache_set_size(uint16_t new_slot_num);
|
||||
|
||||
/**
|
||||
* Invalidate an image source in the cache.
|
||||
* Useful if the image source is updated therefore it needs to be cached again.
|
||||
* @param src an image source path to a file or pointer to an `lv_img_dsc_t` variable.
|
||||
*/
|
||||
void lv_img_cache_invalidate_src(const void * src);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_IMG_CACHE_H*/
|
689
MXC-A36/xrz/lvgl/src/draw/lv_img_decoder.c
Normal file
689
MXC-A36/xrz/lvgl/src/draw/lv_img_decoder.c
Normal file
@ -0,0 +1,689 @@
|
||||
/**
|
||||
* @file lv_img_decoder.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_img_decoder.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "../draw/lv_draw_img.h"
|
||||
#include "../misc/lv_ll.h"
|
||||
#include "../misc/lv_gc.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define CF_BUILT_IN_FIRST LV_IMG_CF_TRUE_COLOR
|
||||
#define CF_BUILT_IN_LAST LV_IMG_CF_ALPHA_8BIT
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_fs_file_t f;
|
||||
lv_color_t * palette;
|
||||
lv_opa_t * opa;
|
||||
} lv_img_decoder_built_in_data_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
|
||||
lv_coord_t len, uint8_t * buf);
|
||||
static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
|
||||
lv_coord_t len, uint8_t * buf);
|
||||
static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
|
||||
lv_coord_t len, uint8_t * buf);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the image decoder module
|
||||
*/
|
||||
void _lv_img_decoder_init(void)
|
||||
{
|
||||
_lv_ll_init(&LV_GC_ROOT(_lv_img_decoder_ll), sizeof(lv_img_decoder_t));
|
||||
|
||||
lv_img_decoder_t * decoder;
|
||||
|
||||
/*Create a decoder for the built in color format*/
|
||||
decoder = lv_img_decoder_create();
|
||||
LV_ASSERT_MALLOC(decoder);
|
||||
if(decoder == NULL) {
|
||||
LV_LOG_WARN("lv_img_decoder_init: out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_img_decoder_set_info_cb(decoder, lv_img_decoder_built_in_info);
|
||||
lv_img_decoder_set_open_cb(decoder, lv_img_decoder_built_in_open);
|
||||
lv_img_decoder_set_read_line_cb(decoder, lv_img_decoder_built_in_read_line);
|
||||
lv_img_decoder_set_close_cb(decoder, lv_img_decoder_built_in_close);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about an image.
|
||||
* Try the created image decoder one by one. Once one is able to get info that info will be used.
|
||||
* @param src the image source. E.g. file name or variable.
|
||||
* @param header the image info will be stored here
|
||||
* @return LV_RES_OK: success; LV_RES_INV: wasn't able to get info about the image
|
||||
*/
|
||||
lv_res_t lv_img_decoder_get_info(const void * src, lv_img_header_t * header)
|
||||
{
|
||||
lv_memset_00(header, sizeof(lv_img_header_t));
|
||||
|
||||
lv_res_t res = LV_RES_INV;
|
||||
lv_img_decoder_t * d;
|
||||
_LV_LL_READ(&LV_GC_ROOT(_lv_img_decoder_ll), d) {
|
||||
if(d->info_cb) {
|
||||
res = d->info_cb(d, src, header);
|
||||
if(res == LV_RES_OK) break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
lv_res_t lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, lv_color_t color, int32_t frame_id)
|
||||
{
|
||||
lv_memset_00(dsc, sizeof(lv_img_decoder_dsc_t));
|
||||
|
||||
dsc->color = color;
|
||||
dsc->src_type = lv_img_src_get_type(src);
|
||||
dsc->frame_id = frame_id;
|
||||
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE) {
|
||||
size_t fnlen = strlen(src);
|
||||
dsc->src = lv_mem_alloc(fnlen + 1);
|
||||
LV_ASSERT_MALLOC(dsc->src);
|
||||
if(dsc->src == NULL) {
|
||||
LV_LOG_WARN("lv_img_decoder_open: out of memory");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
strcpy((char *)dsc->src, src);
|
||||
}
|
||||
else {
|
||||
dsc->src = src;
|
||||
}
|
||||
|
||||
lv_res_t res = LV_RES_INV;
|
||||
|
||||
lv_img_decoder_t * decoder;
|
||||
_LV_LL_READ(&LV_GC_ROOT(_lv_img_decoder_ll), decoder) {
|
||||
/*Info and Open callbacks are required*/
|
||||
if(decoder->info_cb == NULL || decoder->open_cb == NULL) continue;
|
||||
|
||||
res = decoder->info_cb(decoder, src, &dsc->header);
|
||||
if(res != LV_RES_OK) continue;
|
||||
|
||||
dsc->decoder = decoder;
|
||||
res = decoder->open_cb(decoder, dsc);
|
||||
|
||||
/*Opened successfully. It is a good decoder to for this image source*/
|
||||
if(res == LV_RES_OK) return res;
|
||||
|
||||
/*Prepare for the next loop*/
|
||||
lv_memset_00(&dsc->header, sizeof(lv_img_header_t));
|
||||
|
||||
dsc->error_msg = NULL;
|
||||
dsc->img_data = NULL;
|
||||
dsc->user_data = NULL;
|
||||
dsc->time_to_open = 0;
|
||||
}
|
||||
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE)
|
||||
lv_mem_free((void*)dsc->src);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a line from an opened image
|
||||
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
|
||||
* @param x start X coordinate (from left)
|
||||
* @param y start Y coordinate (from top)
|
||||
* @param len number of pixels to read
|
||||
* @param buf store the data here
|
||||
* @return LV_RES_OK: success; LV_RES_INV: an error occurred
|
||||
*/
|
||||
lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
lv_res_t res = LV_RES_INV;
|
||||
if(dsc->decoder->read_line_cb) res = dsc->decoder->read_line_cb(dsc->decoder, dsc, x, y, len, buf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a decoding session
|
||||
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
|
||||
*/
|
||||
void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->decoder) {
|
||||
if(dsc->decoder->close_cb) dsc->decoder->close_cb(dsc->decoder, dsc);
|
||||
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE) {
|
||||
lv_mem_free((void*)dsc->src);
|
||||
dsc->src = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new image decoder
|
||||
* @return pointer to the new image decoder
|
||||
*/
|
||||
lv_img_decoder_t * lv_img_decoder_create(void)
|
||||
{
|
||||
lv_img_decoder_t * decoder;
|
||||
decoder = _lv_ll_ins_head(&LV_GC_ROOT(_lv_img_decoder_ll));
|
||||
LV_ASSERT_MALLOC(decoder);
|
||||
if(decoder == NULL) return NULL;
|
||||
|
||||
lv_memset_00(decoder, sizeof(lv_img_decoder_t));
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an image decoder
|
||||
* @param decoder pointer to an image decoder
|
||||
*/
|
||||
void lv_img_decoder_delete(lv_img_decoder_t * decoder)
|
||||
{
|
||||
_lv_ll_remove(&LV_GC_ROOT(_lv_img_decoder_ll), decoder);
|
||||
lv_mem_free(decoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback to get information about the image
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param info_cb a function to collect info about an image (fill an `lv_img_header_t` struct)
|
||||
*/
|
||||
void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb)
|
||||
{
|
||||
decoder->info_cb = info_cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback to open an image
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param open_cb a function to open an image
|
||||
*/
|
||||
void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb)
|
||||
{
|
||||
decoder->open_cb = open_cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback to a decoded line of an image
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param read_line_cb a function to read a line of an image
|
||||
*/
|
||||
void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb)
|
||||
{
|
||||
decoder->read_line_cb = read_line_cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback to close a decoding session. E.g. close files and free other resources.
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param close_cb a function to close a decoding session
|
||||
*/
|
||||
void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb)
|
||||
{
|
||||
decoder->close_cb = close_cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get info about a built-in image
|
||||
* @param decoder the decoder where this function belongs
|
||||
* @param src the image source: pointer to an `lv_img_dsc_t` variable, a file path or a symbol
|
||||
* @param header store the image data here
|
||||
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
|
||||
{
|
||||
(void)decoder; /*Unused*/
|
||||
|
||||
lv_img_src_t src_type = lv_img_src_get_type(src);
|
||||
if(src_type == LV_IMG_SRC_VARIABLE) {
|
||||
lv_img_cf_t cf = ((lv_img_dsc_t *)src)->header.cf;
|
||||
if(cf < CF_BUILT_IN_FIRST || cf > CF_BUILT_IN_LAST) return LV_RES_INV;
|
||||
|
||||
header->w = ((lv_img_dsc_t *)src)->header.w;
|
||||
header->h = ((lv_img_dsc_t *)src)->header.h;
|
||||
header->cf = ((lv_img_dsc_t *)src)->header.cf;
|
||||
}
|
||||
else if(src_type == LV_IMG_SRC_FILE) {
|
||||
/*Support only "*.bin" files*/
|
||||
if(strcmp(lv_fs_get_ext(src), "bin")) return LV_RES_INV;
|
||||
|
||||
lv_fs_file_t f;
|
||||
lv_fs_res_t res = lv_fs_open(&f, src, LV_FS_MODE_RD);
|
||||
if(res == LV_FS_RES_OK) {
|
||||
uint32_t rn;
|
||||
res = lv_fs_read(&f, header, sizeof(lv_img_header_t), &rn);
|
||||
lv_fs_close(&f);
|
||||
if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) {
|
||||
LV_LOG_WARN("Image get info get read file header");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
}
|
||||
|
||||
if(header->cf < CF_BUILT_IN_FIRST || header->cf > CF_BUILT_IN_LAST) return LV_RES_INV;
|
||||
}
|
||||
else if(src_type == LV_IMG_SRC_SYMBOL) {
|
||||
/*The size depend on the font but it is unknown here. It should be handled outside of the
|
||||
*function*/
|
||||
header->w = 1;
|
||||
header->h = 1;
|
||||
/*Symbols always have transparent parts. Important because of cover check in the draw
|
||||
*function. The actual value doesn't matter because lv_draw_label will draw it*/
|
||||
header->cf = LV_IMG_CF_ALPHA_1BIT;
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Image get info found unknown src type");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a built in image
|
||||
* @param decoder the decoder where this function belongs
|
||||
* @param dsc pointer to decoder descriptor. `src`, `color` are already initialized in it.
|
||||
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
/*Open the file if it's a file*/
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE) {
|
||||
/*Support only "*.bin" files*/
|
||||
if(strcmp(lv_fs_get_ext(dsc->src), "bin")) return LV_RES_INV;
|
||||
|
||||
lv_fs_file_t f;
|
||||
lv_fs_res_t res = lv_fs_open(&f, dsc->src, LV_FS_MODE_RD);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_WARN("Built-in image decoder can't open the file");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
|
||||
/*If the file was open successfully save the file descriptor*/
|
||||
if(dsc->user_data == NULL) {
|
||||
dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
|
||||
LV_ASSERT_MALLOC(dsc->user_data);
|
||||
if(dsc->user_data == NULL) {
|
||||
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
|
||||
lv_fs_close(&f);
|
||||
return LV_RES_INV;
|
||||
}
|
||||
lv_memset_00(dsc->user_data, sizeof(lv_img_decoder_built_in_data_t));
|
||||
}
|
||||
|
||||
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
|
||||
lv_memcpy_small(&user_data->f, &f, sizeof(f));
|
||||
}
|
||||
else if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
|
||||
/*The variables should have valid data*/
|
||||
if(((lv_img_dsc_t *)dsc->src)->data == NULL) {
|
||||
return LV_RES_INV;
|
||||
}
|
||||
}
|
||||
|
||||
lv_img_cf_t cf = dsc->header.cf;
|
||||
/*Process true color formats*/
|
||||
if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
||||
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
|
||||
/*In case of uncompressed formats the image stored in the ROM/RAM.
|
||||
*So simply give its pointer*/
|
||||
dsc->img_data = ((lv_img_dsc_t *)dsc->src)->data;
|
||||
return LV_RES_OK;
|
||||
}
|
||||
else {
|
||||
/*If it's a file it need to be read line by line later*/
|
||||
return LV_RES_OK;
|
||||
}
|
||||
}
|
||||
/*Process indexed images. Build a palette*/
|
||||
else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT || cf == LV_IMG_CF_INDEXED_4BIT ||
|
||||
cf == LV_IMG_CF_INDEXED_8BIT) {
|
||||
uint8_t px_size = lv_img_cf_get_px_size(cf);
|
||||
uint32_t palette_size = 1 << px_size;
|
||||
|
||||
/*Allocate the palette*/
|
||||
if(dsc->user_data == NULL) {
|
||||
dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
|
||||
LV_ASSERT_MALLOC(dsc->user_data);
|
||||
if(dsc->user_data == NULL) {
|
||||
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
lv_memset_00(dsc->user_data, sizeof(lv_img_decoder_built_in_data_t));
|
||||
}
|
||||
|
||||
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
|
||||
user_data->palette = lv_mem_alloc(palette_size * sizeof(lv_color_t));
|
||||
LV_ASSERT_MALLOC(user_data->palette);
|
||||
user_data->opa = lv_mem_alloc(palette_size * sizeof(lv_opa_t));
|
||||
LV_ASSERT_MALLOC(user_data->opa);
|
||||
if(user_data->palette == NULL || user_data->opa == NULL) {
|
||||
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
|
||||
lv_img_decoder_built_in_close(decoder, dsc);
|
||||
return LV_RES_INV;
|
||||
}
|
||||
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE) {
|
||||
/*Read the palette from file*/
|
||||
lv_fs_seek(&user_data->f, 4, LV_FS_SEEK_SET); /*Skip the header*/
|
||||
lv_color32_t cur_color;
|
||||
uint32_t i;
|
||||
for(i = 0; i < palette_size; i++) {
|
||||
lv_fs_read(&user_data->f, &cur_color, sizeof(lv_color32_t), NULL);
|
||||
user_data->palette[i] = lv_color_make(cur_color.ch.red, cur_color.ch.green, cur_color.ch.blue);
|
||||
user_data->opa[i] = cur_color.ch.alpha;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*The palette begins in the beginning of the image data. Just point to it.*/
|
||||
lv_color32_t * palette_p = (lv_color32_t *)((lv_img_dsc_t *)dsc->src)->data;
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; i < palette_size; i++) {
|
||||
user_data->palette[i] = lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue);
|
||||
user_data->opa[i] = palette_p[i].ch.alpha;
|
||||
}
|
||||
}
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
/*Alpha indexed images.*/
|
||||
else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT || cf == LV_IMG_CF_ALPHA_4BIT ||
|
||||
cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
return LV_RES_OK; /*Nothing to process*/
|
||||
}
|
||||
/*Unknown format. Can't decode it.*/
|
||||
else {
|
||||
/*Free the potentially allocated memories*/
|
||||
lv_img_decoder_built_in_close(decoder, dsc);
|
||||
|
||||
LV_LOG_WARN("Image decoder open: unknown color format")
|
||||
return LV_RES_INV;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
|
||||
* Required only if the "open" function can't return with the whole decoded pixel array.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
* @param x start x coordinate
|
||||
* @param y start y coordinate
|
||||
* @param len number of pixels to decode
|
||||
* @param buf a buffer to store the decoded pixels
|
||||
* @return LV_RES_OK: ok; LV_RES_INV: failed
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
|
||||
lv_coord_t y, lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
(void)decoder; /*Unused*/
|
||||
|
||||
lv_res_t res = LV_RES_INV;
|
||||
|
||||
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
|
||||
dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
||||
/*For TRUE_COLOR images read line required only for files.
|
||||
*For variables the image data was returned in `open`*/
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE) {
|
||||
res = lv_img_decoder_built_in_line_true_color(dsc, x, y, len, buf);
|
||||
}
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
|
||||
dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
res = lv_img_decoder_built_in_line_alpha(dsc, x, y, len, buf);
|
||||
}
|
||||
else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || dsc->header.cf == LV_IMG_CF_INDEXED_2BIT ||
|
||||
dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
|
||||
res = lv_img_decoder_built_in_line_indexed(dsc, x, y, len, buf);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Built-in image decoder read not supports the color format");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the pending decoding. Free resources etc.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
*/
|
||||
void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
(void)decoder; /*Unused*/
|
||||
|
||||
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
|
||||
if(user_data) {
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE) {
|
||||
lv_fs_close(&user_data->f);
|
||||
}
|
||||
if(user_data->palette) lv_mem_free(user_data->palette);
|
||||
if(user_data->opa) lv_mem_free(user_data->opa);
|
||||
|
||||
lv_mem_free(user_data);
|
||||
dsc->user_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
|
||||
lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
|
||||
lv_fs_res_t res;
|
||||
uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf);
|
||||
|
||||
uint32_t pos = ((y * dsc->header.w + x) * px_size) >> 3;
|
||||
pos += 4; /*Skip the header*/
|
||||
res = lv_fs_seek(&user_data->f, pos, LV_FS_SEEK_SET);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_WARN("Built-in image decoder seek failed");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
uint32_t btr = len * (px_size >> 3);
|
||||
uint32_t br = 0;
|
||||
res = lv_fs_read(&user_data->f, buf, btr, &br);
|
||||
if(res != LV_FS_RES_OK || btr != br) {
|
||||
LV_LOG_WARN("Built-in image decoder read failed");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
|
||||
lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
const lv_opa_t alpha1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
|
||||
const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
|
||||
const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
|
||||
68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
|
||||
};
|
||||
|
||||
/*Simply fill the buffer with the color. Later only the alpha value will be modified.*/
|
||||
lv_color_t bg_color = dsc->color;
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < len; i++) {
|
||||
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF;
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
*((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full;
|
||||
#else
|
||||
#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
const lv_opa_t * opa_table = NULL;
|
||||
uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf);
|
||||
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
|
||||
|
||||
lv_coord_t w = 0;
|
||||
uint32_t ofs = 0;
|
||||
int8_t pos = 0;
|
||||
switch(dsc->header.cf) {
|
||||
case LV_IMG_CF_ALPHA_1BIT:
|
||||
w = (dsc->header.w + 7) >> 3; /*E.g. w = 20 -> w = 2 + 1*/
|
||||
ofs += w * y + (x >> 3); /*First pixel*/
|
||||
pos = 7 - (x & 0x7);
|
||||
opa_table = alpha1_opa_table;
|
||||
break;
|
||||
case LV_IMG_CF_ALPHA_2BIT:
|
||||
w = (dsc->header.w + 3) >> 2; /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
|
||||
ofs += w * y + (x >> 2); /*First pixel*/
|
||||
pos = 6 - (x & 0x3) * 2;
|
||||
opa_table = alpha2_opa_table;
|
||||
break;
|
||||
case LV_IMG_CF_ALPHA_4BIT:
|
||||
w = (dsc->header.w + 1) >> 1; /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
|
||||
ofs += w * y + (x >> 1); /*First pixel*/
|
||||
pos = 4 - (x & 0x1) * 4;
|
||||
opa_table = alpha4_opa_table;
|
||||
break;
|
||||
case LV_IMG_CF_ALPHA_8BIT:
|
||||
w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
|
||||
ofs += w * y + x; /*First pixel*/
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
|
||||
uint8_t * fs_buf = lv_mem_buf_get(w);
|
||||
if (fs_buf == NULL) return LV_RES_INV;
|
||||
|
||||
const uint8_t * data_tmp = NULL;
|
||||
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
|
||||
const lv_img_dsc_t * img_dsc = dsc->src;
|
||||
|
||||
data_tmp = img_dsc->data + ofs;
|
||||
}
|
||||
else {
|
||||
lv_fs_seek(&user_data->f, ofs + 4, LV_FS_SEEK_SET); /*+4 to skip the header*/
|
||||
lv_fs_read(&user_data->f, fs_buf, w, NULL);
|
||||
data_tmp = fs_buf;
|
||||
}
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
uint8_t val_act = (*data_tmp >> pos) & mask;
|
||||
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] =
|
||||
dsc->header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act];
|
||||
|
||||
pos -= px_size;
|
||||
if(pos < 0) {
|
||||
pos = 8 - px_size;
|
||||
data_tmp++;
|
||||
}
|
||||
}
|
||||
lv_mem_buf_release(fs_buf);
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
|
||||
lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf);
|
||||
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
|
||||
|
||||
lv_coord_t w = 0;
|
||||
int8_t pos = 0;
|
||||
uint32_t ofs = 0;
|
||||
switch(dsc->header.cf) {
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
w = (dsc->header.w + 7) >> 3; /*E.g. w = 20 -> w = 2 + 1*/
|
||||
ofs += w * y + (x >> 3); /*First pixel*/
|
||||
ofs += 8; /*Skip the palette*/
|
||||
pos = 7 - (x & 0x7);
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
w = (dsc->header.w + 3) >> 2; /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
|
||||
ofs += w * y + (x >> 2); /*First pixel*/
|
||||
ofs += 16; /*Skip the palette*/
|
||||
pos = 6 - (x & 0x3) * 2;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
w = (dsc->header.w + 1) >> 1; /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
|
||||
ofs += w * y + (x >> 1); /*First pixel*/
|
||||
ofs += 64; /*Skip the palette*/
|
||||
pos = 4 - (x & 0x1) * 4;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
|
||||
ofs += w * y + x; /*First pixel*/
|
||||
ofs += 1024; /*Skip the palette*/
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
|
||||
|
||||
uint8_t * fs_buf = lv_mem_buf_get(w);
|
||||
if (fs_buf == NULL) return LV_RES_INV;
|
||||
const uint8_t * data_tmp = NULL;
|
||||
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
|
||||
const lv_img_dsc_t * img_dsc = dsc->src;
|
||||
data_tmp = img_dsc->data + ofs;
|
||||
}
|
||||
else {
|
||||
lv_fs_seek(&user_data->f, ofs + 4, LV_FS_SEEK_SET); /*+4 to skip the header*/
|
||||
lv_fs_read(&user_data->f, fs_buf, w, NULL);
|
||||
data_tmp = fs_buf;
|
||||
}
|
||||
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < len; i++) {
|
||||
uint8_t val_act = (*data_tmp >> pos) & mask;
|
||||
|
||||
lv_color_t color = user_data->palette[val_act];
|
||||
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full & 0xFF;
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (color.full >> 8) & 0xFF;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
*((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = color.full;
|
||||
#else
|
||||
#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
|
||||
#endif
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = user_data->opa[val_act];
|
||||
|
||||
pos -= px_size;
|
||||
if(pos < 0) {
|
||||
pos = 8 - px_size;
|
||||
data_tmp++;
|
||||
}
|
||||
}
|
||||
lv_mem_buf_release(fs_buf);
|
||||
return LV_RES_OK;
|
||||
}
|
274
MXC-A36/xrz/lvgl/src/draw/lv_img_decoder.h
Normal file
274
MXC-A36/xrz/lvgl/src/draw/lv_img_decoder.h
Normal file
@ -0,0 +1,274 @@
|
||||
/**
|
||||
* @file lv_img_decoder.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_IMG_DECODER_H
|
||||
#define LV_IMG_DECODER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include "lv_img_buf.h"
|
||||
#include "../misc/lv_fs.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Source of image.*/
|
||||
enum {
|
||||
LV_IMG_SRC_VARIABLE, /** Binary/C variable*/
|
||||
LV_IMG_SRC_FILE, /** File in filesystem*/
|
||||
LV_IMG_SRC_SYMBOL, /** Symbol (@ref lv_symbol_def.h)*/
|
||||
LV_IMG_SRC_UNKNOWN, /** Unknown source*/
|
||||
};
|
||||
|
||||
typedef uint8_t lv_img_src_t;
|
||||
|
||||
/*Decoder function definitions*/
|
||||
struct _lv_img_decoder_dsc_t;
|
||||
struct _lv_img_decoder_t;
|
||||
|
||||
/**
|
||||
* Get info from an image and store in the `header`
|
||||
* @param src the image source. Can be a pointer to a C array or a file name (Use
|
||||
* `lv_img_src_get_type` to determine the type)
|
||||
* @param header store the info here
|
||||
* @return LV_RES_OK: info written correctly; LV_RES_INV: failed
|
||||
*/
|
||||
typedef lv_res_t (*lv_img_decoder_info_f_t)(struct _lv_img_decoder_t * decoder, const void * src,
|
||||
lv_img_header_t * header);
|
||||
|
||||
/**
|
||||
* Open an image for decoding. Prepare it as it is required to read it later
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor. `src`, `color` are already initialized in it.
|
||||
*/
|
||||
typedef lv_res_t (*lv_img_decoder_open_f_t)(struct _lv_img_decoder_t * decoder, struct _lv_img_decoder_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
|
||||
* Required only if the "open" function can't return with the whole decoded pixel array.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
* @param x start x coordinate
|
||||
* @param y start y coordinate
|
||||
* @param len number of pixels to decode
|
||||
* @param buf a buffer to store the decoded pixels
|
||||
* @return LV_RES_OK: ok; LV_RES_INV: failed
|
||||
*/
|
||||
typedef lv_res_t (*lv_img_decoder_read_line_f_t)(struct _lv_img_decoder_t * decoder, struct _lv_img_decoder_dsc_t * dsc,
|
||||
lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
|
||||
|
||||
/**
|
||||
* Close the pending decoding. Free resources etc.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
*/
|
||||
typedef void (*lv_img_decoder_close_f_t)(struct _lv_img_decoder_t * decoder, struct _lv_img_decoder_dsc_t * dsc);
|
||||
|
||||
|
||||
typedef struct _lv_img_decoder_t {
|
||||
lv_img_decoder_info_f_t info_cb;
|
||||
lv_img_decoder_open_f_t open_cb;
|
||||
lv_img_decoder_read_line_f_t read_line_cb;
|
||||
lv_img_decoder_close_f_t close_cb;
|
||||
|
||||
#if LV_USE_USER_DATA
|
||||
void * user_data;
|
||||
#endif
|
||||
} lv_img_decoder_t;
|
||||
|
||||
|
||||
/**Describe an image decoding session. Stores data about the decoding*/
|
||||
typedef struct _lv_img_decoder_dsc_t {
|
||||
/**The decoder which was able to open the image source*/
|
||||
lv_img_decoder_t * decoder;
|
||||
|
||||
/**The image source. A file path like "S:my_img.png" or pointer to an `lv_img_dsc_t` variable*/
|
||||
const void * src;
|
||||
|
||||
/**Color to draw the image. USed when the image has alpha channel only*/
|
||||
lv_color_t color;
|
||||
|
||||
/**Frame of the image, using with animated images*/
|
||||
int32_t frame_id;
|
||||
|
||||
/**Type of the source: file or variable. Can be set in `open` function if required*/
|
||||
lv_img_src_t src_type;
|
||||
|
||||
/**Info about the opened image: color format, size, etc. MUST be set in `open` function*/
|
||||
lv_img_header_t header;
|
||||
|
||||
/** Pointer to a buffer where the image's data (pixels) are stored in a decoded, plain format.
|
||||
* MUST be set in `open` function*/
|
||||
const uint8_t * img_data;
|
||||
|
||||
/** How much time did it take to open the image. [ms]
|
||||
* If not set `lv_img_cache` will measure and set the time to open*/
|
||||
uint32_t time_to_open;
|
||||
|
||||
/**A text to display instead of the image when the image can't be opened.
|
||||
* Can be set in `open` function or set NULL.*/
|
||||
const char * error_msg;
|
||||
|
||||
/**Store any custom data here is required*/
|
||||
void * user_data;
|
||||
} lv_img_decoder_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the image decoder module
|
||||
*/
|
||||
void _lv_img_decoder_init(void);
|
||||
|
||||
/**
|
||||
* Get information about an image.
|
||||
* Try the created image decoder one by one. Once one is able to get info that info will be used.
|
||||
* @param src the image source. Can be
|
||||
* 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_add_drv()`)
|
||||
* 2) Variable: Pointer to an `lv_img_dsc_t` variable
|
||||
* 3) Symbol: E.g. `LV_SYMBOL_OK`
|
||||
* @param header the image info will be stored here
|
||||
* @return LV_RES_OK: success; LV_RES_INV: wasn't able to get info about the image
|
||||
*/
|
||||
lv_res_t lv_img_decoder_get_info(const void * src, lv_img_header_t * header);
|
||||
|
||||
/**
|
||||
* Open an image.
|
||||
* Try the created image decoder one by one. Once one is able to open the image that decoder is save in `dsc`
|
||||
* @param dsc describe a decoding session. Simply a pointer to an `lv_img_decoder_dsc_t` variable.
|
||||
* @param src the image source. Can be
|
||||
* 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_add_drv()`)
|
||||
* 2) Variable: Pointer to an `lv_img_dsc_t` variable
|
||||
* 3) Symbol: E.g. `LV_SYMBOL_OK`
|
||||
* @param color The color of the image with `LV_IMG_CF_ALPHA_...`
|
||||
* @param frame_id the index of the frame. Used only with animated images, set 0 for normal images
|
||||
* @return LV_RES_OK: opened the image. `dsc->img_data` and `dsc->header` are set.
|
||||
* LV_RES_INV: none of the registered image decoders were able to open the image.
|
||||
*/
|
||||
lv_res_t lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, lv_color_t color, int32_t frame_id);
|
||||
|
||||
/**
|
||||
* Read a line from an opened image
|
||||
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
|
||||
* @param x start X coordinate (from left)
|
||||
* @param y start Y coordinate (from top)
|
||||
* @param len number of pixels to read
|
||||
* @param buf store the data here
|
||||
* @return LV_RES_OK: success; LV_RES_INV: an error occurred
|
||||
*/
|
||||
lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len,
|
||||
uint8_t * buf);
|
||||
|
||||
/**
|
||||
* Close a decoding session
|
||||
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
|
||||
*/
|
||||
void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Create a new image decoder
|
||||
* @return pointer to the new image decoder
|
||||
*/
|
||||
lv_img_decoder_t * lv_img_decoder_create(void);
|
||||
|
||||
/**
|
||||
* Delete an image decoder
|
||||
* @param decoder pointer to an image decoder
|
||||
*/
|
||||
void lv_img_decoder_delete(lv_img_decoder_t * decoder);
|
||||
|
||||
/**
|
||||
* Set a callback to get information about the image
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param info_cb a function to collect info about an image (fill an `lv_img_header_t` struct)
|
||||
*/
|
||||
void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb);
|
||||
|
||||
/**
|
||||
* Set a callback to open an image
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param open_cb a function to open an image
|
||||
*/
|
||||
void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb);
|
||||
|
||||
/**
|
||||
* Set a callback to a decoded line of an image
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param read_line_cb a function to read a line of an image
|
||||
*/
|
||||
void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb);
|
||||
|
||||
/**
|
||||
* Set a callback to close a decoding session. E.g. close files and free other resources.
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param close_cb a function to close a decoding session
|
||||
*/
|
||||
void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb);
|
||||
|
||||
/**
|
||||
* Get info about a built-in image
|
||||
* @param decoder the decoder where this function belongs
|
||||
* @param src the image source: pointer to an `lv_img_dsc_t` variable, a file path or a symbol
|
||||
* @param header store the image data here
|
||||
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
|
||||
|
||||
/**
|
||||
* Open a built in image
|
||||
* @param decoder the decoder where this function belongs
|
||||
* @param dsc pointer to decoder descriptor. `src`, `style` are already initialized in it.
|
||||
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
|
||||
* Required only if the "open" function can't return with the whole decoded pixel array.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
* @param x start x coordinate
|
||||
* @param y start y coordinate
|
||||
* @param len number of pixels to decode
|
||||
* @param buf a buffer to store the decoded pixels
|
||||
* @return LV_RES_OK: ok; LV_RES_INV: failed
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
|
||||
lv_coord_t y, lv_coord_t len, uint8_t * buf);
|
||||
|
||||
/**
|
||||
* Close the pending decoding. Free resources etc.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
*/
|
||||
void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_IMG_DECODER_H*/
|
Reference in New Issue
Block a user