feat(draw): support transforming widgets and improfe sw transform
For details see: https://docs.lvgl.io/master/overview/style.html
This commit is contained in:
@@ -27,6 +27,7 @@ extern "C" {
|
||||
#include "lv_draw_triangle.h"
|
||||
#include "lv_draw_arc.h"
|
||||
#include "lv_draw_mask.h"
|
||||
#include "lv_draw_transform.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -80,6 +81,24 @@ typedef struct _lv_draw_ctx_t {
|
||||
void (*draw_polygon)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc,
|
||||
const lv_point_t * points, uint16_t point_cnt);
|
||||
|
||||
|
||||
/**
|
||||
* Get an area of a transformed image (zoomed and/or rotated)
|
||||
* @param draw_ctx pointer to a draw context
|
||||
* @param dest_area get this area of the result image. It assumes that the original image is placed to the 0;0 position.
|
||||
* @param src_buf the source image
|
||||
* @param src_w width of the source image in [px]
|
||||
* @param src_h height of the source image in [px]
|
||||
* @param src_stride the stride in [px].
|
||||
* @param draw_dsc an `lv_draw_img_dsc_t` descriptor containing the transformation parameters
|
||||
* @param cf the color format of `src_buf`
|
||||
* @param cbuf place the colors of the pixels on `dest_area` here in RGB format
|
||||
* @param abuf place the opacity of the pixels on `dest_area` here
|
||||
*/
|
||||
void (*draw_transform)(struct _lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
|
||||
lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
|
||||
const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
|
||||
|
||||
/**
|
||||
* Replace the buffer with a rect without decoration like radius or borders
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ extern "C" {
|
||||
|
||||
typedef struct {
|
||||
|
||||
uint16_t angle;
|
||||
int16_t angle;
|
||||
uint16_t zoom;
|
||||
lv_point_t pivot;
|
||||
|
||||
|
||||
54
src/draw/lv_draw_transform.c
Normal file
54
src/draw/lv_draw_transform.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @file lv_draw_transform.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
#include "lv_draw_transform.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "../misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void lv_draw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w,
|
||||
lv_coord_t src_h,
|
||||
lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_ctx);
|
||||
if(draw_ctx->draw_transform == NULL) {
|
||||
LV_LOG_WARN("draw_ctx->draw_transform == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
draw_ctx->draw_transform(draw_ctx, dest_area, src_buf, src_w, src_h, src_stride, draw_dsc, cf, cbuf, abuf);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
44
src/draw/lv_draw_transform.h
Normal file
44
src/draw/lv_draw_transform.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @file lv_draw_transform.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_TRANSFORM_H
|
||||
#define LV_DRAW_TRANSFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
#include "../misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
struct _lv_draw_ctx_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_transform(struct _lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
|
||||
lv_coord_t src_w, lv_coord_t src_h,
|
||||
lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_TRANSFORM_H*/
|
||||
@@ -410,58 +410,6 @@ 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 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
|
||||
@@ -483,68 +431,21 @@ void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t
|
||||
return;
|
||||
}
|
||||
|
||||
res->x1 = (((int32_t)(-pivot->x) * zoom) >> 8) - 1;
|
||||
res->y1 = (((int32_t)(-pivot->y) * zoom) >> 8) - 1;
|
||||
res->x2 = (((int32_t)(w - pivot->x) * zoom) >> 8) + 2;
|
||||
res->y2 = (((int32_t)(h - pivot->y) * zoom) >> 8) + 2;
|
||||
lv_point_t p[4] = {
|
||||
{0, 0},
|
||||
{w - 1, 0},
|
||||
{0, h - 1},
|
||||
{w - 1, h - 1},
|
||||
};
|
||||
lv_point_transform(&p[0], angle, zoom, pivot);
|
||||
lv_point_transform(&p[1], angle, zoom, pivot);
|
||||
lv_point_transform(&p[2], angle, zoom, pivot);
|
||||
lv_point_transform(&p[3], angle, zoom, pivot);
|
||||
res->x1 = LV_MIN4(p[0].x, p[1].x, p[2].x, p[3].x) - 2;
|
||||
res->x2 = LV_MAX4(p[0].x, p[1].x, p[2].x, p[3].x) + 2;
|
||||
res->y1 = LV_MIN4(p[0].y, p[1].y, p[2].y, p[3].y) - 2;
|
||||
res->y2 = LV_MAX4(p[0].y, p[1].y, p[2].y, p[3].y) + 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);
|
||||
@@ -556,217 +457,6 @@ void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t
|
||||
#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
|
||||
**********************/
|
||||
|
||||
@@ -45,7 +45,6 @@ extern "C" {
|
||||
#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
|
||||
|
||||
/**********************
|
||||
@@ -77,6 +76,13 @@ enum {
|
||||
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_RGB888,
|
||||
LV_IMG_CF_RGBA8888,
|
||||
LV_IMG_CF_RGBX8888,
|
||||
LV_IMG_CF_RGB565,
|
||||
LV_IMG_CF_RGBA5658,
|
||||
LV_IMG_CF_RGB565A8,
|
||||
|
||||
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.*/
|
||||
@@ -138,49 +144,6 @@ typedef struct {
|
||||
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
|
||||
**********************/
|
||||
@@ -263,30 +226,6 @@ void lv_img_buf_free(lv_img_dsc_t * dsc);
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define CF_BUILT_IN_FIRST LV_IMG_CF_TRUE_COLOR
|
||||
#define CF_BUILT_IN_LAST LV_IMG_CF_ALPHA_8BIT
|
||||
#define CF_BUILT_IN_FIRST LV_IMG_CF_TRUE_COLOR
|
||||
#define CF_BUILT_IN_LAST LV_IMG_CF_RGB565A8
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
|
||||
@@ -51,6 +51,9 @@ void lv_draw_sw_init_ctx(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
|
||||
draw_sw_ctx->base_draw.draw_img_decoded = lv_draw_sw_img_decoded;
|
||||
draw_sw_ctx->base_draw.draw_line = lv_draw_sw_line;
|
||||
draw_sw_ctx->base_draw.draw_polygon = lv_draw_sw_polygon;
|
||||
#if LV_DRAW_COMPLEX
|
||||
draw_sw_ctx->base_draw.draw_transform = lv_draw_sw_transform;
|
||||
#endif
|
||||
draw_sw_ctx->base_draw.wait_for_finish = lv_draw_sw_wait_for_finish;
|
||||
draw_sw_ctx->base_draw.buffer_copy = lv_draw_sw_buffer_copy;
|
||||
draw_sw_ctx->blend = lv_draw_sw_blend_basic;
|
||||
|
||||
@@ -66,6 +66,12 @@ void lv_draw_sw_polygon(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc
|
||||
void lv_draw_sw_buffer_copy(lv_draw_ctx_t * draw_ctx,
|
||||
void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area,
|
||||
void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area);
|
||||
|
||||
|
||||
void lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
|
||||
lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
|
||||
const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
|
||||
|
||||
/***********************
|
||||
* GLOBAL VARIABLES
|
||||
***********************/
|
||||
|
||||
@@ -25,8 +25,16 @@
|
||||
|
||||
static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride,
|
||||
lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide);
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
|
||||
lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
|
||||
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
LV_ATTRIBUTE_FAST_MEM static void fill_argb(lv_color_t * dest_buf, const lv_area_t * dest_area,
|
||||
lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
|
||||
#endif /*LV_COLOR_SCREEN_TRANSP*/
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, lv_color_t color,
|
||||
lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode);
|
||||
@@ -38,6 +46,12 @@ static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_co
|
||||
LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
LV_ATTRIBUTE_FAST_MEM static void map_argb(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
|
||||
|
||||
#endif /*LV_COLOR_SCREEN_TRANSP*/
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
|
||||
@@ -55,22 +69,12 @@ static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#if LV_COLOR_SCREEN_TRANSP == 0
|
||||
#define FILL_NORMAL_MASK_PX(color) \
|
||||
if(*mask == LV_OPA_COVER) *dest_buf = color; \
|
||||
else *dest_buf = lv_color_mix(color, *dest_buf, *mask); \
|
||||
mask++; \
|
||||
dest_buf++;
|
||||
|
||||
#else
|
||||
#define FILL_NORMAL_MASK_PX(color) \
|
||||
if(*mask == LV_OPA_COVER) *dest_buf = color; \
|
||||
else if(disp->driver->screen_transp) lv_color_mix_with_alpha(*dest_buf, dest_buf->ch.alpha, color, *mask, dest_buf, &dest_buf->ch.alpha); \
|
||||
else *dest_buf = lv_color_mix(color, *dest_buf, *mask); \
|
||||
mask++; \
|
||||
dest_buf++;
|
||||
#endif
|
||||
|
||||
#define MAP_NORMAL_MASK_PX(x) \
|
||||
if(*mask_tmp_x) { \
|
||||
if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x]; \
|
||||
@@ -78,15 +82,6 @@ static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color
|
||||
} \
|
||||
mask_tmp_x++;
|
||||
|
||||
#define MAP_NORMAL_MASK_PX_SCR_TRANSP(x) \
|
||||
if(*mask_tmp_x) { \
|
||||
if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x]; \
|
||||
else if(disp->driver->screen_transp) lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, \
|
||||
src_buf[x], *mask_tmp_x, &dest_buf[x], &dest_buf[x].ch.alpha); \
|
||||
else dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], *mask_tmp_x); \
|
||||
} \
|
||||
mask_tmp_x++;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
@@ -121,9 +116,19 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, cons
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
lv_color_t * dest_buf = draw_ctx->buf;
|
||||
if(disp->driver->set_px_cb == NULL) {
|
||||
dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
|
||||
if(disp->driver->screen_transp == 0) {
|
||||
dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
|
||||
}
|
||||
else {
|
||||
/*With LV_COLOR_DEPTH 16 it means ARGB8565 (3 bytes format)*/
|
||||
uint8_t * dest_buf8 = (uint8_t *) dest_buf;
|
||||
dest_buf8 += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
dest_buf8 += (blend_area.x1 - draw_ctx->buf_area->x1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
dest_buf = (lv_color_t *)dest_buf8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const lv_color_t * src_buf = dsc->src_buf;
|
||||
lv_coord_t src_stride;
|
||||
if(src_buf) {
|
||||
@@ -154,21 +159,29 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, cons
|
||||
map_set_px(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
|
||||
}
|
||||
}
|
||||
else if(dsc->src_buf == NULL) {
|
||||
if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
else if(disp->driver->screen_transp) {
|
||||
if(dsc->src_buf == NULL) {
|
||||
fill_argb(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
|
||||
}
|
||||
else {
|
||||
map_argb(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
if(dsc->src_buf == NULL) {
|
||||
fill_normal(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
|
||||
}
|
||||
#if LV_DRAW_COMPLEX
|
||||
else {
|
||||
fill_blended(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride, dsc->blend_mode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
map_normal(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if LV_DRAW_COMPLEX
|
||||
if(dsc->src_buf == NULL) {
|
||||
fill_blended(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride, dsc->blend_mode);
|
||||
}
|
||||
else {
|
||||
map_blended(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride, dsc->blend_mode);
|
||||
}
|
||||
@@ -203,6 +216,8 @@ static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
if(mask[x]) {
|
||||
|
||||
|
||||
disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, blend_area->x1 + x, blend_area->y1 + y, color,
|
||||
(uint32_t)((uint32_t)opa * mask[x]) >> 8);
|
||||
}
|
||||
@@ -215,7 +230,6 @@ static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_
|
||||
LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
|
||||
lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
|
||||
{
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
int32_t w = lv_area_get_width(dest_area);
|
||||
int32_t h = lv_area_get_height(dest_area);
|
||||
|
||||
@@ -243,19 +257,7 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_ar
|
||||
for(x = 0; x < w; x++) {
|
||||
if(last_dest_color.full != dest_buf[x].full) {
|
||||
last_dest_color = dest_buf[x];
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
if(disp->driver->screen_transp) {
|
||||
lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, color, opa, &last_res_color,
|
||||
&last_res_color.ch.alpha);
|
||||
}
|
||||
else
|
||||
#else
|
||||
LV_UNUSED(disp);
|
||||
#endif
|
||||
{
|
||||
last_res_color = lv_color_mix_premult(color_premult, dest_buf[x], opa_inv);
|
||||
}
|
||||
last_res_color = lv_color_mix_premult(color_premult, dest_buf[x], opa_inv);
|
||||
}
|
||||
dest_buf[x] = last_res_color;
|
||||
}
|
||||
@@ -335,17 +337,8 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_ar
|
||||
if(*mask != last_mask) opa_tmp = *mask == LV_OPA_COVER ? opa :
|
||||
(uint32_t)((uint32_t)(*mask) * opa) >> 8;
|
||||
if(*mask != last_mask || last_dest_color.full != dest_buf[x].full) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
if(disp->driver->screen_transp) {
|
||||
lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, color, opa_tmp, &last_res_color,
|
||||
&last_res_color.ch.alpha);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if(opa_tmp == LV_OPA_COVER) last_res_color = color;
|
||||
else last_res_color = lv_color_mix(color, dest_buf[x], opa_tmp);
|
||||
}
|
||||
if(opa_tmp == LV_OPA_COVER) last_res_color = color;
|
||||
else last_res_color = lv_color_mix(color, dest_buf[x], opa_tmp);
|
||||
last_mask = *mask;
|
||||
last_dest_color.full = dest_buf[x].full;
|
||||
}
|
||||
@@ -360,6 +353,118 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_ar
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
static inline void set_px_argb(uint8_t * buf, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
lv_color_t bg_color;
|
||||
lv_color_t res_color;
|
||||
lv_opa_t bg_opa = buf[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
||||
#if LV_COLOR_DEPTH == 8
|
||||
bg_color.full = buf[0];
|
||||
lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf[1]);
|
||||
if(buf[1] <= LV_OPA_MIN) return;
|
||||
buf[0] = res_color.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
bg_color.full = buf[0] + (buf[1] << 8);
|
||||
lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf[2]);
|
||||
if(buf[2] <= LV_OPA_MIN) return;
|
||||
buf[0] = res_color.full & 0xff;
|
||||
buf[1] = res_color.full >> 8;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
bg_color = *((lv_color_t *)buf);
|
||||
lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf[3]);
|
||||
if(buf[3] <= LV_OPA_MIN) return;
|
||||
buf[0] = res_color.ch.blue;
|
||||
buf[1] = res_color.ch.green;
|
||||
buf[2] = res_color.ch.red;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void fill_argb(lv_color_t * dest_buf, const lv_area_t * dest_area,
|
||||
lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
|
||||
{
|
||||
uint8_t * dest_buf8 = (uint8_t *) dest_buf;
|
||||
int32_t w = lv_area_get_width(dest_area);
|
||||
int32_t h = lv_area_get_height(dest_area);
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
||||
uint8_t ctmp[LV_IMG_PX_SIZE_ALPHA_BYTE];
|
||||
lv_memcpy(ctmp, &color, sizeof(lv_color_t));
|
||||
ctmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = opa;
|
||||
|
||||
/*No mask*/
|
||||
if(mask == NULL) {
|
||||
if(opa >= LV_OPA_MAX) {
|
||||
for(x = 0; x < w; x++) {
|
||||
lv_memcpy(dest_buf8, ctmp, LV_IMG_PX_SIZE_ALPHA_BYTE);
|
||||
dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
}
|
||||
|
||||
dest_buf8 += (dest_stride - w) * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
|
||||
for(y = 1; y < h; y++) {
|
||||
lv_memcpy(dest_buf8, (uint8_t *) dest_buf, w * LV_IMG_PX_SIZE_ALPHA_BYTE);
|
||||
dest_buf8 += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
}
|
||||
}
|
||||
/*Has opacity*/
|
||||
else {
|
||||
uint8_t * dest_buf8_row = dest_buf8;
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
set_px_argb(dest_buf8, color, opa);
|
||||
dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
}
|
||||
dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
dest_buf8 = dest_buf8_row;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Masked*/
|
||||
else {
|
||||
/*Only the mask matters*/
|
||||
if(opa >= LV_OPA_MAX) {
|
||||
uint8_t * dest_buf8_row = dest_buf8;
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
set_px_argb(dest_buf8, color, *mask);
|
||||
mask++;
|
||||
dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
}
|
||||
dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
dest_buf8 = dest_buf8_row;
|
||||
}
|
||||
}
|
||||
/*With opacity*/
|
||||
else {
|
||||
/*Buffer the result color to avoid recalculating the same color*/
|
||||
lv_opa_t last_mask = LV_OPA_TRANSP;
|
||||
lv_opa_t opa_tmp = LV_OPA_TRANSP;
|
||||
|
||||
uint8_t * dest_buf8_row = dest_buf8;
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
if(*mask) {
|
||||
if(*mask != last_mask) opa_tmp = *mask == LV_OPA_COVER ? opa :
|
||||
(uint32_t)((uint32_t)(*mask) * opa) >> 8;
|
||||
|
||||
set_px_argb(dest_buf8, color, opa_tmp);
|
||||
}
|
||||
dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
mask++;
|
||||
}
|
||||
dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
dest_buf8 = dest_buf8_row;
|
||||
mask += (mask_stride - w);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area,
|
||||
lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride,
|
||||
@@ -477,10 +582,6 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
#endif
|
||||
|
||||
/*Simple fill (maybe with opacity), no masking*/
|
||||
if(mask == NULL) {
|
||||
if(opa >= LV_OPA_MAX) {
|
||||
@@ -493,16 +594,7 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
|
||||
else {
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
if(disp->driver->screen_transp) {
|
||||
lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa, &dest_buf[x],
|
||||
&dest_buf[x].ch.alpha);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa);
|
||||
}
|
||||
dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa);
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf += src_stride;
|
||||
@@ -523,11 +615,7 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
|
||||
}
|
||||
#else
|
||||
for(x = 0; x < w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
|
||||
#else
|
||||
MAP_NORMAL_MASK_PX(x)
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t * mask32 = (uint32_t *)mask_tmp_x;
|
||||
@@ -541,17 +629,10 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
|
||||
}
|
||||
else {
|
||||
mask_tmp_x = (const lv_opa_t *)mask32;
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
|
||||
MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 1)
|
||||
MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 2)
|
||||
MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 3)
|
||||
#else
|
||||
MAP_NORMAL_MASK_PX(x)
|
||||
MAP_NORMAL_MASK_PX(x + 1)
|
||||
MAP_NORMAL_MASK_PX(x + 2)
|
||||
MAP_NORMAL_MASK_PX(x + 3)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
mask32++;
|
||||
@@ -559,11 +640,7 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
|
||||
|
||||
mask_tmp_x = (const lv_opa_t *)mask32;
|
||||
for(; x < w ; x++) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
|
||||
#else
|
||||
MAP_NORMAL_MASK_PX(x)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
dest_buf += dest_stride;
|
||||
@@ -577,16 +654,7 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
|
||||
for(x = 0; x < w; x++) {
|
||||
if(mask[x]) {
|
||||
lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
if(disp->driver->screen_transp) {
|
||||
lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa_tmp,
|
||||
&dest_buf[x], &dest_buf[x].ch.alpha);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa_tmp);
|
||||
}
|
||||
dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa_tmp);
|
||||
}
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
@@ -596,6 +664,101 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_are
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
LV_ATTRIBUTE_FAST_MEM static void map_argb(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
|
||||
|
||||
{
|
||||
|
||||
uint8_t * dest_buf8 = (uint8_t *) dest_buf;
|
||||
|
||||
int32_t w = lv_area_get_width(dest_area);
|
||||
int32_t h = lv_area_get_height(dest_area);
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
||||
/*Simple fill (maybe with opacity), no masking*/
|
||||
if(mask == NULL) {
|
||||
if(opa >= LV_OPA_MAX) {
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
for(y = 0; y < h; y++) {
|
||||
lv_memcpy(dest_buf, src_buf, w * sizeof(lv_color_t));
|
||||
dest_buf += dest_stride;
|
||||
src_buf += src_stride;
|
||||
}
|
||||
#else
|
||||
uint8_t * dest_buf8_row = dest_buf8;
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
set_px_argb(dest_buf8, src_buf[x], LV_OPA_COVER);
|
||||
dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
}
|
||||
|
||||
dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
dest_buf8 = dest_buf8_row;
|
||||
src_buf += src_stride;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
uint8_t * dest_buf8_row = dest_buf8;
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
set_px_argb(dest_buf8, src_buf[x], opa);
|
||||
dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
}
|
||||
|
||||
dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
dest_buf8 = dest_buf8_row;
|
||||
src_buf += src_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Masked*/
|
||||
else {
|
||||
/*Only the mask matters*/
|
||||
if(opa > LV_OPA_MAX) {
|
||||
uint8_t * dest_buf8_row = dest_buf8;
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
set_px_argb(dest_buf8, src_buf[x], mask[x]);
|
||||
dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
|
||||
}
|
||||
dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
dest_buf8 = dest_buf8_row;
|
||||
src_buf += src_stride;
|
||||
mask += mask_stride;
|
||||
}
|
||||
}
|
||||
/*Handle opa and mask values too*/
|
||||
else {
|
||||
uint8_t * dest_buf8_row = dest_buf8;
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
if(mask[x]) {
|
||||
lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
|
||||
|
||||
set_px_argb(dest_buf8, src_buf[x], opa_tmp);
|
||||
|
||||
}
|
||||
dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
}
|
||||
dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
dest_buf8 = dest_buf8_row;
|
||||
src_buf += src_stride;
|
||||
mask += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define MAX_BUF_SIZE (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing())
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -25,6 +26,8 @@
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w, lv_coord_t src_h,
|
||||
lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -38,6 +41,7 @@
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t cf)
|
||||
{
|
||||
@@ -46,278 +50,199 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_c
|
||||
lv_area_copy(&draw_area, draw_ctx->clip_area);
|
||||
|
||||
bool mask_any = lv_draw_mask_is_any(&draw_area);
|
||||
bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false;
|
||||
|
||||
lv_area_t blend_area;
|
||||
lv_draw_sw_blend_dsc_t blend_dsc;
|
||||
lv_memset_00(&blend_dsc, sizeof(blend_dsc));
|
||||
|
||||
lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t));
|
||||
blend_dsc.opa = draw_dsc->opa;
|
||||
blend_dsc.blend_mode = draw_dsc->blend_mode;
|
||||
blend_dsc.blend_area = &blend_area;
|
||||
|
||||
/*The simplest case just copy the pixels into the draw_buf*/
|
||||
if(!mask_any && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE &&
|
||||
cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
|
||||
blend_dsc.blend_area = coords;
|
||||
if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
|
||||
blend_dsc.src_buf = (const lv_color_t *)src_buf;
|
||||
|
||||
blend_dsc.blend_area = coords;
|
||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||
}
|
||||
/*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 = cf == LV_IMG_CF_TRUE_COLOR_ALPHA ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
|
||||
blend_area.x1 = draw_ctx->clip_area->x1;
|
||||
blend_area.x2 = draw_ctx->clip_area->x2;
|
||||
blend_area.y1 = draw_ctx->clip_area->y1;
|
||||
blend_area.y2 = draw_ctx->clip_area->y2;
|
||||
|
||||
/*Go to the first displayed pixel of the map*/
|
||||
int32_t src_stride = lv_area_get_width(coords);
|
||||
lv_coord_t src_w = lv_area_get_width(coords);
|
||||
lv_coord_t src_h = lv_area_get_height(coords);
|
||||
lv_coord_t blend_h = lv_area_get_height(&blend_area);
|
||||
lv_coord_t blend_w = lv_area_get_width(&blend_area);
|
||||
|
||||
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_coord_t draw_area_h = lv_area_get_height(&draw_area);
|
||||
lv_coord_t draw_area_w = lv_area_get_width(&draw_area);
|
||||
|
||||
lv_area_t blend_area;
|
||||
blend_area.x1 = draw_area.x1;
|
||||
blend_area.x2 = draw_area.x2;
|
||||
blend_area.y1 = draw_area.y1;
|
||||
blend_area.y2 = blend_area.y1;
|
||||
blend_dsc.blend_area = &blend_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(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR_ALPHA && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
|
||||
uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing());
|
||||
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 * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||
blend_dsc.mask_buf = mask_buf;
|
||||
blend_dsc.mask_area = &blend_area;
|
||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
blend_dsc.src_buf = src_buf_rgb;
|
||||
|
||||
const uint8_t * src_buf_tmp = src_buf;
|
||||
src_buf_tmp += src_stride * (draw_area.y1 - coords->y1) * px_size_byte;
|
||||
src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte;
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
for(y = 0; y < draw_area_h; y++) {
|
||||
map_px = src_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
|
||||
src_buf_rgb[px_i].full = map_px[0];
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
src_buf_rgb[px_i].full = map_px[0] + (map_px[1] << 8);
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
src_buf_rgb[px_i].full = *((uint32_t *)map_px);
|
||||
#endif
|
||||
}
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
src_buf_rgb[px_i].ch.alpha = 0xFF;
|
||||
#endif
|
||||
}
|
||||
|
||||
src_buf_tmp += src_stride * px_size_byte;
|
||||
if(px_i + draw_area_w <= mask_buf_size) {
|
||||
blend_area.y2 ++;
|
||||
}
|
||||
else {
|
||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||
|
||||
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_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||
}
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
lv_mem_buf_release(src_buf_rgb);
|
||||
uint32_t max_buf_size = MAX_BUF_SIZE;
|
||||
uint32_t blend_size = lv_area_get_size(&blend_area);
|
||||
uint32_t buf_h;
|
||||
uint32_t buf_w = blend_w;
|
||||
if(blend_size <= max_buf_size) {
|
||||
buf_h = blend_h;
|
||||
}
|
||||
/*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(_lv_refr_get_disp_refreshing());
|
||||
uint32_t mask_buf_size = lv_area_get_size(&draw_area) > hor_res ? hor_res : lv_area_get_size(&draw_area);
|
||||
lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||
blend_dsc.mask_buf = mask_buf;
|
||||
blend_dsc.mask_area = &blend_area;
|
||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
blend_dsc.src_buf = src_buf_rgb;
|
||||
|
||||
const uint8_t * src_buf_tmp = NULL;
|
||||
#if LV_DRAW_COMPLEX
|
||||
lv_img_transform_dsc_t trans_dsc;
|
||||
lv_memset_00(&trans_dsc, sizeof(lv_img_transform_dsc_t));
|
||||
if(transform) {
|
||||
trans_dsc.cfg.angle = draw_dsc->angle;
|
||||
trans_dsc.cfg.zoom = draw_dsc->zoom;
|
||||
trans_dsc.cfg.src = src_buf;
|
||||
trans_dsc.cfg.src_w = src_stride;
|
||||
trans_dsc.cfg.src_h = lv_area_get_height(coords);
|
||||
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);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
src_buf_tmp = src_buf;
|
||||
src_buf_tmp += src_stride * (draw_area.y1 - coords->y1) * px_size_byte;
|
||||
src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
blend_dsc.mask_res = (cf != LV_IMG_CF_TRUE_COLOR || 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(mask_any) {
|
||||
lv_memset_ff(mask_buf, mask_buf_size);
|
||||
}
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
#if LV_DRAW_COMPLEX
|
||||
int32_t rot_y = blend_area.y1 - coords->y1;
|
||||
#endif
|
||||
for(y = 0; y < draw_area_h; y++) {
|
||||
map_px = src_buf_tmp;
|
||||
#if LV_DRAW_COMPLEX
|
||||
uint32_t px_i_start = px_i;
|
||||
int32_t rot_x = blend_area.x1 - coords->x1;
|
||||
#endif
|
||||
|
||||
for(x = 0; x < draw_area_w; x++, px_i++, map_px += px_size_byte) {
|
||||
|
||||
#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(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
|
||||
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
|
||||
src_buf_rgb[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(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
||||
if(c.full == chroma_keyed_color.full) {
|
||||
mask_buf[px_i] = LV_OPA_TRANSP;
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
src_buf_rgb[px_i].full = 0;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(draw_dsc->recolor_opa != 0) {
|
||||
c = lv_color_mix_premult(recolor_premult, c, recolor_opa_inv);
|
||||
}
|
||||
|
||||
src_buf_rgb[px_i].full = c.full;
|
||||
}
|
||||
#if LV_DRAW_COMPLEX
|
||||
/*Apply the masks if any*/
|
||||
if(mask_any) {
|
||||
lv_draw_mask_res_t mask_res_sub;
|
||||
mask_res_sub = lv_draw_mask_apply(mask_buf + px_i_start, blend_area.x1,
|
||||
y + draw_area.y1, draw_area_w);
|
||||
if(mask_res_sub == LV_DRAW_MASK_RES_TRANSP) {
|
||||
lv_memset_00(mask_buf + px_i_start, draw_area_w);
|
||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
}
|
||||
else if(mask_res_sub == LV_DRAW_MASK_RES_CHANGED) {
|
||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
src_buf_tmp += src_stride * px_size_byte;
|
||||
if(px_i + draw_area_w < mask_buf_size) {
|
||||
blend_area.y2 ++;
|
||||
}
|
||||
else {
|
||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||
|
||||
blend_area.y1 = blend_area.y2 + 1;
|
||||
blend_area.y2 = blend_area.y1;
|
||||
|
||||
px_i = 0;
|
||||
blend_dsc.mask_res = (cf != LV_IMG_CF_TRUE_COLOR || 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(mask_any) {
|
||||
lv_memset_ff(mask_buf, mask_buf_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Flush the last part*/
|
||||
if(blend_area.y1 != blend_area.y2) {
|
||||
blend_area.y2--;
|
||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||
}
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
lv_mem_buf_release(src_buf_rgb);
|
||||
/*Round to full lines*/
|
||||
buf_h = max_buf_size / blend_w;
|
||||
}
|
||||
|
||||
/*Create buffers and masks*/
|
||||
uint32_t buf_size = buf_w * buf_h;
|
||||
|
||||
lv_color_t * rgb_buf = lv_mem_buf_get(buf_size * sizeof(lv_color_t));
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(buf_size);
|
||||
blend_dsc.mask_buf = mask_buf;
|
||||
blend_dsc.mask_area = &blend_area;
|
||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
blend_dsc.src_buf = rgb_buf;
|
||||
lv_coord_t y_last = blend_area.y2;
|
||||
blend_area.y2 = blend_area.y1 + buf_h - 1;
|
||||
|
||||
lv_draw_mask_res_t mask_res_def = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle ||
|
||||
draw_dsc->zoom != LV_IMG_ZOOM_NONE) ?
|
||||
LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
|
||||
blend_dsc.mask_res = mask_res_def;
|
||||
|
||||
while(blend_area.y1 <= y_last) {
|
||||
/*Apply transformations if any or separate the channels*/
|
||||
lv_area_t transform_area;
|
||||
lv_area_copy(&transform_area, &blend_area);
|
||||
lv_area_move(&transform_area, -coords->x1, -coords->y1);
|
||||
if(transform) {
|
||||
lv_draw_transform(draw_ctx, &transform_area, src_buf, src_w, src_h, src_w,
|
||||
draw_dsc, cf, rgb_buf, mask_buf);
|
||||
}
|
||||
else {
|
||||
convert_cb(&transform_area, src_buf, src_w, src_h, src_w, draw_dsc, cf, rgb_buf, mask_buf);
|
||||
}
|
||||
|
||||
/*Apply recolor*/
|
||||
if(draw_dsc->recolor_opa > LV_OPA_MIN) {
|
||||
uint16_t premult_v[3];
|
||||
lv_opa_t recolor_opa = draw_dsc->recolor_opa;
|
||||
lv_color_t recolor = draw_dsc->recolor;
|
||||
lv_color_premult(recolor, recolor_opa, premult_v);
|
||||
uint32_t i;
|
||||
for(i = 0; i < buf_size; i++) {
|
||||
rgb_buf[i] = lv_color_mix_premult(premult_v, rgb_buf[i], recolor_opa);
|
||||
}
|
||||
}
|
||||
#if LV_DRAW_COMPLEX
|
||||
/*Apply the masks if any*/
|
||||
if(mask_any) {
|
||||
lv_coord_t y;
|
||||
lv_opa_t * mask_buf_tmp = mask_buf;
|
||||
for(y = blend_area.y1; y <= blend_area.y2; y++) {
|
||||
lv_draw_mask_res_t mask_res_line;
|
||||
mask_res_line = lv_draw_mask_apply(mask_buf_tmp, blend_area.x1, y, blend_w);
|
||||
|
||||
if(mask_res_line == LV_DRAW_MASK_RES_TRANSP) {
|
||||
lv_memset_00(mask_buf_tmp, blend_w);
|
||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
}
|
||||
else if(mask_res_line == LV_DRAW_MASK_RES_CHANGED) {
|
||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||
}
|
||||
mask_buf_tmp += blend_w;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*Blend*/
|
||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||
|
||||
/*Go the the next lines*/
|
||||
blend_area.y1 = blend_area.y2 + 1;
|
||||
blend_area.y2 = blend_area.y1 + buf_h - 1;
|
||||
if(blend_area.y2 > y_last) blend_area.y2 = y_last;
|
||||
}
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
lv_mem_buf_release(rgb_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/* Separate the image channels to RGB and Alpha to match LV_COLOR_DEPTH settings*/
|
||||
static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w, lv_coord_t src_h,
|
||||
lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf)
|
||||
{
|
||||
LV_UNUSED(draw_dsc);
|
||||
LV_UNUSED(src_h);
|
||||
LV_UNUSED(src_w);
|
||||
|
||||
const uint8_t * src_tmp8 = (const uint8_t *)src_buf;
|
||||
lv_coord_t y;
|
||||
lv_coord_t x;
|
||||
|
||||
if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
||||
uint32_t px_cnt = lv_area_get_size(dest_area);
|
||||
lv_memset_ff(abuf, px_cnt);
|
||||
|
||||
src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t);
|
||||
uint32_t dest_w = lv_area_get_width(dest_area);
|
||||
uint32_t dest_w_byte = dest_w * sizeof(lv_color_t);
|
||||
|
||||
lv_coord_t src_stride_byte = src_stride * sizeof(lv_color_t);
|
||||
lv_color_t * cbuf_tmp = cbuf;
|
||||
for(y = dest_area->y1; y <= dest_area->y2; y++) {
|
||||
lv_memcpy(cbuf_tmp, src_tmp8, dest_w_byte);
|
||||
src_tmp8 += src_stride_byte;
|
||||
cbuf_tmp += dest_w;
|
||||
}
|
||||
|
||||
/*Make "holes" for with Chroma keying*/
|
||||
if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
||||
uint32_t i;
|
||||
lv_color_t chk = LV_COLOR_CHROMA_KEY;
|
||||
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
||||
uint8_t * cbuf_uint = (uint8_t *)cbuf;
|
||||
uint8_t chk_v = chk.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
uint16_t * cbuf_uint = (uint16_t *)cbuf;
|
||||
uint16_t chk_v = chk.full;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
uint32_t * cbuf_uint = (uint32_t *)cbuf;
|
||||
uint32_t chk_v = chk.full;
|
||||
#endif
|
||||
for(i = 0; i < px_cnt; i++) {
|
||||
if(chk_v == cbuf_uint[i]) abuf[i] = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
|
||||
src_tmp8 += (src_stride * dest_area->y1 * LV_IMG_PX_SIZE_ALPHA_BYTE) + dest_area->x1 * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
|
||||
lv_coord_t src_new_line_step_px = (src_stride - lv_area_get_width(dest_area));
|
||||
lv_coord_t src_new_line_step_byte = src_new_line_step_px * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
|
||||
lv_coord_t dest_h = lv_area_get_height(dest_area);
|
||||
lv_coord_t dest_w = lv_area_get_width(dest_area);
|
||||
for(y = 0; y < dest_h; y++) {
|
||||
for(x = 0; x < dest_w; x++) {
|
||||
abuf[x] = src_tmp8[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
||||
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
||||
cbuf[x].full = *src_tmp8;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
cbuf[x].full = *src_tmp8 + ((*(src_tmp8 + 1)) << 8);
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
cbuf[x] = *((lv_color_t *) src_tmp8);
|
||||
cbuf[x].ch.alpha = 0xff;
|
||||
#endif
|
||||
src_tmp8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
|
||||
}
|
||||
cbuf += dest_w;
|
||||
abuf += dest_w;
|
||||
src_tmp8 += src_new_line_step_byte;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
363
src/draw/sw/lv_draw_sw_transform.c
Normal file
363
src/draw/sw/lv_draw_sw_transform.c
Normal file
@@ -0,0 +1,363 @@
|
||||
/**
|
||||
* @file lv_draw_sw_tranform.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_sw.h"
|
||||
#include "../../misc/lv_assert.h"
|
||||
#include "../../misc/lv_area.h"
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct {
|
||||
int32_t x_in;
|
||||
int32_t y_in;
|
||||
int32_t x_out;
|
||||
int32_t y_out;
|
||||
int32_t sinma;
|
||||
int32_t cosma;
|
||||
int32_t zoom;
|
||||
int32_t angle;
|
||||
lv_point_t pivot;
|
||||
} point_transform_dsc_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
/**
|
||||
* Transform a point with 1/256 precision (the output coordinates are upscaled by 256)
|
||||
* @param t pointer to n initialized `point_transform_dsc_t` structure
|
||||
* @param xin X coordinate to rotate
|
||||
* @param yin Y coordinate to rotate
|
||||
* @param xout upscaled, transformed X
|
||||
* @param yout upscaled, transformed Y
|
||||
*/
|
||||
static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int32_t yin, int32_t * xout,
|
||||
int32_t * yout);
|
||||
|
||||
static void argb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
|
||||
int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
|
||||
int32_t x_end, lv_color_t * cbuf, uint8_t * abuf);
|
||||
|
||||
static void rgb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
|
||||
int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
|
||||
int32_t x_end, lv_color_t * cbuf, uint8_t * abuf);
|
||||
|
||||
static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
|
||||
int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
|
||||
int32_t x_end, lv_color_t * cbuf, uint8_t * abuf, bool has_alpha);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
|
||||
lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
|
||||
const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf)
|
||||
{
|
||||
LV_UNUSED(draw_ctx);
|
||||
|
||||
point_transform_dsc_t tr_dsc;
|
||||
tr_dsc.angle = -draw_dsc->angle;
|
||||
tr_dsc.zoom = (256 * 256) / draw_dsc->zoom;
|
||||
tr_dsc.pivot = draw_dsc->pivot;
|
||||
|
||||
int32_t angle_low = tr_dsc.angle / 10;
|
||||
int32_t angle_high = angle_low + 1;
|
||||
int32_t angle_rem = tr_dsc.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);
|
||||
|
||||
tr_dsc.sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
|
||||
tr_dsc.cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
|
||||
tr_dsc.sinma = tr_dsc.sinma >> (LV_TRIGO_SHIFT - 10);
|
||||
tr_dsc.cosma = tr_dsc.cosma >> (LV_TRIGO_SHIFT - 10);
|
||||
|
||||
lv_coord_t dest_w = lv_area_get_width(dest_area);
|
||||
lv_coord_t dest_h = lv_area_get_height(dest_area);
|
||||
lv_coord_t y;
|
||||
bool has_alpha = lv_img_cf_has_alpha(cf);
|
||||
for(y = 0; y < dest_h; y++) {
|
||||
int32_t xs1_ups, ys1_ups, xs2_ups, ys2_ups;
|
||||
|
||||
transform_point_upscaled(&tr_dsc, dest_area->x1, dest_area->y1 + y, &xs1_ups, &ys1_ups);
|
||||
transform_point_upscaled(&tr_dsc, dest_area->x2, dest_area->y1 + y, &xs2_ups, &ys2_ups);
|
||||
|
||||
int32_t xs_diff = xs2_ups - xs1_ups;
|
||||
int32_t ys_diff = ys2_ups - ys1_ups;
|
||||
int32_t xs_step_256 = 0;
|
||||
int32_t ys_step_256 = 0;
|
||||
if(dest_w > 1) {
|
||||
xs_step_256 = (256 * xs_diff) / (dest_w - 1);
|
||||
ys_step_256 = (256 * ys_diff) / (dest_w - 1);
|
||||
}
|
||||
int32_t xs_ups = xs1_ups + 1 * xs_step_256 / 2 / 256; /*Init. + go the center of the pixel*/
|
||||
int32_t ys_ups = ys1_ups + 1 * ys_step_256 / 2 / 256;
|
||||
|
||||
if(draw_dsc->antialias == 0) {
|
||||
if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
|
||||
argb_no_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf);
|
||||
}
|
||||
else {
|
||||
rgb_no_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
argb_and_rgb_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf,
|
||||
has_alpha);
|
||||
}
|
||||
cbuf += dest_w;
|
||||
abuf += dest_w;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void rgb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
|
||||
int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
|
||||
int32_t x_end, lv_color_t * cbuf, uint8_t * abuf)
|
||||
{
|
||||
int32_t xs_ups_start = xs_ups;
|
||||
int32_t ys_ups_start = ys_ups;
|
||||
|
||||
lv_memset_ff(abuf, x_end);
|
||||
|
||||
lv_coord_t x;
|
||||
for(x = 0; x < x_end; x++) {
|
||||
xs_ups = xs_ups_start + ((xs_step * x) >> 8);
|
||||
ys_ups = ys_ups_start + ((ys_step * x) >> 8);
|
||||
|
||||
int32_t xs_int = xs_ups >> 8;
|
||||
int32_t ys_int = ys_ups >> 8;
|
||||
if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
|
||||
abuf[x] = 0;
|
||||
}
|
||||
else {
|
||||
const uint8_t * src_tmp = src;
|
||||
src_tmp += (ys_int * src_stride * sizeof(lv_color_t)) + xs_int * sizeof(lv_color_t);
|
||||
|
||||
#if LV_COLOR_DEPTH == 8
|
||||
cbuf[x].full = src_tmp[0];
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8);
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
cbuf[x].full = *((uint32_t *)src_tmp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void argb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
|
||||
int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
|
||||
int32_t x_end, lv_color_t * cbuf, uint8_t * abuf)
|
||||
{
|
||||
int32_t xs_ups_start = xs_ups;
|
||||
int32_t ys_ups_start = ys_ups;
|
||||
|
||||
lv_coord_t x;
|
||||
for(x = 0; x < x_end; x++) {
|
||||
xs_ups = xs_ups_start + ((xs_step * x) >> 8);
|
||||
ys_ups = ys_ups_start + ((ys_step * x) >> 8);
|
||||
|
||||
int32_t xs_int = xs_ups >> 8;
|
||||
int32_t ys_int = ys_ups >> 8;
|
||||
if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
|
||||
abuf[x] = 0;
|
||||
}
|
||||
else {
|
||||
const uint8_t * src_tmp = src;
|
||||
src_tmp += (ys_int * src_stride * LV_IMG_PX_SIZE_ALPHA_BYTE) + xs_int * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
|
||||
#if LV_COLOR_DEPTH == 8
|
||||
cbuf[x].full = src_tmp[0];
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8);
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
cbuf[x].full = *((uint32_t *)src_tmp);
|
||||
#endif
|
||||
abuf[x] = src_tmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
|
||||
int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
|
||||
int32_t x_end, lv_color_t * cbuf, uint8_t * abuf, bool has_alpha)
|
||||
{
|
||||
|
||||
int32_t xs_ups_start = xs_ups;
|
||||
int32_t ys_ups_start = ys_ups;
|
||||
const int32_t px_size = has_alpha ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
|
||||
|
||||
lv_coord_t x;
|
||||
for(x = 0; x < x_end; x++) {
|
||||
xs_ups = xs_ups_start + ((xs_step * x) >> 8);
|
||||
ys_ups = ys_ups_start + ((ys_step * x) >> 8);
|
||||
|
||||
int32_t xs_int = xs_ups >> 8;
|
||||
int32_t ys_int = ys_ups >> 8;
|
||||
|
||||
/*Fully out of the image*/
|
||||
if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
|
||||
abuf[x] = 0x00;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/*Get the direction the hor and ver neighbor
|
||||
*`fract` will be in range of 0x00..0xFF and `next` (+/-1) indicates the direction*/
|
||||
int32_t xs_fract = xs_ups & 0xFF;
|
||||
int32_t ys_fract = ys_ups & 0xFF;
|
||||
|
||||
int32_t x_next;
|
||||
int32_t y_next;
|
||||
if(xs_fract < 0x80) {
|
||||
x_next = -1;
|
||||
xs_fract = (0x7F - xs_fract) * 2;
|
||||
}
|
||||
else {
|
||||
x_next = 1;
|
||||
xs_fract = (xs_fract - 0x80) * 2;
|
||||
}
|
||||
if(ys_fract < 0x80) {
|
||||
y_next = -1;
|
||||
ys_fract = (0x7F - ys_fract) * 2;
|
||||
}
|
||||
else {
|
||||
y_next = 1;
|
||||
ys_fract = (ys_fract - 0x80) * 2;
|
||||
}
|
||||
|
||||
const uint8_t * src_tmp = src;
|
||||
src_tmp += (ys_int * src_stride * px_size) + xs_int * px_size;
|
||||
|
||||
if(xs_int + x_next >= 0 &&
|
||||
xs_int + x_next <= src_w - 1 &&
|
||||
ys_int + y_next >= 0 &&
|
||||
ys_int + y_next <= src_h - 1) {
|
||||
|
||||
const uint8_t * px_base = src_tmp;
|
||||
const uint8_t * px_hor = src_tmp + x_next * px_size;
|
||||
const uint8_t * px_ver = src_tmp + y_next * src_stride * px_size;
|
||||
lv_color_t c_base;
|
||||
lv_color_t c_ver;
|
||||
lv_color_t c_hor;
|
||||
|
||||
if(has_alpha) {
|
||||
lv_opa_t a_base = px_base[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
||||
lv_opa_t a_ver = px_ver[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
||||
lv_opa_t a_hor = px_hor[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
||||
|
||||
if(a_ver != a_base) a_ver = ((a_ver * ys_fract) + (a_base * (0x100 - ys_fract))) >> 8;
|
||||
if(a_hor != a_base) a_hor = ((a_hor * xs_fract) + (a_base * (0x100 - xs_fract))) >> 8;
|
||||
abuf[x] = (a_ver + a_hor) >> 1;
|
||||
|
||||
if(abuf[x] == 0x00) continue;
|
||||
|
||||
#if LV_COLOR_DEPTH == 8
|
||||
c_base.full = px_base[0];
|
||||
c_ver.full = px_ver[0];
|
||||
c_hor.full = px_hor[0];
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
c_base.full = px_base[0] + (px_base[1] << 8);
|
||||
c_ver.full = px_ver[0] + (px_ver[1] << 8);
|
||||
c_hor.full = px_hor[0] + (px_hor[1] << 8);
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
c_base.full = *((uint32_t *)px_base);
|
||||
c_ver.full = *((uint32_t *)px_ver);
|
||||
c_hor.full = *((uint32_t *)px_hor);
|
||||
#endif
|
||||
}
|
||||
/*No alpha channel -> RGB*/
|
||||
else {
|
||||
c_base = *((const lv_color_t *) px_base);
|
||||
c_hor = *((const lv_color_t *) px_hor);
|
||||
c_ver = *((const lv_color_t *) px_ver);
|
||||
abuf[x] = 0xff;
|
||||
}
|
||||
|
||||
if(c_base.full == c_ver.full && c_base.full == c_hor.full) {
|
||||
cbuf[x] = c_base;
|
||||
}
|
||||
else {
|
||||
c_ver = lv_color_mix(c_ver, c_base, ys_fract);
|
||||
c_hor = lv_color_mix(c_hor, c_base, xs_fract);
|
||||
cbuf[x] = lv_color_mix(c_hor, c_ver, LV_OPA_50);
|
||||
}
|
||||
}
|
||||
/*Partially out of the image*/
|
||||
else {
|
||||
#if LV_COLOR_DEPTH == 8
|
||||
cbuf[x].full = src_tmp[0];
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8);
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
cbuf[x].full = *((uint32_t *)src_tmp);
|
||||
#endif
|
||||
|
||||
lv_opa_t a = has_alpha ? src_tmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1] : 0xff;
|
||||
|
||||
if((xs_int == 0 && x_next < 0) || (xs_int == src_w - 1 && x_next > 0)) {
|
||||
abuf[x] = (a * (0xFF - xs_fract)) >> 8;
|
||||
}
|
||||
else if((ys_int == 0 && y_next < 0) || (ys_int == src_h - 1 && y_next > 0)) {
|
||||
abuf[x] = (a * (0xFF - ys_fract)) >> 8;
|
||||
}
|
||||
else {
|
||||
abuf[x] = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int32_t yin, int32_t * xout,
|
||||
int32_t * yout)
|
||||
{
|
||||
if(t->angle == 0 && t->zoom == LV_IMG_ZOOM_NONE) {
|
||||
*xout = xin << 8;
|
||||
*yout = yin << 8;
|
||||
return;
|
||||
}
|
||||
|
||||
xin -= t->pivot.x;
|
||||
yin -= t->pivot.y;
|
||||
|
||||
if(t->angle == 0) {
|
||||
*xout = ((int32_t)(xin * t->zoom)) + (t->pivot.x << 8);
|
||||
*yout = ((int32_t)(yin * t->zoom)) + (t->pivot.y << 8);
|
||||
}
|
||||
else if(t->zoom == LV_IMG_ZOOM_NONE) {
|
||||
*xout = ((t->cosma * xin - t->sinma * yin) >> 2) + (t->pivot.x << 8);
|
||||
*yout = ((t->sinma * xin + t->cosma * yin) >> 2) + (t->pivot.y << 8);
|
||||
}
|
||||
else {
|
||||
*xout = (((t->cosma * xin - t->sinma * yin) * t->zoom) >> 10) + (t->pivot.x << 8);
|
||||
*yout = (((t->sinma * xin + t->cosma * yin) * t->zoom) >> 10) + (t->pivot.y << 8);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user