1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-14 06:42:58 +08:00
lvgl/lv_draw/lv_draw_vbasic.c
2016-07-11 16:16:53 +02:00

400 lines
12 KiB
C

/**
* @file lv_vdraw.c
*
*/
#include "lv_conf.h"
#if LV_VDB_SIZE != 0
#include <stddef.h>
#include "lvgl/lv_obj/lv_vdb.h"
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_put_vpx(point_t * point_p, const area_t * mask_p,
color_t color, opa_t opa);
static bool lv_vletter_get_px(const font_t * font_p, uint8_t letter, cord_t x, cord_t y);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Fill an area in the Virtual Display Buffer
* @param cords_p coordinates of the area to fill
* @param mask_p fill only o this mask
* @param color fill color
* @param opa opacity of the area (0..255)
*/
void lv_vfill(const area_t * cords_p, const area_t * mask_p,
color_t color, opa_t opa)
{
area_t res_a;
bool union_ok;
lv_vdb_t * vdb_p = lv_vdb_get();
/*Get the union of cord and mask*/
/* The mask is already truncated to the vdb size
* in 'lv_refr_area_with_vdb' function */
union_ok = area_union(&res_a, cords_p, mask_p);
/*If there are common part of the three area then draw to the vdb*/
if(union_ok == true) {
area_t vdb_rel_a; /*Stores relative coordinates on vdb*/
vdb_rel_a.x1 = res_a.x1 - vdb_p->vdb_area.x1;
vdb_rel_a.y1 = res_a.y1 - vdb_p->vdb_area.y1;
vdb_rel_a.x2 = res_a.x2 - vdb_p->vdb_area.x1;
vdb_rel_a.y2 = res_a.y2 - vdb_p->vdb_area.y1;
color_t * vdb_buf_tmp = vdb_p->buf;
uint32_t vdb_width = area_get_width(&vdb_p->vdb_area);
/*Move the vdb_tmp to the first row*/
vdb_buf_tmp += vdb_width * vdb_rel_a.y1;
/*Set all row in vdb to the given color*/
cord_t row;
uint32_t col;
/*Run simpler function without opacity*/
if(opa == OPA_COVER) {
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
for(col = vdb_rel_a.x1; col <= vdb_rel_a.x2; col++) {
vdb_buf_tmp[col] = color;
}
vdb_buf_tmp += vdb_width;
}
}
/*Calculate the alpha too*/
else {
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
for(col = vdb_rel_a.x1; col <= vdb_rel_a.x2; col++) {
color_t c = color_mix(color, vdb_buf_tmp[col], opa);
vdb_buf_tmp[col] = c;
}
vdb_buf_tmp += vdb_width;
}
}
}
}
/**
* 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
* @param font_p pointer to font
* @param letter a letter to draw
* @param color color of letter
* @param opa opacity of letter (0..255)
*/
void lv_vletter(const point_t * pos_p, const area_t * mask_p,
const font_t * font_p, uint8_t letter,
color_t color, opa_t opa)
{
if(font_p == NULL) return;
uint8_t w = font_get_width(font_p, letter);
uint8_t h = font_get_height(font_p);
/*If the letter is completely out of mask don't draw it */
if(pos_p->x + w < mask_p->x1 || pos_p->x > mask_p->x2 ||
pos_p->y + h < mask_p->y1 || pos_p->y > mask_p->y2) return;
cord_t col, row;
point_t act_point;
for(row = 0; row < h; row ++) {
for(col = 0; col < w; col ++) {
act_point.x = pos_p->x + col;
act_point.y = pos_p->y + row;
if(lv_vletter_get_px(font_p, letter, col, row)) {
lv_put_vpx(&act_point, mask_p, color, opa);
}
}
}
}
/**
* Draw a color map to the display
* @param cords_p coordinates the color map
* @param mask_p the map will drawn only on this area
* @param map_p pointer to a color_t array
* @param opa opacity of the map (ignored, only for compatibility with lv_vmap)
* @param transp true: enable transparency of LV_IMG_COLOR_TRANSP color pixels
*/
void lv_vmap(const area_t * cords_p, const area_t * mask_p,
const color_t * map_p, opa_t opa, bool transp,
color_t recolor, opa_t recolor_opa)
{
area_t masked_a;
bool union_ok;
lv_vdb_t * vdb_p = lv_vdb_get();
/*Get the union of map size and mask*/
/* The mask is already truncated to the vdb size
* in 'lv_refr_area_with_vdb' function */
union_ok = area_union(&masked_a, cords_p, mask_p);
/*If there are common part of the three area then draw to the vdb*/
if(union_ok == false) return;
uint8_t ds_shift = 0;
#if LV_DOWNSCALE <= 1 || LV_UPSCALE_MAP == 0
ds_shift = 0;
#elif LV_DOWNSCALE == 2
ds_shift = 1;
#elif LV_DOWNSCALE == 4
ds_shift = 2;
#else
#error "LV: not supported LV_DOWNSCALE value"
#endif
/*If the map starts OUT of the masked area then calc. the first pixel*/
cord_t map_width = area_get_width(cords_p) >> ds_shift;
if(cords_p->y1 < masked_a.y1) {
map_p += (uint32_t) map_width * ((masked_a.y1 - cords_p->y1) >> ds_shift);
}
if(cords_p->x1 < masked_a.x1) {
map_p += (masked_a.x1 - cords_p->x1) >> ds_shift;
}
/*Stores coordinates relative to the act vdb*/
masked_a.x1 = masked_a.x1 - vdb_p->vdb_area.x1;
masked_a.y1 = masked_a.y1 - vdb_p->vdb_area.y1;
masked_a.x2 = masked_a.x2 - vdb_p->vdb_area.x1;
masked_a.y2 = masked_a.y2 - vdb_p->vdb_area.y1;
cord_t vdb_width = area_get_width(&vdb_p->vdb_area);
color_t * vdb_buf_tmp = vdb_p->buf;
vdb_buf_tmp += (uint32_t) vdb_width * masked_a.y1; /*Move to the first row*/
map_p -= (masked_a.x1 >> ds_shift);
#if LV_DOWNSCALE > 1 && LV_UPSCALE_MAP != 0
cord_t row;
cord_t col;
cord_t row_cnt = 0;
color_t transp_color = LV_IMG_COLOR_TRANSP;
color_t color_tmp;
cord_t map_i;
map_p -= map_width; /*Compensate the first row % LV_DOWNSCALE*/
for(row = masked_a.y1, row_cnt = 0; row <= masked_a.y2; row++, row_cnt ++) {
if(row_cnt % LV_DOWNSCALE == 0) map_p += map_width; /*Next row on the map*/
map_i = masked_a.x1 >> ds_shift;
map_i--; /*Compensate the first col % LV_DOWNSCALE*/
for(col = masked_a.x1; col <= masked_a.x2; col++) {
if(col % LV_DOWNSCALE == 0) {
map_i++;
color_tmp = map_p[map_i];//color_mix(recolor, map_p[map_i], recolor_opa);
}
if(transp == false || map_p[map_i].full != transp_color.full) {
vdb_buf_tmp[col] = color_tmp;//color_mix(color_tmp, vdb_buf_tmp[col], opa);
}
}
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
#else
if(transp == false) { /*Simply copy the pixels to the VDB*/
cord_t row;
if(opa == OPA_COVER) { /*no opa */
for(row = masked_a.y1; row <= masked_a.y2; row++) {
memcpy(&vdb_buf_tmp[masked_a.x1],
&map_p[masked_a.x1],
area_get_width(&masked_a) * sizeof(color_t));
map_p += map_width; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
} else {
cord_t col;
for(row = masked_a.y1; row <= masked_a.y2; row++) {
for(col = masked_a.x1; col <= masked_a.x2; col ++) {
vdb_buf_tmp[col] = color_mix( map_p[col], vdb_buf_tmp[col], opa);
}
map_p += map_width; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
}
/*To recolor draw simply a rectangle above the image*/
#if LV_VDB_SIZE != 0
lv_vfill(cords_p, mask_p, recolor, recolor_opa);
#endif
} else { /*transp == true: Check all pixels */
cord_t row;
cord_t col;
color_t transp_color = LV_IMG_COLOR_TRANSP;
if(recolor_opa == OPA_TRANSP)/*No recolor*/
{
if(opa == OPA_COVER) { /*no opa */
for(row = masked_a.y1; row <= masked_a.y2; row++) {
for(col = masked_a.x1; col <= masked_a.x2; col ++) {
if(map_p[col].full != transp_color.full) {
vdb_buf_tmp[col] = map_p[col];
}
}
map_p += map_width; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
} else {
for(row = masked_a.y1; row <= masked_a.y2; row++) {
for(col = masked_a.x1; col <= masked_a.x2; col ++) {
if(map_p[col].full != transp_color.full) {
vdb_buf_tmp[col] = color_mix( map_p[col], vdb_buf_tmp[col], opa);
}
}
map_p += map_width; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
}
} else { /*Recolor needed*/
color_t color_tmp;
if(opa == OPA_COVER) { /*no opa */
for(row = masked_a.y1; row <= masked_a.y2; row++) {
for(col = masked_a.x1; col <= masked_a.x2; col ++) {
if(map_p[col].full != transp_color.full) {
color_tmp = color_mix(recolor, map_p[col], recolor_opa);
vdb_buf_tmp[col] = color_tmp;
}
}
map_p += map_width; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
} else {
for(row = masked_a.y1; row <= masked_a.y2; row++) {
for(col = masked_a.x1; col <= masked_a.x2; col ++) {
if(map_p[col].full != transp_color.full) {
color_tmp = color_mix(recolor, map_p[col], recolor_opa);
vdb_buf_tmp[col] = color_mix(color_tmp, vdb_buf_tmp[col], opa);
}
}
map_p += map_width; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
}
}
}
#endif /*No upscale and no downscale*/
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Put a pixel into the Virtual Dispaly Buffer
* @param x x coordinate of the pixel
* @param y y coordinate of the pixel
* @param mask_p the pixel will be drawn on this area
* @param color color of the pixel
* @param opa opacity of the pixel
*/
static void lv_put_vpx(point_t * point_p, const area_t * mask_p,
color_t color, opa_t opa)
{
if(opa == OPA_TRANSP) return;
bool point_ok;
lv_vdb_t * vdb_p = lv_vdb_get();
/*The point is on vdb?*/
point_ok = area_is_point_on(mask_p, point_p);
/*If there are common part of the three area then draw to the vdb*/
if(point_ok == false) return;
point_t vdb_rel_point; /*Stores relative coordinates on vdb*/
vdb_rel_point.x = point_p->x - vdb_p->vdb_area.x1;
vdb_rel_point.y = point_p->y - vdb_p->vdb_area.y1;
color_t * vdb_buf_tmp = vdb_p->buf;
uint32_t vdb_width = vdb_p->vdb_area.x2 - vdb_p->vdb_area.x1 + 1;
/*Move the vdb_tmp to the point*/
vdb_buf_tmp += vdb_width * vdb_rel_point.y + vdb_rel_point.x;
if(opa == OPA_COVER) *vdb_buf_tmp = color;
else *vdb_buf_tmp = color_mix(color, *vdb_buf_tmp, opa);
}
/**
* Get a pixel from a letter
* @param font_p pointer to a font
* @param letter a letter
* @param x x coordinate of the pixel to get
* @param y y coordinate of the pixel to get
* @return true: pixel is set, false: pixel is clear
*/
static bool lv_vletter_get_px(const font_t * font_p, uint8_t letter, cord_t x, cord_t y)
{
uint8_t w = font_get_width(font_p, letter);
uint8_t h = font_get_height(font_p);
const uint8_t * map_p = font_get_bitmap(font_p, letter);
if(map_p == NULL) return NULL;
if(x < 0) x = 0;
if(y < 0) x = 0;
if(x >= w) x = w - 1;
if(y >= h) y = h - 1;
#if LV_UPSCALE_FONT != 0
#if LV_DOWNSCALE == 1
/*Do nothing*/
#elif LV_DOWNSCALE == 2
x = x >> 1;
y = y >> 1;
#elif LV_DOWNSCALE == 4
x = x >> 2;
y = y >> 2;
#else
#error "LV: not supported LV_DOWNSCALE value"
#endif
#endif /*LV_UPSCALE_FONT == 0*/
map_p += (uint32_t)y * font_p->width_byte; /*Go to the corresponding row of the map*/
map_p += (x >> 3); /*Go to he corresponding col of the map*/
/*Get the corresponding col within a byte*/
uint8_t map_byte = *map_p;
uint8_t col_sub = 7 - (x % 8);
if((map_byte & (1 << col_sub)) == 0) return false;
else return true;
}
#endif