nova_math/
traits.rs

1/*
2 *
3 * This file is a part of NovaEngine
4 * https://gitlab.com/MindSpunk/NovaEngine
5 *
6 *
7 * MIT License
8 *
9 * Copyright (c) 2018 Nathan Voglsam
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in all
19 * copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30use core::f64::consts::PI;
31use core::fmt::{Debug, Display};
32use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
33use num_traits::Float;
34
35pub enum FloatType {
36    F32,
37    F64,
38}
39
40///
41/// This type represents a real number. A macro trait that makes using generic floats much easier
42///
43pub trait Real:
44    Float
45    + Add
46    + AddAssign
47    + Sub
48    + SubAssign
49    + Mul
50    + MulAssign
51    + Div
52    + DivAssign
53    + Copy
54    + Clone
55    + Pi
56    + IntoDegrees
57    + IntoRadians
58    + PartialEq
59    + PartialOrd
60    + Debug
61    + Display
62{
63    ///
64    /// Is this type a single-precision floating point. Useful for identifying the underlying
65    /// representation for SIMD purposes
66    ///
67    fn is_f32() -> bool;
68
69    ///
70    /// Is this type a double-precision floating point. Useful for identifying the underlying
71    /// representation for SIMD purposes
72    ///
73    fn is_f64() -> bool;
74
75    ///
76    /// Return the floating point type as an enum. Mostly just a convinience instead of using
77    /// `is_f32()` or `is_f64()`
78    ///
79    fn float_type() -> FloatType;
80
81    ///
82    /// Force get this value as single-precision
83    ///
84    fn as_f32(self) -> f32;
85
86    ///
87    /// Force get this value as double-precision
88    ///
89    fn as_f64(self) -> f64;
90}
91
92impl Real for f32 {
93    #[inline]
94    fn is_f32() -> bool {
95        true
96    }
97
98    #[inline]
99    fn is_f64() -> bool {
100        false
101    }
102
103    #[inline]
104    fn float_type() -> FloatType {
105        FloatType::F32
106    }
107
108    #[inline]
109    fn as_f32(self) -> f32 {
110        self
111    }
112
113    #[inline]
114    fn as_f64(self) -> f64 {
115        f64::from(self)
116    }
117}
118
119impl Real for f64 {
120    #[inline]
121    fn is_f32() -> bool {
122        false
123    }
124
125    #[inline]
126    fn is_f64() -> bool {
127        true
128    }
129
130    #[inline]
131    fn float_type() -> FloatType {
132        FloatType::F64
133    }
134
135    #[inline]
136    fn as_f32(self) -> f32 {
137        self as f32
138    }
139
140    #[inline]
141    fn as_f64(self) -> f64 {
142        self
143    }
144}
145
146///
147/// This type can perform linear interpolate from a to b with factor
148///
149pub trait Lerp<F: Real> {
150    ///
151    /// Return the result of interpolating between self and b with factor `factor`
152    ///
153    fn lerp(&self, b: &Self, factor: F) -> Self;
154}
155
156impl Lerp<f32> for f32 {
157    fn lerp(&self, b: &Self, factor: f32) -> Self {
158        *self + ((*self - *b) * factor)
159    }
160}
161
162impl Lerp<f64> for f64 {
163    fn lerp(&self, b: &Self, factor: f64) -> Self {
164        *self + ((*self - *b) * factor)
165    }
166}
167
168///
169/// This type has a constant PI
170///
171pub trait Pi {
172    ///
173    /// Get a value that represents Pi
174    ///
175    fn pi() -> Self;
176}
177
178impl<T: Real> Pi for T {
179    fn pi() -> Self {
180        T::from(PI).unwrap()
181    }
182}
183
184///
185/// This type can convert from degrees to radians
186///
187pub trait IntoRadians {
188    ///
189    /// Consume self and return it after converting the internal elements from degrees to radians
190    ///
191    fn into_radians(self) -> Self;
192}
193
194impl<T: Real + Pi> IntoRadians for T {
195    fn into_radians(self) -> Self {
196        crate::units::radians(self)
197    }
198}
199
200///
201/// This type can convert from radians to degrees
202///
203pub trait IntoDegrees {
204    ///
205    /// Consume self and return it after converting the internal elements from radians to degrees
206    ///
207    fn into_degrees(self) -> Self;
208}
209
210impl<T: Real + Pi> IntoDegrees for T {
211    fn into_degrees(self) -> Self {
212        crate::units::degrees(self)
213    }
214}
215
216///
217/// This type can be used to produce a dot product
218///
219pub trait DotProduct<T: Real> {
220    ///
221    /// Produce the dot product of self and rhs
222    ///
223    fn dot(&self, rhs: &Self) -> T;
224}
225
226///
227/// This type can be used to produce a cross product
228///
229pub trait CrossProduct {
230    ///
231    /// Produce the cross product of self and rhs
232    ///
233    /// # Note
234    ///
235    /// This can only really be implemented for a 3 component vector but is a trait to allow for
236    /// separating storage from implementation
237    ///
238    fn cross(&self, rhs: &Self) -> Self;
239}
240
241///
242/// This types supports performing a matrix transpose
243///
244/// # Info
245///
246/// Similar to the `Add` or `Mul` traits in that it takes ownership and passes the underlying object
247/// through the function.
248///
249pub trait Transpose {
250    fn transpose(self) -> Self;
251}
252
253///
254/// This type supports performing a matrix transpose
255///
256/// # Info
257///
258/// Similar to the `AddAssign` or `MulAssign` traits in that it takes a mutable reference to the
259/// underlying object and performs the transpose in place.
260///
261pub trait TransposeAssign {
262    fn transpose_assign(&mut self);
263}
264
265// TODO: Document me
266
267pub trait Inverse {
268    fn inverse(self) -> Self;
269}
270
271pub trait InverseAssign {
272    fn inverse_assign(&mut self);
273}
274
275///
276/// Packing the underlying data of a vector or matrix
277///
278pub trait Pack {
279    type GLSLOutput;
280    type HLSLOutput;
281    type GLSLOutputArray;
282    type HLSLOutputArray;
283    type CPUOutput;
284
285    ///
286    /// Convert the struct into packed data ready to be uploaded and consumed with hlsl standard
287    /// conventions.
288    ///
289    /// This will often round vectors up to alignment multiple sizes with padding bytes and is
290    /// important for matrices as hlsl shaders are expecting the matrices to be row major.
291    ///
292    /// # Warning
293    ///
294    /// If the matrix this is implemented on is row major it will have to perform an implict
295    /// transpose and so CAN CHANGE the underlying data beyond adding GPU required padding.
296    ///
297    fn into_packed_glsl(self) -> Self::GLSLOutput;
298
299    ///
300    /// Convert the struct into packed data ready to be uploaded and consumed with hlsl standard
301    /// conventions.
302    ///
303    /// This will often round vectors up to alignment multiple sizes with padding bytes and is
304    /// important for matrices as hlsl shaders are expecting the matrices to be row major.
305    ///
306    /// # Warning
307    ///
308    /// If the matrix this is implemented on is column major it will have to perform an implict
309    /// transpose and so CAN CHANGE the underlying data beyond adding GPU required padding
310    ///
311    fn into_packed_hlsl(self) -> Self::HLSLOutput;
312
313    ///
314    /// Convert the struct into packed data ready to be uploaded and consumed with hlsl standard
315    /// conventions.
316    ///
317    /// This function produces a semantically similar result to `into_packed_hlsl` but differs in
318    /// that for some GPU packing conventions (read: std430) the padding for an item, like a vec3,
319    /// differs whether it is on it's own or if it is an array element.
320    ///
321    /// This will often round vectors up to alignment multiple sizes with padding bytes and is
322    /// important for matrices as hlsl shaders are expecting the matrices to be row major.
323    ///
324    /// # Warning
325    ///
326    /// If the matrix this is implemented on is row major it will have to perform an implict
327    /// transpose and so CAN CHANGE the underlying data beyond adding GPU required padding.
328    ///
329    fn into_packed_glsl_array(self) -> Self::GLSLOutputArray;
330
331    ///
332    /// Convert the struct into packed data ready to be uploaded and consumed with hlsl standard
333    /// conventions.
334    ///
335    /// This function produces a semantically similar result to `into_packed_hlsl` but differs in
336    /// that for some GPU packing conventions (read: std430) the padding for an item, like a vec3,
337    /// differs whether it is on it's own or if it is an array element.
338    ///
339    /// This will often round vectors up to alignment multiple sizes with padding bytes and is
340    /// important for matrices as hlsl shaders are expecting the matrices to be row major.
341    ///
342    /// # Warning
343    ///
344    /// If the matrix this is implemented on is column major it will have to perform an implict
345    /// transpose and so CAN CHANGE the underlying data beyond adding GPU required padding.
346    ///
347    fn into_packed_hlsl_array(self) -> Self::HLSLOutputArray;
348
349    ///
350    /// Convert the struct into packed data for general purpose use on the CPU. This would be
351    /// ideal for things like serialization where you don't need to conform to special GPU alignment
352    /// and padding rules.
353    ///
354    /// This should, by general convention, just produce a flat array of the individual components
355    /// and should match the underlying number of components (3 for a Vec3, etc).
356    ///
357    /// # Warning
358    ///
359    /// There should be no padding in the results of this function.
360    ///
361    fn into_packed_cpu(self) -> Self::CPUOutput;
362}
363
364///
365/// Trait that marks a type as able to be packable into a std140 compatible form
366///
367pub trait IntoSTD140 {
368    type Output: Pack;
369
370    fn into_std140(self) -> Self::Output;
371}
372
373///
374/// This type abstracts a matrix where you can get a copy of a column
375///
376pub trait Column {
377    type Output;
378
379    ///
380    /// Get a copy of a given column of a matrix
381    ///
382    fn get_column(&self, col: usize) -> Self::Output;
383}
384
385///
386/// This type abstracts a matrix where you can get a reference of a column
387///
388pub trait ColumnRef: Column {
389    ///
390    /// Get a reference to a given column of a matrix
391    ///
392    fn get_column_ref(&self, col: usize) -> &Self::Output;
393}
394
395///
396/// This type abstracts a matrix where you can get a mutable reference of a column
397///
398pub trait ColumnRefMut: Column {
399    ///
400    /// Get a mutable reference to a given column of a matrix
401    ///
402    fn get_column_ref_mut(&mut self, col: usize) -> &mut Self::Output;
403}
404
405///
406/// This type abstracts a matrix where you can get a copy of a row
407///
408pub trait Row {
409    type Output;
410
411    ///
412    /// Get a copy of a given row of a matrix
413    ///
414    fn get_row(&self, row: usize) -> Self::Output;
415}
416
417///
418/// This type abstracts a matrix where you can get a reference of a row
419///
420pub trait RowRef: Row {
421    ///
422    /// Get a reference to a given row of a matrix
423    ///
424    fn get_row_ref(&self, row: usize) -> &Self::Output;
425}
426
427///
428/// This type abstracts a matrix where you can get a mutable reference of a row
429///
430pub trait RowRefMut: Row {
431    ///
432    /// Get a mutable reference to a given row of a matrix
433    ///
434    fn get_row_ref_mut(&mut self, row: usize) -> &mut Self::Output;
435}
436
437///
438/// This type abstracts a vector or other object that can represents a length
439///
440pub trait Length {
441    type Output;
442
443    fn length(&self) -> Self::Output;
444}
445
446///
447/// This type abstracts a vector or other object that can represents a length. Get's the square of
448/// the length as this can often skip an expensive square root calculation.
449///
450pub trait LengthSquared {
451    type Output;
452
453    fn length_squared(&self) -> Self::Output;
454}
455
456///
457/// This type abstracts a vector or other object that can be normalized to represent the same
458/// direction while having a length of 1
459///
460pub trait Normalize {
461    fn normalize(self) -> Self;
462}
463
464///
465/// This type abstracts a vector or other object that can be normalized to represent the same
466/// direction while having a length of 1
467///
468pub trait NormalizeAssign {
469    fn normalize_assign(&mut self);
470}
471
472pub mod std140 {
473    use crate::traits::{IntoSTD140, Pack};
474
475    ///
476    /// A wrapper struct that is used to implement std140 packing for the underlying type
477    ///
478    #[repr(transparent)]
479    #[derive(Copy, Clone, Debug)]
480    pub struct F32Pack(f32);
481
482    impl IntoSTD140 for f32 {
483        type Output = F32Pack;
484
485        fn into_std140(self) -> Self::Output {
486            F32Pack(self)
487        }
488    }
489
490    impl Pack for F32Pack {
491        type GLSLOutput = f32;
492        type HLSLOutput = f32;
493        type GLSLOutputArray = f32;
494        type HLSLOutputArray = f32;
495        type CPUOutput = f32;
496
497        fn into_packed_glsl(self) -> Self::GLSLOutput {
498            self.0
499        }
500
501        fn into_packed_hlsl(self) -> Self::HLSLOutput {
502            self.0
503        }
504
505        fn into_packed_glsl_array(self) -> Self::GLSLOutputArray {
506            self.0
507        }
508
509        fn into_packed_hlsl_array(self) -> Self::HLSLOutputArray {
510            self.0
511        }
512
513        fn into_packed_cpu(self) -> Self::CPUOutput {
514            self.0
515        }
516    }
517
518    ///
519    /// A wrapper struct that is used to implement std140 packing for the underlying type
520    ///
521    #[repr(transparent)]
522    #[derive(Copy, Clone, Debug)]
523    pub struct F64Pack(f64);
524
525    impl IntoSTD140 for f64 {
526        type Output = F64Pack;
527
528        fn into_std140(self) -> Self::Output {
529            F64Pack(self)
530        }
531    }
532
533    impl Pack for F64Pack {
534        type GLSLOutput = f64;
535        type HLSLOutput = f64;
536        type GLSLOutputArray = f64;
537        type HLSLOutputArray = f64;
538        type CPUOutput = f64;
539
540        fn into_packed_glsl(self) -> Self::GLSLOutput {
541            self.0
542        }
543
544        fn into_packed_hlsl(self) -> Self::HLSLOutput {
545            self.0
546        }
547
548        fn into_packed_glsl_array(self) -> Self::GLSLOutputArray {
549            self.0
550        }
551
552        fn into_packed_hlsl_array(self) -> Self::HLSLOutputArray {
553            self.0
554        }
555
556        fn into_packed_cpu(self) -> Self::CPUOutput {
557            self.0
558        }
559    }
560}