bowtie/sprites/
sprite.rs

1use crate::{
2  general::{color::Color, direction::Direction},
3  gl_utils::{
4    gl_texture::LoadableTexture, gl_texture::Texture,
5    shader_creator::ShaderProgram,
6  },
7  math::matrix::{IdentityMatrix, Matrix},
8  shapes::shape::Shape,
9};
10
11use super::drawable::Drawable;
12use std::marker::PhantomData;
13
14#[derive(Debug, Clone)]
15/// A sprite manages a texture and a texture to create a drawable.
16pub struct Sprite<'a, TShape>
17where
18  TShape: Shape + 'a,
19{
20  shape: TShape,
21  pub name: String,
22  texture: Texture,
23  phantom: PhantomData<&'a TShape>,
24  transformation: Matrix<f32>,
25}
26
27impl<'a, TShape: 'a> Sprite<'a, TShape>
28where
29  TShape: Shape + 'a,
30{
31  pub fn new(shape: TShape, texture: Texture) -> Sprite<'a, TShape> {
32    Sprite {
33      shape,
34      name: texture.image_name.to_owned(),
35      texture,
36      phantom: PhantomData,
37      transformation: Matrix::<f32>::generate_identity(4),
38    }
39  }
40
41  pub fn with_transformation(
42    shape: TShape,
43    texture: Texture,
44    trans: Matrix<f32>,
45  ) -> Sprite<'a, TShape> {
46    Sprite {
47      shape,
48      name: texture.image_name.to_owned(),
49      texture,
50      phantom: PhantomData,
51      transformation: trans,
52    }
53  }
54
55  pub fn move_sprite(&mut self, direction: Direction, amount: f32) {
56    match direction {
57      Direction::Right => {
58        self.move_right(amount);
59      }
60      Direction::Left => {
61        self.move_left(amount);
62      }
63      Direction::Up => {
64        self.move_up(amount);
65      }
66      Direction::Down => {
67        self.move_down(amount);
68      }
69      Direction::UpRight => {
70        self.move_right(amount);
71        self.move_up(amount);
72      }
73      Direction::UpLeft => {
74        self.move_left(amount);
75        self.move_up(amount);
76      }
77      Direction::DownRight => {
78        self.move_right(amount);
79        self.move_down(amount);
80      }
81      Direction::DownLeft => {
82        self.move_left(amount);
83        self.move_down(amount);
84      }
85      _ => {}
86    }
87  }
88
89  pub fn flip_vertical(&mut self) {
90    self.shape.flip_texture_corners_y()
91  }
92
93  pub fn flip_horizontal(&mut self) {
94    self.shape.flip_texture_corners_x()
95  }
96
97  pub fn transform(&mut self, transformation_matrix: Matrix<f32>) {
98    assert!(
99      transformation_matrix.get_num_rows() == 4
100        && transformation_matrix.get_num_columns() == 4,
101      "Not a valid transformation_matrix"
102    );
103
104    self.transformation = transformation_matrix;
105  }
106
107  pub fn load_texture(&mut self) {
108    self.texture.load_texture();
109  }
110
111  pub fn set_x(&mut self, x: f32) {
112    self.shape.set_x(x);
113  }
114  pub fn set_y(&mut self, y: f32) {
115    self.shape.set_y(y);
116  }
117
118  pub fn get_x(&self) -> f32 {
119    self.shape.get_x()
120  }
121
122  pub fn get_y(&self) -> f32 {
123    self.shape.get_y()
124  }
125
126  pub fn get_height(&self) -> f32 {
127    self.shape.get_height()
128  }
129
130  pub fn get_width(&self) -> f32 {
131    self.shape.get_width()
132  }
133
134  pub fn move_up(&mut self, amount: f32) -> bool {
135    let new_amount = self.shape.get_y() + amount;
136
137    if new_amount >= 0.8 {
138      return false;
139    }
140
141    self.shape.set_y(new_amount);
142
143    return true;
144  }
145
146  pub fn move_down(&mut self, amount: f32) -> bool {
147    let new_amount = self.shape.get_y() - amount;
148
149    if new_amount <= -0.7 {
150      return false;
151    }
152
153    self.shape.set_y(new_amount);
154
155    return true;
156  }
157
158  pub fn move_right(&mut self, amount: f32) -> bool {
159    let new_amount = self.shape.get_x() + amount;
160
161    if new_amount > 0.7 {
162      return false;
163    }
164
165    self.shape.set_x(new_amount);
166
167    return true;
168  }
169
170  pub fn set_color_overlay(&mut self, color: Color) {
171    self.shape.set_color(color);
172  }
173
174  pub fn move_left(&mut self, amount: f32) -> bool {
175    let new_amount = self.shape.get_x() - amount;
176
177    if new_amount <= -1.0 {
178      return false;
179    }
180
181    self.shape.set_x(new_amount);
182
183    return true;
184  }
185}
186
187impl<'a, TShape> Drawable<'a> for Sprite<'a, TShape>
188where
189  TShape: Shape + 'a,
190{
191  fn set_texture_uniform(&'a self, program: &ShaderProgram) -> () {
192    self.texture.set_uniform(program);
193  }
194
195  fn get_corner_count(&'a self) -> i32 {
196    self.shape.get_coordinate_corners().len() as i32
197  }
198
199  fn get_elements(&self) -> Vec<i32> {
200    return vec![0, 1, 2, 2, 3, 0];
201  }
202
203  fn load_texture(&'a self) -> () {
204    self.texture.load_texture();
205  }
206
207  fn get_vertices(&self) -> Vec<f32> {
208    let mut vertices = Vec::<f32>::new();
209
210    let shape = &self.shape;
211
212    let coordinate_corners = &self.shape.get_coordinate_corners();
213    let texture_corners = &self.shape.get_texture_corners();
214
215    for i in 0..4 {
216      // X, Y
217      let [x, y] = coordinate_corners[i];
218      vertices.push(x);
219      vertices.push(y);
220
221      // Color
222      vertices.push(shape.get_color().r);
223      vertices.push(shape.get_color().g);
224      vertices.push(shape.get_color().b);
225      vertices.push(shape.get_color().a);
226
227      // Texture Cords
228      let [tx, ty] = texture_corners[i];
229      vertices.push(tx);
230      vertices.push(ty);
231
232      vertices.push(self.texture.texture_id as f32);
233
234      for entry in self.transformation.get_inner_ptr() {
235        vertices.push(entry.to_owned());
236      }
237    }
238    return vertices;
239  }
240}
241
242impl<'a, TShape> From<&Sprite<'a, TShape>> for Sprite<'a, TShape>
243where
244  TShape: Shape + Clone,
245{
246  fn from(sprite_ref: &Sprite<'a, TShape>) -> Self {
247    Sprite::new(sprite_ref.shape.to_owned(), sprite_ref.texture.to_owned())
248  }
249}