From 69cc1904a8b43d309d42f7ebabf2e42f07447519 Mon Sep 17 00:00:00 2001 From: numzero Date: Mon, 10 Jun 2024 00:35:33 +0300 Subject: [PATCH] Trace all objects hit --- src/bin/flat.rs | 76 ++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/src/bin/flat.rs b/src/bin/flat.rs index 518b421..860a583 100644 --- a/src/bin/flat.rs +++ b/src/bin/flat.rs @@ -1,4 +1,3 @@ -use std::cmp::Ordering; use std::f32::consts::PI; use flo_draw::*; use flo_canvas::*; @@ -125,10 +124,14 @@ enum Subspace { Inner, } -enum FlatTraceResult { - Infinity(Vec2), - Edge(Ray), - Object(Ray, i32), +struct Hit { + distance: f32, + id: i32, +} + +struct FlatTraceResult { + end: Option, + objects: Vec, } impl Space { @@ -178,24 +181,23 @@ impl Space { let cell = RectInside { rect: self.rect }; let ray = cell.ray_to_local(ray); let dist = cell.to_boundary(ray).expect("Can't get outta here!"); - let ray = Ray { pos: ray.pos + ray.dir * dist, dir: ray.dir }; + let ray = ray.forward(dist); cell.ray_to_global(ray) } fn trace_outer(&self, ray: Ray) -> FlatTraceResult { assert_eq!(self.which_subspace(ray.pos), Outer); let cell = basic_shapes::Rect { size: vec2(self.rect.outer_radius, self.rect.external_halflength) }; - let obj = Self::trace_to_object(self.list_objects_outer(), ray); - let sub = cell.trace_into(ray); - let rray = |dist: f32| Ray { pos: ray.pos + ray.dir * dist, dir: ray.dir }; - match (sub, obj) { - (None, None) => FlatTraceResult::Infinity(ray.dir), - (Some(dist), None) => FlatTraceResult::Edge(rray(dist)), - (None, Some((id, dist))) => FlatTraceResult::Object(rray(dist), id), - (Some(sdist), Some((id, odist))) => if sdist < odist { - FlatTraceResult::Edge(rray(sdist)) - } else { - FlatTraceResult::Object(rray(odist), id) + let objs = Self::trace_to_objects(self.list_objects_outer(), ray); + if let Some(dist) = cell.trace_into(ray) { + FlatTraceResult { + end: Some(ray.forward(dist)), + objects: objs.into_iter().filter(|hit| hit.distance < dist).collect(), + } + } else { + FlatTraceResult { + end: None, + objects: objs, } } } @@ -211,7 +213,7 @@ impl Space { self.objs.as_slice() } - fn trace_to_object(objs: &[Object], ray: Ray) -> Option<(i32, f32)> { + fn trace_to_objects(objs: &[Object], ray: Ray) -> Vec { objs.iter() .filter_map(|obj| { let rel = ray.pos - obj.loc.pos; @@ -219,16 +221,16 @@ impl Space { if diff > 0.0 { let t = (-rel.dot(ray.dir) - diff.sqrt()) / ray.dir.length_squared(); if t >= 0.0 { - return Some((obj.id, t)); + return Some(Hit { id: obj.id, distance: t }); } } None - }) - .min_by(|(_, d1), (_, d2)| f32::total_cmp(d1, d2)) + }).collect() } } fn draw_ray_2(gc: &mut Vec, space: &Space, base: Vec2, dir: Vec2) { + let mut hits = Vec::::new(); let dir = space.rect.globalize(base, dir); gc.new_path(); gc.move_to(base.x, base.y); @@ -253,23 +255,18 @@ fn draw_ray_2(gc: &mut Vec, space: &Space, base: Vec2, dir: Vec2) { ray = space.trace_inner(ray); } Outer => { - ray = match space.trace_outer(ray) { - FlatTraceResult::Edge(r) => r, - FlatTraceResult::Infinity(dir) => { - ray.pos += dir * (1000.0 / DT); + let ret = space.trace_outer(ray); + for hit in ret.objects { + let r = ray.forward(hit.distance); + hits.circle(r.pos.x, r.pos.y, 1.5); + } + ray = match ret.end { + Some(r) => r, + None => { + ray = ray.forward(1000.0 / DT); gc.line_to(ray.pos.x, ray.pos.y); - gc.stroke(); break; } - FlatTraceResult::Object(r, id) => { - gc.line_to(r.pos.x, r.pos.y); - gc.stroke(); - gc.new_path(); - gc.new_dash_pattern(); - gc.circle(r.pos.x, r.pos.y, 1.5); - gc.stroke(); - r - } }; } Boundary => panic!(), @@ -281,7 +278,10 @@ fn draw_ray_2(gc: &mut Vec, space: &Space, base: Vec2, dir: Vec2) { gc.move_to(ray.pos.x, ray.pos.y); } gc.stroke(); + gc.new_path(); gc.new_dash_pattern(); + gc.append(&mut hits); + gc.stroke(); } fn draw_fan_2(gc: &mut Vec, space: &Space, base: Vec2, dir: Vec2, spread: f32) { @@ -367,6 +367,12 @@ struct Ray { dir: Vec2, } +impl Ray { + fn forward(&self, dist: f32) -> Ray { + Ray { pos: self.pos + self.dir * dist, dir: self.dir } + } +} + mod basic_shapes { use glam::{Vec2, vec2}; use crate::Ray;