Properly use premultiplied alpha
This commit is contained in:
@@ -24,19 +24,18 @@ impl Drawable for Circle {
|
||||
for l_row in 1..self.radius {
|
||||
let inner_diff = (((self.radius-1).pow(2) - l_row.pow(2)) as f64).sqrt();
|
||||
let outer_diff = ((self.radius.pow(2) - l_row.pow(2)) as f64).sqrt();
|
||||
let row: Vec<u32> = vec![self.color; 2*(inner_diff.floor() as usize)];
|
||||
shm_pool.write(&row, (self.y-l_row)*buffer.width + self.x - inner_diff.floor() as usize + buffer.offset);
|
||||
shm_pool.write(&row, (self.y+l_row-1)*buffer.width + self.x - inner_diff.floor() as usize + buffer.offset);
|
||||
shm_pool.write(self.color, (self.y-l_row)*buffer.width + self.x - inner_diff.floor() as usize + buffer.offset, 2*(inner_diff.floor() as usize));
|
||||
shm_pool.write(self.color, (self.y+l_row-1)*buffer.width + self.x - inner_diff.floor() as usize + buffer.offset, 2*(inner_diff.floor() as usize));
|
||||
for l_col in (inner_diff.floor() as usize+1)..(outer_diff.ceil() as usize) {
|
||||
let distance = ((l_row.pow(2) + l_col.pow(2)) as f64).sqrt();
|
||||
let offset = (self.y-l_row)*buffer.width + self.x - l_col + buffer.offset;
|
||||
shm_pool.write_pixel(color_blend(self.color, shm_pool.read_pixel(offset).unwrap(), distance.fract()), offset);
|
||||
shm_pool.write_pixel(color_blend(self.color, 0, distance.fract()), offset);
|
||||
let offset = (self.y-l_row)*buffer.width + self.x + l_col-1 + buffer.offset;
|
||||
shm_pool.write_pixel(color_blend(self.color, shm_pool.read_pixel(offset).unwrap(), distance.fract()), offset);
|
||||
shm_pool.write_pixel(color_blend(self.color, 0, distance.fract()), offset);
|
||||
let offset = (self.y+l_row-1)*buffer.width + self.x - l_col + buffer.offset;
|
||||
shm_pool.write_pixel(color_blend(self.color, shm_pool.read_pixel(offset).unwrap(), distance.fract()), offset);
|
||||
shm_pool.write_pixel(color_blend(self.color, 0, distance.fract()), offset);
|
||||
let offset = (self.y+l_row-1)*buffer.width + self.x + l_col-1 + buffer.offset;
|
||||
shm_pool.write_pixel(color_blend(self.color, shm_pool.read_pixel(offset).unwrap(), distance.fract()), offset);
|
||||
shm_pool.write_pixel(color_blend(self.color, 0, distance.fract()), offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,51 @@
|
||||
use crate::wayland::{shm::ShmPool, wl_shm::wl_buffer};
|
||||
|
||||
pub fn rgb_blend(col1: u32, col2: u32, diff: f64) -> u32 {
|
||||
let r1 = (col1 & 0x00ff0000) >> 16;
|
||||
let g1 = (col1 & 0x0000ff00) >> 8;
|
||||
let b1 = col1 & 0x000000ff;
|
||||
let r2 = (col2 & 0x00ff0000) >> 16;
|
||||
let g2 = (col2 & 0x0000ff00) >> 8;
|
||||
let b2 = col2 & 0x000000ff;
|
||||
let r3 = if r1 < r2 {
|
||||
r1 + ((r2 - r1) as f64 * diff) as u32
|
||||
} else {
|
||||
r1 - ((r1 - r2) as f64 * diff) as u32
|
||||
};
|
||||
let g3 = if g1 < g2 {
|
||||
g1 + ((g2 - g1) as f64 * diff) as u32
|
||||
} else {
|
||||
g1 - ((g1 - g2) as f64 * diff) as u32
|
||||
};
|
||||
let b3 = if b1 < b2 {
|
||||
b1 + ((b2 - b1) as f64 * diff) as u32
|
||||
} else {
|
||||
b1 - ((b1 - b2) as f64 * diff) as u32
|
||||
};
|
||||
(r3 << 16) + (g3 << 8) + b3
|
||||
pub fn premultiply(color: u32) -> u32 {
|
||||
let a = (color & 0xff000000) >> 24;
|
||||
let r = (color & 0x00ff0000) >> 16;
|
||||
let g = (color & 0x0000ff00) >> 8;
|
||||
let b = (color & 0x000000ff) >> 0;
|
||||
let alpha = (a as f64 / 0xff as f64);
|
||||
(a << 24) +
|
||||
(((r as f64*alpha) as u32) << 16) +
|
||||
(((g as f64*alpha) as u32) << 8) +
|
||||
(((b as f64*alpha) as u32) << 0)
|
||||
}
|
||||
|
||||
pub fn color_blend(col1: u32, col2: u32, diff: f64) -> u32 {
|
||||
let a1 = (col1 & 0xff000000) >> 24;
|
||||
let r1 = (col1 & 0x00ff0000) >> 16;
|
||||
let g1 = (col1 & 0x0000ff00) >> 8;
|
||||
let b1 = (col1 & 0x000000ff) >> 0;
|
||||
let a2 = (col2 & 0xff000000) >> 24;
|
||||
((a2 + ((a1 as f64/0xff as f64)*(0xff - a2) as f64*(1.0-diff)) as u32) << 24) + rgb_blend(col1, col2, diff * (a1 as f64 / 0xff as f64))
|
||||
let r2 = (col2 & 0x00ff0000) >> 16;
|
||||
let g2 = (col2 & 0x0000ff00) >> 8;
|
||||
let b2 = (col2 & 0x000000ff) >> 0;
|
||||
(((a1 as f64 + (a2 as f64 - a1 as f64) * diff).round() as u32) << 24) +
|
||||
(((r1 as f64 + (r2 as f64 - r1 as f64) * diff).round() as u32) << 16) +
|
||||
(((g1 as f64 + (b2 as f64 - g1 as f64) * diff).round() as u32) << 8 ) +
|
||||
(((b1 as f64 + (g2 as f64 - b1 as f64) * diff).round() as u32) << 0 )
|
||||
}
|
||||
|
||||
pub fn color_over(over: u32, under: u32) -> u32 {
|
||||
let a_over = (over & 0xff000000) >> 24;
|
||||
let a_under = (under & 0xff000000) >> 24;
|
||||
if a_over == 0xff || a_under == 0 {
|
||||
return over;
|
||||
}
|
||||
if a_over == 0 {
|
||||
return under;
|
||||
}
|
||||
let r_over = (over & 0x00ff0000) >> 16;
|
||||
let r_under = (under & 0x00ff0000) >> 16;
|
||||
let g_over = (over & 0x0000ff00) >> 8;
|
||||
let g_under = (under & 0x0000ff00) >> 8;
|
||||
let b_over = (over & 0x000000ff) >> 0;
|
||||
let b_under = (under & 0x000000ff) >> 0;
|
||||
((a_over + (a_under as f64 * (0xff - a_over) as f64 / 0xff as f64) as u32).min(0xff) << 24).min(0xff) +
|
||||
((r_over + (r_under as f64 * (0xff - a_over) as f64 / 0xff as f64) as u32).min(0xff) << 16).min(0xff) +
|
||||
((g_over + (g_under as f64 * (0xff - a_over) as f64 / 0xff as f64) as u32).min(0xff) << 8) +
|
||||
((b_over + (b_under as f64 * (0xff - a_over) as f64 / 0xff as f64) as u32).min(0xff) << 0)
|
||||
}
|
||||
|
||||
pub trait Drawable : Send {
|
||||
|
||||
@@ -24,24 +24,24 @@ impl Drawable for Rectangle {
|
||||
|
||||
fn draw(&self, buffer: &wl_buffer, shm_pool: &mut ShmPool) {
|
||||
for g_row in self.y+self.radius..self.y+self.height-self.radius+1 {
|
||||
shm_pool.write(&vec![self.color; self.width], g_row*buffer.width as usize+self.x + buffer.offset);
|
||||
shm_pool.write(self.color, g_row*buffer.width as usize+self.x + buffer.offset, self.width);
|
||||
}
|
||||
for l_row in 1..self.radius {
|
||||
let inner_diff = (((self.radius-1).pow(2) - l_row.pow(2)) as f64).sqrt();
|
||||
let outer_diff = ((self.radius.pow(2) - l_row.pow(2)) as f64).sqrt();
|
||||
shm_pool.write(&vec![self.color; self.width - (2*(self.radius - inner_diff.floor() as usize-1))], (self.y+self.radius-l_row)*buffer.width as usize + self.x + self.radius - inner_diff.floor() as usize-1 + buffer.offset);
|
||||
shm_pool.write(&vec![self.color; self.width - (2*(self.radius - inner_diff.floor() as usize-1))], (self.y+self.height-self.radius+l_row)*buffer.width as usize + self.x + self.radius - inner_diff.floor() as usize-1 + buffer.offset);
|
||||
shm_pool.write(self.color, (self.y+self.radius-l_row)*buffer.width as usize + self.x + self.radius - inner_diff.floor() as usize-1 + buffer.offset, self.width - (2*(self.radius - inner_diff.floor() as usize-1)));
|
||||
shm_pool.write(self.color, (self.y+self.height-self.radius+l_row)*buffer.width as usize + self.x + self.radius - inner_diff.floor() as usize-1 + buffer.offset, self.width - (2*(self.radius - inner_diff.floor() as usize-1)));
|
||||
for l_col in inner_diff.floor() as usize+1..outer_diff.ceil() as usize {
|
||||
// TODO: handle error from read_pixel
|
||||
let distance = ((l_row.pow(2) + l_col.pow(2)) as f64).sqrt();
|
||||
let offset = (self.y+self.radius-l_row)*buffer.width as usize + self.x + self.radius - l_col - 1 + buffer.offset;
|
||||
shm_pool.write_pixel(color_blend(self.color, shm_pool.read_pixel(offset).unwrap(), distance.fract()), offset);
|
||||
shm_pool.write_pixel(color_blend(self.color, 0, distance.fract()), offset);
|
||||
let offset = (self.y+self.radius-l_row)*buffer.width as usize + self.x + self.width - self.radius + l_col + buffer.offset;
|
||||
shm_pool.write_pixel(color_blend(self.color, shm_pool.read_pixel(offset).unwrap(), distance.fract()), offset);
|
||||
shm_pool.write_pixel(color_blend(self.color, 0, distance.fract()), offset);
|
||||
let offset = (self.y+self.height-self.radius+l_row)*buffer.width as usize + self.x + self.radius - l_col - 1 + buffer.offset;
|
||||
shm_pool.write_pixel(color_blend(self.color, shm_pool.read_pixel(offset).unwrap(), distance.fract()), offset);
|
||||
shm_pool.write_pixel(color_blend(self.color, 0, distance.fract()), offset);
|
||||
let offset = (self.y+self.height-self.radius+l_row)*buffer.width as usize + self.x + self.width - self.radius + l_col + buffer.offset;
|
||||
shm_pool.write_pixel(color_blend(self.color, shm_pool.read_pixel(offset).unwrap(), distance.fract()), offset);
|
||||
shm_pool.write_pixel(color_blend(self.color, 0, distance.fract()), offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user