TychoVrahe 3 weeks ago committed by GitHub
commit 4c06ef57b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -102,7 +102,8 @@ void gfx_mono8_blend_mono4(const gfx_bitblt_t* bb) {
for (int x = 0; x < bb->width; x++) {
uint8_t src_data = src_row[(x + bb->src_x) / 2];
uint8_t src_alpha = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0x0F;
dst_ptr[x] = (fg * src_alpha + dst_ptr[x] * (15 - src_alpha)) / 15;
src_alpha = src_alpha * bb->src_alpha / 15;
dst_ptr[x] = (fg * src_alpha + dst_ptr[x] * (255 - src_alpha));
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_row += bb->src_stride / sizeof(*src_row);

@ -126,7 +126,8 @@ void gfx_rgb565_blend_mono4(const gfx_bitblt_t* bb) {
for (int x = 0; x < bb->width; x++) {
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
dst_ptr[x] = gfx_color16_blend_a4(
fg_alpha = fg_alpha * bb->src_alpha / 15;
dst_ptr[x] = gfx_color16_blend_a8(
bb->src_fg, gfx_color16_to_color(dst_ptr[x]), fg_alpha);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);

@ -146,7 +146,8 @@ void gfx_rgba8888_blend_mono4(const gfx_bitblt_t* bb) {
for (int x = 0; x < bb->width; x++) {
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
dst_ptr[x] = gfx_color32_blend_a4(
fg_alpha = fg_alpha * bb->src_alpha / 15;
dst_ptr[x] = gfx_color32_blend_a8(
bb->src_fg, gfx_color32_to_color(dst_ptr[x]), fg_alpha);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);

@ -75,6 +75,8 @@ typedef uint32_t gfx_color32_t;
#define gfx_color32_to_g(c) (((c)&0x0000FF00) >> 8)
// Extracts blue component from gfx_color32_t
#define gfx_color32_to_b(c) (((c)&0x000000FF) >> 0)
// Extracts alpha component from gfx_color32_t
#define gfx_color32_to_a(c) (((c)&0xFF000000) >> 0)
// 4-bit linear interpolation between `fg` and `bg`
#define a4_lerp(fg, bg, alpha) (((fg) * (alpha) + ((bg) * (15 - (alpha)))) / 15)
@ -95,6 +97,13 @@ static inline gfx_color32_t gfx_color32_rgb(uint8_t r, uint8_t g, uint8_t b) {
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
}
// Constructs a 32-bit color from the given red (r),
// green (g), blue (b) and alhpa (a) values in the range 0..255.
static inline gfx_color32_t gfx_color32_rgba(uint8_t r, uint8_t g, uint8_t b,
uint8_t a) {
return (a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
}
// Converts a 16-bit color to a 32-bit color; alpha is set to 255
static inline gfx_color32_t gfx_color16_to_color32(gfx_color16_t color) {
uint32_t r = gfx_color16_to_r(color);
@ -342,4 +351,12 @@ const gfx_color16_t* gfx_color16_gradient_a4(gfx_color_t fg, gfx_color_t bg);
// the background (`bg`) color and `retval[15]` the foreground (`fg`) color
const gfx_color32_t* gfx_color32_gradient_a4(gfx_color_t fg, gfx_color_t bg);
// Returns a color with alpha channel set
//
// The original color is not modified
static inline gfx_color32_t gfx_color32_set_alpha(gfx_color32_t c,
uint8_t alpha) {
return (c & 0xFFFFFF) | (alpha << 24);
}
#endif // GFX_COLOR_H

@ -237,7 +237,8 @@ impl<'a> BitBltCopy<'a> {
.with_rect(r)
.with_src(src.bitmap, offset.x, offset.y)
.with_bg(src.bg_color)
.with_fg(src.fg_color),
.with_fg(src.fg_color)
.with_alpha(src.alpha),
src,
})
} else {

@ -275,6 +275,7 @@ pub struct BitmapView<'a> {
pub offset: Offset,
pub fg_color: Color,
pub bg_color: Color,
pub alpha: u8,
}
impl<'a> BitmapView<'a> {
@ -285,6 +286,7 @@ impl<'a> BitmapView<'a> {
offset: Offset::zero(),
fg_color: Color::black(),
bg_color: Color::black(),
alpha: 255,
}
}
@ -306,6 +308,11 @@ impl<'a> BitmapView<'a> {
Self { bg_color, ..self }
}
/// Builds a new structure with alpha set to the specified value
pub fn with_alpha(self, alpha: u8) -> Self {
Self { alpha, ..self }
}
/// Returns the bitmap width and height in pixels
pub fn size(&self) -> Offset {
self.bitmap.size

@ -81,7 +81,7 @@ pub trait Canvas: BasicCanvas {
/// Draws a single pixel and blends its color with the background.
///
/// - If alpha == 255, the (foreground) pixel color is used.
/// - If 0 < alpha << 255, pixel and backround colors are blended.
/// - If 0 < alpha << 255, pixel and background colors are blended.
/// - If alpha == 0, the background color is used.
fn blend_pixel(&mut self, pt: Point, color: Color, alpha: u8);
@ -364,7 +364,7 @@ pub trait Canvas: BasicCanvas {
// Draws circle with the specified center and the radius.
#[cfg(not(feature = "ui_antialiasing"))]
fn draw_circle(&mut self, center: Point, radius: i16, color: Color) {
fn draw_circle(&mut self, center: Point, radius: i16, color: Color, alpha: u8) {
let split = unwrap!(circle_points(radius).last()).v;
let r = Rect::new(
@ -376,8 +376,8 @@ pub trait Canvas: BasicCanvas {
for p in circle_points(radius) {
let pt_l = Point::new(center.x - p.u, center.y - p.v);
let pt_r = Point::new(center.x + p.u, center.y - p.v);
self.draw_pixel(pt_l, color);
self.draw_pixel(pt_r, color);
self.blend_pixel(pt_l, color, alpha);
self.blend_pixel(pt_r, color, alpha);
}
}
@ -390,8 +390,8 @@ pub trait Canvas: BasicCanvas {
for p in circle_points(radius).take_while(|p| p.u < p.v) {
let pt_l = Point::new(center.x - p.v, center.y - p.u);
let pt_r = Point::new(center.x + p.v, center.y - p.u);
self.draw_pixel(pt_l, color);
self.draw_pixel(pt_r, color);
self.blend_pixel(pt_l, color, alpha);
self.blend_pixel(pt_r, color, alpha);
}
}
@ -404,8 +404,8 @@ pub trait Canvas: BasicCanvas {
for p in circle_points(radius).skip(1).take_while(|p| p.u < p.v) {
let pt_l = Point::new(center.x - p.v, center.y + p.u);
let pt_r = Point::new(center.x + p.v, center.y + p.u);
self.draw_pixel(pt_l, color);
self.draw_pixel(pt_r, color);
self.blend_pixel(pt_l, color, alpha);
self.blend_pixel(pt_r, color, alpha);
}
}
@ -418,17 +418,16 @@ pub trait Canvas: BasicCanvas {
for p in circle_points(radius) {
let pt_l = Point::new(center.x - p.u, center.y + p.v);
let pt_r = Point::new(center.x + p.u, center.y + p.v);
self.draw_pixel(pt_l, color);
self.draw_pixel(pt_r, color);
self.blend_pixel(pt_l, color, alpha);
self.blend_pixel(pt_r, color, alpha);
}
}
}
/// Draws filled circle with the specified center and the radius.
#[cfg(not(feature = "ui_antialiasing"))]
fn fill_circle(&mut self, center: Point, radius: i16, color: Color) {
fn fill_circle(&mut self, center: Point, radius: i16, color: Color, alpha: u8) {
let split = unwrap!(circle_points(radius).last()).v;
let alpha = 255;
let r = Rect::new(
Point::new(center.x - radius, center.y - radius),
@ -490,10 +489,9 @@ pub trait Canvas: BasicCanvas {
/// Draws antialiased filled circle with the specified center and the
/// radius.
#[cfg(feature = "ui_antialiasing")]
fn fill_circle(&mut self, center: Point, radius: i16, color: Color) {
fn fill_circle(&mut self, center: Point, radius: i16, color: Color, alpha: u8) {
let split = unwrap!(circle_points(radius).last()).v;
let alpha = 255;
let alpha_mul = |a: u8| -> u8 { ((a as u16 * alpha as u16) / 255) as u8 };
let r = Rect::new(

@ -14,6 +14,7 @@ pub struct Circle {
fg_color: Option<Color>,
bg_color: Option<Color>,
thickness: i16,
alpha: u8,
start_angle: Option<i16>,
end_angle: Option<i16>,
}
@ -26,6 +27,7 @@ impl Circle {
fg_color: None,
bg_color: None,
thickness: 1,
alpha: 255,
start_angle: None,
end_angle: None,
}
@ -49,6 +51,10 @@ impl Circle {
Self { thickness, ..self }
}
pub fn with_alpha(self, alpha: u8) -> Self {
Self { alpha, ..self }
}
pub fn with_start_angle(self, from_angle: i16) -> Self {
Self {
start_angle: Some(from_angle),
@ -94,22 +100,22 @@ impl Shape<'_> for Circle {
if self.start_angle.is_none() && self.end_angle.is_none() {
if th == 1 {
if let Some(color) = self.bg_color {
canvas.fill_circle(self.center, self.radius, color);
canvas.fill_circle(self.center, self.radius, color, self.alpha);
}
if let Some(color) = self.fg_color {
#[cfg(not(feature = "ui_antialiasing"))]
canvas.draw_circle(self.center, self.radius, color);
canvas.draw_circle(self.center, self.radius, color, self.alpha);
#[cfg(feature = "ui_antialiasing")]
canvas.fill_circle(self.center, self.radius, color);
canvas.fill_circle(self.center, self.radius, color, self.alpha);
}
} else {
if let Some(color) = self.fg_color {
if th > 0 {
canvas.fill_circle(self.center, self.radius, color);
canvas.fill_circle(self.center, self.radius, color, self.alpha);
}
}
if let Some(color) = self.bg_color {
canvas.fill_circle(self.center, self.radius - th, color);
canvas.fill_circle(self.center, self.radius - th, color, self.alpha);
}
}
} else {

@ -15,6 +15,8 @@ pub struct Text<'a> {
text: &'a str,
// Text color
color: Color,
// Text alpha
alpha: u8,
// Text font
font: Font,
// Horizontal alignment
@ -31,6 +33,7 @@ impl<'a> Text<'a> {
pos,
text,
color: Color::white(),
alpha: 255,
font: Font::NORMAL,
align: Alignment::Start,
bounds: Rect::zero(),
@ -49,6 +52,10 @@ impl<'a> Text<'a> {
Self { align, ..self }
}
pub fn with_alpha(self, alpha: u8) -> Self {
Self { alpha, ..self }
}
pub fn render<'r>(mut self, renderer: &mut impl Renderer<'r>) {
self.bounds = self.calc_bounds();
renderer.render_shape(self);
@ -98,6 +105,7 @@ impl<'a> Shape<'_> for Text<'a> {
let glyph = self.font.get_glyph(ch);
let glyph_bitmap = glyph.bitmap();
let glyph_view = BitmapView::new(&glyph_bitmap)
.with_alpha(self.alpha)
.with_fg(self.color)
.with_offset(Offset::new(
-glyph.bearing_x,

@ -22,6 +22,8 @@ pub struct ToifImage<'a> {
fg_color: Color,
// Optional background color
bg_color: Option<Color>,
// Alpha value
alpha: u8,
}
impl<'a> ToifImage<'a> {
@ -32,6 +34,7 @@ impl<'a> ToifImage<'a> {
toif,
fg_color: Color::white(),
bg_color: None,
alpha: 255,
}
}
@ -60,6 +63,10 @@ impl<'a> ToifImage<'a> {
}
}
pub fn with_alpha(self, alpha: u8) -> Self {
Self { alpha, ..self }
}
pub fn render(self, renderer: &mut impl Renderer<'a>) {
renderer.render_shape(self);
}
@ -101,7 +108,8 @@ impl<'a> ToifImage<'a> {
let slice_view = slice
.view()
.with_fg(self.fg_color)
.with_offset(Offset::new(r.x0 - bounds.top_left().x, 0));
.with_offset(Offset::new(r.x0 - bounds.top_left().x, 0))
.with_alpha(self.alpha);
match self.bg_color {
Some(bg_color) => canvas.draw_bitmap(r, slice_view.with_bg(bg_color)),

@ -97,13 +97,14 @@ bool dma2d_rgb565_fill(const gfx_bitblt_t* bb) {
return true;
}
static void dma2d_config_clut(uint32_t layer, gfx_color_t fg, gfx_color_t bg) {
static void dma2d_config_clut(uint32_t layer, gfx_color32_t fg,
gfx_color32_t bg) {
#define LAYER_COUNT 2
#define GRADIENT_STEPS 16
static struct {
gfx_color_t c_fg;
gfx_color_t c_bg;
gfx_color32_t c_fg;
gfx_color32_t c_bg;
} cache[LAYER_COUNT] = {0};
if (layer >= LAYER_COUNT) {
@ -118,15 +119,19 @@ static void dma2d_config_clut(uint32_t layer, gfx_color_t fg, gfx_color_t bg) {
cache[layer].c_bg = bg;
for (int step = 0; step < GRADIENT_STEPS; step++) {
clut[step] = gfx_color32_blend_a4(fg, bg, step);
clut[step] = gfx_color32_rgba(
a4_lerp(gfx_color32_to_r(fg), gfx_color32_to_r(bg), step),
a4_lerp(gfx_color32_to_g(fg), gfx_color32_to_g(bg), step),
a4_lerp(gfx_color32_to_b(fg), gfx_color32_to_b(bg), step),
a4_lerp(gfx_color32_to_a(fg), gfx_color32_to_a(bg), step));
}
DMA2D_CLUTCfgTypeDef clut;
clut.CLUTColorMode = DMA2D_CCM_ARGB8888;
clut.Size = GRADIENT_STEPS - 1;
clut.pCLUT = 0; // ???
DMA2D_CLUTCfgTypeDef clut_def = {0};
clut_def.CLUTColorMode = DMA2D_CCM_ARGB8888;
clut_def.Size = GRADIENT_STEPS - 1;
clut_def.pCLUT = 0; // ???
HAL_DMA2D_ConfigCLUT(&dma2d_handle, clut, layer);
HAL_DMA2D_ConfigCLUT(&dma2d_handle, clut_def, layer);
}
}
@ -204,7 +209,8 @@ bool dma2d_rgb565_copy_mono4(const gfx_bitblt_t* params) {
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_config_clut(1, bb->src_fg, bb->src_bg);
dma2d_config_clut(1, gfx_color_to_color32(bb->src_fg),
gfx_color_to_color32(bb->src_bg));
HAL_DMA2D_Start(&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
@ -247,7 +253,8 @@ static void dma2d_rgb565_blend_mono4_first_col(const gfx_bitblt_t* bb) {
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] >> 4;
dst_ptr[0] = gfx_color16_blend_a4(
fg_alpha = (fg_alpha * bb->src_alpha) / 15;
dst_ptr[0] = gfx_color16_blend_a8(
bb->src_fg, gfx_color16_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
@ -262,7 +269,8 @@ static void dma2d_rgb565_blend_mono4_last_col(const gfx_bitblt_t* bb) {
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] & 0x0F;
dst_ptr[0] = gfx_color16_blend_a4(
fg_alpha = (fg_alpha * bb->src_alpha) / 15;
dst_ptr[0] = gfx_color16_blend_a8(
bb->src_fg, gfx_color16_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
@ -302,12 +310,16 @@ bool dma2d_rgb565_blend_mono4(const gfx_bitblt_t* params) {
bb->dst_stride / sizeof(uint16_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4;
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_L4;
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = gfx_color_to_color32(bb->src_fg);
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA;
dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_config_clut(
1, gfx_color_to_color32(bb->src_fg),
gfx_color32_set_alpha(gfx_color_to_color32(bb->src_fg), 0));
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
dma2d_handle.LayerCfg[0].InputOffset =
bb->dst_stride / sizeof(uint16_t) - bb->width;
@ -450,7 +462,8 @@ bool dma2d_rgba8888_copy_mono4(const gfx_bitblt_t* params) {
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_config_clut(1, bb->src_fg, bb->src_bg);
dma2d_config_clut(1, gfx_color_to_color32(bb->src_fg),
gfx_color_to_color32(bb->src_bg));
HAL_DMA2D_Start(&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
@ -493,7 +506,8 @@ static void dma2d_rgba8888_blend_mono4_first_col(const gfx_bitblt_t* bb) {
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] >> 4;
dst_ptr[0] = gfx_color32_blend_a4(
fg_alpha = (fg_alpha * bb->src_alpha) / 15;
dst_ptr[0] = gfx_color32_blend_a8(
bb->src_fg, gfx_color32_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
@ -508,7 +522,8 @@ static void dma2d_rgba8888_blend_mono4_last_col(const gfx_bitblt_t* bb) {
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] & 0x0F;
dst_ptr[0] = gfx_color32_blend_a4(
fg_alpha = (fg_alpha * bb->src_alpha) / 15;
dst_ptr[0] = gfx_color32_blend_a8(
bb->src_fg, gfx_color32_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
@ -548,12 +563,16 @@ bool dma2d_rgba8888_blend_mono4(const gfx_bitblt_t* params) {
bb->dst_stride / sizeof(uint32_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4;
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_L4;
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = gfx_color_to_color32(bb->src_fg);
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA;
dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_config_clut(
1, gfx_color_to_color32(bb->src_fg),
gfx_color32_set_alpha(gfx_color_to_color32(bb->src_fg), 0));
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888;
dma2d_handle.LayerCfg[0].InputOffset =
bb->dst_stride / sizeof(uint32_t) - bb->width;

Loading…
Cancel
Save