Showing
2 changed files
with
142 additions
and
9 deletions
... | ... | @@ -21,7 +21,7 @@ |
21 | 21 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
22 | 22 | // |
23 | 23 | use std::cmp; |
24 | -use std::fmt::{Formatter, Display, Result}; | |
24 | +use std::fmt::{Formatter, Debug, Display, Result}; | |
25 | 25 | use std::ops::{Add, Sub, Div}; |
26 | 26 | use std::sync::mpsc; |
27 | 27 | |
... | ... | @@ -46,6 +46,10 @@ pub trait Drawable<T> { |
46 | 46 | fn plot(&self) -> Coordinates<T>; |
47 | 47 | } |
48 | 48 | |
49 | +pub trait Fillable<T> { | |
50 | + fn fill(&self) -> Coordinates<T>; | |
51 | +} | |
52 | + | |
49 | 53 | #[derive(Debug, Clone, Copy)] |
50 | 54 | pub struct Coordinate<T>(pub i32, pub i32, pub T); |
51 | 55 | |
... | ... | @@ -82,15 +86,15 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> |
82 | 86 | |
83 | 87 | let dx = (bx - ax).abs(); |
84 | 88 | let sx :i32 = if ax < bx { 1 } else { -1 }; |
85 | - let dy = -(by - ay).abs(); | |
89 | + let dy = (by - ay).abs(); | |
86 | 90 | let sy :i32 = if ay < by { 1 } else { -1 }; |
87 | - let size = cmp::max(dx, -dy); | |
91 | + let size = cmp::max(dx, dy); | |
88 | 92 | let dz = (bz - az) / size.into(); |
89 | 93 | |
90 | 94 | let mut v :Vec<Self> = vec!( Coordinate(0, 0, 0.into()) |
91 | 95 | ; (size as usize) + 1); |
92 | 96 | v[0] = Coordinate(ax, ay, az); |
93 | - inner(&mut v, bx, by, dx, dy, sx, sy, dz, dx + dy); | |
97 | + inner(&mut v, bx, by, dx, -dy, sx, sy, dz, dx - dy); | |
94 | 98 | v |
95 | 99 | } |
96 | 100 | } |
... | ... | @@ -258,6 +262,129 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> |
258 | 262 | } |
259 | 263 | } |
260 | 264 | |
265 | +impl<T> Fillable<T> for Polygon<T> | |
266 | +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> | |
267 | + + Debug + Clone + Copy + From<i32> { | |
268 | + fn fill(&self) -> Coordinates<T> { | |
269 | + | |
270 | + /* bresenham kind of thing to get the outer x values for each y of one | |
271 | + * edge of the polygon. */ | |
272 | + fn walk_edge<T>( a :Coordinate<T> | |
273 | + , b :Coordinate<T> ) -> Vec<Coordinate<T>> | |
274 | + where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> | |
275 | + + From<i32> + Debug + Copy { | |
276 | + | |
277 | + let Coordinate(mut x, mut y, mut z) = a; | |
278 | + let Coordinate( bx, by, bz) = b; | |
279 | + | |
280 | + // next should be called with the negative of this… but dz depends | |
281 | + // on the positive this. | |
282 | + let dy = -(by - y).abs(); | |
283 | + let dx = (bx - x).abs(); | |
284 | + let sx = if x < bx { 1 } else { -1 }; | |
285 | + let dz = (bz - z) / (-dy).into(); | |
286 | + let mut err = dx + dy; | |
287 | + | |
288 | + let mut v = Vec::<Coordinate<T>>::with_capacity((-dy) as usize); | |
289 | + | |
290 | + while y != by { | |
291 | + match (2*err >= dy, 2*err <= dx) { | |
292 | + (true, false) => { x = x + sx | |
293 | + ; err = err + dy }, | |
294 | + (false, true) => { v.push(Coordinate(x, y, z)) | |
295 | + ; y = y + 1 | |
296 | + ; z = z + dz | |
297 | + ; err = err + dx }, | |
298 | + _ => { v.push(Coordinate(x, y, z)) | |
299 | + ; x = x + sx | |
300 | + ; y = y + 1 | |
301 | + ; z = z + dz | |
302 | + ; err = err + dx + dy }, | |
303 | + } | |
304 | + } | |
305 | + | |
306 | + v | |
307 | + } | |
308 | + | |
309 | + fn next_y<T>( cs :&[Coordinate<T>] | |
310 | + , c :usize | |
311 | + , f :&dyn Fn(usize) -> usize) -> Option<usize> { | |
312 | + fn inner<T>( cs :&[Coordinate<T>] | |
313 | + , c :usize | |
314 | + , n :usize | |
315 | + , f :&dyn Fn(usize) -> usize) -> Option<usize> { | |
316 | + if c == n { | |
317 | + None | |
318 | + } else { | |
319 | + let Coordinate(_, cy, _) = cs[c]; | |
320 | + let Coordinate(_, ny, _) = cs[n]; | |
321 | + | |
322 | + match ny.cmp(&cy) { | |
323 | + cmp::Ordering::Less => None, | |
324 | + cmp::Ordering::Equal => inner(cs, c, f(n), f), | |
325 | + cmp::Ordering::Greater => Some(n), | |
326 | + } | |
327 | + } | |
328 | + } | |
329 | + | |
330 | + inner(cs, c, f(c), f) | |
331 | + } | |
332 | + | |
333 | + let Polygon(Coordinates(cs)) = self; | |
334 | + | |
335 | + let vert_min = cs.iter().enumerate() | |
336 | + . fold( None | |
337 | + , |acc, x| match acc { | |
338 | + None => Some(x), | |
339 | + Some(a) => { | |
340 | + let Coordinate(_, ay, _) = a.1; | |
341 | + let Coordinate(_, xy, _) = x.1; | |
342 | + if xy < ay {Some(x)} else {Some(a)} } } ) | |
343 | + . unwrap().0; | |
344 | + | |
345 | + println!("== vert_min: [{:?}] - {:?}", vert_min, cs[vert_min]); | |
346 | + | |
347 | + let right = |x :usize| (x + 1) % cs.len(); | |
348 | + let left = |x :usize| if x == 0 { cs.len() - 1 } else { x - 1 }; | |
349 | + | |
350 | + let mut r = (vert_min, next_y(cs, vert_min, &right)); | |
351 | + let mut l = (vert_min, next_y(cs, vert_min, &left)); | |
352 | + | |
353 | + let mut l_edge :Vec<Coordinate<T>> = Vec::new(); | |
354 | + let mut r_edge :Vec<Coordinate<T>> = Vec::new(); | |
355 | + | |
356 | + while l.1 != None || r.1 != None { | |
357 | + match l.1 { | |
358 | + None => {}, | |
359 | + Some(a) => { | |
360 | + println!("== l: [{:?}] - {:?}", l, cs[a]); | |
361 | + l_edge.append(&mut walk_edge(cs[l.0], cs[a])); | |
362 | + l = (a, next_y(cs, a, &left)); | |
363 | + }, | |
364 | + } | |
365 | + | |
366 | + match r.1 { | |
367 | + None => {}, | |
368 | + Some(a) => { | |
369 | + println!("== r: [{:?}] - {:?}", r, cs[a]); | |
370 | + r_edge.append(&mut walk_edge(cs[r.0], cs[a])); | |
371 | + r = (a, next_y(cs, a, &right)); | |
372 | + } | |
373 | + } | |
374 | + } | |
375 | + | |
376 | + println!("== [{}] {:?}", l_edge.len(), l_edge); | |
377 | + println!("== [{}] {:?}", r_edge.len(), r_edge); | |
378 | + | |
379 | + // TODO we always miss the last scanline… | |
380 | + // TODO check what happend with at least 2 vertices with same y and | |
381 | + // different x… | |
382 | + // loop though edges… | |
383 | + | |
384 | + Coordinates(Vec::<Coordinate<T>>::new()) | |
385 | + } | |
386 | +} | |
387 | + | |
261 | 388 | impl<T> Display for Polygon<T> where T: Copy { |
262 | 389 | fn fmt(&self, f: &mut Formatter<'_>) -> Result { |
263 | 390 | let Polygon(a) = self; | ... | ... |
... | ... | @@ -22,7 +22,7 @@ use std::convert::{From, Into}; |
22 | 22 | use std::ops::{Add,Sub,Neg,Mul,Div}; |
23 | 23 | use std::fmt::Debug; |
24 | 24 | |
25 | -use crate::easel::{Canvas,Coordinate,Coordinates,Polygon}; | |
25 | +use crate::easel::{Canvas,Coordinate,Coordinates,Polygon,Fillable}; | |
26 | 26 | use crate::transform::{TMatrix, Transformable}; |
27 | 27 | use crate::trigonometry::Trig; |
28 | 28 | use crate::vector::Vector; |
... | ... | @@ -347,7 +347,7 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
347 | 347 | // matrix we do not need to do it here. |
348 | 348 | let to_coord = |p :&usize| { |
349 | 349 | let Point(v, _) = camera.project(self.points[*p]); |
350 | - println!("== {:?} / {:?}", self.points[*p], (v.z() - 1.into()).recip()); | |
350 | + // println!("== {:?} / {:?}", self.points[*p], (v.z() - 1.into()).recip()); | |
351 | 351 | Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into()) |
352 | 352 | }; |
353 | 353 | let to_poly = |f :&Face<T>| { |
... | ... | @@ -361,6 +361,8 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
361 | 361 | / (n.mag() * light.dir().mag()), |
362 | 362 | }; |
363 | 363 | |
364 | + // this if represents a first simple backface culling | |
365 | + // approach. We only return face that face towards us. | |
364 | 366 | if lf < 0.into() { |
365 | 367 | r = r * -lf; |
366 | 368 | g = g * -lf; |
... | ... | @@ -370,14 +372,18 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
370 | 372 | | (g.round() as u32) << 8 |
371 | 373 | | (b.round() as u32); |
372 | 374 | |
375 | + (&pg).fill(); | |
376 | + | |
373 | 377 | Some((pg, c)) |
374 | 378 | } else { |
375 | 379 | None |
376 | 380 | }}; |
377 | 381 | |
378 | - let mut ps :Vec<(Polygon<T>, u32)> = self.faces.iter() | |
379 | - . filter_map(to_poly).collect(); | |
380 | - ps.sort_by(|a, b| a.1.cmp(&b.1)); | |
382 | + let ps :Vec<(Polygon<T>, u32)> = self.faces.iter() | |
383 | + . filter_map(to_poly).collect(); | |
384 | + // this sorts by the color value which is no longer neccessary as soon | |
385 | + // as the z-buffer is complete. | |
386 | + // ps.sort_by(|a, b| a.1.cmp(&b.1)); | |
381 | 387 | ps |
382 | 388 | } |
383 | 389 | } | ... | ... |
Please
register
or
login
to post a comment