First commit.
WIP basic 3d math code.
This commit is contained in:
commit
aa6b72493b
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
target
|
||||
*.rs.bk
|
||||
|
||||
.zedstate
|
4
Cargo.lock
generated
Normal file
4
Cargo.lock
generated
Normal file
|
@ -0,0 +1,4 @@
|
|||
[root]
|
||||
name = "psychopath"
|
||||
version = "0.1.0"
|
||||
|
4
Cargo.toml
Normal file
4
Cargo.toml
Normal file
|
@ -0,0 +1,4 @@
|
|||
[package]
|
||||
name = "psychopath"
|
||||
version = "0.1.0"
|
||||
authors = ["Nathan Vegdahl <cessen@cessen.com>"]
|
116
src/float4.rs
Normal file
116
src/float4.rs
Normal 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
129
src/lerp.rs
Normal 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
8
src/main.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
mod math;
|
||||
mod lerp;
|
||||
mod float4;
|
||||
mod vector;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
22
src/math.rs
Normal file
22
src/math.rs
Normal 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
169
src/vector.rs
Normal 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));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user