onyx 0.2.0

A simple engine for simple minds
Documentation
use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::cell::Cell;
use std::time::Duration;
use glium::{self, DisplayBuild};
use rusttype;
use text;
use mesh;
use math::Vec2;
use color::Color;

static VERTEX_SHADER: &'static str = r"
    #version 150

    in vec3 position;
    in vec2 uv;
    
    out vec3 v_position;
    out vec2 v_uv;

    uniform mat4 u_model;
    uniform mat4 u_projection;

    void main() {
        gl_Position = u_projection * u_model * vec4(position, 1);
        v_position = position;
        v_uv = uv;
    }
";

static FRAGMENT_SHADER: &'static str = r"
    #version 140

    in vec3 v_position;
    in vec2 v_uv;

    out vec4 color;
    
    uniform vec4 u_color;
    uniform sampler2D u_texture;

    void main() {
        color = texture(u_texture, v_uv) * u_color;
    }
";


fn load_bytes<P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut bytes = Vec::new();
    File::open(path).and_then(|mut file| file.read_to_end(&mut bytes)).unwrap();
    bytes
}

pub struct Context {
    pub display: glium::Display,
    pub color: Cell<Color>,
    pub background_color: Cell<Color>,
    pub size: Cell<Vec2>,
    pub mouse: Cell<Vec2>,
    pub dt: Cell<Duration>,
    pub quad: mesh::Mesh,
    pub white: Texture,
    pub default_shader: Shader,
}

impl Context {
    pub fn new(title: &str, size: (u32, u32)) -> Self {
        let display = glium::glutin::WindowBuilder::new()
            .with_title(title)
            .with_dimensions(size.0, size.1)
            .with_vsync()
            .build_glium()
            .unwrap(); 
        let quad = new_mesh(&display, &[
            mesh::Vertex::new(Vec2::new(0.0, 0.0), Vec2::new(0.0, 0.0)),
            mesh::Vertex::new(Vec2::new(1.0, 0.0), Vec2::new(1.0, 0.0)),
            mesh::Vertex::new(Vec2::new(0.0, 1.0), Vec2::new(0.0, 1.0)),
            mesh::Vertex::new(Vec2::new(1.0, 1.0), Vec2::new(1.0, 1.0)),
        ], &[0, 1, 2, 3]);
        let white = new_texture(&display, vec![255, 255, 255, 255], (1, 1));
        let default_shader = new_shader(&display, VERTEX_SHADER, FRAGMENT_SHADER);
        Context {
            display: display,
            color: Cell::new((1.0, 1.0, 1.0, 1.0)),
            background_color: Cell::new((0.0, 0.0, 0.0, 1.0)),
            size: Cell::new(Vec2::new(size.0 as f32, size.1 as f32)),
            mouse: Cell::new(Vec2::zero()),
            dt: Cell::new(Default::default()),
            quad: quad,
            white: white,
            default_shader: default_shader,
        }
    }

    pub fn new_shader(&self, vertex_src: &str, fragment_src: &str) -> Shader {
        new_shader(&self.display, vertex_src, fragment_src)
    }

    pub fn new_mesh(&self, vertices: &[mesh::Vertex], indices: &[mesh::Index]) -> mesh::Mesh {
        new_mesh(&self.display, vertices, indices)
    }

    pub fn new_texture(&self, bytes: Vec<u8>, size: (u32, u32)) -> Texture {
        new_texture(&self.display, bytes, size)
    }

    pub fn new_text(&self, text: &str, font: &text::Font, height: f32) -> Texture {
        let text::Text { bytes, size } = text::Text::new(text, font, height);
        self.new_texture(bytes, size)
    }

    pub fn new_font<P: AsRef<Path>>(&self, path: P) -> text::Font {
        let bytes = load_bytes(path);
        rusttype::FontCollection::from_bytes(bytes).into_font().unwrap()
    }

    pub fn dt(&self) -> f32 {
        let dt = self.dt.get();
        dt.subsec_nanos() as f32 / 1_000_000_000.0 + dt.as_secs() as f32
    }

    pub fn size(&self) -> Vec2 {
        self.size.get()
    }
}

fn new_shader(display: &glium::Display, vertex_src: &str, fragment_src: &str) -> Shader {
    Shader::from_source(display, vertex_src, fragment_src, None).unwrap()
}

fn new_mesh(display: &glium::Display, vertices: &[mesh::Vertex], indices: &[mesh::Index]) -> mesh::Mesh {
    mesh::Mesh {
        vertices: glium::VertexBuffer::new(display, vertices).unwrap(),
        indices: glium::IndexBuffer::new(display, glium::index::PrimitiveType::TriangleStrip, indices).unwrap(),
    }
}

fn new_texture(display: &glium::Display, bytes: Vec<u8>, size: (u32, u32)) -> Texture {
    Texture::new(display, 
        glium::texture::RawImage2d::from_raw_rgba(bytes, size)).unwrap()
}

pub type Texture = glium::texture::Texture2d;
pub type Shader = glium::Program;