Skip to content

Instantly share code, notes, and snippets.

@dobkeratops
Created July 8, 2013 09:10
Show Gist options
  • Select an option

  • Save dobkeratops/5947366 to your computer and use it in GitHub Desktop.

Select an option

Save dobkeratops/5947366 to your computer and use it in GitHub Desktop.
#[allow(default_methods)];
// TODO - parameterize the type f32 ..
// eg Vec3<T> etc..
//
#[deriving(Clone,ToStr)]
pub use std::num::*;
pub type VScalar=f32;
pub struct Vec2 {x:VScalar, y:VScalar}
#[deriving(Clone,ToStr)]
pub struct Vec3 {x:VScalar, y:VScalar, z:VScalar}
pub struct Vec4 {x:VScalar, y:VScalar, z:VScalar, w:VScalar}
/*
pub struct Vec3f {x:float,y:float,z:float}
impl Vec3f {
pub fn new2(x:float,y:float)->Vec3f { Vec3f{x:x,y:y,z:0.0} }
}
*/
impl Vec2 {
pub fn new(x:VScalar,y:VScalar)->Vec2 {Vec2{x:x,y:y}}
pub fn crossToScalar(&self,other:&Vec2)->VScalar{self.x*other.y-self.y*other.x}
}
impl Vec3 {
pub fn new(x:VScalar,y:VScalar,z:VScalar)->Vec3 {Vec3{x:x,y:y,z:z}}
pub fn fromVec2(xy:Vec2,z:VScalar)->Vec3 {Vec3{x:xy.x,y:xy.y,z:z}}
}
impl Vec4 {
pub fn new(x:VScalar,y:VScalar,z:VScalar,w:VScalar)->Vec4 {Vec4{x:x,y:y,z:z,w:w}}
pub fn fromVec3(xyz:Vec3,w:VScalar)->Vec4 {Vec4{x:xyz.x,y:xyz.y,z:xyz.z,w:w}}
pub fn fromVec2(xy:Vec2,z:VScalar,w:VScalar)->Vec4 {Vec4{x:xy.x,y:xy.y,z:z,w:w}}
pub fn fromVec2Vec2(xy:Vec2,zw:Vec2)->Vec4 {Vec4{x:xy.x,y:xy.y,z:zw.x,w:zw.y}}
}
// Primitive operations
// TODO move to the appropriate rust stdlib traits where possible
pub trait VecOps:Clone {
pub fn add(&self,b:&Self)->Self;
pub fn sub(&self,b:&Self)->Self;
pub fn scale(&self,f:VScalar)->Self;
pub fn mul(&self,b:&Self)->Self;
pub fn min(&self,b:&Self)->Self;
pub fn max(&self,b:&Self)->Self;
pub fn sumElems(&self)->VScalar;// {self.x+self.y+self.z}
pub fn splat(v:VScalar)->Self;
// pub fn zero()->Self;
pub fn cross(&self,b:&Self)->Self;
pub fn axis(i:int)->Self;
pub fn fromXYZ(x:VScalar,y:VScalar,z:VScalar)->Self;
pub fn x(&self)->VScalar;
pub fn y(&self)->VScalar;
pub fn z(&self)->VScalar;
pub fn w(&self)->VScalar;
// fn rsub(&self,&b:Self)->Self { b.sub(self)}
pub fn xy(&self)->Vec2 { Vec2::new(self.x(),self.y())}
pub fn xz(&self)->Vec2 { Vec2::new(self.x(),self.z())}
pub fn yz(&self)->Vec2 { Vec2::new(self.y(),self.z())}
pub fn xyz(&self)->Vec3 { Vec3::new(self.x(),self.y(),self.z())}
pub fn dot(&self,b:&Self)->VScalar {self.mul(b).sumElems()}
pub fn para(&self,vaxis:&Self)->Self { let dotp=self.dot(vaxis); vaxis.scale(dotp) }
pub fn avr(&self,b:&Self)->Self {self.add(b).scale(0.5)}
pub fn mad(&self,b:&Self,f:VScalar)->Self {self.add(&b.scale(f))}
pub fn lerp(&self,b:&Self,f:VScalar)->Self {self.mad(&b.sub(self),f)}
pub fn sqr(&self)->VScalar { self.dot(self)}
pub fn length(&self)->VScalar { self.sqr().sqrt()}
pub fn invlength(&self)->VScalar { self.sqr().rsqrt()}
pub fn toLength(&self,length:VScalar)->Self { self.scale(length/self.sqr().sqrt())}
pub fn normalize(&self)->Self { self.scale(self.sqr().rsqrt()) }
pub fn perp(&self,axis:&Self)->Self { let vpara =self.para(axis); self.sub(&vpara)}
pub fn paraPerp(&self,vaxis:&Self)->(Self,Self) {
let vpara=self.para(vaxis);
(vpara.clone(),self.sub(&vpara))
// ^^^^ CLONE STILL NEEDED HERE ?
// - possible bug because the default impl hasn't been told Self:Clone
// from the trait itself;
// - VERIFIED that when this function is defined in the IMPL,
// the .clone() is not needed.
}
pub fn crossToVec3(&self,b:&Self)->Vec3;
}
// Workaround - v*** free functions do similar things to the methods,
// since default methods dont work across module boundaries yet
pub fn vadd<V:VecOps>(a:&V,b:&V)->V { a.add(b)}
pub fn vsub<V:VecOps>(a:&V,b:&V)->V { a.sub(b)}
pub fn vmad<V:VecOps>(a:&V,b:&V,f:VScalar)->V { a.add(&b.scale(f))}
pub fn vmul<V:VecOps>(a:&V,b:&V)->V { a.mul(b)}
pub fn vsqr<V:VecOps>(a:&V)->VScalar { vmul(a,a).sumElems()}
pub fn vlerp<V:VecOps>( a:&V,b:&V,f:VScalar)->V { vmad(a, &vsub(b,a), f) }
pub fn vdot<V:VecOps>( a:&V,b:&V)->VScalar { a.mul(b).sumElems()}
pub fn vlength<V:VecOps>( a:&V)->VScalar { a.mul(a).sumElems().sqrt()}
pub fn vnormalize<V:VecOps>( a:&V)->V { a.scale(a.mul(a).sumElems().rsqrt()) }
impl Zero for Vec2 {
pub fn zero()->Vec2{Vec2{x:0.0,y:0.0}}
pub fn is_zero(&self)->bool { self.x==0.0 && self.y==0.0 }
}
impl VecOps for Vec2 {
// todo-trait VecPrimOps
pub fn add(&self,b:&Vec2)->Vec2 {Vec2::new(self.x+b.x,self.y+b.y)}
pub fn sub(&self,b:&Vec2)->Vec2 {Vec2::new(self.x-b.x,self.y-b.y)}
pub fn min(&self,b:&Vec2)->Vec2 {Vec2::new(self.x.min(&b.x),self.y.min(&b.y))}
pub fn max(&self,b:&Vec2)->Vec2 {Vec2::new(self.x.max(&b.x),self.y.max(&b.y))}
pub fn scale(&self,f:VScalar)->Vec2 {Vec2::new(self.x*f,self.y*f)}
pub fn mul(&self,b:&Vec2)->Vec2 {Vec2::new(self.x*b.x,self.y*b.y)}
pub fn sumElems(&self)->VScalar {self.x+self.y}
pub fn splat(v:VScalar)->Vec2{Vec2{x:v,y:v}}
pub fn fromXYZ(x:VScalar,y:VScalar,z:VScalar)->Vec2{Vec2::new(x,y)}
// todo .. not entirely happy with this interface.
// cross product for a vector type returning its own type seems awkward
// perhaps 'crossToSelf and crossToVec3' .. and 'cross' for vec3 only?
pub fn cross(&self,other:&Vec2)->Vec2{Vec2{x:0.0,y:0.0}}
pub fn crossToVec3(&self,b:&Vec2)->Vec3 {Vec3{x:0.0,y:0.0,z:self.crossToScalar(b)}}
pub fn axis(i:int)->Vec2{
match i{ 0=>Vec2::new(1.0,0.0),1=>Vec2::new(0.0,1.0),_=>Vec2::new(0.0,0.0)}
}
pub fn x(&self)->VScalar { self.x}
pub fn y(&self)->VScalar { self.y}
pub fn z(&self)->VScalar { 0.0}
pub fn w(&self)->VScalar { 0.0}
}
impl Zero for Vec3 {
pub fn zero()->Vec3{Vec3{x:0.0,y:0.0,z:0.0}}
pub fn is_zero(&self)->bool {self.x==0.0 && self.y==0.0 && self.z==0.0}
}
impl VecOps for Vec3 {
// todo-trait VecPrimOps
pub fn fromXYZ(x:VScalar,y:VScalar,z:VScalar)->Vec3{Vec3::new(x,y,z)}
pub fn add(&self,b:&Vec3)->Vec3 {Vec3::new(self.x+b.x,self.y+b.y,self.z+b.z)}
pub fn sub(&self,b:&Vec3)->Vec3 {Vec3::new(self.x-b.x,self.y-b.y,self.z-b.z)}
pub fn min(&self,b:&Vec3)->Vec3 {Vec3::new(
self.x.min(&b.x),
self.y.min(&b.y),
self.z.min(&b.z))}
pub fn max(&self,b:&Vec3)->Vec3 {Vec3::new(self.x.max(&b.x),self.y.max(&b.y),self.z.max(&b.z))}
pub fn scale(&self,f:VScalar)->Vec3 {Vec3::new(self.x*f,self.y*f,self.z*f)}
pub fn mul(&self,b:&Vec3)->Vec3 {Vec3::new(self.x*b.x,self.y*b.y,self.z*b.z)}
pub fn sumElems(&self)->VScalar {self.x+self.y+self.z}
pub fn splat(v:VScalar)->Vec3{Vec3{x:v,y:v,z:v}}
pub fn cross(&self,b:&Vec3)->Vec3 {Vec3::new(self.y*b.z-self.z*b.y,self.z*b.x-self.x*b.z,self.x*b.y-self.y*b.x)}
pub fn crossToVec3(&self,b:&Vec3)->Vec3 {self.cross(b)}
pub fn axis(i:int)->Vec3{
match i{ 0=>Vec3::new(1.0,0.0,0.0),1=>Vec3::new(0.0,1.0,0.0),2=>Vec3::new(0.0,0.0,1.0),_=>Vec3::new(0.0,0.0,0.0)}
}
pub fn x(&self)->VScalar { self.x}
pub fn y(&self)->VScalar { self.y}
pub fn z(&self)->VScalar { self.z}
pub fn w(&self)->VScalar { 0.0}
}
impl Vec3 {
pub fn vadd(self,b:Vec3)->Vec3{
Vec3::new(self.x+b.x,self.y+b.y,self.z+b.z)
}
pub fn vsub(self,b:Vec3)->Vec3{
Vec3::new(self.x-b.x,self.y-b.y,self.z-b.z)
}
pub fn vscale(self,f:VScalar)->Vec3{
Vec3::new(self.x*f,self.y*f,self.z*f)
}
pub fn vlerp(self,b:Vec3,f:VScalar)->Vec3{
self.vadd(self.vsub(b).vscale(f))
}
}
impl Zero for Vec4 {
pub fn zero()->Vec4{Vec4{x:0.0,y:0.0,z:0.0,w:0.0}}
pub fn is_zero(&self)->bool {self.x==0.0 && self.y==0.0 && self.z==0.0 && self.w==0.0}
}
impl VecOps for Vec4 {
// todo-trait VecPrimOps
pub fn fromXYZ(x:VScalar,y:VScalar,z:VScalar)->Vec4{Vec4::new(x,y,z,0.0)}
pub fn add(&self,b:&Vec4)->Vec4 {Vec4::new(self.x+b.x,self.y+b.y,self.z+b.z,self.w+b.w)}
pub fn sub(&self,b:&Vec4)->Vec4 {Vec4::new(self.x-b.x,self.y-b.y,self.z-b.z,self.w-b.w)}
pub fn scale(&self,f:VScalar)->Vec4 {Vec4::new(self.x*f,self.y*f,self.z*f,self.w*f)}
pub fn mul(&self,b:&Vec4)->Vec4 {Vec4::new(self.x*b.x,self.y*b.y,self.z*b.z,self.w*b.w)}
pub fn sumElems(&self)->VScalar {self.x+self.y+self.z+self.w}
pub fn splat(v:VScalar)->Vec4{Vec4{x:v,y:v,z:v,w:v}}
// pub fn zero()->Vec4{Vec4{x:0.0,y:0.0,z:0.0,w:0.0}}
pub fn min(&self,b:&Vec4)->Vec4 {Vec4::new(
self.x.min(&b.x),
self.y.min(&b.y),
self.z.min(&b.z),
self.w.min(&b.w))}
pub fn max(&self,b:&Vec4)->Vec4 {Vec4::new(
self.x.max(&b.x),
self.y.max(&b.y),
self.z.max(&b.z),
self.w.max(&b.w))}
pub fn cross(&self,b:&Vec4)->Vec4 {Vec4::new(self.y*b.z-self.z*b.y,self.z*b.x-self.x*b.z,self.x*b.y-self.y*b.x,0.0)}
pub fn crossToVec3(&self,b:&Vec4)->Vec3 {self.cross(b).xyz()}
pub fn axis(i:int)->Vec4{
match i{ 0=>Vec4::new(1.0,0.0,0.0,0.0),1=>Vec4::new(0.0,1.0,0.0,0.0),2=>Vec4::new(0.0,0.0,1.0,0.0),3=>Vec4::new(0.0,0.0,0.0,1.0),_=>Vec4::new(0.0,0.0,0.0,0.0)}
}
pub fn x(&self)->VScalar { self.x}
pub fn y(&self)->VScalar { self.y}
pub fn z(&self)->VScalar { self.z}
pub fn w(&self)->VScalar { self.w}
}
/*
fn repeated<T:Num+Ord>(count:T, myfunc:&fn(x:T)->T){
let mut i:T=count;
while i>core::Zero::zero() { myfunc(i); i-=(1 as T)}
}
*/
/*
use core::io;
let a:~[i32]=~[1,2,3,4,5,6];
let x=a.len();
let r=do a.map |x|{*x +1};
io::println(r[0].to_str());
io::println(lerp!(1.0f,2.0f by: 0.4f between: 0.3f,0.6f).to_str());
io::println(fooToStr(foo2{x:10.0,y:20.0}));
*/
macro_rules! lerp{
($y0:expr:$y1:expr by $t:expr)=>
(
$y0+($y1-$y0)*$t
);
($y0:expr,$y1:expr by: $x:expr between: $x0:expr,$x1:expr)=>
(
$y0+($x*($y1-$y0)/($x1-$x0))
)
}
// operations unique to Vec3
pub fn v3add(a:Vec3, b:Vec3)->Vec3{
Vec3{x:a.x+b.x,y:a.y+b.y,z:a.z+b.z}
}
pub fn v3sub(a:Vec3, b:Vec3)->Vec3{
Vec3{x:a.x-b.x,y:a.y-b.y,z:a.z-b.z}
}
pub fn v3scale(a:Vec3, f:VScalar)->Vec3{
Vec3{x:a.x*f,y:a.y*f,z:a.z*f}
}
pub fn v3lerp(a:Vec3,b:Vec3,f:VScalar)->Vec3 {v3add(a,v3scale(v3sub(b,a),f))}
#[deriving(Clone,ToStr)]
pub struct Range<T> {
min:T,max:T
}
impl<T:VecOps> Range<T> {
pub fn size(&self)->T { self.max.sub(&self.min) }
pub fn centre(&self)->T { self.min.add(&self.max).scale(0.5) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment