Commit de6d78411a031212c40ed1f0967e3198d6b2c919

Authored by Georg Hopp
1 parent ed113306

split geometry in several source files

... ... @@ -35,9 +35,5 @@ extern crate lazy_static;
35 35 pub type Error = &'static str;
36 36
37 37 pub mod easel;
38   -pub mod transform;
39   -pub mod trigonometry;
40   -pub mod vector;
41   -pub mod geometry;
42   -
43   -use vector::Vector;
  38 +pub mod space;
  39 +pub mod math;
... ...
  1 +//
  2 +// Math needed for 3D transformations and projection.
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2020 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +
  22 +// generics for needed trigonometric stuff. As well as an implementation for
  23 +// f64.
  24 +pub mod trigonometry;
  25 +
  26 +// generics for 3D math stuff.
  27 +pub mod vector;
  28 +pub mod transform;
... ...
... ... @@ -21,8 +21,8 @@
21 21 use std::ops::{Add, Sub, Neg, Mul, Div};
22 22 use std::fmt::Debug;
23 23
24   -use crate::Vector;
25   -use crate::trigonometry::Trig;
  24 +use crate::math::vector::Vector;
  25 +use crate::math::trigonometry::Trig;
26 26
27 27 #[derive(Debug, Clone, Copy)]
28 28 pub struct TMatrix<T>( (T, T, T, T)
... ...
... ... @@ -21,8 +21,8 @@
21 21 use std::fmt::{Debug, Display, Formatter, Result};
22 22 use std::ops::{Add, Sub, Neg, Mul, Div};
23 23
24   -use crate::trigonometry::Trig;
25   -use crate::transform::{TMatrix, Transformable};
  24 +use crate::math::trigonometry::Trig;
  25 +use crate::math::transform::{TMatrix, Transformable};
26 26
27 27 #[derive(Debug, Eq, Clone, Copy)]
28 28 pub struct Vector<T>(pub T, pub T, pub T)
... ...
  1 +//
  2 +// Basic geometric things...
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2019 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +
  22 +use std::fmt::Debug;
  23 +use std::ops::{Add, Div, Mul, Neg, Sub};
  24 +
  25 +use crate::easel::canvas::{Canvas, Vertex};
  26 +use crate::math::transform::{TMatrix, Transformable};
  27 +use crate::math::trigonometry::Trig;
  28 +use crate::math::vector::Vector;
  29 +
  30 +use super::point::Point;
  31 +
  32 +#[derive(Debug, Clone, Copy)]
  33 +pub struct Camera<T>
  34 +where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
  35 + width :T,
  36 + height :T,
  37 + distance :T,
  38 + project :TMatrix<T>,
  39 +}
  40 +
  41 +impl<T> Camera<T>
  42 +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
  43 + + Mul<Output = T> + Div<Output = T>
  44 + + PartialEq + Debug + Copy + Trig + From<i32> {
  45 + // This code assumes that the size of the viewport is always
  46 + // equal to the size of the physical screen… e.g. window/canvas thus some
  47 + // effects can't be done. See book for examples with different viewport
  48 + // and screen sizes.
  49 + pub fn new(c :&dyn Canvas<T>, angle :i32) -> Self {
  50 + let width :T = (c.width() as i32).into();
  51 + let height :T = (c.height() as i32).into();
  52 + let d :T = 1.into();
  53 + let fov = T::cot(angle) * width;
  54 + let wh = width / 2.into();
  55 + let hh = height / 2.into();
  56 +
  57 + Camera { width: width
  58 + , height: height
  59 + , distance: d
  60 + , project: TMatrix::new(
  61 + ( fov, 0.into(), wh, 0.into())
  62 + , (0.into(), fov, hh, 0.into())
  63 + , (0.into(), 0.into(), d, 1.into())
  64 + , (0.into(), 0.into(), 1.into(), 0.into()) ) }
  65 + }
  66 +
  67 + pub fn get_distance(&self) -> T {
  68 + self.distance
  69 + }
  70 +
  71 + pub fn get_projection(&self) -> TMatrix<T> {
  72 + self.project
  73 + }
  74 +
  75 + pub fn project(&self, p :Point<T>) -> Vertex<T> {
  76 + let v :Vector<T> = p.transform(&self.project).into();
  77 + Vertex::new( T::round(&v.x())
  78 + , T::round(&v.y())
  79 + , v.z() - self.distance )
  80 + }
  81 +}
... ...
  1 +//
  2 +// Basic geometric things...
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2019 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +
  22 +use std::fmt::Debug;
  23 +use std::ops::{Add, Div, Mul, Neg, Sub};
  24 +
  25 +use crate::math::trigonometry::Trig;
  26 +use crate::math::vector::Vector;
  27 +
  28 +use super::point::Point;
  29 +
  30 +#[derive(Debug, Clone)]
  31 +pub struct Face<T>
  32 +where T: Add + Sub + Neg + Mul + Div + Copy + Trig {
  33 + corners :Vec<usize>,
  34 + normal :Option<Vector<T>>,
  35 +}
  36 +
  37 +impl<'a, T> Face<T>
  38 +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
  39 + + Mul<Output = T> + Div<Output = T>
  40 + + PartialEq + Debug + Copy + Trig + From<i32> {
  41 + pub fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self {
  42 + let mut f = Face{ corners: corners, normal: None };
  43 + f.update_normal(ps);
  44 + f
  45 + }
  46 +
  47 + #[inline]
  48 + pub fn corners(&self) -> &[usize] {
  49 + &self.corners
  50 + }
  51 +
  52 + #[inline]
  53 + pub fn normal(&self) -> Option<&Vector<T>> {
  54 + (&self.normal).as_ref()
  55 + }
  56 +
  57 + pub fn update_normal(&mut self, ps :&[Point<T>]) {
  58 + let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into();
  59 + let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into();
  60 + self.normal = Some(edge10 * edge12);
  61 + }
  62 +}
... ...
  1 +//
  2 +// Basic geometric things...
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2019 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +
  22 +use std::fmt::Debug;
  23 +use std::ops::{Add, Div, Mul, Neg, Sub};
  24 +
  25 +use crate::math::transform::{TMatrix, Transformable};
  26 +use crate::math::trigonometry::Trig;
  27 +use crate::math::vector::Vector;
  28 +
  29 +pub struct DirectLight<T>
  30 +where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
  31 + direction: Vector<T>,
  32 +}
  33 +
  34 +impl<T> DirectLight<T>
  35 +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
  36 + + Mul<Output = T> + Div<Output = T>
  37 + + Debug + Copy + Trig + From<i32> {
  38 + pub fn new(v :Vector<T>) -> Self {
  39 + DirectLight{ direction: v }
  40 + }
  41 +
  42 + pub fn transform(&self, m :&TMatrix<T>) -> Self {
  43 + let DirectLight{ direction: v } = self;
  44 + DirectLight { direction: v.transform(m) }
  45 + }
  46 +
  47 + pub fn dir(&self) -> Vector<T> {
  48 + self.direction
  49 + }
  50 +}
... ...
  1 +//
  2 +// This holds 3D primitives.
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2020 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +
  22 +pub mod face;
  23 +pub mod point;
  24 +pub mod polyeder;
  25 +pub mod primitives;
  26 +pub mod camera;
  27 +pub mod light;
... ...
... ... @@ -18,22 +18,13 @@
18 18 // You should have received a copy of the GNU General Public License
19 19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 20 //
21   -use std::convert::{From, Into};
22   -use std::ops::{Add,Sub,Neg,Mul,Div};
23   -use std::fmt::Debug;
24 21
25   -use crate::easel::canvas::{Canvas, Vertex};
26   -use crate::easel::polygon::Polygon;
27   -use crate::transform::{TMatrix, Transformable};
28   -use crate::trigonometry::Trig;
29   -use crate::vector::Vector;
  22 +use std::fmt::Debug;
  23 +use std::ops::{Add, Div, Mul, Neg, Sub};
30 24
31   -#[derive(Debug, Clone)]
32   -pub struct Face<T>
33   -where T: Add + Sub + Neg + Mul + Div + Copy + Trig {
34   - corners :Vec<usize>,
35   - normal :Option<Vector<T>>,
36   -}
  25 +use crate::math::transform::{TMatrix, Transformable};
  26 +use crate::math::trigonometry::Trig;
  27 +use crate::math::vector::Vector;
37 28
38 29 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
39 30 pub struct Point<T>(pub Vector<T>, T)
... ... @@ -137,237 +128,3 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
137 128 }
138 129 }
139 130 }
140   -
141   -#[derive(Debug)]
142   -pub struct Polyeder<T>
143   -where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig {
144   - points :Vec<Point<T>>,
145   - faces :Vec<Face<T>>,
146   -}
147   -
148   -pub trait Primitives<T>
149   -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
150   - fn transform(&self, m :&TMatrix<T>) -> Self;
151   - fn project( &self
152   - , camera :&Camera<T>
153   - , light :&DirectLight<T>
154   - , col :u32 ) -> Vec<(Polygon<T>, u32)>;
155   -}
156   -
157   -#[derive(Debug, Clone, Copy)]
158   -pub struct Camera<T>
159   -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
160   - width :T,
161   - height :T,
162   - distance :T,
163   - project :TMatrix<T>,
164   -}
165   -
166   -pub struct DirectLight<T>
167   -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
168   - direction: Vector<T>,
169   -}
170   -
171   -impl<T> Camera<T>
172   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
173   - + Mul<Output = T> + Div<Output = T>
174   - + PartialEq + Debug + Copy + Trig + From<i32> {
175   - // This code assumes that the size of the viewport is always
176   - // equal to the size of the physical screen… e.g. window/canvas thus some
177   - // effects can't be done. See book for examples with different viewport
178   - // and screen sizes.
179   - pub fn new(c :&dyn Canvas<T>, angle :i32) -> Self {
180   - let width :T = (c.width() as i32).into();
181   - let height :T = (c.height() as i32).into();
182   - let d :T = 1.into();
183   - let fov = T::cot(angle) * width;
184   - let wh = width / 2.into();
185   - let hh = height / 2.into();
186   -
187   - Camera { width: width
188   - , height: height
189   - , distance: d
190   - , project: TMatrix::new(
191   - ( fov, 0.into(), wh, 0.into())
192   - , (0.into(), fov, hh, 0.into())
193   - , (0.into(), 0.into(), d, 1.into())
194   - , (0.into(), 0.into(), 1.into(), 0.into()) ) }
195   - }
196   -
197   - pub fn get_distance(&self) -> T {
198   - self.distance
199   - }
200   -
201   - pub fn get_projection(&self) -> TMatrix<T> {
202   - self.project
203   - }
204   -
205   - pub fn project(&self, p :Point<T>) -> Point<T> {
206   - p.transform(&self.project)
207   - }
208   -}
209   -
210   -impl<T> DirectLight<T>
211   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
212   - + Mul<Output = T> + Div<Output = T>
213   - + Debug + Copy + Trig + From<i32> {
214   - pub fn new(v :Vector<T>) -> Self {
215   - DirectLight{ direction: v }
216   - }
217   -
218   - pub fn dir(&self) -> Vector<T> {
219   - self.direction
220   - }
221   -}
222   -
223   -impl<T> Face<T>
224   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
225   - + Mul<Output = T> + Div<Output = T>
226   - + PartialEq + Debug + Copy + Trig + From<i32> {
227   - fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self {
228   - let mut f = Face{ corners: corners, normal: None };
229   - f.update_normal(ps);
230   - f
231   - }
232   -
233   - fn update_normal(&mut self, ps :&[Point<T>]) {
234   - let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into();
235   - let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into();
236   - self.normal = Some(edge10 * edge12);
237   - }
238   -}
239   -
240   -impl<T> Polyeder<T>
241   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
242   - + Mul<Output = T> + Div<Output = T>
243   - + PartialEq + Debug + Copy + Trig + From<i32> {
244   - fn update_normals(&mut self) {
245   - for f in self.faces.iter_mut() {
246   - f.update_normal(&self.points);
247   - }
248   - }
249   -
250   - // construct via cube, see polyhedra.pdf
251   - pub fn tetrahedron(a :T) -> Polyeder<T> {
252   - let f2 :T = 2.into();
253   - let ch = a / (f2 * T::sqrt(f2).unwrap());
254   -
255   - let ps = vec!( Point::new(-ch, -ch, ch)
256   - , Point::new(-ch, ch, -ch)
257   - , Point::new( ch, -ch, -ch)
258   - , Point::new( ch, ch, ch) );
259   -
260   - let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom
261   - , Face::new(vec!(3, 2, 0), &ps)
262   - , Face::new(vec!(0, 1, 3), &ps)
263   - , Face::new(vec!(1, 2, 3), &ps) );
264   -
265   - Polyeder{ points: ps, faces: fs }
266   - }
267   -
268   - pub fn triangle(a :T) -> Polyeder<T> {
269   - let f0 :T = 0.into();
270   - let f3 :T = 3.into();
271   - let f6 :T = 6.into();
272   - let zi :T = T::sqrt(f3).unwrap() / f6 * a;
273   - let zc :T = T::sqrt(f3).unwrap() / f3 * a;
274   - let ah :T = a / 2.into();
275   -
276   - let ps = vec!( Point::new(-ah, f0, -zi)
277   - , Point::new( f0, f0, zc)
278   - , Point::new( ah, f0, -zi) );
279   -
280   - let fs = vec!(Face::new(vec!(0, 1, 2), &ps));
281   -
282   - Polyeder{ points: ps, faces: fs }
283   - }
284   -
285   - pub fn cube(a :T) -> Polyeder<T> {
286   - let ah :T = a / From::<i32>::from(2);
287   -
288   - let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1
289   - , Point::new(-ah, -ah, -ah) // 1 => front 2
290   - , Point::new( ah, -ah, -ah) // 2 => front 3
291   - , Point::new( ah, ah, -ah) // 3 => front 4
292   - , Point::new(-ah, ah, ah) // 4 => back 1
293   - , Point::new(-ah, -ah, ah) // 5 => back 2
294   - , Point::new( ah, -ah, ah) // 6 => back 3
295   - , Point::new( ah, ah, ah) ); // 7 => back 4
296   -
297   - let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front
298   - , Face::new(vec!(7, 6, 5, 4), &ps) // back
299   - , Face::new(vec!(1, 5, 6, 2), &ps) // top
300   - , Face::new(vec!(0, 3, 7, 4), &ps) // bottom
301   - , Face::new(vec!(0, 4, 5, 1), &ps) // left
302   - , Face::new(vec!(2, 6, 7, 3), &ps) ); // right
303   -
304   - Polyeder{ points: ps, faces: fs }
305   - }
306   -}
307   -
308   -impl<T> Primitives<T> for Polyeder<T>
309   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
310   - + Mul<Output = T> + Div<Output = T>
311   - + Debug + Copy + Trig + From<i32> + PartialOrd {
312   - // TODO Maybe this should also be an instance of Transformable…
313   - fn transform(&self, m :&TMatrix<T>) -> Self {
314   - let Polyeder{ points: ps, faces: fs } = self;
315   -
316   - let mut p = Polyeder{
317   - points: ps.iter().map(|p| p.transform(m)).collect()
318   - , faces: fs.to_vec()
319   - };
320   -
321   - // TODO alternatively we could rotate the normals too, but this cannot
322   - // done with the original matrix… the question is, what is faster.
323   - p.update_normals();
324   - p
325   - }
326   -
327   - fn project( &self
328   - , camera :&Camera<T>
329   - , light :&DirectLight<T>
330   - , color :u32 ) -> Vec<(Polygon<T>, u32)> {
331   - // Helper to create a Polygon from Coordinates…
332   - // TODO probably there needs to be a Polygon constructor for this.
333   - fn polygon<I, T>(c :I) -> Polygon<T>
334   - where I: Iterator<Item = Vertex<T>> {
335   - Polygon(c.collect())
336   - }
337   -
338   - // this one does the projection... as the projection was the last
339   - // matrix we do not need to do it here.
340   - let to_coord = |p :&usize| {
341   - let Point(v, _) = camera.project(self.points[*p]);
342   - Vertex::new(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())
343   - };
344   - let to_poly = |f :&Face<T>| {
345   - let pg = polygon(f.corners.iter().map(to_coord));
346   - let mut r :T = (((color >> 16) & 0xFF) as i32).into();
347   - let mut g :T = (((color >> 8) & 0xFF) as i32).into();
348   - let mut b :T = (((color ) & 0xFF) as i32).into();
349   - let lf :T = match f.normal {
350   - None => 1.into(),
351   - Some(n) => n.dot(light.dir())
352   - / (n.mag() * light.dir().mag()),
353   - };
354   -
355   - // this "if" represents a first simple backface culling
356   - // approach. We only return face that face towards us.
357   - if lf < 0.into() {
358   - r = r * -lf;
359   - g = g * -lf;
360   - b = b * -lf;
361   -
362   - let c :u32 = (r.round() as u32) << 16
363   - | (g.round() as u32) << 8
364   - | (b.round() as u32);
365   -
366   - Some((pg, c))
367   - } else {
368   - None
369   - }};
370   -
371   - self.faces.iter().filter_map(to_poly).collect()
372   - }
373   -}
... ...
  1 +//
  2 +// Basic geometric things...
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2019 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +
  22 +use std::fmt::Debug;
  23 +use std::ops::{Add, Div, Mul, Neg, Sub};
  24 +
  25 +use crate::easel::polygon::Polygon;
  26 +use crate::easel::canvas::Vertex;
  27 +
  28 +use crate::math::transform::{TMatrix, Transformable};
  29 +use crate::math::trigonometry::Trig;
  30 +use crate::math::vector::Vector;
  31 +
  32 +use super::camera::Camera;
  33 +use super::face::Face;
  34 +use super::light::DirectLight;
  35 +use super::point::Point;
  36 +use super::primitives::Primitives;
  37 +
  38 +#[derive(Debug)]
  39 +pub struct Polyeder<T>
  40 +where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig {
  41 + points :Vec<Point<T>>,
  42 + faces :Vec<Face<T>>,
  43 +}
  44 +
  45 +impl<T> Polyeder<T>
  46 +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
  47 + + Mul<Output = T> + Div<Output = T>
  48 + + PartialEq + Debug + Copy + Trig + From<i32> {
  49 + fn update_normals(&mut self) {
  50 + for f in self.faces.iter_mut() {
  51 + f.update_normal(&self.points);
  52 + }
  53 + }
  54 +
  55 + // construct via cube, see polyhedra.pdf
  56 + pub fn tetrahedron(a :T) -> Polyeder<T> {
  57 + let f2 :T = 2.into();
  58 + let ch = a / (f2 * T::sqrt(f2).unwrap());
  59 +
  60 + let ps = vec!( Point::new(-ch, -ch, ch)
  61 + , Point::new(-ch, ch, -ch)
  62 + , Point::new( ch, -ch, -ch)
  63 + , Point::new( ch, ch, ch) );
  64 +
  65 + let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom
  66 + , Face::new(vec!(3, 2, 0), &ps)
  67 + , Face::new(vec!(0, 1, 3), &ps)
  68 + , Face::new(vec!(1, 2, 3), &ps) );
  69 +
  70 + Polyeder{ points: ps, faces: fs }
  71 + }
  72 +
  73 + pub fn triangle(a :T) -> Polyeder<T> {
  74 + let f0 :T = 0.into();
  75 + let f3 :T = 3.into();
  76 + let f6 :T = 6.into();
  77 + let zi :T = T::sqrt(f3).unwrap() / f6 * a;
  78 + let zc :T = T::sqrt(f3).unwrap() / f3 * a;
  79 + let ah :T = a / 2.into();
  80 +
  81 + let ps = vec!( Point::new(-ah, f0, -zi)
  82 + , Point::new( f0, f0, zc)
  83 + , Point::new( ah, f0, -zi) );
  84 +
  85 + let fs = vec!(Face::new(vec!(0, 1, 2), &ps));
  86 +
  87 + Polyeder{ points: ps, faces: fs }
  88 + }
  89 +
  90 + pub fn cube(a :T) -> Polyeder<T> {
  91 + let ah :T = a / From::<i32>::from(2);
  92 +
  93 + let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1
  94 + , Point::new(-ah, -ah, -ah) // 1 => front 2
  95 + , Point::new( ah, -ah, -ah) // 2 => front 3
  96 + , Point::new( ah, ah, -ah) // 3 => front 4
  97 + , Point::new(-ah, ah, ah) // 4 => back 1
  98 + , Point::new(-ah, -ah, ah) // 5 => back 2
  99 + , Point::new( ah, -ah, ah) // 6 => back 3
  100 + , Point::new( ah, ah, ah) ); // 7 => back 4
  101 +
  102 + let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front
  103 + , Face::new(vec!(7, 6, 5, 4), &ps) // back
  104 + , Face::new(vec!(1, 5, 6, 2), &ps) // top
  105 + , Face::new(vec!(0, 3, 7, 4), &ps) // bottom
  106 + , Face::new(vec!(0, 4, 5, 1), &ps) // left
  107 + , Face::new(vec!(2, 6, 7, 3), &ps) ); // right
  108 +
  109 + Polyeder{ points: ps, faces: fs }
  110 + }
  111 +}
  112 +
  113 +impl<T> Primitives<T> for Polyeder<T>
  114 +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
  115 + + Mul<Output = T> + Div<Output = T>
  116 + + Debug + Copy + Trig + From<i32> + From<f64> + PartialOrd {
  117 + // TODO Maybe this should also be an instance of Transformable…
  118 + fn transform(&self, m :&TMatrix<T>) -> Self {
  119 + let Polyeder{ points: ps, faces: fs } = self;
  120 +
  121 + let mut p = Polyeder{
  122 + points: ps.iter().map(|p| p.transform(m)).collect()
  123 + , faces: fs.to_vec()
  124 + };
  125 +
  126 + // TODO alternatively we could rotate the normals too, but this cannot
  127 + // done with the original matrix… the question is, what is faster.
  128 + p.update_normals();
  129 + p
  130 + }
  131 +
  132 + fn project( &self
  133 + , camera :&Camera<T>
  134 + , light :&DirectLight<T>
  135 + , color :u32 ) -> Vec<(Polygon<T>, u32)> {
  136 + // Helper to create a Polygon from Coordinates…
  137 + // TODO probably there needs to be a Polygon constructor for this.
  138 + fn polygon<I, T>(c :I) -> Polygon<T>
  139 + where I: Iterator<Item = Vertex<T>> {
  140 + Polygon(c.collect())
  141 + }
  142 +
  143 + // currently our cam has only one direction...
  144 + let cam_dir = Vector(0.into(), 0.into(), 1.into());
  145 +
  146 + // this one does the projection... as the projection was the last
  147 + // matrix we do not need to do it here.
  148 + let to_coord = |p :&usize| camera.project(self.points[*p]);
  149 + let to_poly = |f :&Face<T>| {
  150 + let pg = polygon(f.corners().iter().map(to_coord));
  151 + let mut r :T = (((color >> 16) & 0xFF) as i32).into();
  152 + let mut g :T = (((color >> 8) & 0xFF) as i32).into();
  153 + let mut b :T = (((color ) & 0xFF) as i32).into();
  154 + let lf :T = match f.normal() {
  155 + None => 1.into(),
  156 + Some(n) => n.dot(light.dir())
  157 + / (n.mag() * light.dir().mag()),
  158 + };
  159 + let view_f :T = match f.normal() {
  160 + None => 1.into(),
  161 + Some(n) => n.dot(cam_dir)
  162 + / (n.mag() * cam_dir.mag()),
  163 + };
  164 +
  165 + // this "if" represents a first simple backface culling
  166 + // approach. We only return face that face towards us.
  167 + if view_f >= 0.into() {
  168 + None
  169 + } else {
  170 + if lf < (-0.1).into() {
  171 + r = r * -lf;
  172 + g = g * -lf;
  173 + b = b * -lf;
  174 + } else {
  175 + r = r * 0.1.into();
  176 + g = g * 0.1.into();
  177 + b = b * 0.1.into();
  178 + }
  179 +
  180 + let c :u32 = (r.round() as u32) << 16
  181 + | (g.round() as u32) << 8
  182 + | (b.round() as u32);
  183 +
  184 + Some((pg, c))
  185 + }};
  186 +
  187 + self.faces.iter().filter_map(to_poly).collect()
  188 + }
  189 +}
... ...
  1 +//
  2 +// Basic geometric things...
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2019 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +
  22 +use std::fmt::Debug;
  23 +use std::ops::{Add, Div, Mul, Neg, Sub};
  24 +
  25 +use crate::easel::polygon::Polygon;
  26 +use crate::math::transform::TMatrix;
  27 +use crate::math::trigonometry::Trig;
  28 +
  29 +use super::camera::Camera;
  30 +use super::light::DirectLight;
  31 +
  32 +pub trait Primitives<T>
  33 +where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
  34 + fn transform(&self, m :&TMatrix<T>) -> Self;
  35 + fn project( &self
  36 + , camera :&Camera<T>
  37 + , light :&DirectLight<T>
  38 + , col :u32 ) -> Vec<(Polygon<T>, u32)>;
  39 +}
... ...
Please register or login to post a comment