sprite/
sprite.rs

1use std::rc::Rc;
2use std::collections::HashMap;
3
4use uuid::Uuid;
5
6use graphics::{ self, Graphics, ImageSize };
7use graphics::math::{ Scalar, Matrix2d, Vec2d };
8use graphics::types::SourceRectangle;
9
10/// A sprite is a texture with some properties.
11pub struct Sprite<I: ImageSize> {
12    id: Uuid,
13
14    visible: bool,
15
16    anchor: Vec2d,
17
18    position: Vec2d,
19    rotation: Scalar,
20    scale: Vec2d,
21    color: [f32;3],
22
23
24    flip_x: bool,
25    flip_y: bool,
26
27    opacity: f32,
28
29    children: Vec<Sprite<I>>,
30    children_index: HashMap<Uuid, usize>,
31
32    src_rect: Option<SourceRectangle>,
33    texture: Rc<I>,
34}
35
36impl<I: ImageSize> Sprite<I> {
37    /// Crate sprite from a texture
38    pub fn from_texture(texture: Rc<I>) -> Sprite<I> {
39        Sprite {
40            id: Uuid::new_v4(),
41
42            visible: true,
43
44            anchor: [0.5, 0.5],
45
46            position: [0.0, 0.0],
47            rotation: 0.0,
48            scale: [1.0, 1.0],
49            color: [1.0,1.0,1.0],
50
51            flip_x: false,
52            flip_y: false,
53
54            opacity: 1.0,
55
56            texture: texture,
57            src_rect: None,
58
59            children: Vec::new(),
60            children_index: HashMap::new(),
61        }
62    }
63
64    /// Create sprite from a rectangle selection of a texture
65    pub fn from_texture_rect(texture: Rc<I>, src_rect: SourceRectangle) -> Sprite<I> {
66        Sprite {
67            id: Uuid::new_v4(),
68
69            visible: true,
70
71            anchor: [0.5, 0.5],
72
73            position: [0.0, 0.0],
74            rotation: 0.0,
75            scale: [1.0, 1.0],
76            color: [1.0,1.0,1.0],
77
78            flip_x: false,
79            flip_y: false,
80
81            opacity: 1.0,
82
83            texture: texture,
84            src_rect: From::from(src_rect),
85
86            children: Vec::new(),
87            children_index: HashMap::new(),
88        }        
89    }
90
91    /// Get the sprite's id
92    #[inline(always)]
93    pub fn id(&self) -> Uuid {
94        self.id.clone()
95    }
96
97    /// Whether or not the sprite is visible
98    pub fn get_visible(&self) -> bool {
99        self.visible
100    }
101
102    /// Set the sprite's visibility
103    pub fn set_visible(&mut self, visible: bool) {
104        self.visible = visible;
105    }
106
107    /// Get the sprite's anchor point
108    ///
109    /// The value is normalized. Default value is [0.5, 0.5] (the center of texture)
110    #[inline(always)]
111    pub fn get_anchor(&self) -> (Scalar, Scalar) {
112        (self.anchor[0], self.anchor[1])
113    }
114
115    /// Set the sprite's anchor point
116    #[inline(always)]
117    pub fn set_anchor(&mut self, x: Scalar, y: Scalar) {
118        self.anchor = [x, y];
119    }
120
121    /// Get the sprite's position
122    #[inline(always)]
123    pub fn get_position(&self) -> (Scalar, Scalar) {
124        (self.position[0], self.position[1])
125    }
126
127    /// Set the sprite's position
128    #[inline(always)]
129    pub fn set_position(&mut self, x: Scalar, y: Scalar) {
130        self.position = [x, y];
131    }
132
133    /// Set the sprite's draw color (tint)
134    #[inline(always)]
135    pub fn set_color(&mut self, r: f32, g: f32, b: f32) {
136        self.color = [r, g, b];
137    }
138
139    /// get the sprite's color.s
140    #[inline(always)]
141    pub fn get_color(&self) -> (f32, f32, f32) {
142        (self.color[0], self.color[1], self.color[2])
143    }
144
145    /// Get the sprite's rotation (in degree)
146    #[inline(always)]
147    pub fn get_rotation(&self) -> Scalar {
148        self.rotation
149    }
150
151    /// Set the sprite's rotation (in degree)
152    #[inline(always)]
153    pub fn set_rotation(&mut self, deg: Scalar) {
154        self.rotation = deg;
155    }
156
157    /// Get the sprite's scale
158    #[inline(always)]
159    pub fn get_scale(&self) -> (Scalar, Scalar) {
160        (self.scale[0], self.scale[1])
161    }
162
163    /// Set the sprite's scale
164    #[inline(always)]
165    pub fn set_scale(&mut self, sx: Scalar, sy: Scalar) {
166        self.scale = [sx, sy];
167    }
168
169    /// Whether or not the sprite is flipped horizontally.
170    ///
171    /// It only flips the texture of the sprite,
172    /// and not the texture of the sprite’s children.
173    ///
174    /// Also, flipping the texture doesn’t alter the `anchor`.
175    ///
176    /// If you want to flip the `anchor` too,
177    /// and/or to flip the children too use: sprite.scale.x *= -1;
178    #[inline(always)]
179    pub fn get_flip_x(&self) -> bool {
180        self.flip_x
181    }
182
183    /// Flip the sprite
184    #[inline(always)]
185    pub fn set_flip_x(&mut self, flip_x: bool) {
186        self.flip_x = flip_x;
187    }
188
189    /// Whether or not the sprite is flipped vertically.
190    ///
191    /// It only flips the texture of the sprite,
192    /// and not the texture of the sprite’s children.
193    ///
194    /// Also, flipping the texture doesn’t alter the `anchor`.
195    ///
196    /// If you want to flip the `anchor` too,
197    /// and/or to flip the children too use: sprite.scale.y *= -1;
198    #[inline(always)]
199    pub fn get_flip_y(&self) -> bool {
200        self.flip_y
201    }
202
203    /// Flip the sprite
204    #[inline(always)]
205    pub fn set_flip_y(&mut self, flip_y: bool) {
206        self.flip_y = flip_y;
207    }
208
209    /// Get the sprite's opacity
210    #[inline(always)]
211    pub fn get_opacity(&self) -> f32 {
212        self.opacity
213    }
214
215    /// Set the sprite's opacity
216    #[inline(always)]
217    pub fn set_opacity(&mut self, opacity: f32) {
218        self.opacity = opacity;
219    }
220
221    /// Get the sprite's source rectangle
222    #[inline(always)]
223    pub fn get_src_rect(&self) -> Option<SourceRectangle> {
224        self.src_rect
225    }
226    
227    /// Set the sprite's source rectangle
228    #[inline(always)]
229    pub fn set_src_rect(&mut self, src_rect: SourceRectangle) {
230        self.src_rect = From::from(src_rect);
231    }
232
233    /// Get the sprite's texture
234    #[inline(always)]
235    pub fn get_texture(&self) -> &Rc<I> {
236        &self.texture
237    }
238
239    /// Set the sprite's texture
240    #[inline(always)]
241    pub fn set_texture(&mut self, texture: Rc<I>) {
242        self.texture = texture;
243    }
244
245    /// Add a sprite as the child of this sprite, return the added sprite's id.
246    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
247        let id = sprite.id();
248        self.children.push(sprite);
249        self.children_index.insert(id.clone(), self.children.len() - 1);
250        id
251    }
252
253    /// Remove the child by `id` from this sprite's children or grandchild
254    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
255        if let Some(index) = self.children_index.remove(&id) {
256            let removed = self.children.remove(index);
257            // Removing a element of vector will alter the index,
258            // update the mapping from uuid to index.
259            for i in index..self.children.len() {
260                let uuid = self.children[i].id();
261                self.children_index.insert(uuid, i);
262            }
263            Some(removed)
264        } else {
265            for child in &mut self.children {
266                if let Some(c) = child.remove_child(id.clone()) {
267                    return Some(c);
268                }
269            }
270            None
271        }
272    }
273
274    /// Find the child by `id` from this sprite's children or grandchild
275    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
276        if let Some(index) = self.children_index.get(&id) {
277            Some(&self.children[*index])
278        } else {
279            for child in &self.children {
280                if let Some(c) = child.child(id.clone()) {
281                    return Some(c);
282                }
283            }
284            None
285        }
286    }
287
288    /// Find the child by `id` from this sprite's children or grandchild, mutability
289    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
290        if let Some(index) = self.children_index.get(&id) {
291            Some(&mut self.children[*index])
292        } else {
293            for child in &mut self.children {
294                if let Some(c) = child.child_mut(id.clone()) {
295                    return Some(c);
296                }
297            }
298            None
299        }
300    }
301
302    /// Get the sprite's children
303    #[inline(always)]
304    pub fn children(&self) -> &Vec<Sprite<I>> {
305        &self.children
306    }
307
308    /// Draw this sprite and its children
309    pub fn draw<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
310        use graphics::*;
311
312        if !self.visible {
313            return;
314        }
315
316        let (tex_w, tex_h) = self.texture.get_size();
317        let tex_w = tex_w as f64;
318        let tex_h = tex_h as f64;
319        let source_rectangle = self.src_rect.unwrap_or({
320            let (w, h) = (tex_w, tex_h);
321            [0.0, 0.0, w as f64, h as f64]
322        });        
323        let anchor = [self.anchor[0] * source_rectangle[2], self.anchor[1] * source_rectangle[3]];
324
325        let transformed = t.trans(self.position[0], self.position[1])
326                           .rot_deg(self.rotation)
327                           .scale(self.scale[0], self.scale[1]);
328
329        let mut model = transformed;
330
331        if self.flip_x {
332            model = model.trans(source_rectangle[2] - 2.0 * anchor[0], 0.0).flip_h();
333        }
334
335        if self.flip_y {
336            model = model.trans(0.0, source_rectangle[3] - 2.0 * anchor[1]).flip_v();
337        }
338
339        let ref draw_state: graphics::DrawState = Default::default();
340
341        // for debug: bounding_box
342        //model.rgb(1.0, 0.0, 0.0).draw(b);
343
344        graphics::Image::new()
345            .color([self.color[0], self.color[1], self.color[2], self.opacity])
346            .rect([-anchor[0], -anchor[1], source_rectangle[2], source_rectangle[3]])
347            .maybe_src_rect(self.src_rect)
348            .draw(&*self.texture, draw_state, model, b);
349
350        // for debug: anchor point
351        //c.trans(self.position[0], self.position[1]).rect(-5.0, -5.0, 10.0, 10.0).rgb(0.0, 0.0, 1.0).draw(b);
352
353        for child in &self.children {
354            child.draw(transformed, b);
355        }
356    }
357
358    /// Draw this sprite and its children with color
359    pub fn draw_tinted<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B, c: [f32;3]) {
360        use graphics::*;
361
362        if !self.visible {
363            return;
364        }
365
366        let (tex_w, tex_h) = self.texture.get_size();
367        let tex_w = tex_w as f64;
368        let tex_h = tex_h as f64;
369        let source_rectangle = self.src_rect.unwrap_or({
370            let (w, h) = (tex_w, tex_h);
371            [0.0, 0.0, w as f64, h as f64]
372        });        
373        let anchor = [self.anchor[0] * source_rectangle[2], self.anchor[1] * source_rectangle[3]];
374
375        let transformed = t.trans(self.position[0], self.position[1])
376                           .rot_deg(self.rotation)
377                           .scale(self.scale[0], self.scale[1]);
378
379        let mut model = transformed;
380
381        if self.flip_x {
382            model = model.trans(source_rectangle[2] - 2.0 * anchor[0], 0.0).flip_h();
383        }
384
385        if self.flip_y {
386            model = model.trans(0.0, source_rectangle[3] - 2.0 * anchor[1]).flip_v();
387        }
388        
389        let ref draw_state: graphics::DrawState = Default::default();
390
391        // for debug: bounding_box
392        //model.rgb(1.0, 0.0, 0.0).draw(b);
393
394        graphics::Image::new()
395            .color([c[0], c[1], c[2], self.opacity])
396            .rect([-anchor[0], -anchor[1], source_rectangle[2], source_rectangle[3]])
397            .maybe_src_rect(self.src_rect)
398            .draw(&*self.texture, draw_state, model, b);
399
400        // for debug: anchor point
401        //c.trans(self.position[0], self.position[1]).rect(-5.0, -5.0, 10.0, 10.0).rgb(0.0, 0.0, 1.0).draw(b);
402
403        for child in &self.children {
404            child.draw_tinted(transformed, b, c);
405        }
406    }
407
408
409    /// Get the sprite's bounding box
410    pub fn bounding_box(&self) -> graphics::types::Rectangle {
411        let (w, h) = self.texture.get_size();
412        let source_rectangle = self.src_rect.unwrap_or({
413            let (sprite_w, sprite_h) = (w, h);
414            [0.0, 0.0, sprite_w as f64, sprite_h as f64]
415        });                
416        let sprite_w = source_rectangle[2] * self.scale[0];
417        let sprite_h = source_rectangle[3] * self.scale[1];
418
419        [
420            self.position[0] - self.anchor[0] * sprite_w,
421            self.position[1] - self.anchor[1] * sprite_h,
422            sprite_w,
423            sprite_h
424        ]
425    }
426}