initial commit

This commit is contained in:
Brendan Zabarauskas 2012-09-07 20:48:47 +10:00
commit aed74ae3c9
12 changed files with 1579 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
.DS_Store
build
lib
*.sublime-workspace

10
Makefile Normal file
View file

@ -0,0 +1,10 @@
# adapted from https://github.com/z0w0/rusty-math/blob/master/Makefile
all:
rustc src/om3d.rc --lib --out-dir=lib
test: all
rustc --test -L lib test/*-test.rs -o test/build/test.elf
./test/build/test.elf
clean:
rm -R -f ./lib/*
rm -R -f ./test/*.elf

27
README.md Normal file
View file

@ -0,0 +1,27 @@
# om3D: A Linear Algebra Library for Rust
Here's some linear algebra I've been working on. I've translated it over from my unpublished D library that I was using to teach myself 3D mathematics.
For some reason my makefile isn't working - it give me the following error:
rustc src/om3d.rc --lib --out-dir=lib
error: failed to resolve imports
src/quat.rs:5:7: 5:14 error: unresolved import
src/quat.rs:5 import mat::*;
^~~~~~~
src/mat.rs:5:7: 5:15 error: unresolved import
src/mat.rs:5 import quat::*;
^~~~~~~~
src/projection.rs:2:7: 2:14 error: unresolved import
src/projection.rs:2 import mat::*;
^~~~~~~
error: aborting due to 4 previous errors
make: *** [all] Error 101
Any assistance would be most appreciated!
## Disclaimer:
I'm new to Rust and a novice at linear algebra. I also haven't written any unittests yet (although I plan to soon). I've almost certainly made mistakes, so use this at your own risk!
At the time of writing (September 2012) the Rust language is still in a state of flux. There is a good chance that the code will be soon out of date.

700
src/mat.rs Normal file
View file

@ -0,0 +1,700 @@
import std::cmp::FuzzyEq;
import cmp::Ord;
import num::Num;
// import to_str::ToStr;
import quat::*;
import vec::*;
// TODO: Unittests! I've probably made lots of mistakes...
//
// NxN Matrix
//
trait Matrix<T:Num Ord FuzzyEq, V:Vector<T>> {
pure fn rows() -> uint;
pure fn cols() -> uint;
pure fn is_col_major() -> bool;
pure fn index(&&index:uint) -> V;
pure fn row(&&i:uint) -> V;
pure fn col(&&i:uint) -> V;
pure fn neg() -> self;
pure fn add_m(&&other:self) -> self;
pure fn sub_m(&&other:self) -> self;
pure fn mul_f(&&value:T) -> self;
pure fn mul_v(&&other:V) -> V;
pure fn mul_m(&&other:self) -> self;
// pure fn invert(&&other:self) -> self;
pure fn transpose() -> self;
pure fn exact_eq(&&other:self) -> bool;
pure fn fuzzy_eq(&&other:self) -> bool;
pure fn eq(&&other:self) -> bool;
pure fn is_identity() -> bool;
pure fn is_symmetric() -> bool;
pure fn is_diagonal() -> bool;
pure fn is_rotated() -> bool;
}
//
// 3x3 Matrix
//
trait Matrix3<T:Num Ord FuzzyEq, V:Vector<T>> {
pure fn scale(&&vec:V) -> self;
pure fn to_mat4() -> mat4;
pure fn to_quat() -> quat;
}
//
// 4x4 Matrix
//
trait Matrix4<T:Num Ord FuzzyEq, V:Vector<T>> {
pure fn scale(&&vec:vec3) -> self; // I don't like the use of `vec3` here
pure fn translate(&&vec:vec3) -> self;
}
//
// Mat2: A 2x2, column major matrix
//
struct mat2 { data:[vec2 * 2] }
//
// Mat2 Constructor
//
#[inline(always)]
pure fn mat2(m00:float, m01:float,
m10:float, m11:float) -> mat2 {
mat2 { data: [ vec2(m00, m01),
vec2(m10, m11) ] }
}
//
// Construct Mat2 from column vectors
//
#[inline(always)]
pure fn mat2_v(col0:vec2, col1:vec2) -> mat2 {
mat2 { data: [ col0, col1 ] }
}
#[inline(always)]
pure fn mat2_zero() -> mat2 {
mat2 (0.0, 0.0,
0.0, 0.0)
}
#[inline(always)]
pure fn mat2_identity() -> mat2 {
mat2 (1.0, 0.0,
0.0, 1.0)
}
//
// Matrix2x2 Implementation
//
impl mat2: Matrix<float, vec2> {
#[inline(always)]
pure fn rows() -> uint { 2 }
#[inline(always)]
pure fn cols() -> uint { 2 }
#[inline(always)]
pure fn is_col_major() -> bool { true }
#[inline(always)]
pure fn index(&&i: uint) -> vec2 {
self.data[i]
}
#[inline(always)]
pure fn row(&&i:uint) -> vec2 {
vec2(self[0][i],
self[1][i])
}
#[inline(always)]
pure fn col(&&i:uint) -> vec2 {
self.data[i]
}
#[inline(always)]
pure fn neg() -> mat2 {
mat2_v(-self[0], -self[1])
}
#[inline(always)]
pure fn add_m(&&other:mat2) -> mat2 {
mat2_v(self[0].add_v(other[0]),
self[1].add_v(other[1]))
}
#[inline(always)]
pure fn sub_m(&&other:mat2) -> mat2 {
mat2_v(self[0].add_v(other[0]),
self[1].add_v(other[1]))
}
#[inline(always)]
pure fn mul_f(&&value:float) -> mat2 {
mat2_v(self[0].mul_f(value),
self[1].mul_f(value))
}
#[inline(always)]
pure fn mul_v(&&other:vec2) -> vec2 {
vec2(self[0][0]*other[0] + self[1][0]*other[1],
self[0][1]*other[0] + self[1][1]*other[1])
}
#[inline(always)]
pure fn mul_m(&&other:mat2) -> mat2 {
mat2(self[0][0]*other[0][0] + self[1][0]*other[0][1],
self[0][1]*other[0][0] + self[1][1]*other[0][1],
self[0][0]*other[1][0] + self[1][0]*other[1][1],
self[0][1]*other[1][0] + self[1][1]*other[1][1])
}
// TODO - inversion is harrrd D:
// #[inline(always)]
// pure fn invert(&&other:mat2) -> mat2 {}
#[inline(always)]
pure fn transpose() -> mat2 {
mat2(self[0][0], self[1][0],
self[0][1], self[1][1])
}
#[inline(always)]
pure fn exact_eq(&&other:mat2) -> bool {
self[0].exact_eq(other[0]) &&
self[1].exact_eq(other[1])
}
#[inline(always)]
pure fn fuzzy_eq(&&other:mat2) -> bool {
self[0].fuzzy_eq(other[0]) &&
self[1].fuzzy_eq(other[1])
}
#[inline(always)]
pure fn eq(&&other:mat2) -> bool {
self.fuzzy_eq(other)
}
#[inline(always)]
pure fn is_identity() -> bool {
self.fuzzy_eq(mat2_identity())
}
#[inline(always)]
pure fn is_symmetric() -> bool {
self[0][1].fuzzy_eq(&self[1][0]) &&
self[1][0].fuzzy_eq(&self[0][1])
}
#[inline(always)]
pure fn is_diagonal() -> bool {
self[0][1].fuzzy_eq(&0.0) &&
self[1][0].fuzzy_eq(&0.0)
}
#[inline(always)]
pure fn is_rotated() -> bool {
!self.fuzzy_eq(mat2_identity())
}
}
//
// Mat3: A 3x3, column major matrix
//
struct mat3 { data:[vec3 * 3] }
//
// Mat3 Constructor
//
#[inline(always)]
pure fn mat3(m00:float, m01:float, m02:float,
m10:float, m11:float, m12:float,
m20:float, m21:float, m22:float) -> mat3 {
mat3 { data: [ vec3(m00, m01, m02),
vec3(m10, m11, m12),
vec3(m20, m21, m22) ] }
}
//
// Construct Mat3 from column vectors
//
#[inline(always)]
pure fn mat3_v(col0:vec3, col1:vec3, col2:vec3) -> mat3 {
mat3 { data: [ col0, col1, col2 ] }
}
#[inline(always)]
pure fn mat3_zero() -> mat3 {
mat3 (0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0)
}
#[inline(always)]
pure fn mat3_identity() -> mat3 {
mat3 (1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0)
}
//
// Matrix3x3 Implementation
//
impl mat3: Matrix<float, vec3> {
#[inline(always)]
pure fn rows() -> uint { 3 }
#[inline(always)]
pure fn cols() -> uint { 3 }
#[inline(always)]
pure fn is_col_major() -> bool { true }
#[inline(always)]
pure fn index(&&i: uint) -> vec3 {
self.data[i]
}
#[inline(always)]
pure fn row(&&i:uint) -> vec3 {
vec3(self[0][i],
self[1][i],
self[2][i])
}
#[inline(always)]
pure fn col(&&i:uint) -> vec3 {
self.data[i]
}
#[inline(always)]
pure fn neg() -> mat3 {
mat3_v(-self[0], -self[1], -self[2])
}
#[inline(always)]
pure fn add_m(&&other:mat3) -> mat3 {
mat3_v(self[0].add_v(other[0]),
self[1].add_v(other[1]),
self[2].add_v(other[2]))
}
#[inline(always)]
pure fn sub_m(&&other:mat3) -> mat3 {
mat3_v(self[0].add_v(other[0]),
self[1].add_v(other[1]),
self[2].add_v(other[2]))
}
#[inline(always)]
pure fn mul_f(&&value:float) -> mat3 {
mat3_v(self[0].mul_f(value),
self[1].mul_f(value),
self[2].mul_f(value))
}
#[inline(always)]
pure fn mul_v(&&other:vec3) -> vec3 {
vec3(self[0][0]*other[0] + self[1][0]*other[1] + self[2][0]*other[2],
self[0][1]*other[0] + self[1][1]*other[1] + self[2][1]*other[2],
self[0][2]*other[0] + self[1][2]*other[1] + self[2][2]*other[2])
}
#[inline(always)]
pure fn mul_m(&&other:mat3) -> mat3 {
mat3(self[0][0]*other[0][0] + self[1][0]*other[0][1] + self[2][0]*other[0][2],
self[0][1]*other[0][0] + self[1][1]*other[0][1] + self[2][1]*other[0][2],
self[0][2]*other[0][0] + self[1][2]*other[0][1] + self[2][2]*other[0][2],
self[0][0]*other[1][0] + self[1][0]*other[1][1] + self[2][0]*other[1][2],
self[0][1]*other[1][0] + self[1][1]*other[1][1] + self[2][1]*other[1][2],
self[0][2]*other[1][0] + self[1][2]*other[1][1] + self[2][2]*other[1][2],
self[0][0]*other[2][0] + self[1][0]*other[2][1] + self[2][0]*other[2][2],
self[0][1]*other[2][0] + self[1][1]*other[2][1] + self[2][1]*other[2][2],
self[0][2]*other[2][0] + self[1][2]*other[2][1] + self[2][2]*other[2][2])
}
// TODO - inversion is harrrd D:
// #[inline(always)]
// pure fn invert(&&other:mat3) -> mat3 {}
#[inline(always)]
pure fn transpose() -> mat3 {
mat3(self[0][0], self[1][0], self[2][0],
self[0][1], self[1][1], self[2][1],
self[0][2], self[1][2], self[2][2])
}
#[inline(always)]
pure fn exact_eq(&&other:mat3) -> bool {
self[0].exact_eq(other[0]) &&
self[1].exact_eq(other[1]) &&
self[2].exact_eq(other[2])
}
#[inline(always)]
pure fn fuzzy_eq(&&other:mat3) -> bool {
self[0].fuzzy_eq(other[0]) &&
self[1].fuzzy_eq(other[1]) &&
self[2].fuzzy_eq(other[2])
}
#[inline(always)]
pure fn eq(&&other:mat3) -> bool {
self.fuzzy_eq(other)
}
#[inline(always)]
pure fn is_identity() -> bool {
self.fuzzy_eq(mat3_identity())
}
#[inline(always)]
pure fn is_symmetric() -> bool {
self[0][1].fuzzy_eq(&self[1][0]) &&
self[0][2].fuzzy_eq(&self[2][0]) &&
self[1][0].fuzzy_eq(&self[0][1]) &&
self[1][2].fuzzy_eq(&self[2][1]) &&
self[2][0].fuzzy_eq(&self[0][2]) &&
self[2][1].fuzzy_eq(&self[1][2])
}
#[inline(always)]
pure fn is_diagonal() -> bool {
self[0][1].fuzzy_eq(&0.0) &&
self[0][2].fuzzy_eq(&0.0) &&
self[1][0].fuzzy_eq(&0.0) &&
self[1][2].fuzzy_eq(&0.0) &&
self[2][0].fuzzy_eq(&0.0) &&
self[2][1].fuzzy_eq(&0.0)
}
#[inline(always)]
pure fn is_rotated() -> bool {
!self.fuzzy_eq(mat3_identity())
}
}
impl mat3: Matrix3<float, vec3> {
#[inline(always)]
pure fn scale(&&vec:V) -> mat3 {
self.mul_m(mat3(vec.x(), 0, 0,
0, vec.y(), 0,
0, 0, vec.z()))
}
#[inline(always)]
pure fn to_mat4() -> mat4 {
mat4(self[0][0], self[0][1], self[0][2], 0,
self[1][0], self[1][1], self[1][2], 0,
self[2][0], self[2][1], self[2][2], 0,
0, 0, 0, 1)
}
pure fn to_quat() -> quat {
// Implemented using a mix of ideas from jMonkeyEngine and Ken Shoemake's
// paper on Quaternions: http://www.cs.ucr.edu/~vbz/resources/quatut.pdf
let w:float, x:float, y:float, z:float, s:float;
let trace:float = self[0][0] + self[1][1] + self[2][2];
if trace >= 0 {
s = sqrt(trace + 1);
w = 0.5 * s;
s = 0.5 / s;
x = self[1][2] - self[2][1] * s;
y = self[2][0] - self[0][2] * s;
z = self[0][1] - self[1][0] * s;
} else if (self[0][0] > self[1][1]) && (self[0][0] > self[2][2]) {
s = sqrt(1 + self[0][0] - self[1][1] - self[2][2]);
w = 0.5 * s;
s = 0.5 / s;
x = self[0][1] - self[1][0] * s;
y = self[2][0] - self[0][2] * s;
z = self[1][2] - self[2][1] * s;
} else if self[1][1] > self[2][2] {
s = sqrt(1 + self[1][1] - self[0][0] - self[2][2]);
w = 0.5 * s;
s = 0.5 / s;
x = self[0][1] - self[1][0] * s;
y = self[1][2] - self[2][1] * s;
z = self[2][0] - self[0][2] * s;
} else {
s = sqrt(1 + self[2][2] - self[0][0] - self[1][1]);
w = 0.5 * s;
s = 0.5 / s;
x = self[2][0] - self[0][2] * s;
y = self[1][2] - self[2][1] * s;
z = self[0][1] - self[1][0] * s;
}
return quat(w, x, y, z);
}
}
//
// Mat4: A 4x4, column major matrix
//
struct mat4 { data:[vec4 * 4] }
//
// Mat4 Constructor
//
#[inline(always)]
pure fn mat4(m00:float, m01:float, m02:float, m03:float,
m10:float, m11:float, m12:float, m13:float,
m20:float, m21:float, m22:float, m23:float,
m30:float, m31:float, m32:float, m33:float) -> mat4 {
mat4 { data: [ vec4(m00, m01, m02, m03),
vec4(m10, m11, m12, m13),
vec4(m20, m21, m22, m23),
vec4(m30, m31, m32, m33) ] }
}
//
// Construct Mat4 from column vectors
//
#[inline(always)]
pure fn mat4_v(col0:vec4, col1:vec4, col2:vec4, col3:vec4) -> mat4 {
mat4 { data: [ col0, col1, col2, col3 ] }
}
#[inline(always)]
pure fn mat4_zero() -> mat4 {
mat4 (0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0)
}
#[inline(always)]
pure fn mat4_identity() -> mat4 {
mat4 (1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0)
}
//
// Matrix4x4 Implementation
//
impl mat4: Matrix<float, vec4> {
#[inline(always)]
pure fn rows() -> uint { 4 }
#[inline(always)]
pure fn cols() -> uint { 4 }
#[inline(always)]
pure fn is_col_major() -> bool { true }
#[inline(always)]
pure fn index(&&i: uint) -> vec4 {
self.data[i]
}
#[inline(always)]
pure fn row(&&i:uint) -> vec4 {
vec4(self[0][i],
self[1][i],
self[2][i],
self[3][i])
}
#[inline(always)]
pure fn col(&&i:uint) -> vec4 {
self.data[i]
}
#[inline(always)]
pure fn neg() -> mat4 {
mat4_v(-self[0], -self[1], -self[2], -self[3])
}
#[inline(always)]
pure fn add_m(&&other:mat4) -> mat4 {
mat4_v(self[0].add_v(other[0]),
self[1].add_v(other[1]),
self[2].add_v(other[2]),
self[3].add_v(other[3]))
}
#[inline(always)]
pure fn sub_m(&&other:mat4) -> mat4 {
mat4_v(self[0].add_v(other[0]),
self[1].add_v(other[1]),
self[2].add_v(other[2]),
self[3].add_v(other[3]))
}
#[inline(always)]
pure fn mul_f(&&value:float) -> mat4 {
mat4_v(self[0].mul_f(value),
self[1].mul_f(value),
self[2].mul_f(value),
self[3].mul_f(value))
}
#[inline(always)]
pure fn mul_v(&&other:vec4) -> vec4 {
vec4(self[0][0]*other[0] + self[1][0]*other[1] + self[2][0]*other[2] + self[3][0]*other[3],
self[0][1]*other[0] + self[1][1]*other[1] + self[2][1]*other[2] + self[3][1]*other[3],
self[0][2]*other[0] + self[1][2]*other[1] + self[2][2]*other[2] + self[3][2]*other[3],
self[0][3]*other[0] + self[1][3]*other[1] + self[2][3]*other[2] + self[3][3]*other[3])
}
#[inline(always)]
pure fn mul_m(&&other:mat4) -> mat4 {
mat4(self[0][0]*other[0][0] + self[1][0]*other[0][1] + self[2][0]*other[0][2] + self[3][0]*other[0][3],
self[0][1]*other[0][0] + self[1][1]*other[0][1] + self[2][1]*other[0][2] + self[3][1]*other[0][3],
self[0][2]*other[0][0] + self[1][2]*other[0][1] + self[2][2]*other[0][2] + self[3][2]*other[0][3],
self[0][3]*other[0][0] + self[1][3]*other[0][1] + self[2][3]*other[0][2] + self[3][3]*other[0][3],
self[0][0]*other[1][0] + self[1][0]*other[1][1] + self[2][0]*other[1][2] + self[3][0]*other[1][3],
self[0][1]*other[1][0] + self[1][1]*other[1][1] + self[2][1]*other[1][2] + self[3][1]*other[1][3],
self[0][2]*other[1][0] + self[1][2]*other[1][1] + self[2][2]*other[1][2] + self[3][2]*other[1][3],
self[0][3]*other[1][0] + self[1][3]*other[1][1] + self[2][3]*other[1][2] + self[3][3]*other[1][3],
self[0][0]*other[2][0] + self[1][0]*other[2][1] + self[2][0]*other[2][2] + self[3][0]*other[2][3],
self[0][1]*other[2][0] + self[1][1]*other[2][1] + self[2][1]*other[2][2] + self[3][1]*other[2][3],
self[0][2]*other[2][0] + self[1][2]*other[2][1] + self[2][2]*other[2][2] + self[3][2]*other[2][3],
self[0][3]*other[2][0] + self[1][3]*other[2][1] + self[2][3]*other[2][2] + self[3][3]*other[2][3],
self[0][0]*other[3][0] + self[1][0]*other[3][1] + self[2][0]*other[3][2] + self[3][0]*other[3][3],
self[0][1]*other[3][0] + self[1][1]*other[3][1] + self[2][1]*other[3][2] + self[3][1]*other[3][3],
self[0][2]*other[3][0] + self[1][2]*other[3][1] + self[2][2]*other[3][2] + self[3][2]*other[3][3],
self[0][3]*other[3][0] + self[1][3]*other[3][1] + self[2][3]*other[3][2] + self[3][3]*other[3][3])
}
// TODO - inversion is harrrd D:
// #[inline(always)]
// pure fn invert(&&other:mat4) -> mat4 {}
#[inline(always)]
pure fn transpose() -> mat4 {
mat4(self[0][0], self[1][0], self[2][0], self[3][0],
self[0][1], self[1][1], self[2][1], self[3][1],
self[0][2], self[1][2], self[2][2], self[3][2],
self[0][3], self[1][3], self[2][3], self[3][3])
}
#[inline(always)]
pure fn exact_eq(&&other:mat4) -> bool {
self[0].exact_eq(other[0]) &&
self[1].exact_eq(other[1]) &&
self[2].exact_eq(other[2]) &&
self[3].exact_eq(other[3])
}
#[inline(always)]
pure fn fuzzy_eq(&&other:mat4) -> bool {
self[0].fuzzy_eq(other[0]) &&
self[1].fuzzy_eq(other[1]) &&
self[2].fuzzy_eq(other[2]) &&
self[3].fuzzy_eq(other[3])
}
#[inline(always)]
pure fn eq(&&other:mat4) -> bool {
self.fuzzy_eq(other)
}
#[inline(always)]
pure fn is_identity() -> bool {
self.fuzzy_eq(mat4_identity())
}
#[inline(always)]
pure fn is_symmetric() -> bool {
self[0][1].fuzzy_eq(&self[1][0]) &&
self[0][2].fuzzy_eq(&self[2][0]) &&
self[0][3].fuzzy_eq(&self[3][0]) &&
self[1][0].fuzzy_eq(&self[0][1]) &&
self[1][2].fuzzy_eq(&self[2][1]) &&
self[1][3].fuzzy_eq(&self[3][1]) &&
self[2][0].fuzzy_eq(&self[0][2]) &&
self[2][1].fuzzy_eq(&self[1][2]) &&
self[2][3].fuzzy_eq(&self[3][2]) &&
self[3][0].fuzzy_eq(&self[0][3]) &&
self[3][1].fuzzy_eq(&self[1][3]) &&
self[3][2].fuzzy_eq(&self[2][3])
}
#[inline(always)]
pure fn is_diagonal() -> bool {
self[0][1].fuzzy_eq(&0.0) &&
self[0][2].fuzzy_eq(&0.0) &&
self[0][3].fuzzy_eq(&0.0) &&
self[1][0].fuzzy_eq(&0.0) &&
self[1][2].fuzzy_eq(&0.0) &&
self[1][3].fuzzy_eq(&0.0) &&
self[2][0].fuzzy_eq(&0.0) &&
self[2][1].fuzzy_eq(&0.0) &&
self[2][3].fuzzy_eq(&0.0) &&
self[3][0].fuzzy_eq(&0.0) &&
self[3][1].fuzzy_eq(&0.0) &&
self[3][2].fuzzy_eq(&0.0)
}
#[inline(always)]
pure fn is_rotated() -> bool {
!self.fuzzy_eq(mat4_identity())
}
}
impl mat4: Matrix4<float, vec4> {
#[inline(always)]
pure fn scale(&&vec:vec3) -> mat4 {
self.mul_m(mat3(vec.x(), 0, 0, 0,
0, vec.y(), 0, 0,
0, 0, vec.z(), 0,
0, 0, 0, 1))
}
#[inline(always)]
pure fn translate(&&vec:vec3) -> mat4 {
mat4(self[0],
self[1],
self[2],
vec4(self[3][0] + vec.x(),
self[3][1] + vec.y(),
self[3][2] + vec.z(),
self[3][3]))
}
}

13
src/om3d.rc Normal file
View file

@ -0,0 +1,13 @@
#[link(name = "om3d",
vers = "0.1",
author = "Brendan Zabarauskas")];
#[comment = "Linear algebra library for Rust. Incomplete and probably buggy."];
#[crate_type = "lib"];
use std;
mod mat;
mod projection;
mod quat;
mod vec;

45
src/projection.rs Normal file
View file

@ -0,0 +1,45 @@
import float::consts::pi;
import mat::*;
//
// Create a perspective projection matrix
//
// fov is in degrees
// http://www.opengl.org/wiki/GluPerspective_code
//
pure fn perspective(fovy:float, aspectRatio:float, near:float, fa:float) -> mat4 {
let ymax = near * tan(fovy * PI / 360.0);
let xmax = ymax * aspectRatio;
return frustum(-xmax, xmax, -ymax, ymax, near, far);
}
//
// Define a view frustrum
// http://www.felixgers.de/teaching/jogl/perspectiveProjection.html
// http://www.opengl.org/wiki/GluPerspective_code
//
// TODO: double check algorithm
//
pure fn frustum(left:float, right:float, bottom:float, top:float, near:float, far:float) -> mat4 {
let m00:float = (2*near)/(right-left);
let m01:float = 0.0;
let m02:float = 0.0;
let m03:float = 0.0;
let m10:float = 0.0;
let m11:float = (2*near)/(top-bottom);
let m12:float = 0.0;
let m13:float = 0.0;
let m20:float = (right+left)/(right-left);
let m21:float = (top+bottom)/(top-bottom);
let m22:float = -(far+near)/(far-near);
let m23:float = -1.0;
let m30:float = 0.0;
let m31:float = 0.0;
let m32:float = -(2*far*near)/(far-near);
let m33:float = 0.0;
return mat4(m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33);
}

206
src/quat.rs Normal file
View file

@ -0,0 +1,206 @@
import std::cmp::FuzzyEq;
import cmp::Ord;
import num::Num;
import to_str::ToStr;
import mat::*;
import vec::*;
// TODO: Unittests! I've probably made lots of mistakes...
//
// Quaternion
//
trait Quaternion<T:Num Ord FuzzyEq> {
pure fn dim() -> uint;
pure fn index(&&index:uint) -> T;
fn w() -> T;
fn x() -> T;
fn y() -> T;
fn z() -> T;
pure fn neg() -> self;
pure fn mul_f(&&value:T) -> self;
pure fn div_f(&&value:T) -> self;
// pure fn mul_v(&&vec3) -> vec3;
pure fn add_q(&&other:self) -> self;
pure fn sub_q(&&other:self) -> self;
pure fn mul_q(&&other:self) -> self;
pure fn exact_eq(&&other:self) -> bool;
pure fn fuzzy_eq(&&other:self) -> bool;
pure fn eq(&&other:self) -> bool;
pure fn conjugate() -> self;
pure fn inverse() -> self;
pure fn magnitude2() -> T;
pure fn magnitude() -> T;
pure fn to_mat3() -> mat3;
pure fn to_mat4() -> mat4;
}
//
// Quat struct definition
//
struct quat { data:[float * 4] }
//
// Quat Constructor
//
#[inline(always)]
pure fn quat(w:float, x:float, y:float, z:float) -> quat {
quat { data: [ w, x, y, z ] }
}
//
// Quaternion Implementation
//
impl quat<float> {
#[inline(always)]
pure fn dim() -> uint { 4 }
#[inline(always)]
pure fn index(&&i: uint) -> float {
self.data[i]
}
#[inline(always)]
pure fn neg() -> quat {
quat(-self[0], -self[1], -self[2], -self[3])
}
#[inline(always)] fn w() -> float { self.data[0] }
#[inline(always)] fn x() -> float { self.data[1] }
#[inline(always)] fn y() -> float { self.data[2] }
#[inline(always)] fn z() -> float { self.data[3] }
#[inline(always)]
pure fn mul_f(&&value:float) -> quat {
quat(self[0] * value,
self[1] * value,
self[2] * value,
self[3] * value)
}
#[inline(always)]
pure fn div_f(&&value:float) -> quat {
quat(self[0] / value,
self[1] / value,
self[2] / value,
self[3] / value)
}
#[inline(always)]
pure fn add_q(&&other:quat) -> quat{
quat(self[0] + other[0],
self[1] + other[1],
self[2] + other[2],
self[3] + other[3])
}
#[inline(always)]
pure fn sub_q(&&other:quat) -> quat{
quat(self[0] - other[0],
self[1] - other[1],
self[2] - other[2],
self[3] - other[3])
}
#[inline(always)]
pure fn mul_q(&&other:quat) -> quat {
quat(self.w()*other.w() - self.x()*other.x() - self.y()*other.y() - self.z()*other.z(),
self.w()*other.x() + self.x()*other.w() + self.y()*other.z() - self.z()*other.y(),
self.w()*other.y() + self.y()*other.w() + self.z()*other.x() - self.x()*other.z(),
self.w()*other.z() + self.z()*other.w() + self.x()*other.y() - self.y()*other.x())
}
#[inline(always)]
pure fn exact_eq(&&other:quat) -> bool {
self[0] == other[0] &&
self[1] == other[1] &&
self[2] == other[2] &&
self[3] == other[3]
}
#[inline(always)]
pure fn fuzzy_eq(&&other: quat) -> bool {
self[0].fuzzy_eq(&other[0]) &&
self[1].fuzzy_eq(&other[1]) &&
self[2].fuzzy_eq(&other[2]) &&
self[3].fuzzy_eq(&other[3])
}
#[inline(always)]
pure fn eq(&&other:quat) -> bool {
self.fuzzy_eq(other)
}
#[inline(always)]
pure fn conjugate() -> quat {
quat(self.w(), -self.x(), -self.y(), -self.z());
}
#[inline(always)]
pure fn inverse() -> quat {
}
#[inline(always)]
pure fn magnitude2() -> float {
self.w() * self.w() +
self.x() * self.x() +
self.y() * self.y() +
self.z() * self.z()
}
#[inline(always)]
pure fn magnitude() -> float {
sqrt(self.magnitude2)
}
#[inline(always)]
pure fn to_mat3() -> mat3 {
let x2 = self.x() + self.x();
let y2 = self.y() + self.y();
let z2 = self.z() + self.z();
let xx2 = x2 * self.x();
let xy2 = x2 * self.y();
let xz2 = x2 * self.z();
let yy2 = y2 * self.y();
let yz2 = y2 * self.z();
let zz2 = z2 * self.z();
let wy2 = y2 * self.w();
let wz2 = z2 * self.w();
let wx2 = x2 * self.w();
return mat3(1 - yy2 - zz2, xy2 - wz2, xz2 + wy2,
xy2 + wz2, 1 - xx2 - zz2, yz2 - wx2,
xz2 - wy2, yz2 + wx2, 1 - xx2 - yy2);
}
#[inline(always)]
pure fn to_mat4() -> mat4 {
self.to_mat3().to_mat4()
}
}
//
// Convert To String
//
impl quat: ToStr {
fn to_str() -> ~str {
fmt!("quat[ %f, %f, %f, %f ]", self.w(), self.x(), self.y(), self.z())
}
}

526
src/vec.rs Normal file
View file

@ -0,0 +1,526 @@
import std::cmp::FuzzyEq;
import cmp::Ord;
import num::Num;
import float::sqrt;
import to_str::ToStr;
// TODO: Unittests! I've probably made lots of mistakes...
//
// N-dimensional Vector
//
trait Vector<T:Num Ord FuzzyEq> {
pure fn dim() -> uint;
pure fn index(&&index:uint) -> T;
pure fn neg() -> self;
pure fn add_f(&&value:T) -> self;
pure fn sub_f(&&value:T) -> self;
pure fn mul_f(&&value:T) -> self;
pure fn div_f(&&value:T) -> self;
pure fn add_v(&&other: self) -> self;
pure fn sub_v(&&other: self) -> self;
pure fn exact_eq(&&other:self) -> bool;
pure fn fuzzy_eq(&&other:self) -> bool;
pure fn eq(&&other:self) -> bool;
pure fn dot(&&other: self) -> T;
pure fn magnitude2() -> T;
pure fn magnitude() -> T;
pure fn normalize() -> self;
// pure fn lerp(&&other:self, &&value:T) -> self;
// pure fn abs(&&other:self) -> self;
// pure fn min(&&other:self) -> self;
// pure fn max(&&other:self) -> self;
}
//
// 2-Dimensional Vector
//
trait Vector2<T:Num Ord FuzzyEq> {
// This is where I wish rust had properties ;)
fn x() -> T;
fn y() -> T;
}
//
// 3-Dimensional Vector
//
trait Vector3<T:Num Ord FuzzyEq> {
fn x() -> T;
fn y() -> T;
fn z() -> T;
fn cross(&&other:self) -> self;
}
//
// 4-Dimensional Vector
//
trait Vector4<T:Num Ord FuzzyEq> {
fn x() -> T;
fn y() -> T;
fn z() -> T;
fn w() -> T;
}
//
// Vec2 struct definition
//
struct vec2 { data:[float * 2] }
//
// Vec2 Constructor
//
#[inline(always)]
pure fn vec2(x:float, y:float) -> vec2 {
vec2 { data: [ x, y ] }
}
//
// Constants
//
#[inline(always)] pure fn vec2_zero() -> vec2 { vec2 (0.0, 0.0) }
#[inline(always)] pure fn vec2_unit_x() -> vec2 { vec2 (1.0, 0.0) }
#[inline(always)] pure fn vec2_unit_y() -> vec2 { vec2 (0.0, 1.0) }
#[inline(always)] pure fn vec2_identity() -> vec2 { vec2 (1.0, 1.0) }
//
// Vector2 Implementation
//
impl vec2: Vector2<float> {
#[inline(always)] fn x() -> float { self.data[0] }
#[inline(always)] fn y() -> float { self.data[1] }
}
//
// Vector Implementation
//
impl vec2: Vector<float> {
#[inline(always)]
pure fn dim() -> uint { 2 }
#[inline(always)]
pure fn index(&&i: uint) -> float {
self.data[i]
}
#[inline(always)]
pure fn neg() -> vec2 {
vec2(-self[0], -self[1])
}
#[inline(always)]
pure fn add_f(&&value:float) -> vec2 {
vec2(self[0] + value,
self[1] + value)
}
#[inline(always)]
pure fn sub_f(&&value:float) -> vec2 {
vec2(self[0] - value,
self[1] - value)
}
#[inline(always)]
pure fn mul_f(&&value:float) -> vec2 {
vec2(self[0] * value,
self[1] * value)
}
#[inline(always)]
pure fn div_f(&&value:float) -> vec2 {
vec2(self[0] / value,
self[1] / value)
}
#[inline(always)]
pure fn add_v(&&other: vec2) -> vec2{
vec2(self[0] + other[0],
self[1] + other[1])
}
#[inline(always)]
pure fn sub_v(&&other: vec2) -> vec2{
vec2(self[0] - other[0],
self[1] - other[1])
}
#[inline(always)]
pure fn exact_eq(&&other:vec2) -> bool {
self[0] == other[0] &&
self[1] == other[1]
}
#[inline(always)]
pure fn fuzzy_eq(&&other: vec2) -> bool {
self[0].fuzzy_eq(&other[0]) &&
self[1].fuzzy_eq(&other[1])
}
#[inline(always)]
pure fn eq(&&other:vec2) -> bool {
self.fuzzy_eq(other)
}
#[inline(always)]
pure fn dot(&&other: vec2) -> float {
self[0] * other[0] +
self[1] * other[1]
}
#[inline(always)]
pure fn magnitude2() -> float {
self[0] * self[0] +
self[1] * self[1]
}
#[inline(always)]
pure fn magnitude() -> float {
sqrt(self.magnitude2())
}
#[inline(always)]
pure fn normalize() -> vec2 {
let n = 1.0 / self.magnitude();
return self.mul_f(n);
}
}
//
// Convert To String
//
impl vec2: ToStr {
fn to_str() -> ~str {
fmt!("vec2[ %f, %f ]", self[0], self[1])
}
}
//
// Vec3 struct definition
//
struct vec3 { data:[float * 3] }
//
// Constants
//
#[inline(always)] pure fn vec3_zero() -> vec3 { vec3(0.0, 0.0, 0.0) }
#[inline(always)] pure fn vec3_unit_x() -> vec3 { vec3(1.0, 0.0, 0.0) }
#[inline(always)] pure fn vec3_unit_y() -> vec3 { vec3(0.0, 1.0, 0.0) }
#[inline(always)] pure fn vec3_unit_z() -> vec3 { vec3(0.0, 0.0, 1.0) }
#[inline(always)] pure fn vec3_identity() -> vec3 { vec3(1.0, 1.0, 1.0) }
//
// Vec3 Constructor
//
#[inline(always)]
pure fn vec3(x:float, y:float, z:float) -> vec3 {
vec3 { data: [ x, y, z ] }
}
//
// Vector3 Implementation
//
impl vec3: Vector3<float> {
#[inline(always)] fn x() -> float { self.data[0] }
#[inline(always)] fn y() -> float { self.data[1] }
#[inline(always)] fn z() -> float { self.data[2] }
#[inline(always)]
fn cross(&&other:vec3) -> vec3 {
vec3((self[1] * other[2]) - (self[2] * other[1]),
(self[2] * other[0]) - (self[0] * other[2]),
(self[0] * other[1]) - (self[1] * other[0]))
}
}
//
// Vector Implementation
//
impl vec3: Vector<float> {
#[inline(always)]
pure fn dim() -> uint { 3 }
#[inline(always)]
pure fn index(&&i: uint) -> float {
self.data[i]
}
#[inline(always)]
pure fn neg() -> vec3 {
vec3(-self[0], -self[1], -self[2])
}
#[inline(always)]
pure fn add_f(&&value:float) -> vec3 {
vec3(self[0] + value,
self[1] + value,
self[2] + value)
}
#[inline(always)]
pure fn sub_f(&&value:float) -> vec3 {
vec3(self[0] - value,
self[1] - value,
self[2] - value)
}
#[inline(always)]
pure fn mul_f(&&value:float) -> vec3 {
vec3(self[0] * value,
self[1] * value,
self[2] * value)
}
#[inline(always)]
pure fn div_f(&&value:float) -> vec3 {
vec3(self[0] / value,
self[1] / value,
self[2] / value)
}
#[inline(always)]
pure fn add_v(&&other: vec3) -> vec3{
vec3(self[0] + other[0],
self[1] + other[1],
self[2] + other[2])
}
#[inline(always)]
pure fn sub_v(&&other: vec3) -> vec3{
vec3(self[0] - other[0],
self[1] - other[1],
self[2] - other[2])
}
#[inline(always)]
pure fn exact_eq(&&other:vec3) -> bool {
self[0] == other[0] &&
self[1] == other[1] &&
self[2] == other[2]
}
#[inline(always)]
pure fn fuzzy_eq(&&other: vec3) -> bool {
self[0].fuzzy_eq(&other[0]) &&
self[1].fuzzy_eq(&other[1]) &&
self[2].fuzzy_eq(&other[2])
}
#[inline(always)]
pure fn eq(&&other:vec3) -> bool {
self.fuzzy_eq(other)
}
#[inline(always)]
pure fn dot(&&other: vec3) -> float {
self[0] * other[0] +
self[1] * other[1] +
self[2] * other[2]
}
#[inline(always)]
pure fn magnitude2() -> float {
self[0] * self[0] +
self[1] * self[1] +
self[2] * self[2]
}
#[inline(always)]
pure fn magnitude() -> float {
sqrt(self.magnitude2())
}
#[inline(always)]
pure fn normalize() -> vec3 {
let n = 1.0 / self.magnitude();
return self.mul_f(n);
}
}
//
// Convert To String
//
impl vec3: ToStr {
fn to_str() -> ~str {
fmt!("vec3[ %f, %f, %f ]", self[0], self[1], self[2])
}
}
//
// Vec4 struct definition
//
struct vec4 { data:[float * 4] }
//
// Constants
//
#[inline(always)] pure fn vec4_zero() -> vec4 { vec4(0.0, 0.0, 0.0, 0.0) }
#[inline(always)] pure fn vec4_unit_x() -> vec4 { vec4(1.0, 0.0, 0.0, 0.0) }
#[inline(always)] pure fn vec4_unit_y() -> vec4 { vec4(0.0, 1.0, 0.0, 0.0) }
#[inline(always)] pure fn vec4_unit_z() -> vec4 { vec4(0.0, 0.0, 1.0, 0.0) }
#[inline(always)] pure fn vec4_unit_w() -> vec4 { vec4(0.0, 0.0, 0.0, 1.0) }
#[inline(always)] pure fn vec4_identity() -> vec4 { vec4(1.0, 1.0, 1.0, 1.0) }
//
// Vec4 Constructor
//
#[inline(always)]
pure fn vec4(x:float, y:float, z:float, w:float) -> vec4 {
vec4 { data: [ x, y, z, w ] }
}
//
// Vector4 Implementation
//
impl vec4: Vector4<float> {
#[inline(always)] fn x() -> float { self.data[0] }
#[inline(always)] fn y() -> float { self.data[1] }
#[inline(always)] fn z() -> float { self.data[2] }
#[inline(always)] fn w() -> float { self.data[3] }
}
//
// Vector Implementation
//
impl vec4: Vector<float> {
#[inline(always)]
pure fn dim() -> uint { 4 }
#[inline(always)]
pure fn index(&&i: uint) -> float {
self.data[i]
}
#[inline(always)]
pure fn neg() -> vec4 {
vec4(-self[0], -self[1], -self[2], -self[3])
}
#[inline(always)]
pure fn add_f(&&value:float) -> vec4 {
vec4(self[0] + value,
self[1] + value,
self[2] + value,
self[3] + value)
}
#[inline(always)]
pure fn sub_f(&&value:float) -> vec4 {
vec4(self[0] - value,
self[1] - value,
self[2] - value,
self[3] - value)
}
#[inline(always)]
pure fn mul_f(&&value:float) -> vec4 {
vec4(self[0] * value,
self[1] * value,
self[2] * value,
self[3] * value)
}
#[inline(always)]
pure fn div_f(&&value:float) -> vec4 {
vec4(self[0] / value,
self[1] / value,
self[2] / value,
self[3] / value)
}
#[inline(always)]
pure fn add_v(&&other: vec4) -> vec4{
vec4(self[0] + other[0],
self[1] + other[1],
self[2] + other[2],
self[3] + other[3])
}
#[inline(always)]
pure fn sub_v(&&other: vec4) -> vec4{
vec4(self[0] - other[0],
self[1] - other[1],
self[2] - other[2],
self[3] - other[3])
}
#[inline(always)]
pure fn exact_eq(&&other:vec4) -> bool {
self[0] == other[0] &&
self[1] == other[1] &&
self[2] == other[2] &&
self[3] == other[3]
}
#[inline(always)]
pure fn fuzzy_eq(&&other: vec4) -> bool {
self[0].fuzzy_eq(&other[0]) &&
self[1].fuzzy_eq(&other[1]) &&
self[2].fuzzy_eq(&other[2]) &&
self[3].fuzzy_eq(&other[3])
}
#[inline(always)]
pure fn eq(&&other:vec4) -> bool {
self.fuzzy_eq(other)
}
#[inline(always)]
pure fn dot(&&other:vec4) -> float {
self[0] * other[0] +
self[1] * other[1] +
self[2] * other[2] +
self[3] * other[3]
}
#[inline(always)]
pure fn magnitude2() -> float {
self[0] * self[0] +
self[1] * self[1] +
self[2] * self[2] +
self[3] + self[3]
}
#[inline(always)]
pure fn magnitude() -> float {
sqrt(self.magnitude2())
}
#[inline(always)]
pure fn normalize() -> vec4 {
let n = 1.0 / self.magnitude();
return self.mul_f(n);
}
}
//
// Convert To String
//
impl vec4: ToStr {
fn to_str() -> ~str {
fmt!("vec4[ %f, %f, %f, %f ]", self[0], self[1], self[2], self[3])
}
}

View file

@ -0,0 +1,10 @@
{
"folders":
[
{
"path": "../",
"file_exclude_patterns": ["*.sublime-workspace"],
"folder_exclude_patterns": ["*.dSYM"]
}
]
}

16
test/mat-test.rs Normal file
View file

@ -0,0 +1,16 @@
// TODO
#[test]
fn test_mat2() {
}
#[test]
fn test_mat3() {
}
#[test]
fn test_mat4() {
}

6
test/quat-test.rs Normal file
View file

@ -0,0 +1,6 @@
// TODO
#[test]
fn test_quat() {
}

16
test/vec-test.rs Normal file
View file

@ -0,0 +1,16 @@
// TODO
#[test]
fn test_mat2() {
}
#[test]
fn test_mat3() {
}
#[test]
fn test_mat4() {
}