@ -27,18 +27,27 @@ use crate::transform::TMatrix;
use crate ::trigonometry ::Trig ;
use crate ::vector ::Vector ;
#[ derive(Debug, Clone) ]
pub struct Face < T >
where T : Add + Sub + Neg + Mul + Div + Copy + Trig {
corners :Vec < usize > ,
normal :Option < Vector < T > > ,
}
#[ derive(Debug) ]
pub struct Polyeder < T >
where T : Add + Sub + Neg + Mul + Div + Debug + Copy + Trig {
points :Vec < Vector < T > > ,
faces :Vec < Vec < usize > > ,
normals :Vec < Vector < T > > ,
where T : Add + Sub + Neg + Mul + Div + Copy + Trig {
points :Vec < Vector < T > > ,
faces :Vec < Face < T > > ,
}
pub trait Primitives < T >
where T : Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From < i32 > {
fn transform ( & self , m :& TMatrix < T > ) -> Self ;
fn project ( & self , camera :& Camera < T > ) -> Vec < Polygon > ;
fn project ( & self
, camera :& Camera < T >
, light :& DirectLight < T >
, col :u32 ) -> Vec < ( Polygon , u32 ) > ;
}
pub struct Camera < T >
@ -48,6 +57,11 @@ where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
project :TMatrix < T > ,
}
pub struct DirectLight < T >
where T : Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From < i32 > {
direction : Vector < T > ,
}
impl < T > Camera < T >
where T : Add < Output = T > + Sub < Output = T > + Neg < Output = T >
+ Mul < Output = T > + Div < Output = T >
@ -83,10 +97,46 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
}
}
impl < T > DirectLight < T >
where T : Add < Output = T > + Sub < Output = T > + Neg < Output = T >
+ Mul < Output = T > + Div < Output = T >
+ Debug + Copy + Trig + From < i32 > {
pub fn new ( v :Vector < T > ) -> Self {
DirectLight { direction : v }
}
pub fn dir ( & self ) -> Vector < T > {
self . direction
}
}
impl < T > Face < T >
where T : Add < Output = T > + Sub < Output = T > + Neg < Output = T >
+ Mul < Output = T > + Div < Output = T >
+ Debug + Copy + Trig + From < i32 > {
fn new ( corners :Vec < usize > , ps :& [ Vector < T > ] ) -> Self {
let mut f = Face { corners : corners , normal : None } ;
f . update_normal ( ps ) ;
f
}
fn update_normal ( & mut self , ps :& [ Vector < T > ] ) {
let edge10 = ps [ self . corners [ 1 ] ] - ps [ self . corners [ 0 ] ] ;
let edge12 = ps [ self . corners [ 1 ] ] - ps [ self . corners [ 2 ] ] ;
self . normal = Some ( edge10 * edge12 ) ;
}
}
impl < T > Polyeder < T >
where T : Add < Output = T > + Sub < Output = T > + Neg < Output = T >
+ Mul < Output = T > + Div < Output = T >
+ Debug + Copy + Trig + From < i32 > {
fn update_normals ( & mut self ) {
for f in self . faces . iter_mut ( ) {
f . update_normal ( & self . points ) ;
}
}
// https://rechneronline.de/pi/tetrahedron.php
pub fn tetrahedron ( a :T ) -> Polyeder < T > {
let f0 :T = 0. into ( ) ;
@ -106,49 +156,86 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
// half the deeps in z
let _zh :T = T ::sqrt ( f3 ) . unwrap ( ) / f4 * a ;
Polyeder { points : vec ! ( Vector ( f0 , yc , f0 )
, Vector ( - ah , - yi , - zi )
, Vector ( ah , - yi , - zi )
, Vector ( f0 , - yi , zc ) )
, faces : vec ! ( vec ! ( 1 , 2 , 3 )
, vec ! ( 1 , 0 , 2 )
, vec ! ( 3 , 0 , 1 )
, vec ! ( 2 , 0 , 3 ) ) }
let ps = vec ! ( Vector ( f0 , yc , f0 )
, Vector ( - ah , - yi , - zi )
, Vector ( ah , - yi , - zi )
, Vector ( f0 , - yi , zc ) ) ;
let fs = vec ! ( Face ::new ( vec ! ( 1 , 2 , 3 ) , & ps )
, Face ::new ( vec ! ( 1 , 0 , 2 ) , & ps )
, Face ::new ( vec ! ( 3 , 0 , 1 ) , & ps )
, Face ::new ( vec ! ( 2 , 0 , 3 ) , & ps ) ) ;
Polyeder { points : ps , faces : fs }
}
pub fn triangle ( a :T ) -> Polyeder < T > {
let f0 :T = 0. into ( ) ;
let f3 :T = 3. into ( ) ;
let f6 :T = 6. into ( ) ;
let zi :T = T ::sqrt ( f3 ) . unwrap ( ) / f6 * a ;
let zc :T = T ::sqrt ( f3 ) . unwrap ( ) / f3 * a ;
let ah :T = a / 2. into ( ) ;
let ps = vec ! ( Vector ( - ah , f0 , - zi )
, Vector ( f0 , f0 , zc )
, Vector ( ah , f0 , - zi ) ) ;
let fs = vec ! ( Face ::new ( vec ! ( 0 , 1 , 2 ) , & ps ) ) ;
println ! ( "== {:?}" , fs ) ;
Polyeder { points : ps , faces : fs }
}
pub fn cube ( a :T ) -> Polyeder < T > {
let ah :T = a / From ::< i32 > ::from ( 2 ) ;
Polyeder { points : vec ! ( Vector ( - ah , ah , - ah ) // 0 => front 1
, Vector ( - ah , - ah , - ah ) // 1 => front 2
, Vector ( ah , - ah , - ah ) // 2 => front 3
, Vector ( ah , ah , - ah ) // 3 => front 4
, Vector ( - ah , ah , ah ) // 4 => back 1
, Vector ( - ah , - ah , ah ) // 5 => back 2
, Vector ( ah , - ah , ah ) // 6 => back 3
, Vector ( ah , ah , ah ) ) // 7 => back 4
, faces : vec ! ( vec ! ( 0 , 1 , 2 , 3 ) // front
, vec ! ( 7 , 6 , 5 , 4 ) // back
, vec ! ( 1 , 5 , 6 , 2 ) // top
, vec ! ( 0 , 3 , 7 , 4 ) // bottom
, vec ! ( 0 , 4 , 5 , 1 ) // left
, vec ! ( 2 , 6 , 7 , 3 ) ) } // right
let ps = vec ! ( Vector ( - ah , ah , - ah ) // 0 => front 1
, Vector ( - ah , - ah , - ah ) // 1 => front 2
, Vector ( ah , - ah , - ah ) // 2 => front 3
, Vector ( ah , ah , - ah ) // 3 => front 4
, Vector ( - ah , ah , ah ) // 4 => back 1
, Vector ( - ah , - ah , ah ) // 5 => back 2
, Vector ( ah , - ah , ah ) // 6 => back 3
, Vector ( ah , ah , ah ) ) ; // 7 => back 4
let fs = vec ! ( Face ::new ( vec ! ( 0 , 1 , 2 , 3 ) , & ps ) // front
, Face ::new ( vec ! ( 7 , 6 , 5 , 4 ) , & ps ) // back
, Face ::new ( vec ! ( 1 , 5 , 6 , 2 ) , & ps ) // top
, Face ::new ( vec ! ( 0 , 3 , 7 , 4 ) , & ps ) // bottom
, Face ::new ( vec ! ( 0 , 4 , 5 , 1 ) , & ps ) // left
, Face ::new ( vec ! ( 2 , 6 , 7 , 3 ) , & ps ) ) ; // right
Polyeder { points : ps , faces : fs }
}
}
impl < T > Primitives < T > for Polyeder < T >
where T : Add < Output = T > + Sub < Output = T > + Neg < Output = T >
+ Mul < Output = T > + Div < Output = T >
+ Debug + Copy + Trig + From < i32 > + From < i32 > {
+ Debug + Copy + Trig + From < i32 > + PartialOrd {
fn transform ( & self , m :& TMatrix < T > ) -> Self {
Polyeder { points : self . points . iter ( ) . map ( | p | m . apply ( p ) ) . collect ( )
, faces : self . faces . to_vec ( ) }
let Polyeder { points : ps , faces : fs } = self ;
let mut p = Polyeder { points : ps . iter ( ) . map ( | p | m . apply ( p ) ) . collect ( )
, faces : fs . to_vec ( ) } ;
// TODO alternatively we could rotate the normals too, but this cannot
// done with the original matrix… the question is, what is faster.
p . update_normals ( ) ;
p
}
// TODO for now we assume already prejected vertices (points)
// in future we need to distinguish more clear between vertex and point
// and projected_point.
fn project ( & self , _camera :& Camera < T > ) -> Vec < Polygon > {
fn project ( & self
, camera :& Camera < T >
, light :& DirectLight < T >
, color :u32 ) -> Vec < ( Polygon , u32 ) > {
// Helper to create a Polygon from Coordinates…
// TODO probably there needs to be a Polygon constructor for this.
fn polygon < I > ( c :I ) -> Polygon
where I : Iterator < Item = Coordinate > {
Polygon ( Coordinates ( c . collect ( ) ) )
@ -156,12 +243,34 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
// this one does the projection... as the projection was the last
// matrix we do not need to do it here.
// let to_coord = |p :&usize| _camera.project(self.points[*p]);
let to_coord = | p :& usize | {
let v = self . points [ * p ] ;
Coordinate ( v . x ( ) . round ( ) , v . y ( ) . round ( ) ) } ;
let to_poly = | f :& Vec < usize > | polygon ( f . iter ( ) . map ( to_coord ) ) ;
let to_coord = | p :& usize | camera . project ( self . points [ * p ] ) ;
let to_poly = | f :& Face < T > | {
let pg = polygon ( f . corners . iter ( ) . map ( to_coord ) ) ;
let mut r :T = ( ( ( color > > 16 ) & 0xFF ) as i32 ) . into ( ) ;
let mut g :T = ( ( ( color > > 8 ) & 0xFF ) as i32 ) . into ( ) ;
let mut b :T = ( ( ( color ) & 0xFF ) as i32 ) . into ( ) ;
let lf :T = match f . normal {
None = > 1. into ( ) ,
Some ( n ) = > n . dot ( light . dir ( ) )
/ ( n . mag ( ) * light . dir ( ) . mag ( ) ) ,
} ;
if lf < 0. into ( ) {
r = r * - lf ;
g = g * - lf ;
b = b * - lf ;
let c :u32 = ( r . round ( ) as u32 ) < < 16
| ( g . round ( ) as u32 ) < < 8
| ( b . round ( ) as u32 ) ;
Some ( ( pg , c ) )
} else {
None
} } ;
self . faces . iter ( ) . map ( to_poly ) . collect ( )
let mut ps :Vec < ( Polygon , u32 ) > = self . faces . iter ( ) . filter_map ( to_poly ) . collect ( ) ;
ps . sort_by ( | a , b | a . 1. cmp ( & b . 1 ) ) ;
ps
}
}