this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

triangles, mostly

alice bea9969f 549905c0

+46 -50
+46 -50
tic80_rust/src/gfx/framebuffer.rs
··· 365 365 366 366 // Filled triangle using scanline rasterization 367 367 #[allow(clippy::too_many_arguments)] 368 - pub fn tri(&mut self, mut x1: i32, mut y1: i32, mut x2: i32, mut y2: i32, mut x3: i32, mut y3: i32, color: u8) { 368 + pub fn tri(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, x2: i32, y2: i32, color: u8) { 369 369 let c = color & 0x0F; 370 - // Sort by y, then x 371 - if y2 < y1 || (y2 == y1 && x2 < x1) { std::mem::swap(&mut x1, &mut x2); std::mem::swap(&mut y1, &mut y2); } 372 - if y3 < y1 || (y3 == y1 && x3 < x1) { std::mem::swap(&mut x1, &mut x3); std::mem::swap(&mut y1, &mut y3); } 373 - if y3 < y2 || (y3 == y2 && x3 < x2) { std::mem::swap(&mut x2, &mut x3); std::mem::swap(&mut y2, &mut y3); } 374 - if y1 == y3 { return; } 375 - 376 - if y2 == y3 { 377 - // flat-bottom 378 - let inv1 = (x2 - x1) as f32 / (y2 - y1) as f32; 379 - let inv2 = (x3 - x1) as f32 / (y2 - y1) as f32; 380 - let mut cx1 = x1 as f32; 381 - let mut cx2 = x1 as f32; 382 - for y in y1..=y2 { 383 - self.hspan(cx1.floor() as i32, cx2.floor() as i32, y, c); 384 - cx1 += inv1; 385 - cx2 += inv2; 386 - } 387 - } else if y1 == y2 { 388 - // flat-top 389 - let inv1 = (x3 - x1) as f32 / (y3 - y1) as f32; 390 - let inv2 = (x3 - x2) as f32 / (y3 - y2) as f32; 391 - let mut cx1 = x1 as f32; 392 - let mut cx2 = x2 as f32; 393 - for y in y1..=y3 { 394 - self.hspan(cx1.floor() as i32, cx2.floor() as i32, y, c); 395 - cx1 += inv1; 396 - cx2 += inv2; 397 - } 370 + // Convert to CCW orientation for consistent edge tests 371 + let area = (x1 - x0) as i64 * (y2 - y0) as i64 - (x2 - x0) as i64 * (y1 - y0) as i64; 372 + let (v0x, v0y, v1x, v1y, v2x, v2y) = if area < 0 { 373 + (x0, y0, x2, y2, x1, y1) 398 374 } else { 399 - // general: split at y2 400 - let x4 = x1 + (((y2 - y1) as f32) * ((x3 - x1) as f32) / ((y3 - y1) as f32)).floor() as i32; 401 - // flat-bottom part 402 - let inv1 = (x2 - x1) as f32 / (y2 - y1) as f32; 403 - let inv2 = (x4 - x1) as f32 / (y2 - y1) as f32; 404 - let mut cx1 = x1 as f32; 405 - let mut cx2 = x1 as f32; 406 - for y in y1..=y2 { 407 - self.hspan(cx1.floor() as i32, cx2.floor() as i32, y, c); 408 - cx1 += inv1; 409 - cx2 += inv2; 410 - } 411 - // flat-top part 412 - let inv1b = (x3 - x2) as f32 / (y3 - y2) as f32; 413 - let inv2b = (x3 - x4) as f32 / (y3 - y2) as f32; 414 - let mut cx1b = x2 as f32; 415 - let mut cx2b = x4 as f32; 416 - for y in y2..=y3 { 417 - self.hspan(cx1b.floor() as i32, cx2b.floor() as i32, y, c); 418 - cx1b += inv1b; 419 - cx2b += inv2b; 375 + (x0, y0, x1, y1, x2, y2) 376 + }; 377 + 378 + // Bounding box (exclusive max per top-left rule) 379 + let min_x = v0x.min(v1x).min(v2x); 380 + let min_y = v0y.min(v1y).min(v2y); 381 + let max_x = v0x.max(v1x).max(v2x); 382 + let max_y = v0y.max(v1y).max(v2y); 383 + 384 + // Doubling coordinates to evaluate edge functions at pixel centers (x+0.5, y+0.5) 385 + let (ax2, ay2) = ((v0x as i64) * 2, (v0y as i64) * 2); 386 + let (bx2, by2) = ((v1x as i64) * 2, (v1y as i64) * 2); 387 + let (cx2, cy2) = ((v2x as i64) * 2, (v2y as i64) * 2); 388 + 389 + // Edge deltas 390 + let e0_dx = bx2 - ax2; let e0_dy = by2 - ay2; // v0->v1 391 + let e1_dx = cx2 - bx2; let e1_dy = cy2 - by2; // v1->v2 392 + let e2_dx = ax2 - cx2; let e2_dy = ay2 - cy2; // v2->v0 393 + 394 + // Top-left classification 395 + let e0_top_left = e0_dy > 0 || (e0_dy == 0 && e0_dx < 0); 396 + let e1_top_left = e1_dy > 0 || (e1_dy == 0 && e1_dx < 0); 397 + let e2_top_left = e2_dy > 0 || (e2_dy == 0 && e2_dx < 0); 398 + 399 + // Iterate over pixels in bounding box with top-left rule: y in [min_y, max_y), x in [min_x, max_x) 400 + for y in min_y..max_y { 401 + for x in min_x..max_x { 402 + let px = (x as i64) * 2 + 1; 403 + let py = (y as i64) * 2 + 1; 404 + // Edge functions 405 + let e0 = (py - ay2) * e0_dx - (px - ax2) * e0_dy; 406 + let e1 = (py - by2) * e1_dx - (px - bx2) * e1_dy; 407 + let e2 = (py - cy2) * e2_dx - (px - cx2) * e2_dy; 408 + 409 + // Apply top-left inclusion rules 410 + if (e0 > 0 || (e0 == 0 && e0_top_left)) 411 + && (e1 > 0 || (e1 == 0 && e1_top_left)) 412 + && (e2 > 0 || (e2 == 0 && e2_top_left)) 413 + { 414 + let _ = self.set_pixel(x, y, c); 415 + } 420 416 } 421 417 } 422 418 }