andrew/
lib.rs

1//! Andrew is a crate for drawing objects
2#![warn(missing_docs)]
3extern crate rusttype;
4extern crate walkdir;
5extern crate xdg;
6extern crate xml;
7
8#[macro_use]
9extern crate bitflags;
10
11/// A module that contains functions and objects relating to lines
12pub mod line;
13/// A module that contains functions and objects relating to shapes
14pub mod shapes;
15/// A module that contains functions and objects relating to text
16pub mod text;
17
18/// The Drawable trait allows object to be drawn to a buffer or canvas
19pub trait Drawable {
20    /// A function that draws the object to a canvas
21    fn draw(&self, canvas: &mut Canvas);
22}
23
24/// Describes an endianness (aka byte order)
25#[derive(Debug, PartialEq)]
26pub enum Endian {
27    /// Little Endian
28    Little,
29    /// Big Endian
30    Big,
31}
32
33impl Endian {
34    /// Returns the native endianness
35    pub fn native() -> Endian {
36        if cfg!(target_endian = "little") {
37            Endian::Little
38        } else {
39            Endian::Big
40        }
41    }
42}
43
44/// The canvas object acts as a wrapper around a buffer, providing information and functions
45/// for drawing
46pub struct Canvas<'a> {
47    /// A buffer for the canvas to draw to
48    pub buffer: &'a mut [u8],
49    /// The width in pixels of the canvas
50    pub width: usize,
51    /// The height in pixels of the canvas
52    pub height: usize,
53    /// The number of bytes between each line of pixels on the canvas
54    pub stride: usize,
55    /// The number of bytes contained in each pixel
56    pub pixel_size: usize,
57    /// The endianness of the canvas
58    pub endianness: Endian,
59}
60
61impl<'a> Canvas<'a> {
62    /// Creates a new canvas object
63    pub fn new(
64        buffer: &'a mut [u8],
65        width: usize,
66        height: usize,
67        stride: usize,
68        endianness: Endian,
69    ) -> Canvas<'a> {
70        assert!(
71            stride % width == 0,
72            "Incorrect Dimensions - Stride is not a multiple of width"
73        );
74        assert!(buffer.len() == stride * height);
75        let pixel_size = stride / width;
76        Canvas {
77            buffer,
78            width,
79            height,
80            stride,
81            pixel_size,
82            endianness,
83        }
84    }
85
86    /// Draws an object that implements the Drawable trait to the buffer
87    pub fn draw<D: Drawable>(&mut self, drawable: &D) {
88        drawable.draw(self);
89    }
90
91    /// Draws a pixel at the x and y coordinate
92    pub fn draw_point(&mut self, x: usize, y: usize, color: [u8; 4]) {
93        let base = self.stride * y + self.pixel_size * x;
94        if self.endianness == Endian::Little {
95            if color[0] == 255 {
96                self.buffer[base + 3] = color[0];
97                self.buffer[base + 2] = color[1];
98                self.buffer[base + 1] = color[2];
99                self.buffer[base] = color[3];
100            } else {
101                for c in 0..3 {
102                    let alpha = f32::from(color[0]) / 255.0;
103                    let color_diff =
104                        (color[3 - c] as isize - self.buffer[base + c] as isize) as f32 * alpha;
105                    let new_color = (f32::from(self.buffer[base + c]) + color_diff) as u8;
106                    self.buffer[base + c] = new_color as u8;
107                }
108                self.buffer[base + 3] = 255 as u8;
109            }
110        } else if color[0] == 255 {
111            self.buffer[base] = color[0];
112            self.buffer[base + 1] = color[1];
113            self.buffer[base + 2] = color[2];
114            self.buffer[base + 3] = color[3];
115        } else {
116            for c in 1..4 {
117                let alpha = f32::from(color[0]) / 255.0;
118                let color_diff =
119                    (color[c] as isize - self.buffer[base + c] as isize) as f32 * alpha;
120                let new_color = (f32::from(self.buffer[base + c]) + color_diff) as u8;
121                self.buffer[base + c] = new_color as u8;
122            }
123            self.buffer[base] = 255 as u8;
124        }
125    }
126
127    /// Clears the entire canvas buffer by zeroing it
128    pub fn clear(&mut self) {
129        for i in 0..self.width * self.height * 4 {
130            self.buffer[i] = 0x00;
131        }
132    }
133}