First commit.

WIP basic 3d math code.
This commit is contained in:
Nathan Vegdahl 2015-12-26 00:38:29 -08:00
commit aa6b72493b
8 changed files with 456 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
target
*.rs.bk
.zedstate

4
Cargo.lock generated Normal file
View File

@ -0,0 +1,4 @@
[root]
name = "psychopath"
version = "0.1.0"

4
Cargo.toml Normal file
View File

@ -0,0 +1,4 @@
[package]
name = "psychopath"
version = "0.1.0"
authors = ["Nathan Vegdahl <cessen@cessen.com>"]

116
src/float4.rs Normal file
View File

@ -0,0 +1,116 @@
#![allow(dead_code)]
use std::ops::{Index, IndexMut, Add, Sub, Mul, Div};
use std::cmp::PartialEq;
/// Essentially a tuple of four floats, which will use SIMD operations
/// where possible on a platform.
#[derive(Debug, Copy, Clone)]
pub struct Float4 {
data: [f32; 4],
}
impl Float4 {
pub fn new(a: f32, b: f32, c: f32, d: f32) -> Float4 {
Float4 { data: [a, b, c, d] }
}
pub fn h_sum(&self) -> f32 {
self[0] + self[1] + self[2] + self[3]
}
pub fn h_product(&self) -> f32 {
self[0] * self[1] * self[2] * self[3]
}
pub fn h_min(&self) -> f32 {
self[0].min(self[1]).min(self[2].min(self[3]))
}
pub fn h_max(&self) -> f32 {
self[0].max(self[1]).max(self[2].max(self[3]))
}
}
impl Index<usize> for Float4 {
type Output = f32;
fn index(&self, index: usize) -> &f32 {
&self.data[index]
}
}
impl IndexMut<usize> for Float4 {
fn index_mut(&mut self, index: usize) -> &mut f32 {
&mut self.data[index]
}
}
impl PartialEq for Float4 {
fn eq(&self, other: &Float4) -> bool {
self.data[0] == other.data[0] && self.data[1] == other.data[1] &&
self.data[2] == other.data[2] && self.data[3] == other.data[3]
}
}
impl Add for Float4 {
type Output = Float4;
fn add(self, other: Float4) -> Float4 {
Float4 {
data: [self[0] + other[0], self[1] + other[1], self[2] + other[2], self[3] + other[3]],
}
}
}
impl Sub for Float4 {
type Output = Float4;
fn sub(self, other: Float4) -> Float4 {
Float4 {
data: [self[0] - other[0], self[1] - other[1], self[2] - other[2], self[3] - other[3]],
}
}
}
impl Mul for Float4 {
type Output = Float4;
fn mul(self, other: Float4) -> Float4 {
Float4 {
data: [self[0] * other[0], self[1] * other[1], self[2] * other[2], self[3] * other[3]],
}
}
}
impl Mul<f32> for Float4 {
type Output = Float4;
fn mul(self, other: f32) -> Float4 {
Float4 { data: [self[0] * other, self[1] * other, self[2] * other, self[3] * other] }
}
}
impl Div for Float4 {
type Output = Float4;
fn div(self, other: Float4) -> Float4 {
Float4 {
data: [self[0] / other[0], self[1] / other[1], self[2] / other[2], self[3] / other[3]],
}
}
}
impl Div<f32> for Float4 {
type Output = Float4;
fn div(self, other: f32) -> Float4 {
Float4 { data: [self[0] / other, self[1] / other, self[2] / other, self[3] / other] }
}
}

129
src/lerp.rs Normal file
View File

@ -0,0 +1,129 @@
#![allow(dead_code)]
/// Trait for allowing a type to be linearly interpolated.
pub trait Lerp
{
fn lerp(self, other: Self, alpha: f32) -> Self;
}
/// Interpolates between two instances of a Lerp types.
pub fn lerp<T: Lerp>(a: T, b: T, alpha: f32) -> T {
debug_assert!(alpha >= 0.0);
debug_assert!(alpha <= 1.0);
a.lerp(b, alpha)
}
/// Interpolates a slice of Lerp data.
pub fn lerp_slice<T: Lerp + Copy>(s: &[T], alpha: f32) -> T {
debug_assert!(s.len() > 0);
debug_assert!(alpha >= 0.0);
debug_assert!(alpha <= 1.0);
if alpha == 1.0 || s.len() == 1 {
return *s.last().unwrap();
} else {
let tmp = alpha * ((s.len() - 1) as f32);
let i1 = tmp as usize;
let i2 = i1 + 1;
let alpha2 = tmp - (i1 as f32);
return lerp(s[i1], s[i2], alpha2);
}
}
impl Lerp for f32 {
fn lerp(self, other: f32, alpha: f32) -> f32 {
self + ((other - self) * alpha)
}
}
impl Lerp for f64 {
fn lerp(self, other: f64, alpha: f32) -> f64 {
self + ((other - self) * (alpha as f64))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lerp1() {
let a = 1.0f32;
let b = 2.0f32;
let alpha = 0.0f32;
assert_eq!(1.0, lerp(a, b, alpha));
}
#[test]
fn lerp2() {
let a = 1.0f32;
let b = 2.0f32;
let alpha = 1.0f32;
assert_eq!(2.0, lerp(a, b, alpha));
}
#[test]
fn lerp3() {
let a = 1.0f32;
let b = 2.0f32;
let alpha = 0.5f32;
assert_eq!(1.5, lerp(a, b, alpha));
}
#[test]
fn lerp_slice1() {
let s = [0.0f32, 1.0, 2.0, 3.0, 4.0];
let alpha = 0.0f32;
assert_eq!(0.0, lerp_slice(&s[..], alpha));
}
#[test]
fn lerp_slice2() {
let s = [0.0f32, 1.0, 2.0, 3.0, 4.0];
let alpha = 1.0f32;
assert_eq!(4.0, lerp_slice(&s[..], alpha));
}
#[test]
fn lerp_slice3() {
let s = [0.0f32, 1.0, 2.0, 3.0, 4.0];
let alpha = 0.5f32;
assert_eq!(2.0, lerp_slice(&s[..], alpha));
}
#[test]
fn lerp_slice4() {
let s = [0.0f32, 1.0, 2.0, 3.0, 4.0];
let alpha = 0.25f32;
assert_eq!(1.0, lerp_slice(&s[..], alpha));
}
#[test]
fn lerp_slice5() {
let s = [0.0f32, 1.0, 2.0, 3.0, 4.0];
let alpha = 0.75f32;
assert_eq!(3.0, lerp_slice(&s[..], alpha));
}
#[test]
fn lerp_slice6() {
let s = [0.0f32, 1.0, 2.0, 3.0, 4.0];
let alpha = 0.625f32;
assert_eq!(2.5, lerp_slice(&s[..], alpha));
}
}

8
src/main.rs Normal file
View File

@ -0,0 +1,8 @@
mod math;
mod lerp;
mod float4;
mod vector;
fn main() {
println!("Hello, world!");
}

22
src/math.rs Normal file
View File

@ -0,0 +1,22 @@
#![allow(dead_code)]
/// Trait for calculating dot products.
pub trait DotProduct
{
fn dot(self, other: Self) -> f32;
}
pub fn dot<T: DotProduct>(a: T, b: T) -> f32 {
a.dot(b)
}
/// Trait for calculating cross products.
pub trait CrossProduct
{
fn cross(self, other: Self) -> Self;
}
pub fn cross<T: CrossProduct>(a: T, b: T) -> T {
a.cross(b)
}

169
src/vector.rs Normal file
View File

@ -0,0 +1,169 @@
#![allow(dead_code)]
use std::ops::{Index, IndexMut, Add, Sub, Mul, Div};
use std::cmp::PartialEq;
use lerp::Lerp;
use math::{DotProduct, CrossProduct};
use float4::Float4;
/// A direction vector in 3d homogeneous space.
#[derive(Debug, Copy, Clone)]
pub struct Vector {
co: Float4,
}
impl Vector {
pub fn new(x: f32, y: f32, z: f32) -> Vector {
Vector { co: Float4::new(x, y, z, 0.0) }
}
}
impl Index<usize> for Vector {
type Output = f32;
fn index(&self, index: usize) -> &f32 {
debug_assert!(index < 3);
&self.co[index]
}
}
impl IndexMut<usize> for Vector {
fn index_mut(&mut self, index: usize) -> &mut f32 {
debug_assert!(index < 3);
&mut self.co[index]
}
}
impl PartialEq for Vector {
fn eq(&self, other: &Vector) -> bool {
self.co == other.co
}
}
impl Add for Vector {
type Output = Vector;
fn add(self, other: Vector) -> Vector {
Vector { co: self.co + other.co }
}
}
impl Sub for Vector {
type Output = Vector;
fn sub(self, other: Vector) -> Vector {
Vector { co: self.co - other.co }
}
}
impl Mul<f32> for Vector {
type Output = Vector;
fn mul(self, other: f32) -> Vector {
Vector { co: self.co * other }
}
}
impl Div<f32> for Vector {
type Output = Vector;
fn div(self, other: f32) -> Vector {
Vector { co: self.co / other }
}
}
impl Lerp for Vector {
fn lerp(self, other: Vector, alpha: f32) -> Vector {
self + ((other - self) * alpha)
}
}
impl DotProduct for Vector {
fn dot(self, other: Vector) -> f32 {
(self.co * other.co).h_sum()
}
}
impl CrossProduct for Vector {
fn cross(self, other: Vector) -> Vector {
Vector {
co: Float4::new((self[1] * other[2]) - (self[2] * other[1]),
(self[2] * other[0]) - (self[0] * other[2]),
(self[0] * other[1]) - (self[1] * other[0]),
0.0),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use math::*;
#[test]
fn add() {
let v1 = Vector::new(1.0, 2.0, 3.0);
let v2 = Vector::new(1.5, 4.5, 2.5);
let v3 = Vector::new(2.5, 6.5, 5.5);
assert_eq!(v3, v1 + v2);
}
#[test]
fn sub() {
let v1 = Vector::new(1.0, 2.0, 3.0);
let v2 = Vector::new(1.5, 4.5, 2.5);
let v3 = Vector::new(-0.5, -2.5, 0.5);
assert_eq!(v3, v1 - v2);
}
#[test]
fn mul() {
let v1 = Vector::new(1.0, 2.0, 3.0);
let v2 = 2.0;
let v3 = Vector::new(2.0, 4.0, 6.0);
assert_eq!(v3, v1 * v2);
}
#[test]
fn div() {
let v1 = Vector::new(1.0, 2.0, 3.0);
let v2 = 2.0;
let v3 = Vector::new(0.5, 1.0, 1.5);
assert_eq!(v3, v1 / v2);
}
#[test]
fn dot_test() {
let v1 = Vector::new(1.0, 2.0, 3.0);
let v2 = Vector::new(1.5, 4.5, 2.5);
let v3 = 18.0f32;
assert_eq!(v3, v1.dot(v2));
}
#[test]
fn cross_test() {
let v1 = Vector::new(1.0, 0.0, 0.0);
let v2 = Vector::new(0.0, 1.0, 0.0);
let v3 = Vector::new(0.0, 0.0, 1.0);
assert_eq!(v3, v1.cross(v2));
}
}