#[cfg(not(target_arch="wasm32"))]
extern crate glutin;
use geom::{Circle, Line, Rectangle, Shape, Transform, Vector};
#[cfg(not(target_arch="wasm32"))]
use glutin::{GlContext};
use graphics::Window;
use graphics::{Backend, Camera, Color, Image, Vertex};
pub struct Canvas {
pub(crate) backend: Backend,
pub(crate) cam: Camera,
}
const CIRCLE_POINTS: usize = 32;
impl Canvas {
pub fn set_camera(&mut self, cam: Camera) {
self.cam = cam;
}
fn camera(&self) -> Transform {
self.cam.transform()
}
pub fn clear(&mut self, color: Color) {
self.backend.clear(color);
}
pub fn present(&mut self, _window: &Window) {
self.backend.flush();
#[cfg(not(target_arch="wasm32"))]
_window.gl_window.swap_buffers().unwrap();
}
pub fn draw_image(&mut self, image: &Image, center: Vector) {
self.draw_image_blend(image, center, Color::white());
}
pub fn draw_image_blend(&mut self, image: &Image, center: Vector, col: Color) {
self.draw_image_trans(image, center, col, Transform::identity());
}
pub fn draw_image_trans(&mut self, image: &Image, center: Vector, col: Color, trans: Transform) {
let area = image.area().with_center(center);
let trans = self.camera()
* Transform::translate(area.top_left())
* Transform::translate(area.size() / 2)
* trans
* Transform::translate(-area.size() / 2)
* Transform::scale(area.size());
let recip_size = image.source_size().recip();
let normalized_pos = image.area().top_left().times(recip_size);
let normalized_size = image.area().size().times(recip_size);
let get_vertex = |v: Vector| {
Vertex {
pos: trans * v,
tex_pos: normalized_pos + v.times(normalized_size),
col: col,
use_texture: true,
}
};
self.backend.add(
image.get_id(),
&[
get_vertex(Vector::zero()),
get_vertex(Vector::zero() + Vector::x()),
get_vertex(Vector::zero() + Vector::one()),
get_vertex(Vector::zero() + Vector::y()),
],
&[0, 1, 2, 2, 3, 0],
);
}
pub fn draw_rect(&mut self, rect: Rectangle, col: Color) {
self.draw_rect_trans(rect, col, Transform::identity());
}
pub fn draw_rect_trans(&mut self, rect: Rectangle, col: Color, trans: Transform) {
self.draw_polygon_trans(&[Vector::zero(), rect.size().x_comp(), rect.size(), rect.size().y_comp()], col, Transform::translate(rect.top_left()) * trans);
}
pub fn draw_circle(&mut self, circ: Circle, col: Color) {
self.draw_circle_trans(circ, col, Transform::identity());
}
pub fn draw_circle_trans(&mut self, circ: Circle, col: Color, trans: Transform) {
let mut points = [Vector::zero(); CIRCLE_POINTS];
let rotation = Transform::rotate(360f32 / CIRCLE_POINTS as f32);
let mut arrow = Vector::new(0f32, -circ.radius);
for i in 0..CIRCLE_POINTS {
points[i] = arrow;
arrow = rotation * arrow;
}
self.draw_polygon_trans(&points, col, Transform::translate(circ.center()) * trans);
}
pub fn draw_polygon(&mut self, vertices: &[Vector], col: Color) {
self.draw_polygon_trans(vertices, col, Transform::identity());
}
pub fn draw_polygon_trans(&mut self, vertices: &[Vector], col: Color, trans: Transform) {
let first_index = self.backend.num_vertices() as u32;
let trans = self.camera() * trans;
for vertex in vertices {
self.backend.add_vertex(&Vertex {
pos: trans * vertex.clone(),
tex_pos: Vector::zero(),
col: col,
use_texture: false
});
}
let mut current = 1;
let mut i = 0;
let indices = (vertices.len() - 2) * 3;
while i < indices {
self.backend.add_index(first_index);
self.backend.add_index(first_index + current);
self.backend.add_index(first_index + current + 1);
current += 1;
i += 3;
}
}
pub fn draw_line(&mut self, line: Line, col: Color) {
self.draw_line_trans(line, col, Transform::identity());
}
pub fn draw_line_trans(&mut self, line: Line, col: Color, trans: Transform) {
let start = Vector::zero();
let end = line.end - line.start;
if (end - start).normalize() == Vector::x() {
self.draw_polygon_trans(&[start, start + Vector::y(), end + Vector::y(), end], col,
Transform::translate(line.start) * trans);
} else {
self.draw_polygon_trans(&[start, start + Vector::x(), end + Vector::y(), end], col,
Transform::translate(line.start) * trans);
}
}
pub fn draw_point(&mut self, vec: Vector, col: Color) {
self.draw_polygon_trans(&[vec, vec + Vector::x(), vec + Vector::one(), vec + Vector::y()],
col, Transform::identity());
}
pub fn draw_shape(&mut self, shape: Shape, col: Color) {
self.draw_shape_trans(shape, col, Transform::identity());
}
pub fn draw_shape_trans(&mut self, shape: Shape, col: Color, trans: Transform) {
match shape {
Shape::Rect(r) => self.draw_rect_trans(r, col, trans),
Shape::Circ(c) => self.draw_circle_trans(c, col, trans),
Shape::Line(l) => self.draw_line_trans(l, col, trans),
Shape::Vect(v) => self.draw_point(trans * v, col)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use graphics::Backend;
#[test]
fn test_backend() {
let mut canvas = Canvas {
backend: Backend::new(),
cam: Camera::new(Rectangle::newi(-1, -1, 2, 2))
};
canvas.draw_shape(Shape::Rect(Rectangle::newi(-1, -1, 0, 0)), Color::white());
let expected_vertices = &[-1f32, 1f32, 0f32, 0f32, 1f32, 1f32, 1f32, 1f32, 0f32, -1f32,
1f32, 0f32, 0f32, 1f32, 1f32, 1f32, 1f32, 0f32, -1f32, 1f32, 0f32, 0f32, 1f32, 1f32,
1f32, 1f32, 0f32, -1f32, 1f32, 0f32, 0f32, 1f32, 1f32, 1f32, 1f32, 0f32];
let expected_indices = &[0, 1, 2, 0, 2, 3];
assert!(canvas.backend.vertices.as_slice() == &expected_vertices[..]);
assert!(canvas.backend.indices.as_slice() == &expected_indices[..]);
}
}