drawing_stuff/canvas.rs
1use crate::color::{RGB, RGBA};
2
3/// Trait for drawing anything arbitrary onto a [`Canvas`].
4///
5/// # Examples
6///
7/// ```
8/// use drawing_stuff::canvas::{Canvas, Draw};
9/// use drawing_stuff::color::RGBA;
10///
11/// pub struct Circle {
12/// pub center: (isize, isize),
13/// pub radius: u32,
14/// pub solid: bool,
15///
16/// pub color: RGBA,
17/// }
18///
19/// impl Draw for Circle {
20/// fn draw(&self, canvas: &mut Canvas) {
21/// match self.solid {
22/// true => canvas.draw_circle_solid(self.center.0, self.center.1, self.radius, self.color),
23/// false => canvas.draw_circle(self.center.0, self.center.1, self.radius, self.color),
24/// }
25/// }
26/// }
27/// ```
28pub trait Draw {
29 /// Draws onto a [`Canvas`].
30 fn draw(&self, canvas: &mut Canvas);
31}
32
33#[derive(Debug, Clone)]
34/// A [`Canvas`] is just a glorified pixel buffer with some usefull functionality.
35pub struct Canvas {
36 width: usize,
37 height: usize,
38
39 buffer: Vec<RGB>,
40}
41
42impl Canvas {
43 /// Creates a new black canvas.
44 ///
45 /// # Examples
46 ///
47 /// ```
48 /// use drawing_stuff::canvas::Canvas;
49 ///
50 /// const WIDTH: usize = 1080;
51 /// const HEIGHT: usize = 720;
52 ///
53 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
54 /// ```
55 pub fn new(width: usize, height: usize) -> Self {
56 Canvas {
57 width,
58 height,
59 buffer: vec![RGB { r: 0, g: 0, b: 0 }; width * height],
60 }
61 }
62}
63
64impl Canvas {
65 /// Returns the width of the canvas.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// use drawing_stuff::canvas::Canvas;
71 ///
72 /// const WIDTH: usize = 1080;
73 /// const HEIGHT: usize = 720;
74 ///
75 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
76 ///
77 /// assert_eq!(WIDTH, canvas.width());
78 /// ```
79 pub fn width(&self) -> usize {
80 self.width
81 }
82
83 /// Returns the height of the canvas.
84 ///
85 /// # Examples
86 ///
87 /// ```
88 /// use drawing_stuff::canvas::Canvas;
89 ///
90 /// const WIDTH: usize = 1080;
91 /// const HEIGHT: usize = 720;
92 ///
93 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
94 ///
95 /// assert_eq!(HEIGHT, canvas.height());
96 /// ```
97 pub fn height(&self) -> usize {
98 self.height
99 }
100
101 /// Returns a reference to the pixel buffer of the canvas.
102 ///
103 /// # Examples
104 ///
105 /// ```
106 /// use drawing_stuff::canvas::Canvas;
107 ///
108 /// const WIDTH: usize = 1080;
109 /// const HEIGHT: usize = 720;
110 ///
111 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
112 ///
113 /// let buffer = canvas.buffer();
114 /// ```
115 pub fn buffer(&self) -> &Vec<RGB> {
116 &self.buffer
117 }
118
119 /// Returns a mutabel reference to the pixel buffer of the canvas.
120 ///
121 /// # Examples
122 ///
123 /// ```
124 /// use drawing_stuff::canvas::Canvas;
125 /// use drawing_stuff::color::RGB;
126 ///
127 /// const WIDTH: usize = 1080;
128 /// const HEIGHT: usize = 720;
129 ///
130 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
131 ///
132 /// let buffer = canvas.buffer_mut();
133 /// for pixel in buffer {
134 /// *pixel = RGB { r: 255, g: 255, b: 255 };
135 /// }
136 /// ```
137 pub fn buffer_mut(&mut self) -> &mut Vec<RGB> {
138 &mut self.buffer
139 }
140
141 /// Returns the pixel buffer as a 32-bit buffer in the format `0RGB`.
142 ///
143 /// # Examples
144 ///
145 /// ```
146 /// use drawing_stuff::canvas::Canvas;
147 ///
148 /// const WIDTH: usize = 1080;
149 /// const HEIGHT: usize = 720;
150 ///
151 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
152 ///
153 /// let buffer = canvas.buffer_u32();
154 /// ```
155 pub fn buffer_u32(&self) -> Vec<u32> {
156 self.buffer
157 .iter()
158 .map(|c| (c.r as u32) << 16 | (c.g as u32) << 8 | (c.b as u32))
159 .collect::<Vec<u32>>()
160 }
161
162 /// Checks if the pixel specified lays inside of the canvas.
163 ///
164 /// # Examples
165 ///
166 /// ```
167 /// use drawing_stuff::canvas::Canvas;
168 ///
169 /// const WIDTH: usize = 1080;
170 /// const HEIGHT: usize = 720;
171 ///
172 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
173 ///
174 /// let in_bound = canvas.pixel_inside(200, 100);
175 /// assert_eq!(true, in_bound);
176 /// ```
177 pub fn pixel_inside(&self, x: isize, y: isize) -> bool {
178 x >= 0 && x < self.width as isize && y >= 0 && y < self.height as isize
179 }
180
181 /// Returns the color of the pixel at the specified position.
182 ///
183 /// Returns `None` if position is not inside the canvas.
184 ///
185 /// # Examples
186 ///
187 /// ```
188 /// use drawing_stuff::canvas::Canvas;
189 ///
190 /// const WIDTH: usize = 1080;
191 /// const HEIGHT: usize = 720;
192 ///
193 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
194 ///
195 /// let pixel = canvas.get(200, 100);
196 ///
197 /// assert_eq!(true, pixel.is_some());
198 /// ```
199 pub fn get(&self, x: usize, y: usize) -> Option<&RGB> {
200 self.buffer.get(y * self.width + x)
201 }
202
203 /// Sets the color of the pixel at the specified position.
204 ///
205 /// Returns `None` if position is not inside the canvas.
206 ///
207 /// # Examples
208 ///
209 /// ```
210 /// use drawing_stuff::canvas::Canvas;
211 /// use drawing_stuff::color::RGB;
212 ///
213 /// const WIDTH: usize = 1080;
214 /// const HEIGHT: usize = 720;
215 ///
216 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
217 ///
218 /// let color = RGB { r: 255, g: 255, b: 255 };
219 /// let success = canvas.set(200, 100, color);
220 ///
221 /// assert_eq!(true, success.is_some());
222 /// ```
223 pub fn set(&mut self, x: usize, y: usize, color: RGB) -> Option<()> {
224 *self.buffer.get_mut(y * self.width + x)? = color;
225 Some(())
226 }
227
228 /// Fills the whole canvas with a given color.
229 ///
230 /// # Examples
231 ///
232 /// ```
233 /// use drawing_stuff::canvas::Canvas;
234 /// use drawing_stuff::color::RGB;
235 ///
236 /// const WIDTH: usize = 1080;
237 /// const HEIGHT: usize = 720;
238 ///
239 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
240 ///
241 /// let color = RGB { r: 255, g: 255, b: 255 };
242 /// canvas.fill(color);
243 /// ```
244 pub fn fill(&mut self, color: RGB) {
245 self.buffer = vec![color; self.width * self.height];
246 }
247}
248
249impl Canvas {
250 /// Draws anything arbitrary implementing the `Draw` trait onto the canvas.
251 ///
252 /// # Examples
253 ///
254 /// ```
255 /// use drawing_stuff::canvas::{Canvas, Draw};
256 /// use drawing_stuff::color::RGBA;
257 ///
258 /// pub struct Circle {
259 /// pub center: (isize, isize),
260 /// pub radius: u32,
261 /// pub solid: bool,
262 ///
263 /// pub color: RGBA,
264 /// }
265 ///
266 /// impl Draw for Circle {
267 /// fn draw(&self, canvas: &mut Canvas) {
268 /// match self.solid {
269 /// true => canvas.draw_circle_solid(self.center.0, self.center.1, self.radius, self.color),
270 /// false => canvas.draw_circle(self.center.0, self.center.1, self.radius, self.color),
271 /// }
272 /// }
273 /// }
274 ///
275 /// const WIDTH: usize = 1080;
276 /// const HEIGHT: usize = 720;
277 ///
278 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
279 ///
280 /// let color = RGBA { r: 255, g: 255, b: 255, a: 255 };
281 /// let circle = Circle {
282 /// center: (200, 100),
283 /// radius: 50,
284 /// solid: true,
285 /// color,
286 /// };
287 ///
288 /// canvas.draw(&circle);
289 /// // or
290 /// circle.draw(&mut canvas);
291 /// ```
292 pub fn draw<T>(&mut self, drawable: &T)
293 where
294 T: Draw,
295 {
296 drawable.draw(self);
297 }
298
299 /// Draws a single pixel onto the canvas.
300 ///
301 /// Returns `None` if position is not inside the canvas.
302 ///
303 /// # Examples
304 ///
305 /// ```
306 /// use drawing_stuff::canvas::Canvas;
307 /// use drawing_stuff::color::RGBA;
308 ///
309 /// const WIDTH: usize = 1080;
310 /// const HEIGHT: usize = 720;
311 ///
312 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
313 ///
314 /// let color = RGBA { r: 255, g: 255, b: 255, a: 255 };
315 /// let success = canvas.draw_pixel(200, 100, color);
316 ///
317 /// assert_eq!(true, success.is_some());
318 /// ```
319 pub fn draw_pixel(&mut self, x: isize, y: isize, color: RGBA) -> Option<()> {
320 if !self.pixel_inside(x, y) {
321 return None;
322 };
323
324 let old_color = self.get(x as usize, y as usize)?;
325 let new_color = old_color.add_rgba(color);
326 self.set(x as usize, y as usize, new_color)
327 }
328
329 /// Draws a line onto the canvas.
330 ///
331 /// # Examples
332 ///
333 /// ```
334 /// use drawing_stuff::canvas::Canvas;
335 /// use drawing_stuff::color::RGBA;
336 ///
337 /// const WIDTH: usize = 1080;
338 /// const HEIGHT: usize = 720;
339 ///
340 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
341 ///
342 /// let color = RGBA { r: 255, g: 255, b: 255, a: 255 };
343 /// canvas.draw_line(200, 100, 500, 700, color);
344 /// ```
345 pub fn draw_line(&mut self, x1: isize, y1: isize, x2: isize, y2: isize, color: RGBA) {
346 if x1 == x2 {
347 let (start_y, end_y) = if y1 < y2 { (y1, y2) } else { (y2, y1) };
348 for i in 0..(end_y - start_y) {
349 self.draw_pixel(x1, start_y + i, color);
350 }
351 return;
352 }
353
354 let dx = (x2 - x1).abs();
355 let dy = (y2 - y1).abs();
356
357 let abs_m = dy as f32 / dx as f32;
358 match abs_m <= 1.0 {
359 true => {
360 let (start_x, start_y, end_x, end_y) = if x1 < x2 {
361 (x1, y1, x2, y2)
362 } else {
363 (x2, y2, x1, y1)
364 };
365
366 let step = if start_y < end_y { 1 } else { -1 };
367
368 let a = 2 * dy;
369 let b = a - 2 * dx;
370 let mut p = a - dx;
371 self.draw_pixel(start_x, start_y, color);
372
373 let mut offset = 0isize;
374 for i in 1..=(end_x - start_x) {
375 match p < 0 {
376 true => {
377 p += a;
378 }
379 false => {
380 offset += step;
381 p += b;
382 }
383 }
384
385 self.draw_pixel(start_x + i, start_y + offset, color);
386 }
387 }
388 false => {
389 let (start_x, start_y, end_x, end_y) = if y1 < y2 {
390 (x1, y1, x2, y2)
391 } else {
392 (x2, y2, x1, y1)
393 };
394
395 let step = if start_x < end_x { 1 } else { -1 };
396
397 let a = 2 * dx;
398 let b = a - 2 * dy;
399 let mut p = a - dy;
400
401 self.draw_pixel(start_x, start_y, color);
402
403 let mut offset = 0isize;
404 for i in 1..=(end_y - start_y) {
405 match p < 0 {
406 true => {
407 p += a;
408 }
409 false => {
410 offset += step;
411 p += b;
412 }
413 }
414
415 self.draw_pixel(start_x + offset, start_y + i, color);
416 }
417 }
418 }
419 }
420
421 /// Draws a line with specified width onto the canvas.
422 /// Drawing the line as a filled polygon.
423 ///
424 /// # Examples
425 ///
426 /// ```
427 /// use drawing_stuff::canvas::Canvas;
428 /// use drawing_stuff::color::RGBA;
429 ///
430 /// const WIDTH: usize = 1080;
431 /// const HEIGHT: usize = 720;
432 ///
433 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
434 ///
435 /// let color = RGBA { r: 255, g: 255, b: 255, a: 255 };
436 /// canvas.draw_polyline(200, 100, 500, 700, 5, color);
437 /// ```
438 pub fn draw_polyline(
439 &mut self,
440 x1: isize,
441 y1: isize,
442 x2: isize,
443 y2: isize,
444 width: u32,
445 color: RGBA,
446 ) {
447 if width == 0 {
448 return;
449 }
450
451 if width == 1 {
452 self.draw_line(x1, y1, x2, y2, color);
453 return;
454 }
455
456 let dx = x2 - x1;
457 let dy = y2 - y1;
458
459 let d_len = ((dx * dx + dy * dy) as f32).sqrt();
460 let dx_n = dx as f32 / d_len;
461 let dy_n = dy as f32 / d_len;
462
463 let v1 = (
464 x1 - (dy_n * width as f32 / 2.0).round() as isize,
465 y1 + (dx_n * width as f32 / 2.0).round() as isize,
466 );
467 let v2 = (
468 x1 + (dy_n * width as f32 / 2.0).round() as isize,
469 y1 - (dx_n * width as f32 / 2.0).round() as isize,
470 );
471 let v3 = (
472 x2 + (dy_n * width as f32 / 2.0).round() as isize,
473 y2 - (dx_n * width as f32 / 2.0).round() as isize,
474 );
475 let v4 = (
476 x2 - (dy_n * width as f32 / 2.0).round() as isize,
477 y2 + (dx_n * width as f32 / 2.0).round() as isize,
478 );
479
480 let vertices = vec![v1, v2, v3, v4];
481
482 self.draw_polygon_solid(&vertices, true, color);
483 }
484
485 /// Draws a line with specified width and capped ends onto the canvas.
486 /// Drawing the line as a filled polygon with circles on both ends.
487 ///
488 /// # Examples
489 ///
490 /// ```
491 /// use drawing_stuff::canvas::Canvas;
492 /// use drawing_stuff::color::RGBA;
493 ///
494 /// const WIDTH: usize = 1080;
495 /// const HEIGHT: usize = 720;
496 ///
497 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
498 ///
499 /// let color = RGBA { r: 255, g: 255, b: 255, a: 255 };
500 /// canvas.draw_polyline_capped(200, 100, 500, 700, 5, color);
501 /// ```
502 pub fn draw_polyline_capped(
503 &mut self,
504 x1: isize,
505 y1: isize,
506 x2: isize,
507 y2: isize,
508 width: u32,
509 color: RGBA,
510 ) {
511 self.draw_polyline(x1, y1, x2, y2, width, color);
512 self.draw_circle_solid(x1, y1, width / 2, color);
513 self.draw_circle_solid(x2, y2, width / 2, color);
514 }
515
516 /// Draws a circle onto the canvas.
517 ///
518 /// # Examples
519 ///
520 /// ```
521 /// use drawing_stuff::canvas::Canvas;
522 /// use drawing_stuff::color::RGBA;
523 ///
524 /// const WIDTH: usize = 1080;
525 /// const HEIGHT: usize = 720;
526 ///
527 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
528 ///
529 /// let color = RGBA { r: 255, g: 255, b: 255, a: 255 };
530 /// canvas.draw_circle(200, 100, 15, color);
531 /// ```
532 pub fn draw_circle(&mut self, x: isize, y: isize, r: u32, color: RGBA) {
533 if r == 0 {
534 return;
535 }
536
537 let mut e = -(r as isize);
538 let mut x_offset = r as isize;
539 let mut y_offset = 0isize;
540
541 while y_offset <= x_offset {
542 self.draw_pixel(x + x_offset, y + y_offset, color);
543 self.draw_pixel(x + x_offset, y - y_offset, color);
544 self.draw_pixel(x - x_offset, y + y_offset, color);
545 self.draw_pixel(x - x_offset, y - y_offset, color);
546
547 self.draw_pixel(x + y_offset, y + x_offset, color);
548 self.draw_pixel(x + y_offset, y - x_offset, color);
549 self.draw_pixel(x - y_offset, y - x_offset, color);
550 self.draw_pixel(x - y_offset, y + x_offset, color);
551
552 e += 2 * y_offset + 1;
553 y_offset += 1;
554 if e >= 0 {
555 e -= 2 * x_offset - 1;
556 x_offset -= 1;
557 }
558 }
559 }
560
561 /// Draws a solid circle onto the canvas.
562 ///
563 /// # Examples
564 ///
565 /// ```
566 /// use drawing_stuff::canvas::Canvas;
567 /// use drawing_stuff::color::RGBA;
568 ///
569 /// const WIDTH: usize = 1080;
570 /// const HEIGHT: usize = 720;
571 ///
572 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
573 ///
574 /// let color = RGBA { r: 255, g: 255, b: 255, a: 255 };
575 /// canvas.draw_circle_solid(200, 100, 15, color);
576 /// ```
577 pub fn draw_circle_solid(&mut self, x: isize, y: isize, r: u32, color: RGBA) {
578 if r == 0 {
579 return;
580 }
581
582 let mut e = -(r as isize);
583 let mut x_offset = r as isize;
584 let mut y_offset = 0isize;
585
586 let dy = 2 * r;
587
588 let mut left_buff = vec![0isize; dy as usize + 1];
589 let mut right_buff = vec![0isize; dy as usize + 1];
590
591 while y_offset <= x_offset {
592 right_buff[(y + y_offset - (y - r as isize)) as usize] = x + x_offset;
593 right_buff[(y - y_offset - (y - r as isize)) as usize] = x + x_offset;
594 left_buff[(y + y_offset - (y - r as isize)) as usize] = x - x_offset;
595 left_buff[(y - y_offset - (y - r as isize)) as usize] = x - x_offset;
596
597 right_buff[(y + x_offset - (y - r as isize)) as usize] = x + y_offset;
598 right_buff[(y - x_offset - (y - r as isize)) as usize] = x + y_offset;
599 left_buff[(y + x_offset - (y - r as isize)) as usize] = x - y_offset;
600 left_buff[(y - x_offset - (y - r as isize)) as usize] = x - y_offset;
601
602 e += 2 * y_offset + 1;
603 y_offset += 1;
604 if e >= 0 {
605 e -= 2 * x_offset - 1;
606 x_offset -= 1;
607 }
608 }
609
610 for i in 0..dy {
611 let y = i as isize + (y - r as isize);
612 let x1 = left_buff[i as usize];
613 let x2 = right_buff[i as usize];
614
615 for x in x1..x2 {
616 self.draw_pixel(x, y, color);
617 }
618 }
619 }
620
621 /// Draws a polygon onto the canvas.
622 ///
623 /// # Examples
624 ///
625 /// ```
626 /// use drawing_stuff::canvas::Canvas;
627 /// use drawing_stuff::color::RGBA;
628 ///
629 /// const WIDTH: usize = 1080;
630 /// const HEIGHT: usize = 720;
631 ///
632 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
633 ///
634 /// let color = RGBA { r: 255, g: 255, b: 255, a: 255 };
635 /// let vertices = vec![(200, 100), (500, 700), (300, 800)];
636 /// canvas.draw_polygon(&vertices, color);
637 /// ```
638 pub fn draw_polygon(&mut self, vertices: &Vec<(isize, isize)>, color: RGBA) {
639 if vertices.is_empty() {
640 return;
641 }
642
643 for i in 1..vertices.len() {
644 let (x1, y1) = vertices[i];
645 let (x2, y2) = vertices[i - 1];
646 self.draw_line(x1, y1, x2, y2, color);
647 }
648
649 let (x1, y1) = vertices[0];
650 let (x2, y2) = vertices[vertices.len() - 1];
651 self.draw_line(x1, y1, x2, y2, color);
652 }
653
654 /// Draws a solid polygon onto the canvas.
655 ///
656 /// The vertices of the polygon have to be given in the specified order (clockwise / anti-clockwise).
657 ///
658 /// # Examples
659 ///
660 /// ```
661 /// use drawing_stuff::canvas::Canvas;
662 /// use drawing_stuff::color::RGBA;
663 ///
664 /// const WIDTH: usize = 1080;
665 /// const HEIGHT: usize = 720;
666 ///
667 /// let mut canvas = Canvas::new(WIDTH, HEIGHT);
668 ///
669 /// let color = RGBA { r: 255, g: 255, b: 255, a: 255 };
670 /// let clockwise = true;
671 /// let vertices = vec![(200, 100), (500, 700), (300, 800)]; // clockwise
672 /// canvas.draw_polygon_solid(&vertices, clockwise, color);
673 /// ```
674 pub fn draw_polygon_solid(
675 &mut self,
676 vertices: &Vec<(isize, isize)>,
677 clockwise: bool,
678 color: RGBA,
679 ) {
680 if vertices.is_empty() {
681 return;
682 }
683
684 let mut min_vert = 0;
685 let mut max_vert = 0;
686 for i in 0..vertices.len() {
687 if vertices[i].1 < vertices[min_vert].1 {
688 min_vert = i;
689 }
690 if vertices[i].1 > vertices[max_vert].1 {
691 max_vert = i;
692 }
693 }
694
695 let (start_x, start_y) = vertices[min_vert];
696
697 let vertices = vertices
698 .into_iter()
699 .map(|(x, y)| (x - start_x, y - start_y))
700 .collect::<Vec<_>>();
701
702 let dy = (vertices[max_vert].1 + 1) as usize;
703
704 let mut left_buff = vec![0isize; dy];
705 let mut right_buff = vec![0isize; dy];
706
707 let start_vert = if clockwise { min_vert } else { max_vert };
708 let end_vert = if clockwise { max_vert } else { min_vert };
709
710 let mut vert_index = start_vert;
711 loop {
712 let (x1, y1) = vertices[vert_index % vertices.len()];
713 let (x2, y2) = vertices[(vert_index + 1) % vertices.len()];
714
715 Self::polygon_buffer_line(&mut right_buff, true, x1, y1, x2, y2);
716
717 vert_index += 1;
718 if vert_index % vertices.len() == end_vert {
719 break;
720 }
721 }
722
723 let mut vert_index = end_vert;
724 loop {
725 let (x1, y1) = vertices[vert_index % vertices.len()];
726 let (x2, y2) = vertices[(vert_index + 1) % vertices.len()];
727
728 Self::polygon_buffer_line(&mut left_buff, false, x1, y1, x2, y2);
729
730 vert_index += 1;
731 if vert_index % vertices.len() == start_vert {
732 break;
733 }
734 }
735
736 for i in 0..dy {
737 let y = i as isize + start_y;
738 let x1 = left_buff[i] + start_x;
739 let x2 = right_buff[i] + start_x;
740
741 for x in x1..x2 {
742 self.draw_pixel(x, y, color);
743 }
744 }
745 }
746}
747
748impl Canvas {
749 /// Computes a line for use of drawing solid polygons.
750 fn polygon_buffer_line(
751 buff: &mut Vec<isize>,
752 right: bool,
753 x1: isize,
754 y1: isize,
755 x2: isize,
756 y2: isize,
757 ) {
758 let dx = (x2 - x1).abs();
759 let dy = (y2 - y1).abs();
760
761 let abs_m = dy as f32 / dx as f32;
762 match abs_m <= 1.0 {
763 true => {
764 let (start_x, start_y, end_x, end_y) = if x1 < x2 {
765 (x1, y1, x2, y2)
766 } else {
767 (x2, y2, x1, y1)
768 };
769
770 let step = if start_y < end_y { 1 } else { -1 };
771
772 let a = 2 * dy;
773 let b = a - 2 * dx;
774 let mut p = a - dx;
775
776 buff[start_y as usize] = start_x;
777 let mut new_line = false;
778
779 let mut offset = 0isize;
780 for i in 1..=(end_x - start_x) {
781 match p < 0 {
782 true => {
783 p += a;
784 }
785 false => {
786 offset += step;
787 new_line = true;
788 p += b;
789 }
790 }
791
792 if right || new_line {
793 buff[(start_y + offset) as usize] = start_x + i;
794 new_line = false;
795 }
796 }
797 }
798 false => {
799 let (start_x, start_y, end_x, end_y) = if y1 < y2 {
800 (x1, y1, x2, y2)
801 } else {
802 (x2, y2, x1, y1)
803 };
804
805 let step = if start_x < end_x { 1 } else { -1 };
806
807 let a = 2 * dx;
808 let b = a - 2 * dy;
809 let mut p = a - dy;
810
811 buff[start_y as usize] = start_x;
812
813 let mut offset = 0isize;
814 for i in 1..=(end_y - start_y) {
815 match p < 0 {
816 true => {
817 p += a;
818 }
819 false => {
820 offset += step;
821 p += b;
822 }
823 }
824
825 buff[(start_y + i) as usize] = start_x + offset;
826 }
827 }
828 }
829 }
830}