use geom::{Circle, Positioned, Rectangle, Scalar, Shape, Transform, Vector};
use graphics::{Color, GpuTriangle, Image, Vertex, Window};
use std::iter;
pub trait Drawable {
fn draw(&self, &mut Window);
}
#[derive(Clone, Debug)]
enum DrawPayload {
Image(Image),
Rectangle(Vector),
Circle(f32),
}
#[derive(Clone, Debug)]
pub struct Draw {
item: DrawPayload,
position: Vector,
color: Color,
transform: Transform,
z: f32
}
impl Draw {
pub fn image(image: &Image, position: Vector) -> Draw {
Draw {
item: DrawPayload::Image(image.clone()),
position,
color: Color::white(),
transform: Transform::identity(),
z: 0.0
}
}
pub fn shape(shape: Shape) -> Draw {
match shape {
Shape::Circle(circ) => Draw::circle(circ),
Shape::Rectangle(rect) => Draw::rectangle(rect),
Shape::Vector(v) => Draw::point(v),
}
}
pub fn point(position: Vector) -> Draw {
Draw::rectangle(Rectangle::newv(position, Vector::one()))
}
pub fn rectangle(rectangle: Rectangle) -> Draw {
Draw {
item: DrawPayload::Rectangle(rectangle.size()),
position: rectangle.center(),
color: Color::white(),
transform: Transform::identity(),
z: 0.0
}
}
pub fn circle(circle: Circle) -> Draw {
Draw {
item: DrawPayload::Circle(circle.radius),
position: circle.center(),
color: Color::white(),
transform: Transform::identity(),
z: 0.0
}
}
pub fn with_position(self, position: Vector) -> Draw {
Draw {
position,
..self
}
}
pub fn with_color(self, color: Color) -> Draw {
Draw {
color,
..self
}
}
pub fn with_transform(self, transform: Transform) -> Draw {
Draw {
transform,
..self
}
}
pub fn with_z<T: Scalar>(self, z: T) -> Draw {
Draw {
z: z.float(),
..self
}
}
}
impl Drawable for Draw {
fn draw(&self, window: &mut Window) {
match self.item {
DrawPayload::Image(ref image) => {
let area = image.area().with_center(self.position);
let trans = Transform::translate(area.top_left() + area.size() / 2)
* self.transform
* 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: Some(normalized_pos + v.times(normalized_size)),
col: self.color
}
};
let vertices = &[
get_vertex(Vector::zero()),
get_vertex(Vector::zero() + Vector::x()),
get_vertex(Vector::zero() + Vector::one()),
get_vertex(Vector::zero() + Vector::y()),
];
let triangles = &[
GpuTriangle {
z: self.z,
indices: [0, 1, 2],
image: Some(image.clone())
},
GpuTriangle {
z: self.z,
indices: [2, 3, 0],
image: Some(image.clone())
}
];
window.add_vertices(vertices.iter().cloned(), triangles.iter().cloned());
}
DrawPayload::Rectangle(size) => {
let area = Rectangle::newv_sized(size).with_center(self.position);
let trans = Transform::translate(area.top_left() + area.size() / 2)
* self.transform
* Transform::translate(-area.size() / 2)
* Transform::scale(area.size());
let get_vertex = |v: Vector| {
Vertex {
pos: trans * v,
tex_pos: None,
col: self.color
}
};
let vertices = &[
get_vertex(Vector::zero()),
get_vertex(Vector::zero() + Vector::x()),
get_vertex(Vector::zero() + Vector::one()),
get_vertex(Vector::zero() + Vector::y()),
];
let triangles = &[
GpuTriangle {
z: self.z,
indices: [0, 1, 2],
image: None
},
GpuTriangle {
z: self.z,
indices: [2, 3, 0],
image: None
}
];
window.add_vertices(vertices.iter().cloned(), triangles.iter().cloned());
}
DrawPayload::Circle(radius) => {
let transform = Transform::translate(self.position)
* self.transform
* Transform::translate(-self.position);
let mut points = [Vector::zero(); 24]; let rotation = Transform::rotate(360f32 / points.len() as f32);
let mut arrow = Vector::new(0f32, -radius);
for i in 0..points.len() {
points[i] = arrow + self.position;
arrow = rotation * arrow;
}
let vertices = points.iter().map(|point| Vertex {
pos: transform * point.clone(),
tex_pos: None,
col: self.color
});
let indices = iter::repeat(self.z).take(points.len() - 1).enumerate().map(|(index, z)| GpuTriangle {
z,
indices: [0, index as u32, index as u32 + 1],
image: None
});
window.add_vertices(vertices, indices);
}
}
}
}