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
10pub 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 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 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 #[inline(always)]
93 pub fn id(&self) -> Uuid {
94 self.id.clone()
95 }
96
97 pub fn get_visible(&self) -> bool {
99 self.visible
100 }
101
102 pub fn set_visible(&mut self, visible: bool) {
104 self.visible = visible;
105 }
106
107 #[inline(always)]
111 pub fn get_anchor(&self) -> (Scalar, Scalar) {
112 (self.anchor[0], self.anchor[1])
113 }
114
115 #[inline(always)]
117 pub fn set_anchor(&mut self, x: Scalar, y: Scalar) {
118 self.anchor = [x, y];
119 }
120
121 #[inline(always)]
123 pub fn get_position(&self) -> (Scalar, Scalar) {
124 (self.position[0], self.position[1])
125 }
126
127 #[inline(always)]
129 pub fn set_position(&mut self, x: Scalar, y: Scalar) {
130 self.position = [x, y];
131 }
132
133 #[inline(always)]
135 pub fn set_color(&mut self, r: f32, g: f32, b: f32) {
136 self.color = [r, g, b];
137 }
138
139 #[inline(always)]
141 pub fn get_color(&self) -> (f32, f32, f32) {
142 (self.color[0], self.color[1], self.color[2])
143 }
144
145 #[inline(always)]
147 pub fn get_rotation(&self) -> Scalar {
148 self.rotation
149 }
150
151 #[inline(always)]
153 pub fn set_rotation(&mut self, deg: Scalar) {
154 self.rotation = deg;
155 }
156
157 #[inline(always)]
159 pub fn get_scale(&self) -> (Scalar, Scalar) {
160 (self.scale[0], self.scale[1])
161 }
162
163 #[inline(always)]
165 pub fn set_scale(&mut self, sx: Scalar, sy: Scalar) {
166 self.scale = [sx, sy];
167 }
168
169 #[inline(always)]
179 pub fn get_flip_x(&self) -> bool {
180 self.flip_x
181 }
182
183 #[inline(always)]
185 pub fn set_flip_x(&mut self, flip_x: bool) {
186 self.flip_x = flip_x;
187 }
188
189 #[inline(always)]
199 pub fn get_flip_y(&self) -> bool {
200 self.flip_y
201 }
202
203 #[inline(always)]
205 pub fn set_flip_y(&mut self, flip_y: bool) {
206 self.flip_y = flip_y;
207 }
208
209 #[inline(always)]
211 pub fn get_opacity(&self) -> f32 {
212 self.opacity
213 }
214
215 #[inline(always)]
217 pub fn set_opacity(&mut self, opacity: f32) {
218 self.opacity = opacity;
219 }
220
221 #[inline(always)]
223 pub fn get_src_rect(&self) -> Option<SourceRectangle> {
224 self.src_rect
225 }
226
227 #[inline(always)]
229 pub fn set_src_rect(&mut self, src_rect: SourceRectangle) {
230 self.src_rect = From::from(src_rect);
231 }
232
233 #[inline(always)]
235 pub fn get_texture(&self) -> &Rc<I> {
236 &self.texture
237 }
238
239 #[inline(always)]
241 pub fn set_texture(&mut self, texture: Rc<I>) {
242 self.texture = texture;
243 }
244
245 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 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 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 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 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 #[inline(always)]
304 pub fn children(&self) -> &Vec<Sprite<I>> {
305 &self.children
306 }
307
308 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 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 child in &self.children {
354 child.draw(transformed, b);
355 }
356 }
357
358 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 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 child in &self.children {
404 child.draw_tinted(transformed, b, c);
405 }
406 }
407
408
409 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}