display.rs 8.01 KB
Newer Older
1
#[cfg(feature="rusttype")]
Jeremy Soller's avatar
Jeremy Soller committed
2 3
extern crate rusttype;

Jeremy Soller's avatar
Jeremy Soller committed
4 5
use alloc::heap;
use std::{cmp, slice};
6

7
use primitive::{fast_set32, fast_set64, fast_copy, fast_copy64};
8

9
#[cfg(feature="rusttype")]
Jeremy Soller's avatar
Jeremy Soller committed
10 11
use self::rusttype::{Font, FontCollection, Scale, point};

12 13
#[cfg(not(feature="rusttype"))]
static FONT: &'static [u8] = include_bytes!("../../../res/fonts/unifont.font");
14

Jeremy Soller's avatar
Jeremy Soller committed
15 16 17 18 19 20 21 22 23
#[cfg(feature="rusttype")]
static FONT: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono.ttf");
#[cfg(feature="rusttype")]
static FONT_BOLD: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf");
#[cfg(feature="rusttype")]
static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf");
#[cfg(feature="rusttype")]
static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf");

24
/// A display
25 26 27 28 29 30 31 32 33 34
#[cfg(not(feature="rusttype"))]
pub struct Display {
    pub width: usize,
    pub height: usize,
    pub onscreen: &'static mut [u32],
    pub offscreen: &'static mut [u32]
}

/// A display
#[cfg(feature="rusttype")]
35 36 37 38 39
pub struct Display {
    pub width: usize,
    pub height: usize,
    pub onscreen: &'static mut [u32],
    pub offscreen: &'static mut [u32],
40
    #[cfg(feature="rusttype")]
Jeremy Soller's avatar
Jeremy Soller committed
41
    pub font: Font<'static>,
42
    #[cfg(feature="rusttype")]
Jeremy Soller's avatar
Jeremy Soller committed
43
    pub font_bold: Font<'static>,
44
    #[cfg(feature="rusttype")]
Jeremy Soller's avatar
Jeremy Soller committed
45
    pub font_bold_italic: Font<'static>,
46
    #[cfg(feature="rusttype")]
Jeremy Soller's avatar
Jeremy Soller committed
47
    pub font_italic: Font<'static>
48 49 50
}

impl Display {
51
    #[cfg(not(feature="rusttype"))]
Jeremy Soller's avatar
Jeremy Soller committed
52 53 54 55
    pub fn new(width: usize, height: usize, onscreen: usize) -> Display {
        let size = width * height;
        let offscreen = unsafe { heap::allocate(size * 4, 4096) };
        unsafe { fast_set64(offscreen as *mut u64, 0, size/2) };
56 57 58
        Display {
            width: width,
            height: height,
Jeremy Soller's avatar
Jeremy Soller committed
59 60
            onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) },
            offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }
61 62 63 64
        }
    }

    #[cfg(feature="rusttype")]
Jeremy Soller's avatar
Jeremy Soller committed
65 66 67 68
    pub fn new(width: usize, height: usize, onscreen: usize) -> Display {
        let size = width * height;
        let offscreen = unsafe { heap::allocate(size * 4, 4096) };
        unsafe { fast_set64(offscreen as *mut u64, 0, size/2) };
69 70 71
        Display {
            width: width,
            height: height,
Jeremy Soller's avatar
Jeremy Soller committed
72 73 74 75 76 77
            onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) },
            offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) },
            font: FontCollection::from_bytes(FONT).into_font().unwrap(),
            font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(),
            font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(),
            font_italic: FontCollection::from_bytes(FONT_ITALIC).into_font().unwrap()
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
        }
    }

    /// Draw a rectangle
    pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
        let start_y = cmp::min(self.height - 1, y);
        let end_y = cmp::min(self.height, y + h);

        let start_x = cmp::min(self.width - 1, x);
        let len = cmp::min(self.width, x + w) - start_x;

        let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;

        let stride = self.width * 4;

        let offset = y * stride + start_x * 4;
        offscreen_ptr += offset;

        let mut rows = end_y - start_y;
        while rows > 0 {
            unsafe {
Jeremy Soller's avatar
Jeremy Soller committed
99
                fast_set32(offscreen_ptr as *mut u32, color, len);
100 101 102 103 104 105 106
            }
            offscreen_ptr += stride;
            rows -= 1;
        }
    }

    /// Draw a character
107 108 109
    #[cfg(not(feature="rusttype"))]
    pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) {
        if x + 8 <= self.width && y + 16 <= self.height {
110
            let mut dst = self.offscreen.as_mut_ptr() as usize + (y * self.width + x) * 4;
111 112 113 114 115 116 117

            let font_i = 16 * (character as usize);
            if font_i + 16 <= FONT.len() {
                for row in 0..16 {
                    let row_data = FONT[font_i + row];
                    for col in 0..8 {
                        if (row_data >> (7 - col)) & 1 == 1 {
118
                            unsafe { *((dst + col * 4) as *mut u32)  = color; }
119 120
                        }
                    }
121
                    dst += self.width * 4;
122 123 124 125 126 127 128
                }
            }
        }
    }

    /// Draw a character
    #[cfg(feature="rusttype")]
Jeremy Soller's avatar
Jeremy Soller committed
129 130 131
    pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, bold: bool, italic: bool) {
        let width = self.width;
        let height = self.height;
132
        let offscreen = self.offscreen.as_mut_ptr() as usize;
Jeremy Soller's avatar
Jeremy Soller committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

        let font = if bold && italic {
            &self.font_bold_italic
        } else if bold {
            &self.font_bold
        } else if italic {
            &self.font_italic
        } else {
            &self.font
        };

        if let Some(glyph) = font.glyph(character){
            let scale = Scale::uniform(16.0);
            let v_metrics = font.v_metrics(scale);
            let point = point(0.0, v_metrics.ascent);
Jeremy Soller's avatar
Jeremy Soller committed
148 149 150 151 152 153 154
            let glyph = glyph.scaled(scale).positioned(point);
            if let Some(bb) = glyph.pixel_bounding_box() {
                glyph.draw(|off_x, off_y, v| {
                    let off_x = x + (off_x as i32 + bb.min.x) as usize;
                    let off_y = y + (off_y as i32 + bb.min.y) as usize;
                    // There's still a possibility that the glyph clips the boundaries of the bitmap
                    if off_x < width && off_y < height {
155 156 157 158 159
                        if v > 0.0 {
                            let f_a = (v * 255.0) as u32;
                            let f_r = (((color >> 16) & 0xFF) * f_a)/255;
                            let f_g = (((color >> 8) & 0xFF) * f_a)/255;
                            let f_b = ((color & 0xFF) * f_a)/255;
Jeremy Soller's avatar
Jeremy Soller committed
160

161
                            let offscreen_ptr = (offscreen + (off_y * width + off_x) * 4) as *mut u32;
162

163
                            let bg = unsafe { *offscreen_ptr };
164 165 166 167 168 169 170 171

                            let b_a = 255 - f_a;
                            let b_r = (((bg >> 16) & 0xFF) * b_a)/255;
                            let b_g = (((bg >> 8) & 0xFF) * b_a)/255;
                            let b_b = ((bg & 0xFF) * b_a)/255;

                            let c = ((f_r + b_r) << 16) | ((f_g + b_g) << 8) | (f_b + b_b);

172
                            unsafe { *offscreen_ptr = c; }
Jeremy Soller's avatar
Jeremy Soller committed
173 174 175 176
                        }
                    }
                });
            }
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
        }
    }

    /// Scroll display
    pub fn scroll(&mut self, rows: usize, color: u32) {
        let data = (color as u64) << 32 | color as u64;

        let width = self.width/2;
        let height = self.height;
        if rows > 0 && rows < height {
            let off1 = rows * width;
            let off2 = height * width - off1;
            unsafe {
                let data_ptr = self.offscreen.as_mut_ptr() as *mut u64;
                fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2);
                fast_set64(data_ptr.offset(off2 as isize), data, off1);
193 194 195 196 197 198 199 200 201 202 203 204 205 206
            }
        }
    }

    /// Copy from offscreen to onscreen
    pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize) {
        let start_y = cmp::min(self.height - 1, y);
        let end_y = cmp::min(self.height, y + h);

        let start_x = cmp::min(self.width - 1, x);
        let len = (cmp::min(self.width, x + w) - start_x) * 4;

        let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
        let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;
207

208 209 210 211 212 213 214 215 216 217
        let stride = self.width * 4;

        let offset = y * stride + start_x * 4;
        offscreen_ptr += offset;
        onscreen_ptr += offset;

        let mut rows = end_y - start_y;
        while rows > 0 {
            unsafe {
                fast_copy(onscreen_ptr as *mut u8, offscreen_ptr as *const u8, len);
218
            }
219 220 221
            offscreen_ptr += stride;
            onscreen_ptr += stride;
            rows -= 1;
222 223 224
        }
    }
}