mod texture;
mod font;
mod bitmap_font;
mod dynamic_font;
pub use glfw_backend::Display;
pub use self::{texture::*, font::Font, bitmap_font::BitmapFont, dynamic_font::DynamicFont};
use std::rc::Rc;
use glium::{self, Surface};
use cgmath::{self, Matrix4, Transform, Vector3, Rad, Deg};
#[derive(Copy, Clone, Debug)]
pub(crate) struct Vertex {
pub pos: [f32; 2],
pub uv: [f32; 2]
}
pub struct Renderer<'a> {
display: &'a Display,
target: &'a mut glium::Frame,
quad: &'a glium::VertexBuffer<Vertex>,
tex_program: &'a glium::Program,
rect_program: &'a glium::Program,
text_program: &'a glium::Program,
default_fonts: &'a mut Vec<(u32, Rc<Font>)>,
font: Option<Rc<Font>>,
transform: Matrix4<f32>,
stack: Vec<Matrix4<f32>>,
screen_width: u32,
screen_height: u32
}
impl<'a> Renderer<'a> {
pub(crate) fn new(
display: &'a Display,
target: &'a mut glium::Frame,
quad: &'a glium::VertexBuffer<Vertex>,
tex_program: &'a glium::Program,
rect_program: &'a glium::Program,
text_program: &'a glium::Program,
default_fonts: &'a mut Vec<(u32, Rc<Font>)>,
screen_width: u32,
screen_height: u32
) -> Renderer<'a> {
Renderer {
display,
target,
quad,
tex_program,
rect_program,
text_program,
default_fonts,
font: None,
transform: cgmath::ortho(0.0, screen_width as f32, screen_height as f32, 0.0, -1.0, 1.0),
stack: Vec::new(),
screen_width,
screen_height
}
}
pub fn push_matrix(&mut self) {
self.stack.push(self.transform);
}
pub fn pop_matrix(&mut self) {
match self.stack.pop() {
Some(v) => {self.transform = v;},
None => {}
}
}
pub fn keep_matrix<F: FnOnce(&mut Renderer)>(&mut self, f: F) {
let prev = self.transform;
f(self);
self.transform = prev;
}
pub fn set_ortho(&mut self, left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32) {
self.transform = cgmath::ortho(left, right, bottom, top, near, far);
}
pub fn set_perspective(&mut self, fov: f32, near: f32, far: f32) {
self.transform = cgmath::perspective(Deg(fov), self.screen_width as f32 / self.screen_height as f32, near, far);
}
pub fn translate(&mut self, x: i32, y: i32) {
self.transform.concat_self(&Matrix4::from_translation(Vector3::new(x as f32, y as f32, 0.0)));
}
pub fn scale(&mut self, x: f32, y: f32) {
self.transform.concat_self(&Matrix4::from_nonuniform_scale(x, y, 1.0));
}
pub fn rotate(&mut self, angle: f32) {
self.transform.concat_self(&Matrix4::from_angle_z(Deg(angle)));
}
pub fn rotate_rad(&mut self, angle: f32) {
self.transform.concat_self(&Matrix4::from_angle_z(Rad(angle)));
}
pub fn translate_3d(&mut self, x: f32, y: f32, z: f32) {
self.transform.concat_self(&Matrix4::from_translation(Vector3::new(x, y, z)));
}
pub fn scale_3d(&mut self, x: f32, y: f32, z: f32) {
self.transform.concat_self(&Matrix4::from_nonuniform_scale(x, y, z));
}
pub fn rotate_3d(&mut self, x: f32, y: f32, z: f32) {
self.transform.concat_self(&Matrix4::from_angle_x(Deg(x)));
self.transform.concat_self(&Matrix4::from_angle_y(Deg(y)));
self.transform.concat_self(&Matrix4::from_angle_z(Deg(z)));
}
pub fn rotate_rad_3d(&mut self, x: f32, y: f32, z: f32) {
self.transform.concat_self(&Matrix4::from_angle_x(Rad(x)));
self.transform.concat_self(&Matrix4::from_angle_y(Rad(y)));
self.transform.concat_self(&Matrix4::from_angle_z(Rad(z)));
}
pub fn clear(&mut self) {
self.target.clear_color(0.0, 0.0, 0.0, 1.0);
}
pub fn font(&mut self) -> Rc<Font> {
if let Some(ref font) = self.font {
font.clone()
} else {
self.set_default_font(24);
self.font.as_ref().unwrap().clone()
}
}
pub fn set_font(&mut self, font: Rc<Font>) {
self.font = Some(font);
}
pub fn set_default_font(&mut self, height: u32) {
for (height2, font) in self.default_fonts.iter() {
if *height2 == height {
self.font = Some(font.clone());
return;
}
}
let font = Rc::new(Font::Dynamic(DynamicFont::load_default(height)));
self.default_fonts.push((height, font.clone()));
self.font = Some(font);
}
pub fn draw_text(&mut self, text: &str, x: i32, y: i32, r: f32, g: f32, b: f32, a: f32) {
if let None = self.font {
self.set_default_font(24);
}
let transform = self.transform.concat(&Matrix4::from_translation(Vector3::new(x as f32, y as f32, 0.0)));
match &**self.font.as_ref().unwrap() {
Font::Dynamic(font) => {
let texture = font.draw_to_texture(text, self.display);
let (w, h) = texture.size();
self.target.draw(
self.quad,
&glium::index::NoIndices(glium::index::PrimitiveType::TriangleFan),
self.text_program,
&uniform! {
size: [w as f32, h as f32],
tex: texture.internal(),
color: [r, g, b, a],
mvp: [
[transform.x.x, transform.x.y, transform.x.z, transform.x.w],
[transform.y.x, transform.y.y, transform.y.z, transform.y.w],
[transform.z.x, transform.z.y, transform.z.z, transform.z.w],
[transform.w.x, transform.w.y, transform.w.z, transform.w.w]
]
},
&glium::DrawParameters {
blend: glium::draw_parameters::Blend::alpha_blending(),
.. glium::DrawParameters::default()
}
).unwrap();
},
Font::Bitmap(font) => {
font.draw(text, transform, r, g, b, a, self.text_program, self.target, self.display);
}
}
}
pub fn draw_rect(&mut self, x: i32, y: i32, w: i32, h: i32, r: f32, g: f32, b: f32, a: f32) {
let transform = self.transform.concat(&Matrix4::from_translation(Vector3::new(x as f32, y as f32, 0.0)));
if x < self.screen_width as i32 && y < self.screen_height as i32 && x > -w && y > -h {
self.target.draw(
self.quad,
&glium::index::NoIndices(glium::index::PrimitiveType::TriangleFan),
self.rect_program,
&uniform! {
size: [w as f32, h as f32],
color: [r, g, b, a],
mvp: [
[transform.x.x, transform.x.y, transform.x.z, transform.x.w],
[transform.y.x, transform.y.y, transform.y.z, transform.y.w],
[transform.z.x, transform.z.y, transform.z.z, transform.z.w],
[transform.w.x, transform.w.y, transform.w.z, transform.w.w]
]
},
&glium::DrawParameters {
blend: glium::draw_parameters::Blend::alpha_blending(),
.. glium::DrawParameters::default()
}
).unwrap();
}
}
pub fn draw_texture(&mut self, texture: &Texture, x: i32, y: i32) {
let (w, h) = texture.size();
self.draw_texture_region_sized_tinted(texture, x, y, 0, 0, w, h, w, h, 1.0, 1.0, 1.0, 1.0);
}
pub fn draw_texture_sized(&mut self, texture: &Texture, x: i32, y: i32, sw: u32, sh: u32) {
let (w, h) = texture.size();
self.draw_texture_region_sized_tinted(texture, x, y, 0, 0, w, h, sw, sh, 1.0, 1.0, 1.0, 1.0);
}
pub fn draw_texture_region(&mut self, texture: &Texture, x: i32, y: i32, rx: u32, ry: u32, rw: u32, rh: u32) {
self.draw_texture_region_sized_tinted(texture, x, y, rx, ry, rw, rh, rw, rh, 1.0, 1.0, 1.0, 1.0);
}
pub fn draw_texture_tinted(&mut self, texture: &Texture, x: i32, y: i32, r: f32, g: f32, b: f32, a: f32) {
let (w, h) = texture.size();
self.draw_texture_region_sized_tinted(texture, x, y, 0, 0, w, h, w, h, r, g, b, a);
}
pub fn draw_texture_sized_tinted(&mut self, texture: &Texture, x: i32, y: i32, sw: u32, sh: u32, r: f32, g: f32, b: f32, a: f32) {
let (w, h) = texture.size();
self.draw_texture_region_sized_tinted(texture, x, y, 0, 0, w, h, sw, sh, r, g, b, a);
}
pub fn draw_texture_region_sized(&mut self, texture: &Texture, x: i32, y: i32, rx: u32, ry: u32, rw: u32, rh: u32, sw: u32, sh: u32) {
self.draw_texture_region_sized_tinted(texture, x, y, rx, ry, rw, rh, sw, sh, 1.0, 1.0, 1.0, 1.0);
}
pub fn draw_texture_region_tinted(&mut self, texture: &Texture, x: i32, y: i32, rx: u32, ry: u32, rw: u32, rh: u32, r: f32, g: f32, b: f32, a: f32) {
self.draw_texture_region_sized_tinted(texture, x, y, rx, ry, rw, rh, rw, rh, r, g, b, a);
}
pub fn draw_texture_region_sized_tinted(&mut self, texture: &Texture, x: i32, y: i32, rx: u32, ry: u32, rw: u32, rh: u32, sw: u32, sh: u32, r: f32, g: f32, b: f32, a: f32) {
let (w, h) = texture.size();
let transform = self.transform.concat(&Matrix4::from_translation(Vector3::new(x as f32, y as f32, 0.0)));
self.target.draw(
self.quad,
&glium::index::NoIndices(glium::index::PrimitiveType::TriangleFan),
self.tex_program,
&uniform! {
size: [sw as f32, sh as f32],
region: [rx as f32 / w as f32, ry as f32 / w as f32, (rx + rw) as f32 / w as f32, (ry + rh) as f32 / h as f32],
tex: texture.internal().sampled().wrap_function(texture.wrap).minify_filter(texture.min).magnify_filter(texture.mag),
color: [r, g, b, a],
mvp: [
[transform.x.x, transform.x.y, transform.x.z, transform.x.w],
[transform.y.x, transform.y.y, transform.y.z, transform.y.w],
[transform.z.x, transform.z.y, transform.z.z, transform.z.w],
[transform.w.x, transform.w.y, transform.w.z, transform.w.w]
]
},
&glium::DrawParameters {
blend: glium::draw_parameters::Blend::alpha_blending(),
.. glium::DrawParameters::default()
}
).unwrap();
}
}