use std::rc::Rc;
use std::collections::HashMap;
use uuid::Uuid;
use graphics::{ self, Graphics, ImageSize };
use graphics::math::{ Scalar, Matrix2d, Vec2d };
use graphics::types::SourceRectangle;
pub struct Sprite<I: ImageSize> {
id: Uuid,
visible: bool,
anchor: Vec2d,
position: Vec2d,
rotation: Scalar,
scale: Vec2d,
color: [f32;3],
flip_x: bool,
flip_y: bool,
opacity: f32,
children: Vec<Sprite<I>>,
children_index: HashMap<Uuid, usize>,
src_rect: Option<SourceRectangle>,
texture: Rc<I>,
}
impl<I: ImageSize> Sprite<I> {
pub fn from_texture(texture: Rc<I>) -> Sprite<I> {
Sprite {
id: Uuid::new_v4(),
visible: true,
anchor: [0.5, 0.5],
position: [0.0, 0.0],
rotation: 0.0,
scale: [1.0, 1.0],
color: [1.0,1.0,1.0],
flip_x: false,
flip_y: false,
opacity: 1.0,
texture: texture,
src_rect: None,
children: Vec::new(),
children_index: HashMap::new(),
}
}
pub fn from_texture_rect(texture: Rc<I>, src_rect: SourceRectangle) -> Sprite<I> {
Sprite {
id: Uuid::new_v4(),
visible: true,
anchor: [0.5, 0.5],
position: [0.0, 0.0],
rotation: 0.0,
scale: [1.0, 1.0],
color: [1.0,1.0,1.0],
flip_x: false,
flip_y: false,
opacity: 1.0,
texture: texture,
src_rect: From::from(src_rect),
children: Vec::new(),
children_index: HashMap::new(),
}
}
#[inline(always)]
pub fn id(&self) -> Uuid {
self.id.clone()
}
pub fn get_visible(&self) -> bool {
self.visible
}
pub fn set_visible(&mut self, visible: bool) {
self.visible = visible;
}
#[inline(always)]
pub fn get_anchor(&self) -> (Scalar, Scalar) {
(self.anchor[0], self.anchor[1])
}
#[inline(always)]
pub fn set_anchor(&mut self, x: Scalar, y: Scalar) {
self.anchor = [x, y];
}
#[inline(always)]
pub fn get_position(&self) -> (Scalar, Scalar) {
(self.position[0], self.position[1])
}
#[inline(always)]
pub fn set_position(&mut self, x: Scalar, y: Scalar) {
self.position = [x, y];
}
#[inline(always)]
pub fn set_color(&mut self, r: f32, g: f32, b: f32) {
self.color = [r, g, b];
}
#[inline(always)]
pub fn get_color(&self) -> (f32, f32, f32) {
(self.color[0], self.color[1], self.color[2])
}
#[inline(always)]
pub fn get_rotation(&self) -> Scalar {
self.rotation
}
#[inline(always)]
pub fn set_rotation(&mut self, deg: Scalar) {
self.rotation = deg;
}
#[inline(always)]
pub fn get_scale(&self) -> (Scalar, Scalar) {
(self.scale[0], self.scale[1])
}
#[inline(always)]
pub fn set_scale(&mut self, sx: Scalar, sy: Scalar) {
self.scale = [sx, sy];
}
#[inline(always)]
pub fn get_flip_x(&self) -> bool {
self.flip_x
}
#[inline(always)]
pub fn set_flip_x(&mut self, flip_x: bool) {
self.flip_x = flip_x;
}
#[inline(always)]
pub fn get_flip_y(&self) -> bool {
self.flip_y
}
#[inline(always)]
pub fn set_flip_y(&mut self, flip_y: bool) {
self.flip_y = flip_y;
}
#[inline(always)]
pub fn get_opacity(&self) -> f32 {
self.opacity
}
#[inline(always)]
pub fn set_opacity(&mut self, opacity: f32) {
self.opacity = opacity;
}
#[inline(always)]
pub fn get_src_rect(&self) -> Option<SourceRectangle> {
self.src_rect
}
#[inline(always)]
pub fn set_src_rect(&mut self, src_rect: SourceRectangle) {
self.src_rect = From::from(src_rect);
}
#[inline(always)]
pub fn get_texture(&self) -> &Rc<I> {
&self.texture
}
#[inline(always)]
pub fn set_texture(&mut self, texture: Rc<I>) {
self.texture = texture;
}
pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
let id = sprite.id();
self.children.push(sprite);
self.children_index.insert(id.clone(), self.children.len() - 1);
id
}
pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
if let Some(index) = self.children_index.remove(&id) {
let removed = self.children.remove(index);
for i in index..self.children.len() {
let uuid = self.children[i].id();
self.children_index.insert(uuid, i);
}
Some(removed)
} else {
for child in &mut self.children {
if let Some(c) = child.remove_child(id.clone()) {
return Some(c);
}
}
None
}
}
pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
if let Some(index) = self.children_index.get(&id) {
Some(&self.children[*index])
} else {
for child in &self.children {
if let Some(c) = child.child(id.clone()) {
return Some(c);
}
}
None
}
}
pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
if let Some(index) = self.children_index.get(&id) {
Some(&mut self.children[*index])
} else {
for child in &mut self.children {
if let Some(c) = child.child_mut(id.clone()) {
return Some(c);
}
}
None
}
}
#[inline(always)]
pub fn children(&self) -> &Vec<Sprite<I>> {
&self.children
}
pub fn draw<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
use graphics::*;
if !self.visible {
return;
}
let (tex_w, tex_h) = self.texture.get_size();
let tex_w = tex_w as f64;
let tex_h = tex_h as f64;
let source_rectangle = self.src_rect.unwrap_or({
let (w, h) = (tex_w, tex_h);
[0.0, 0.0, w as f64, h as f64]
});
let anchor = [self.anchor[0] * source_rectangle[2], self.anchor[1] * source_rectangle[3]];
let transformed = t.trans(self.position[0], self.position[1])
.rot_deg(self.rotation)
.scale(self.scale[0], self.scale[1]);
let mut model = transformed;
if self.flip_x {
model = model.trans(source_rectangle[2] - 2.0 * anchor[0], 0.0).flip_h();
}
if self.flip_y {
model = model.trans(0.0, source_rectangle[3] - 2.0 * anchor[1]).flip_v();
}
let ref draw_state: graphics::DrawState = Default::default();
graphics::Image::new()
.color([self.color[0], self.color[1], self.color[2], self.opacity])
.rect([-anchor[0], -anchor[1], source_rectangle[2], source_rectangle[3]])
.maybe_src_rect(self.src_rect)
.draw(&*self.texture, draw_state, model, b);
for child in &self.children {
child.draw(transformed, b);
}
}
pub fn draw_tinted<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B, c: [f32;3]) {
use graphics::*;
if !self.visible {
return;
}
let (tex_w, tex_h) = self.texture.get_size();
let tex_w = tex_w as f64;
let tex_h = tex_h as f64;
let source_rectangle = self.src_rect.unwrap_or({
let (w, h) = (tex_w, tex_h);
[0.0, 0.0, w as f64, h as f64]
});
let anchor = [self.anchor[0] * source_rectangle[2], self.anchor[1] * source_rectangle[3]];
let transformed = t.trans(self.position[0], self.position[1])
.rot_deg(self.rotation)
.scale(self.scale[0], self.scale[1]);
let mut model = transformed;
if self.flip_x {
model = model.trans(source_rectangle[2] - 2.0 * anchor[0], 0.0).flip_h();
}
if self.flip_y {
model = model.trans(0.0, source_rectangle[3] - 2.0 * anchor[1]).flip_v();
}
let ref draw_state: graphics::DrawState = Default::default();
graphics::Image::new()
.color([c[0], c[1], c[2], self.opacity])
.rect([-anchor[0], -anchor[1], source_rectangle[2], source_rectangle[3]])
.maybe_src_rect(self.src_rect)
.draw(&*self.texture, draw_state, model, b);
for child in &self.children {
child.draw_tinted(transformed, b, c);
}
}
pub fn bounding_box(&self) -> graphics::types::Rectangle {
let (w, h) = self.texture.get_size();
let source_rectangle = self.src_rect.unwrap_or({
let (sprite_w, sprite_h) = (w, h);
[0.0, 0.0, sprite_w as f64, sprite_h as f64]
});
let sprite_w = source_rectangle[2] * self.scale[0];
let sprite_h = source_rectangle[3] * self.scale[1];
[
self.position[0] - self.anchor[0] * sprite_w,
self.position[1] - self.anchor[1] * sprite_h,
sprite_w,
sprite_h
]
}
}