Browse Source

Start polygon fill

master
Georg Hopp 6 years ago
parent
commit
721b89a171
Signed by: ghopp GPG Key ID: 4C5D226768784538
  1. 135
      fractional/src/easel.rs
  2. 16
      fractional/src/geometry.rs

135
fractional/src/easel.rs

@ -21,7 +21,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
use std::cmp; use std::cmp;
use std::fmt::{Formatter, Display, Result};
use std::fmt::{Formatter, Debug, Display, Result};
use std::ops::{Add, Sub, Div}; use std::ops::{Add, Sub, Div};
use std::sync::mpsc; use std::sync::mpsc;
@ -46,6 +46,10 @@ pub trait Drawable<T> {
fn plot(&self) -> Coordinates<T>; fn plot(&self) -> Coordinates<T>;
} }
pub trait Fillable<T> {
fn fill(&self) -> Coordinates<T>;
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Coordinate<T>(pub i32, pub i32, pub T); pub struct Coordinate<T>(pub i32, pub i32, pub T);
@ -82,15 +86,15 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
let dx = (bx - ax).abs(); let dx = (bx - ax).abs();
let sx :i32 = if ax < bx { 1 } else { -1 }; let sx :i32 = if ax < bx { 1 } else { -1 };
let dy = -(by - ay).abs();
let dy = (by - ay).abs();
let sy :i32 = if ay < by { 1 } else { -1 }; let sy :i32 = if ay < by { 1 } else { -1 };
let size = cmp::max(dx, -dy);
let size = cmp::max(dx, dy);
let dz = (bz - az) / size.into(); let dz = (bz - az) / size.into();
let mut v :Vec<Self> = vec!( Coordinate(0, 0, 0.into()) let mut v :Vec<Self> = vec!( Coordinate(0, 0, 0.into())
; (size as usize) + 1); ; (size as usize) + 1);
v[0] = Coordinate(ax, ay, az); v[0] = Coordinate(ax, ay, az);
inner(&mut v, bx, by, dx, dy, sx, sy, dz, dx + dy);
inner(&mut v, bx, by, dx, -dy, sx, sy, dz, dx - dy);
v v
} }
} }
@ -258,6 +262,129 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
} }
} }
impl<T> Fillable<T> for Polygon<T>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
+ Debug + Clone + Copy + From<i32> {
fn fill(&self) -> Coordinates<T> {
/* bresenham kind of thing to get the outer x values for each y of one
* edge of the polygon. */
fn walk_edge<T>( a :Coordinate<T>
, b :Coordinate<T> ) -> Vec<Coordinate<T>>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
+ From<i32> + Debug + Copy {
let Coordinate(mut x, mut y, mut z) = a;
let Coordinate( bx, by, bz) = b;
// next should be called with the negative of this… but dz depends
// on the positive this.
let dy = -(by - y).abs();
let dx = (bx - x).abs();
let sx = if x < bx { 1 } else { -1 };
let dz = (bz - z) / (-dy).into();
let mut err = dx + dy;
let mut v = Vec::<Coordinate<T>>::with_capacity((-dy) as usize);
while y != by {
match (2*err >= dy, 2*err <= dx) {
(true, false) => { x = x + sx
; err = err + dy },
(false, true) => { v.push(Coordinate(x, y, z))
; y = y + 1
; z = z + dz
; err = err + dx },
_ => { v.push(Coordinate(x, y, z))
; x = x + sx
; y = y + 1
; z = z + dz
; err = err + dx + dy },
}
}
v
}
fn next_y<T>( cs :&[Coordinate<T>]
, c :usize
, f :&dyn Fn(usize) -> usize) -> Option<usize> {
fn inner<T>( cs :&[Coordinate<T>]
, c :usize
, n :usize
, f :&dyn Fn(usize) -> usize) -> Option<usize> {
if c == n {
None
} else {
let Coordinate(_, cy, _) = cs[c];
let Coordinate(_, ny, _) = cs[n];
match ny.cmp(&cy) {
cmp::Ordering::Less => None,
cmp::Ordering::Equal => inner(cs, c, f(n), f),
cmp::Ordering::Greater => Some(n),
}
}
}
inner(cs, c, f(c), f)
}
let Polygon(Coordinates(cs)) = self;
let vert_min = cs.iter().enumerate()
. fold( None
, |acc, x| match acc {
None => Some(x),
Some(a) => {
let Coordinate(_, ay, _) = a.1;
let Coordinate(_, xy, _) = x.1;
if xy < ay {Some(x)} else {Some(a)} } } )
. unwrap().0;
println!("== vert_min: [{:?}] - {:?}", vert_min, cs[vert_min]);
let right = |x :usize| (x + 1) % cs.len();
let left = |x :usize| if x == 0 { cs.len() - 1 } else { x - 1 };
let mut r = (vert_min, next_y(cs, vert_min, &right));
let mut l = (vert_min, next_y(cs, vert_min, &left));
let mut l_edge :Vec<Coordinate<T>> = Vec::new();
let mut r_edge :Vec<Coordinate<T>> = Vec::new();
while l.1 != None || r.1 != None {
match l.1 {
None => {},
Some(a) => {
println!("== l: [{:?}] - {:?}", l, cs[a]);
l_edge.append(&mut walk_edge(cs[l.0], cs[a]));
l = (a, next_y(cs, a, &left));
},
}
match r.1 {
None => {},
Some(a) => {
println!("== r: [{:?}] - {:?}", r, cs[a]);
r_edge.append(&mut walk_edge(cs[r.0], cs[a]));
r = (a, next_y(cs, a, &right));
}
}
}
println!("== [{}] {:?}", l_edge.len(), l_edge);
println!("== [{}] {:?}", r_edge.len(), r_edge);
// TODO we always miss the last scanline…
// TODO check what happend with at least 2 vertices with same y and
// different x…
// loop though edges…
Coordinates(Vec::<Coordinate<T>>::new())
}
}
impl<T> Display for Polygon<T> where T: Copy { impl<T> Display for Polygon<T> where T: Copy {
fn fmt(&self, f: &mut Formatter<'_>) -> Result { fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let Polygon(a) = self; let Polygon(a) = self;

16
fractional/src/geometry.rs

@ -22,7 +22,7 @@ use std::convert::{From, Into};
use std::ops::{Add,Sub,Neg,Mul,Div}; use std::ops::{Add,Sub,Neg,Mul,Div};
use std::fmt::Debug; use std::fmt::Debug;
use crate::easel::{Canvas,Coordinate,Coordinates,Polygon};
use crate::easel::{Canvas,Coordinate,Coordinates,Polygon,Fillable};
use crate::transform::{TMatrix, Transformable}; use crate::transform::{TMatrix, Transformable};
use crate::trigonometry::Trig; use crate::trigonometry::Trig;
use crate::vector::Vector; use crate::vector::Vector;
@ -347,7 +347,7 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
// matrix we do not need to do it here. // matrix we do not need to do it here.
let to_coord = |p :&usize| { let to_coord = |p :&usize| {
let Point(v, _) = camera.project(self.points[*p]); let Point(v, _) = camera.project(self.points[*p]);
println!("== {:?} / {:?}", self.points[*p], (v.z() - 1.into()).recip());
// println!("== {:?} / {:?}", self.points[*p], (v.z() - 1.into()).recip());
Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into()) Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())
}; };
let to_poly = |f :&Face<T>| { let to_poly = |f :&Face<T>| {
@ -361,6 +361,8 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
/ (n.mag() * light.dir().mag()), / (n.mag() * light.dir().mag()),
}; };
// this if represents a first simple backface culling
// approach. We only return face that face towards us.
if lf < 0.into() { if lf < 0.into() {
r = r * -lf; r = r * -lf;
g = g * -lf; g = g * -lf;
@ -370,14 +372,18 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
| (g.round() as u32) << 8 | (g.round() as u32) << 8
| (b.round() as u32); | (b.round() as u32);
(&pg).fill();
Some((pg, c)) Some((pg, c))
} else { } else {
None None
}}; }};
let mut ps :Vec<(Polygon<T>, u32)> = self.faces.iter()
. filter_map(to_poly).collect();
ps.sort_by(|a, b| a.1.cmp(&b.1));
let ps :Vec<(Polygon<T>, u32)> = self.faces.iter()
. filter_map(to_poly).collect();
// this sorts by the color value which is no longer neccessary as soon
// as the z-buffer is complete.
// ps.sort_by(|a, b| a.1.cmp(&b.1));
ps ps
} }
} }
Loading…
Cancel
Save