1use std::ops::Mul;
2use crate::graphics::*;
3use crate::vertex::*;
4use nalgebra_glm as glm;
5
6pub const PI: f32 = 3.1415926535897932384626433832795;
7pub const HALF_PI: f32 = 1.5707963267948966192313216916398;
8pub const TWO_PI: f32 = 6.283185307179586476925286766559;
9pub const DEG_TO_RAD: f32 = 0.017453292519943295769236907684886;
10pub const RAD_TO_DEG: f32 = 57.295779513082320876798154814105;
11pub const EULER: f32 = 2.718281828459045235360287471352;
12
13#[macro_export]
14macro_rules! memory_offset {
15 ($ty:ty, $field:ident) => {
16 unsafe { &((*(0 as *const $ty)).$field) as *const _ as usize }
17 };
18}
19
20pub fn radians(degrees: f32) -> f32 {
21 degrees * DEG_TO_RAD
22}
23
24pub fn degrees(radians: f32) -> f32 {
25 radians * RAD_TO_DEG
26}
27
28pub fn min_f(a: f32, b: f32) -> f32 {
29 if a < b { a } else { b }
30}
31
32pub fn max_f(a: f32, b: f32) -> f32 {
33 if a > b { a } else { b }
34}
35
36pub fn clamp_s(s: f32, smin: f32, smax: f32) -> f32 {
37 min_f(max_f(s, smin), smax)
38}
39
40pub struct Rect<T: NumDefault> {
41 pub x: T, pub y: T, pub w: T, pub h: T
42}
43
44impl<T> Rect<T> where T: NumDefault {
45 pub fn new(x: T, y: T, w: T, h: T) -> Self {
46 Rect { x, y, w, h }
47 }
48
49 pub fn bottom(&self) -> T {
50 self.y + self.h
51 }
52
53 pub fn right(&self) -> T {
54 self.x + self.w
55 }
56}
57
58impl<T> Default for Rect<T> where T: NumDefault {
59
60 fn default() -> Self {
61 let default = T::default();
62 Rect {
63 x: default,
64 y: default,
65 w: default,
66 h: default
67 }
68 }
69}
70
71pub type Rectf = Rect<f32>;
72pub type Recti = Rect<i32>;
73pub type Rectui = Rect<u32>;
74
75pub struct Quad {
76 pub verts: [Vertex2D; 4]
77}
78
79impl Quad {
80 pub const fn default_verts() -> [Vertex2D; 4] {
81 let mut result = [Vertex2D::new(); 4];
82 result[0] = Vertex2D{ position: Vert2DPosition { x: -0.5, y: 0.5, z: 0. }, text_coord: Vert2DTextureCoord { u: 0., v: 1. }, color: Vert2DColor::white() };
83 result[1] = Vertex2D{ position: Vert2DPosition { x: -0.5, y: -0.5, z: 0. }, text_coord: Vert2DTextureCoord { u: 0., v: 0. }, color: Vert2DColor::white() };
84 result[2] = Vertex2D{ position: Vert2DPosition { x: 0.5, y: 0.5, z: 0. }, text_coord: Vert2DTextureCoord { u: 1., v: 1. }, color: Vert2DColor::white() };
85 result[3] = Vertex2D{ position: Vert2DPosition { x: 0.5, y: -0.5, z: 0. }, text_coord: Vert2DTextureCoord { u: 1., v: 0. }, color: Vert2DColor::white() };
86 result
91 }
92
93 pub fn new<T>(pos: glm::Vec2, size: glm::Vec2, rotation_degrees: f32, texture_rect: T) -> Self where T: Into<Option<Rectui>> {
94 let mut t = Transform::default();
95 t.translate(glm::vec2_to_vec3(&pos))
96 .rotate(rotation_degrees)
97 .scale(size);
98
99 Self::with_xform(&t, texture_rect)
100 }
101
102 pub fn with_xform<T>(xform: &Transform, texture_rect: T) -> Self where T: Into<Option<Rectui>> {
103 let mut verts = Self::default_verts();
104 verts.iter_mut().translate(xform);
105
106 if let Some(r) = texture_rect.into() {
107 verts.iter_mut().calc_texture_coords(&r);
108 }
109
110 Self::with_verts(&verts)
111 }
112
113 pub fn with_verts(verts: &[Vertex2D]) -> Self {
114 let mut vs = [Vertex2D::default(); 4];
115 for (i, v) in vs.iter_mut().enumerate() {
116 *v = verts[i];
117 }
118 Quad { verts: vs }
119 }
120
121 pub fn flip_vertical_text_coords(&mut self, min: f32, max: f32) {
122 self.verts.iter_mut().flip_texture_coords_vert(min, max);
123 }
124}
125
126impl Default for Quad {
127 fn default() -> Self {
128 Quad { verts: Self::default_verts() }
129 }
130}
131
132pub struct Transform(glm::Mat4);
134
135impl Transform {
136
137 pub fn new(mat: &glm::Mat4) -> Self {
138 Transform(*mat)
139 }
140
141 pub fn translate(&mut self, offset: glm::Vec3) -> &mut Self {
142 self.0 = self.0 * Transform::from_position(offset).model();
143 self
144 }
145
146 pub fn scale(&mut self, scale: glm::Vec2) -> &mut Self {
147 self.0 = self.0 * Transform::from_scale(scale).model();
148 self
149 }
150
151 pub fn rotate(&mut self, angle_degrees: f32) -> &mut Self {
152 self.0 = self.0 * Transform::from_rotation(angle_degrees).model();
153 self
154 }
155
156 pub fn rotate_offset(&mut self, angle_degrees: f32, offset: glm::Vec2) -> &mut Self {
160 self.translate(glm::vec2_to_vec3(&offset))
161 .rotate(angle_degrees)
162 .translate(glm::vec2_to_vec3(&-offset))
163 }
164
165 pub fn from_position<T>(position: T) -> Self where T: Into<glm::Vec3> {
166 let position = position.into();
167 let (x, y, z) = (position.x, position.y, position.z);
168 let model = glm::mat4(
169 1., 0., 0., x,
170 0., 1., 0., y,
171 0., 0., 1., z,
172 0., 0., 0., 1.
173 );
174 Transform(model)
175 }
176
177 pub fn from_scale<T>(scale: T) -> Self where T: Into<glm::Vec2> {
178 let scale = scale.into();
179 let (x, y) = (scale.x, scale.y);
180 let model = glm::mat4(
181 x , 0., 0., 0.,
182 0., y , 0., 0.,
183 0., 0., 1., 0.,
184 0., 0., 0., 1.
185 );
186 Transform(model)
187 }
188
189 pub fn from_rotation(angle_degrees: f32) -> Self {
190 let rotation = radians(angle_degrees);
191 let (sin, cos) = (f32::sin(rotation), f32::cos(rotation));
192 let model = glm::mat4(
193 cos, -sin, 0., 0.,
194 sin, cos, 0., 0.,
195 0. , 0. , 1., 0.,
196 0. , 0. , 0., 1.
197 );
198 Transform(model)
199 }
200
201 pub fn combine_mut(&mut self, other: &Self) {
202 self.0 = self.0 * other.0;
203 }
204
205 pub fn combine(left: &Self, right: &Self) -> Self {
206 Transform(left.0 * right.0)
207 }
208
209 pub fn model(&self) -> &glm::Mat4 { &self.0 }
210}
211
212pub struct FrameTimer {
213 clock: std::time::Instant,
214 accumulator: f32,
215 target_delta: f32
216}
217
218impl FrameTimer {
219 pub fn new(target_delta: f32) -> Self {
220 FrameTimer {
221 clock: std::time::Instant::now(),
222 accumulator: 0.0,
223 target_delta
224 }
225 }
226
227 pub fn elapsed(&mut self) -> f32 {
232 let elapsed = self.clock.elapsed().as_secs_f32();
233 self.clock = std::time::Instant::now();
234 elapsed
235 }
236
237 pub fn accum_elapsed(&mut self) -> f32 {
238 self.accumulator += self.elapsed();
239 self.accumulator
240 }
241
242 pub fn reset(&mut self) {
243 self.accumulator = 0.0;
244 self.clock = std::time::Instant::now();
245 }
246
247 pub fn frame(&mut self) -> bool {
252 let acc = self.accum_elapsed();
253 if acc >= self.target_delta {
254 true
255 } else {
256 false
257 }
258 }
259}
260
261impl Mul for Transform {
262 type Output = Self;
263
264 fn mul(self, right: Self) -> Self {
265 Self::combine(&self, &right)
266 }
267}
268
269impl Default for Transform {
270 fn default() -> Self {
271 Transform(glm::Mat4::identity())
272 }
273}
274
275pub fn read_file(path: &str) -> std::io::Result<String> {
276 use std::fs::File;
277 use std::io::BufReader;
278 use std::io::prelude::*;
279
280 let f = File::open(path)?;
281 let mut reader = BufReader::new(f);
282 let mut contents = String::new();
283 reader.read_to_string(&mut contents)?;
284 Ok(contents)
285}