Browse Source

Implemented matrix types

raster
Bergmann89 4 years ago
parent
commit
41d8007d98
3 changed files with 575 additions and 1 deletions
  1. +1
    -0
      glc/src/lib.rs
  2. +508
    -0
      glc/src/matrix.rs
  3. +66
    -1
      glc/src/vector.rs

+ 1
- 0
glc/src/lib.rs View File

@@ -1,5 +1,6 @@
pub mod array_buffer;
pub mod error;
pub mod matrix;
pub mod misc;
pub mod shader;
pub mod vector;


+ 508
- 0
glc/src/matrix.rs View File

@@ -0,0 +1,508 @@
#![allow(dead_code)]

use std::convert::{AsMut, AsRef};
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::ops::{Deref, DerefMut, Mul};

use super::vector::{Element, Vector2, Vector3, Vector4};

macro_rules! define_mat {
($Name:ident, $Vector:ident, $size:tt, $($T:ident => $i:tt => $f:ident),*) => {
#[repr(C, packed)]
pub struct $Name<T> {
$(pub $f: $Vector<T>,)+
}

impl<T> $Name<T> {
#[inline]
pub fn new($($f: $Vector<T>,)+) -> Self {
Self { $($f,)+ }
}
}

impl<T> Default for $Name<T>
where
T: Element
{
#[inline]
fn default() -> Self {
Self::identity()
}
}

impl<T> Debug for $Name<T>
where
T: Debug
{
fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
fmt.debug_list().entries(self.as_ref().iter()).finish()
}
}

impl<T, S> PartialEq<$Name<S>> for $Name<T>
where
$Vector<S>: PartialEq<$Vector<T>>,
{
fn eq(&self, other: &$Name<S>) -> bool {
unsafe { true $(&& other.$f.eq(&self.$f))+ }
}
}

impl<T> Eq for $Name<T>
where
T: Eq
{ }

impl<T> Deref for $Name<T> {
type Target = [$Vector<T>; $size];

#[inline]
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}

impl<T> DerefMut for $Name<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}

impl<T> AsRef<[$Vector<T>; $size]> for $Name<T> {
#[inline]
fn as_ref(&self) -> &[$Vector<T>; $size] {
unsafe {
let raw: * const _ = self;
let raw = raw as * const [$Vector<T>; $size];

&*raw
}
}
}

impl<T> AsMut<[$Vector<T>; $size]> for $Name<T> {
#[inline]
fn as_mut(&mut self) -> &mut [$Vector<T>; $size] {
unsafe {
let raw: * mut _ = self;
let raw = raw as * mut [$Vector<T>; $size];

&mut *raw
}
}
}

impl<T> Clone for $Name<T>
where
T: Clone
{
#[inline]
fn clone(&self) -> Self {
unsafe {
Self {
$($f: self.$f.clone(),)+
}
}
}
}

impl<T> Copy for $Name<T>
where
T: Copy
{ }

impl<T> From<[$Vector<T>; $size]> for $Name<T>
where
T: Copy,
{
#[inline]
fn from(arr: [$Vector<T>; $size]) -> Self {
Self {
$($f: arr[$i],)+
}
}
}

impl<T> From<($($Vector<$T>,)+)> for $Name<T> {
#[inline]
fn from(($($f,)+): ($($Vector<$T>,)+)) -> Self {
Self {
$($f,)+
}
}
}
};
}

define_mat!(Matrix2, Vector2, 2, T => 0 => axis_x, T => 1 => axis_y);
define_mat!(Matrix3, Vector3, 3, T => 0 => axis_x, T => 1 => axis_y, T => 2 => axis_z);
define_mat!(Matrix4, Vector4, 4, T => 0 => axis_x, T => 1 => axis_y, T => 2 => axis_z, T => 3 => position);

type Matrix2f = Matrix2<gl::GLfloat>;
type Matrix3f = Matrix3<gl::GLfloat>;
type Matrix4f = Matrix4<gl::GLfloat>;

type Matrix2d = Matrix2<gl::GLdouble>;
type Matrix3d = Matrix3<gl::GLdouble>;
type Matrix4d = Matrix4<gl::GLdouble>;

type Matrix2i = Matrix2<gl::GLint>;
type Matrix3i = Matrix3<gl::GLint>;
type Matrix4i = Matrix4<gl::GLint>;

/* Matrix2 */

impl<T> Matrix2<T>
where
T: Element,
{
#[inline]
pub fn identity() -> Self {
let one = T::one();
let zero = T::zero();

Self::new(Vector2::new(one, zero), Vector2::new(zero, one))
}
}

/* Matrix3 */

impl<T> Matrix3<T>
where
T: Element,
{
#[inline]
pub fn identity() -> Self {
let one = T::one();
let zero = T::zero();

Self::new(
Vector3::new(one, zero, zero),
Vector3::new(zero, one, zero),
Vector3::new(zero, zero, one),
)
}

#[inline]
pub fn determinant(&self) -> T {
let m = self;

m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * m[0][1] * m[1][2]
- m[2][0] * m[1][1] * m[0][2]
- m[1][0] * m[0][1] * m[2][2]
- m[0][0] * m[2][1] * m[1][2]
}
}

/* Matrix4 */

impl<T> Matrix4<T>
where
T: Element,
{
#[inline]
pub fn identity() -> Self {
let one = T::one();
let zero = T::zero();

Self::new(
Vector4::new(one, zero, zero, zero),
Vector4::new(zero, one, zero, zero),
Vector4::new(zero, zero, one, zero),
Vector4::new(zero, zero, zero, one),
)
}

#[inline]
pub fn translate(v: Vector3<T>) -> Self {
let one = T::one();
let zero = T::zero();

Self::new(
Vector4::new(one, zero, zero, zero),
Vector4::new(zero, one, zero, zero),
Vector4::new(zero, zero, one, zero),
Vector4::new(v.x, v.y, v.z, one),
)
}

#[inline]
pub fn scale(v: Vector3<T>) -> Self {
let one = T::one();
let zero = T::zero();

Self::new(
Vector4::new(v.x, zero, zero, zero),
Vector4::new(zero, v.y, zero, zero),
Vector4::new(zero, zero, v.z, zero),
Vector4::new(zero, zero, zero, one),
)
}

#[inline]
#[allow(clippy::many_single_char_names)]
pub fn rotate(axis: Vector3<T>, angle: Angle<T>) -> Self {
let axis = axis.normalize();
let x = axis.x;
let y = axis.y;
let z = axis.z;
let angle = angle.into_rad().into_inner();
let s = T::sin(angle);
let c = T::cos(angle);
let one = T::one();
let zero = T::zero();

Self::new(
Vector4::new(
x * x + (one - y * y) * c,
x * y * (one - c) + z * s,
x * z * (one - c) - y * s,
zero,
),
Vector4::new(
x * y * (one - c) - z * s,
y * y + (one - y * y) * c,
y * z * (one - c) + x * s,
zero,
),
Vector4::new(
x * z * (one - c) + y * s,
y * z * (one - c) - x * s,
z * z + (one - z * z) * c,
zero,
),
Vector4::new(zero, zero, zero, one),
)
}

#[inline]
pub fn multiply(&self, other: &Self) -> Self {
let m1 = self;
let m2 = other;

macro_rules! mul {
($x:tt, $y:tt) => {
m1[0][$y] * m2[$x][0]
+ m1[1][$y] * m2[$x][1]
+ m1[2][$y] * m2[$x][2]
+ m1[3][$y] * m2[$x][3]
};
}

Self::new(
Vector4::new(mul!(0, 0), mul!(0, 1), mul!(0, 2), mul!(0, 3)),
Vector4::new(mul!(1, 0), mul!(1, 1), mul!(1, 2), mul!(1, 3)),
Vector4::new(mul!(2, 0), mul!(2, 1), mul!(2, 2), mul!(2, 3)),
Vector4::new(mul!(3, 0), mul!(3, 1), mul!(3, 2), mul!(3, 3)),
)
}

#[inline]
pub fn transform(&self, v: &Vector4<T>) -> Vector4<T> {
let m = self;

macro_rules! mul {
($i:tt) => {
m[0][$i] * v[0] + m[1][$i] * v[1] + m[2][$i] * v[2] + m[3][$i] * v[3]
};
}

Vector4::new(mul!(0), mul!(1), mul!(2), mul!(3))
}

#[inline]
pub fn transpose(&self) -> Self {
let m = self;

Self::new(
Vector4::new(m[0][0], m[1][0], m[2][0], m[3][0]),
Vector4::new(m[0][1], m[1][1], m[2][1], m[3][1]),
Vector4::new(m[0][2], m[1][2], m[2][2], m[3][2]),
Vector4::new(m[0][3], m[1][3], m[2][3], m[3][3]),
)
}

#[inline]
pub fn submatrix(&self, s: usize, z: usize) -> Matrix3<T> {
let mut ret = Matrix3::identity();

for i in 0..=2 {
for j in 0..=2 {
let x = if i >= s { i + 1 } else { i };
let y = if j >= z { j + 1 } else { j };

ret[i][j] = self[x][y];
}
}

ret
}

#[inline]
pub fn determinant(&self) -> T {
let m = self;

m[0][0] * m.submatrix(0, 0).determinant() - m[1][0] * m.submatrix(1, 0).determinant()
+ m[2][0] * m.submatrix(2, 0).determinant()
+ m[3][0] * m.submatrix(3, 0).determinant()
}

#[inline]
pub fn adjoint(&self) -> Self {
let m = self;

Self::new(
Vector4::new(
m.submatrix(0, 0).determinant(),
-m.submatrix(1, 0).determinant(),
m.submatrix(2, 0).determinant(),
-m.submatrix(3, 0).determinant(),
),
Vector4::new(
-m.submatrix(0, 1).determinant(),
m.submatrix(1, 1).determinant(),
-m.submatrix(2, 1).determinant(),
m.submatrix(3, 1).determinant(),
),
Vector4::new(
m.submatrix(0, 2).determinant(),
-m.submatrix(1, 2).determinant(),
m.submatrix(2, 2).determinant(),
-m.submatrix(3, 2).determinant(),
),
Vector4::new(
-m.submatrix(0, 3).determinant(),
m.submatrix(1, 3).determinant(),
-m.submatrix(2, 3).determinant(),
m.submatrix(3, 3).determinant(),
),
)
}

#[inline]
pub fn invert(&self) -> Self {
let d = self.determinant();
let mut ret = self.adjoint();

ret[0][0] = ret[0][0] / d;
ret[0][1] = ret[0][1] / d;
ret[0][2] = ret[0][2] / d;
ret[0][3] = ret[0][3] / d;

ret[1][0] = ret[1][0] / d;
ret[1][1] = ret[1][1] / d;
ret[1][2] = ret[1][2] / d;
ret[1][3] = ret[1][3] / d;

ret[2][0] = ret[2][0] / d;
ret[2][1] = ret[2][1] / d;
ret[2][2] = ret[2][2] / d;
ret[2][3] = ret[2][3] / d;

ret[3][0] = ret[3][0] / d;
ret[3][1] = ret[3][1] / d;
ret[3][2] = ret[3][2] / d;
ret[3][3] = ret[3][3] / d;

ret
}
}

impl<T> Mul<Matrix4<T>> for Matrix4<T>
where
T: Element,
{
type Output = Self;

fn mul(self, rhs: Self) -> Self::Output {
self.multiply(&rhs)
}
}

impl<T> Mul<Vector4<T>> for Matrix4<T>
where
T: Element,
{
type Output = Vector4<T>;

fn mul(self, rhs: Vector4<T>) -> Self::Output {
self.transform(&rhs)
}
}

/* Angle */

pub enum Angle<T> {
Deg(T),
Rad(T),
}

impl<T> Angle<T>
where
T: Element,
{
pub fn into_inner(self) -> T {
match self {
Self::Deg(v) => v,
Self::Rad(v) => v,
}
}

pub fn into_deg(self) -> Self {
match self {
Self::Deg(v) => Self::Deg(v),
Self::Rad(v) => Self::Rad(T::to_degrees(v)),
}
}

pub fn into_rad(self) -> Self {
match self {
Self::Deg(v) => Self::Deg(T::to_radians(v)),
Self::Rad(v) => Self::Rad(v),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn invert() {
let m = Matrix4d::identity()
* Matrix4::translate(Vector3::new(1.0, 2.0, 3.0))
* Matrix4::scale(Vector3::new(30.0, 20.0, 10.0))
* Matrix4::rotate(Vector3::new(1.0, 0.0, 0.0), Angle::Deg(45.0));
let m = m.invert();

let e = Matrix4d::new(
Vector4::new(
0.019526214587563498,
-0.000000000000000000,
0.000000000000000000,
-0.000000000000000000,
),
Vector4::new(
-0.000000000000000000,
0.035355339059327376,
-0.035355339059327376,
0.000000000000000000,
),
Vector4::new(
0.00000000000000000,
0.07071067811865475,
0.07071067811865475,
-0.00000000000000000,
),
Vector4::new(
-0.019526214587563498,
-0.282842712474619000,
-0.141421356237309560,
1.000000000000000000,
),
);

assert_eq!(e, m);
}
}

+ 66
- 1
glc/src/vector.rs View File

@@ -2,7 +2,7 @@

use std::convert::{AsMut, AsRef};
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::ops::{Add, Deref, DerefMut, Div, Mul, Sub};
use std::ops::{Add, Deref, DerefMut, Div, Mul, Neg, Sub};

macro_rules! define_vec {
($Name:ident, $size:tt, $($T:ident => $i:tt => $f:ident),*) => {
@@ -469,6 +469,7 @@ impl<T> From<(Vector3<T>, T)> for Vector4<T> {

pub trait Element:
Sized
+ Neg<Output = Self>
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Mul<Self, Output = Self>
@@ -479,11 +480,15 @@ pub trait Element:

fn one() -> Self;
fn zero() -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
fn sqrt(self) -> Self;
fn acos(self) -> Self::AsFloat;
fn atan(self) -> Self::AsFloat;
fn atan2(a: Self, b: Self) -> Self::AsFloat;
fn is_zero(&self) -> bool;
fn to_degrees(self) -> Self;
fn to_radians(self) -> Self;
}

impl Element for gl::GLfloat {
@@ -499,6 +504,16 @@ impl Element for gl::GLfloat {
0.0
}

#[inline]
fn sin(self) -> Self {
f32::sin(self)
}

#[inline]
fn cos(self) -> Self {
f32::cos(self)
}

#[inline]
fn sqrt(self) -> Self {
f32::sqrt(self)
@@ -523,6 +538,16 @@ impl Element for gl::GLfloat {
fn is_zero(&self) -> bool {
PartialEq::<f32>::eq(self, &0.0)
}

#[inline]
fn to_degrees(self) -> Self {
f32::to_degrees(self)
}

#[inline]
fn to_radians(self) -> Self {
f32::to_radians(self)
}
}

impl Element for gl::GLdouble {
@@ -538,6 +563,16 @@ impl Element for gl::GLdouble {
0.0
}

#[inline]
fn sin(self) -> Self {
f64::sin(self)
}

#[inline]
fn cos(self) -> Self {
f64::cos(self)
}

#[inline]
fn sqrt(self) -> Self {
f64::sqrt(self)
@@ -562,6 +597,16 @@ impl Element for gl::GLdouble {
fn is_zero(&self) -> bool {
PartialEq::<f64>::eq(self, &0.0)
}

#[inline]
fn to_degrees(self) -> Self {
f64::to_degrees(self)
}

#[inline]
fn to_radians(self) -> Self {
f64::to_radians(self)
}
}

impl Element for gl::GLint {
@@ -577,6 +622,16 @@ impl Element for gl::GLint {
0
}

#[inline]
fn sin(self) -> Self {
f32::sin(self as f32) as i32
}

#[inline]
fn cos(self) -> Self {
f32::cos(self as f32) as i32
}

#[inline]
fn sqrt(self) -> Self {
f64::sqrt(self as f64) as i32
@@ -601,6 +656,16 @@ impl Element for gl::GLint {
fn is_zero(&self) -> bool {
PartialEq::<i32>::eq(self, &0)
}

#[inline]
fn to_degrees(self) -> Self {
f32::to_degrees(self as f32) as i32
}

#[inline]
fn to_radians(self) -> Self {
f32::to_radians(self as f32) as i32
}
}

#[cfg(test)]


Loading…
Cancel
Save