ruckus/
sys.rs

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[0] = Vertex2D{ position: Vert2DPosition { x: 0., y: 0., z: 0. }, text_coord: Vert2DTextureCoord { u: 0., v: 1. }, color: Vert2DColor::white() };
87        // result[1] = Vertex2D{ position: Vert2DPosition { x: 0., y: 1., z: 0. }, text_coord: Vert2DTextureCoord { u: 0., v: 0. }, color: Vert2DColor::white() };
88        // result[2] = Vertex2D{ position: Vert2DPosition { x: 1., y: 0., z: 0. }, text_coord: Vert2DTextureCoord { u: 1., v: 1. }, color: Vert2DColor::white() };
89        // result[3] = Vertex2D{ position: Vert2DPosition { x: 1., y: 1., z: 0. }, text_coord: Vert2DTextureCoord { u: 1., v: 0. }, color: Vert2DColor::white() };
90        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
132// Move to new file? Doesnt really seem like it belongs here...
133pub 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    /**
157     * Rotates transform from offset of top left corner
158     */
159    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    /**
228     *  Gets elapsed time since last call to elapsed() or new().
229     *  Used to get time from last frame to current frame
230    */
231    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    /**
248     * Called every frame to add up the accumulator and return true
249     * if we have passed enough time for an update
250    */
251    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}