feat: Implement eraser
This commit is contained in:
130
src/mscanvas.rs
130
src/mscanvas.rs
@@ -40,16 +40,15 @@ pub struct MSCanvas {
|
||||
width: i32,
|
||||
height: i32,
|
||||
|
||||
// 原始像素数据:RGBA 格式
|
||||
// 长度 = width * height * 4
|
||||
/// 原始像素数据:RGBA 格式
|
||||
/// 长度 = width * height * 4
|
||||
pixels: Vec<u8>,
|
||||
pixels_bak: Vec<u8>,
|
||||
|
||||
// 当前笔画颜色
|
||||
/// 当前笔画颜色
|
||||
color: MSColor,
|
||||
|
||||
// brush 大小
|
||||
brush_radius: f32,
|
||||
line_width: i32,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
@@ -61,7 +60,7 @@ impl MSCanvas {
|
||||
pixels: vec![255; (width * height * 4) as usize],
|
||||
pixels_bak: Vec::new(),
|
||||
color: MSColor::BLACK,
|
||||
brush_radius: 0.5,
|
||||
line_width: 1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,13 +68,17 @@ impl MSCanvas {
|
||||
self.color = color;
|
||||
}
|
||||
|
||||
pub fn set_brush_radius(&mut self, brush_radius: f32) {
|
||||
self.brush_radius = brush_radius;
|
||||
pub fn set_line_width(&mut self, line_width: i32) {
|
||||
self.line_width = line_width;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl MSCanvas {
|
||||
pub fn size(&self) -> (i32, i32) {
|
||||
(self.width, self.height)
|
||||
}
|
||||
|
||||
pub fn get_pixels(&self) -> Vec<u8> {
|
||||
self.pixels.clone()
|
||||
}
|
||||
@@ -157,15 +160,16 @@ impl MSCanvas {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_brush_at(&mut self, center: Point) {
|
||||
if self.brush_radius < 1.0 {
|
||||
pub fn brush_circle(&mut self, center: Point) {
|
||||
if self.line_width <= 1 {
|
||||
self.draw_pixel_at(center);
|
||||
return;
|
||||
}
|
||||
let square = self.brush_radius * self.brush_radius;
|
||||
let r = self.brush_radius.floor() as i32;
|
||||
for dy in -r..=r {
|
||||
for dx in -r..=r {
|
||||
let square = (self.line_width as f32) * (self.line_width as f32) / 4.0;
|
||||
let l = self.line_width / 2;
|
||||
let r = self.line_width - l;
|
||||
for dy in -l..r {
|
||||
for dx in -l..r {
|
||||
if (dx * dx + dy * dy) as f32 <= square {
|
||||
self.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
|
||||
}
|
||||
@@ -173,6 +177,20 @@ impl MSCanvas {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn brush_square(&mut self, center: Point) {
|
||||
if self.line_width <= 1 {
|
||||
self.draw_pixel_at(center);
|
||||
return;
|
||||
}
|
||||
let l = self.line_width / 2;
|
||||
let r = self.line_width - l;
|
||||
for dy in -l..r {
|
||||
for dx in -l..r {
|
||||
self.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bresenham_line(&mut self, begin: Point, end: Point) -> Vec<Point> {
|
||||
let x1 = begin.x;
|
||||
let y1 = begin.y;
|
||||
@@ -259,10 +277,25 @@ impl MSCanvas {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_line_thick(&mut self, begin: Point, end: Point) {
|
||||
pub fn draw_line_with_circle_brush(&mut self, begin: Point, end: Point) {
|
||||
// let points = self.bresenham_line(begin, end);
|
||||
// for point in points {
|
||||
// self.draw_brush_at(point);
|
||||
// }
|
||||
self.draw_line_with(begin, end, MSCanvas::brush_circle);
|
||||
}
|
||||
|
||||
pub fn draw_line_with_square_brush(&mut self, begin: Point, end: Point) {
|
||||
self.draw_line_with(begin, end, MSCanvas::brush_square);
|
||||
}
|
||||
|
||||
pub fn draw_line_with<F>(&mut self, begin: Point, end: Point, brush_fn: F)
|
||||
where
|
||||
F: Fn(&mut MSCanvas, Point) -> (),
|
||||
{
|
||||
let points = self.bresenham_line(begin, end);
|
||||
for point in points {
|
||||
self.draw_brush_at(point);
|
||||
brush_fn(self, point);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,22 +420,65 @@ impl MSCanvas {
|
||||
(iter_count, fill_count)
|
||||
}
|
||||
|
||||
pub fn stroke_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
|
||||
self.draw_line_thick(Point::new(x, y), Point::new(x, y + height));
|
||||
self.draw_line_thick(Point::new(x, y + height), Point::new(x + width, y + height));
|
||||
self.draw_line_thick(Point::new(x + width, y + height), Point::new(x + width, y));
|
||||
self.draw_line_thick(Point::new(x, y), Point::new(x + width, y));
|
||||
pub fn clear_rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
|
||||
for yi in y..(y + height) {
|
||||
self.clear_row(x, x + width, yi);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stroke_rect1(&mut self, left_top: Point, right_bottom: Point) {
|
||||
let x = left_top.x;
|
||||
let y = left_top.y;
|
||||
let width = (right_bottom.x - left_top.x);
|
||||
let height = (right_bottom.y - left_top.y);
|
||||
self.stroke_rect(x, y, width, height);
|
||||
pub fn fill_rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
|
||||
for yi in y..(y + height) {
|
||||
self.draw_pixel_row(x, x + width, yi);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stroke_rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
|
||||
self.fill_rect(x, y, width, self.line_width);
|
||||
self.fill_rect(x, y + height - self.line_width, width, self.line_width);
|
||||
self.fill_rect(x, y, self.line_width, height);
|
||||
self.fill_rect(x + width - self.line_width, y, self.line_width, height);
|
||||
}
|
||||
|
||||
pub fn stroke_rect1(&mut self, p1: Point, p2: Point) {
|
||||
let mut x = p1.x;
|
||||
let mut y = p1.y;
|
||||
let mut width = (p2.x - p1.x);
|
||||
let mut height = (p2.y - p1.y);
|
||||
if width < 0.0 && height < 0.0 {
|
||||
x = p2.x;
|
||||
y = p2.y;
|
||||
width = (p1.x - p2.x);
|
||||
height = (p1.y - p2.y);
|
||||
} else if width < 0.0 {
|
||||
x += width;
|
||||
width = -width;
|
||||
} else if height < 0.0 {
|
||||
y += height;
|
||||
height = -height;
|
||||
}
|
||||
self.stroke_rect(x as i32, y as i32, width as i32, height as i32);
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.pixels.fill(255);
|
||||
}
|
||||
|
||||
pub fn clear_row(&mut self, xs: i32, xe: i32, y: i32) {
|
||||
if y < 0 || y >= self.height {
|
||||
return;
|
||||
}
|
||||
|
||||
let xs = xs.clamp(0, self.width - 1);
|
||||
let xe = xe.clamp(0, self.width as i32);
|
||||
for x in xs..xe {
|
||||
let index = ((y * self.width + x) * 4) as usize;
|
||||
|
||||
// 写入 RGBA 数据
|
||||
// 注意:Color 的 r, g, b, a 是 0.0 - 1.0,需要转为 0 - 255
|
||||
self.pixels[index] = 255; // R
|
||||
self.pixels[index + 1] = 255; // G
|
||||
self.pixels[index + 2] = 255; // B
|
||||
self.pixels[index + 3] = 255; // A
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user