1use color::Color;
4use draw::{BlendMode, Context, Drawable, DrawableMut, Drawer};
5use nalgebra;
6use nalgebra::*;
7use resources::Resource;
8use shader::DEFAULT_SHADER;
9use std::convert::From;
10use std::error::Error;
11use std::fmt;
12use texture::Texture;
13use transform::{Movable, Rotable, Scalable, Transformable};
14use vertex::Vertex;
15use vertex::*;
16use vertex_buffer::{Primitive, VertexBuffer};
17
18#[derive(Debug, Clone, PartialEq)]
32pub struct Sprite {
33 pos: Vector2<f32>,
34 scale: Vector2<f32>,
35 rotation: f32,
36 origin: Vector2<f32>,
37 vertice: VertexBuffer,
38 texture: Option<Resource<Texture>>,
39 model: Matrix4<f32>,
40 need_update: bool,
41}
42
43impl Sprite {
44 pub fn new() -> Sprite {
47 Sprite {
48 pos: Vector2::new(0.0, 0.0),
49 scale: Vector2::new(1.0, 1.0),
50 vertice: VertexBuffer::new(
51 Primitive::TrianglesStrip,
52 VertexArray::from(
53 vec![
54 Vertex::default(),
55 Vertex::default(),
56 Vertex::default(),
57 Vertex::default(),
58 ]
59 .as_slice(),
60 ),
61 ),
62 need_update: true,
63 texture: None,
64 origin: Vector2::new(0.0, 0.0),
65 model: Matrix4::identity(),
66 rotation: 0.0,
67 }
68 }
69
70 pub fn set_color(&mut self, color: &Color) {
72 self.vertice[0].color = *color;
73 self.vertice[1].color = *color;
74 self.vertice[2].color = *color;
75 self.vertice[3].color = *color;
76 self.vertice.update();
77 }
78
79 pub fn get_sizes(&self) -> Vector2<u32> {
81 if let Some(ref texture) = self.texture {
82 Vector2::new(texture.width() as u32, texture.height() as u32)
83 } else {
84 Vector2::new(0, 0)
85 }
86 }
87
88 pub fn set_origin_to_center(&mut self) -> Result<(), SpriteError> {
92 if self.texture.is_some() {
93 let mut center = Vector2::new(0.0, 0.0);
94 let sizes = self.get_sizes();
95 center.x = sizes.x as f32 / 2.0;
96 center.y = sizes.y as f32 / 2.0;
97 self.set_origin(center);
98 Ok(())
99 } else {
100 Err(SpriteError::NoTexture)
101 }
102 }
103
104 pub fn set_texture(&mut self, texture: &Resource<Texture>) {
106 self.texture = Some(Resource::clone(texture));
107 self.need_update = true;
108 }
109}
110
111impl<'a> From<&'a Resource<Texture>> for Sprite {
112 fn from(tex: &'a Resource<Texture>) -> Sprite {
122 let width = tex.width() as f32;
123 let height = tex.height() as f32;
124 let pos = Vector2::new(0.0, 0.0);
125 Sprite {
126 pos,
127 scale: Vector2::new(1.0, 1.0),
128 vertice: VertexBuffer::new(
129 Primitive::TrianglesStrip,
130 VertexArray::from(
131 vec![
132 Vertex::new(
133 Vector2::new(0.0, 0.0),
134 Vector2::new(0.0, 0.0),
135 Color::white(),
136 ),
137 Vertex::new(
138 Vector2::new(0.0, height),
139 Vector2::new(0.0, 1.0),
140 Color::white(),
141 ),
142 Vertex::new(
143 Vector2::new(width, 0.0),
144 Vector2::new(1.0, 0.0),
145 Color::white(),
146 ),
147 Vertex::new(
148 Vector2::new(width, height),
149 Vector2::new(1.0, 1.0),
150 Color::white(),
151 ),
152 ]
153 .as_slice(),
154 ),
155 ),
156 texture: Some(Resource::clone(tex)),
157 need_update: true,
158 model: Matrix4::identity().append_translation(&Vector3::new(pos.x, pos.y, 0.0)),
159 rotation: 0.0,
160 origin: Vector2::new(0.0, 0.0),
161 }
162 }
163}
164
165impl Transformable for Sprite {
166 fn contain<T: nalgebra::Scalar + Into<f32>>(&self, _point: ::Point<T>) -> bool {
168 true
177 }
178
179 fn set_origin<T: nalgebra::Scalar + Into<f32>>(&mut self, origin: Vector2<T>) {
180 self.origin.x = origin.x.into();
181 self.origin.y = origin.y.into();
182 self.need_update = true;
183 }
184
185 fn get_origin(&self) -> Vector2<f32> {
186 self.origin
187 }
188}
189
190impl Scalable for Sprite {
191 fn set_scale<T>(&mut self, vec: Vector2<T>)
192 where
193 T: Scalar + Into<f32>,
194 {
195 self.scale.x = vec.x.into();
196 self.scale.y = vec.y.into();
197 self.need_update = true;
198 }
199
200 fn get_scale(&self) -> Vector2<f32> {
201 self.scale
202 }
203
204 fn scale<T>(&mut self, factor: Vector2<T>)
205 where
206 T: Scalar + Into<f32>,
207 {
208 self.scale.x += factor.x.into();
209 self.scale.y += factor.y.into();
210 self.need_update = true;
211 }
212}
213
214impl Rotable for Sprite {
215 fn rotate<T>(&mut self, angle: T)
216 where
217 T: Scalar + Into<f32>,
218 {
219 self.rotation += angle.into();
220 self.need_update = true;
221 }
222
223 fn set_rotation<T>(&mut self, angle: T)
224 where
225 T: Scalar + Into<f32>,
226 {
227 self.rotation = angle.into();
228 self.need_update = true;
229 }
230
231 fn get_rotation(&self) -> f32 {
232 self.rotation
233 }
234}
235
236impl Movable for Sprite {
237 fn translate<T>(&mut self, vec: Vector2<T>)
238 where
239 T: Scalar + Into<f32>,
240 {
241 self.pos.x += vec.x.into();
242 self.pos.y += vec.y.into();
243 self.need_update = true;
244 }
245
246 fn get_position(&self) -> Vector2<f32> {
247 self.pos
248 }
249
250 fn set_position<T>(&mut self, vec: Vector2<T>)
251 where
252 T: Scalar + Into<f32>,
253 {
254 self.pos.x = vec.x.into();
255 self.pos.y = vec.y.into();
256 self.need_update = true;
257 }
258}
259
260impl Default for Sprite {
261 fn default() -> Self {
262 Sprite {
263 pos: Vector2::new(0.0, 0.0),
264 scale: Vector2::new(0.0, 0.0),
265 rotation: 0.0,
266 origin: Vector2::new(0.0, 0.0),
267 vertice: VertexBuffer::default(),
268 texture: Some(Resource::new(Texture::default())),
269 model: Matrix4::<f32>::identity(),
270 need_update: false,
271 }
272 }
273}
274
275impl DrawableMut for Sprite {
276 fn draw_mut<T: Drawer>(&mut self, window: &mut T) {
278 self.update();
279 self.draw(window);
280 }
281
282 fn draw_with_context_mut<'a>(&mut self, context: &'a mut Context) {
283 self.update();
284 self.vertice.draw_with_context(context);
285 }
286}
287
288impl Drawable for Sprite {
290 fn draw<T: Drawer>(&self, window: &mut T) {
292 let texture = if let Some(ref rc_texture) = self.texture {
293 Some(rc_texture.as_ref())
294 } else {
295 None
296 };
297
298 let mut context = Context::new(
299 texture,
300 &*DEFAULT_SHADER,
301 vec![
302 ("transform".to_string(), &self.model),
303 ("projection".to_string(), window.projection()),
304 ],
305 BlendMode::Alpha,
306 );
307 self.vertice.draw_with_context(&mut context);
308 }
309
310 fn draw_with_context<'a>(&self, context: &'a mut Context) {
312 self.vertice.draw_with_context(context);
313 }
314
315 fn update(&mut self) {
320 if !self.need_update {
321 return;
322 }
323 self.model = Matrix4::<f32>::identity().append_translation(&Vector3::new(
325 self.pos.x - self.origin.x,
326 self.pos.y - self.origin.y,
327 0.0,
328 ));
329
330 if self.origin.x != 0.0 && self.origin.y != 0.0 {
331 self.model
332 .append_translation_mut(&Vector3::new(self.origin.x, self.origin.y, 0.0));
333 self.model *= Matrix4::from_euler_angles(0.0, 0.0, self.rotation * (3.14116 * 180.0));
334 self.model
335 .prepend_translation_mut(&Vector3::new(-self.origin.x, -self.origin.y, 0.0));
336 } else {
337 self.model *= Matrix4::from_euler_angles(0.0, 0.0, self.rotation * (3.14116 * 180.0));
338 }
339 self.model
340 .append_nonuniform_scaling_mut(&Vector3::new(self.scale.x, self.scale.y, 0.0));
341
342 if self.rotation > 360.0 {
343 self.rotation = 0.0;
344 }
345
346 self.need_update = false;
347 }
348}
349
350#[derive(Debug)]
351pub enum SpriteError {
353 NoTexture,
354}
355
356impl fmt::Display for SpriteError {
357 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
358 match self {
359 SpriteError::NoTexture => write!(f, "There is no texture linked to this Sprite"),
360 }
361 }
362}
363
364impl Error for SpriteError {
365 fn cause(&self) -> Option<&Error> {
366 match self {
367 SpriteError::NoTexture => None,
368 }
369 }
370}