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}