From b0e0bda101594ff48d6486c099b1483ac8b45214 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 20 Feb 2025 09:29:49 -0800
Subject: [PATCH] common: Ray

---
 engine/physics/src/push_solve.rs |  22 +---
 lib/common/src/bvh.rs            | 191 +++++++++++++++----------------
 lib/common/src/lib.rs            |   1 +
 lib/common/src/ray.rs            |  20 ++++
 4 files changed, 114 insertions(+), 120 deletions(-)
 create mode 100644 lib/common/src/ray.rs

diff --git a/engine/physics/src/push_solve.rs b/engine/physics/src/push_solve.rs
index a40eaa8..5b1c5a7 100644
--- a/engine/physics/src/push_solve.rs
+++ b/engine/physics/src/push_solve.rs
@@ -1,4 +1,6 @@
-use strafesnet_common::integer::{self,vec3::{self,Vector3},Fixed,Planar64,Planar64Vec3,Ratio};
+use strafesnet_common::integer::vec3::{self,Vector3};
+use strafesnet_common::integer::{Fixed,Planar64Vec3,Ratio};
+use strafesnet_common::ray::Ray;
 
 // This algorithm is based on Lua code
 // written by Trey Reynolds in 2021
@@ -12,24 +14,6 @@ type Conts<'a>=arrayvec::ArrayVec<&'a Contact,4>;
 // hack to allow comparing ratios to zero
 const RATIO_ZERO:Ratio<Fixed<1,32>,Fixed<1,32>>=Ratio::new(Fixed::ZERO,Fixed::EPSILON);
 
-struct Ray{
-	origin:Planar64Vec3,
-	direction:Planar64Vec3,
-}
-impl Ray{
-	fn extrapolate<Num,Den,N1,T1>(&self,t:Ratio<Num,Den>)->Planar64Vec3
-	where
-		Num:Copy,
-		Den:Copy,
-		Num:core::ops::Mul<Planar64,Output=N1>,
-		Planar64:core::ops::Mul<Den,Output=N1>,
-		N1:integer::Divide<Den,Output=T1>,
-		T1:integer::Fix<Planar64>,
-	{
-		self.origin+self.direction.map(|elem|(t*elem).divide().fix())
-	}
-}
-
 /// Information about a contact restriction
 pub struct Contact{
 	pub position:Planar64Vec3,
diff --git a/lib/common/src/bvh.rs b/lib/common/src/bvh.rs
index 5309ae4..836cf8c 100644
--- a/lib/common/src/bvh.rs
+++ b/lib/common/src/bvh.rs
@@ -1,11 +1,9 @@
 use std::cmp::Ordering;
 use std::collections::BTreeMap;
 
-use fixed_wide::fixed::Fixed;
-use linear_ops::types::Vector3;
-
 use crate::aabb::Aabb;
-use crate::integer::{Ratio,Planar64,Planar64Vec3};
+use crate::ray::Ray;
+use crate::integer::{Ratio,Planar64};
 use crate::instruction::{InstructionCollector,TimedInstruction};
 
 //da algaritum
@@ -18,103 +16,94 @@ use crate::instruction::{InstructionCollector,TimedInstruction};
 //sort the centerpoints on each axis (3 lists)
 //bv is put into octant based on whether it is upper or lower in each list
 
-pub struct Ray{
-	pub origin:Planar64Vec3,
-	pub direction:Planar64Vec3,
-}
-impl Ray{
-	pub fn extrapolate(&self,t:Ratio<Planar64,Planar64>)->Ratio<Vector3<Fixed<2,64>>,Planar64>{
-		// o+d*t
-		(self.origin*t.den+self.direction*t.num)/t.den
+
+pub fn intersect_aabb(ray:&Ray,aabb:&Aabb)->Option<Ratio<Planar64,Planar64>>{
+	// n.(o+d*t)==n.p
+	// n.o + n.d * t == n.p
+	// t == (n.p - n.o)/n.d
+	let mut hit=None;
+	match ray.direction.x.cmp(&Planar64::ZERO){
+		Ordering::Less=>{
+			let rel_min=aabb.min()-ray.origin;
+			let rel_max=aabb.max()-ray.origin;
+			let dy=rel_max.x*ray.direction.y;
+			let dz=rel_max.x*ray.direction.z;
+			// x is negative, so inequalities are flipped
+			if rel_min.y*ray.direction.x>dy&&dy>rel_max.y*ray.direction.x
+			 &&rel_min.z*ray.direction.x>dz&&dz>rel_max.z*ray.direction.x{
+				let t=rel_max.x/ray.direction.x;
+				hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
+			}
+		},
+		Ordering::Equal=>(),
+		Ordering::Greater=>{
+			let rel_min=aabb.min()-ray.origin;
+			let rel_max=aabb.max()-ray.origin;
+			let dy=rel_min.x*ray.direction.y;
+			let dz=rel_min.x*ray.direction.z;
+			// x is positive, so inequalities are normal
+			if rel_min.y*ray.direction.x<dy&&dy<rel_max.y*ray.direction.x
+			 &&rel_min.z*ray.direction.x<dz&&dz<rel_max.z*ray.direction.x{
+				let t=rel_min.x/ray.direction.x;
+				hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
+			}
+		},
 	}
-	pub fn intersect_aabb(&self,aabb:&Aabb)->Option<Ratio<Planar64,Planar64>>{
-		// n.(o+d*t)==n.p
-		// n.o + n.d * t == n.p
-		// t == (n.p - n.o)/n.d
-		let mut hit=None;
-		match self.direction.x.cmp(&Planar64::ZERO){
-			Ordering::Less=>{
-				let rel_min=aabb.min()-self.origin;
-				let rel_max=aabb.max()-self.origin;
-				let dy=rel_max.x*self.direction.y;
-				let dz=rel_max.x*self.direction.z;
-				// x is negative, so inequalities are flipped
-				if rel_min.y*self.direction.x>dy&&dy>rel_max.y*self.direction.x
-				 &&rel_min.z*self.direction.x>dz&&dz>rel_max.z*self.direction.x{
-					let t=rel_max.x/self.direction.x;
-					hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
-				}
-			},
-			Ordering::Equal=>(),
-			Ordering::Greater=>{
-				let rel_min=aabb.min()-self.origin;
-				let rel_max=aabb.max()-self.origin;
-				let dy=rel_min.x*self.direction.y;
-				let dz=rel_min.x*self.direction.z;
-				// x is positive, so inequalities are normal
-				if rel_min.y*self.direction.x<dy&&dy<rel_max.y*self.direction.x
-				 &&rel_min.z*self.direction.x<dz&&dz<rel_max.z*self.direction.x{
-					let t=rel_min.x/self.direction.x;
-					hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
-				}
-			},
-		}
-		match self.direction.z.cmp(&Planar64::ZERO){
-			Ordering::Less=>{
-				let rel_min=aabb.min()-self.origin;
-				let rel_max=aabb.max()-self.origin;
-				let dx=rel_max.z*self.direction.x;
-				let dy=rel_max.z*self.direction.y;
-				// z is negative, so inequalities are flipped
-				if rel_min.x*self.direction.z>dx&&dx>rel_max.x*self.direction.z
-				 &&rel_min.y*self.direction.z>dy&&dy>rel_max.y*self.direction.z{
-					let t=rel_max.z/self.direction.z;
-					hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
-				}
-			},
-			Ordering::Equal=>(),
-			Ordering::Greater=>{
-				let rel_min=aabb.min()-self.origin;
-				let rel_max=aabb.max()-self.origin;
-				let dx=rel_min.z*self.direction.x;
-				let dy=rel_min.z*self.direction.y;
-				// z is positive, so inequalities are normal
-				if rel_min.x*self.direction.z<dx&&dx<rel_max.x*self.direction.z
-				 &&rel_min.y*self.direction.z<dy&&dy<rel_max.y*self.direction.z{
-					let t=rel_min.z/self.direction.z;
-					hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
-				}
-			},
-		}
-		match self.direction.y.cmp(&Planar64::ZERO){
-			Ordering::Less=>{
-				let rel_min=aabb.min()-self.origin;
-				let rel_max=aabb.max()-self.origin;
-				let dz=rel_max.y*self.direction.z;
-				let dx=rel_max.y*self.direction.x;
-				// y is negative, so inequalities are flipped
-				if rel_min.z*self.direction.y>dz&&dz>rel_max.z*self.direction.y
-				 &&rel_min.x*self.direction.y>dx&&dx>rel_max.x*self.direction.y{
-					let t=rel_max.y/self.direction.y;
-					hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
-				}
-			},
-			Ordering::Equal=>(),
-			Ordering::Greater=>{
-				let rel_min=aabb.min()-self.origin;
-				let rel_max=aabb.max()-self.origin;
-				let dz=rel_min.y*self.direction.z;
-				let dx=rel_min.y*self.direction.x;
-				// y is positive, so inequalities are normal
-				if rel_min.z*self.direction.y<dz&&dz<rel_max.z*self.direction.y
-				 &&rel_min.x*self.direction.y<dx&&dx<rel_max.x*self.direction.y{
-					let t=rel_min.y/self.direction.y;
-					hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
-				}
-			},
-		}
-		hit
+	match ray.direction.z.cmp(&Planar64::ZERO){
+		Ordering::Less=>{
+			let rel_min=aabb.min()-ray.origin;
+			let rel_max=aabb.max()-ray.origin;
+			let dx=rel_max.z*ray.direction.x;
+			let dy=rel_max.z*ray.direction.y;
+			// z is negative, so inequalities are flipped
+			if rel_min.x*ray.direction.z>dx&&dx>rel_max.x*ray.direction.z
+			 &&rel_min.y*ray.direction.z>dy&&dy>rel_max.y*ray.direction.z{
+				let t=rel_max.z/ray.direction.z;
+				hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
+			}
+		},
+		Ordering::Equal=>(),
+		Ordering::Greater=>{
+			let rel_min=aabb.min()-ray.origin;
+			let rel_max=aabb.max()-ray.origin;
+			let dx=rel_min.z*ray.direction.x;
+			let dy=rel_min.z*ray.direction.y;
+			// z is positive, so inequalities are normal
+			if rel_min.x*ray.direction.z<dx&&dx<rel_max.x*ray.direction.z
+			 &&rel_min.y*ray.direction.z<dy&&dy<rel_max.y*ray.direction.z{
+				let t=rel_min.z/ray.direction.z;
+				hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
+			}
+		},
 	}
+	match ray.direction.y.cmp(&Planar64::ZERO){
+		Ordering::Less=>{
+			let rel_min=aabb.min()-ray.origin;
+			let rel_max=aabb.max()-ray.origin;
+			let dz=rel_max.y*ray.direction.z;
+			let dx=rel_max.y*ray.direction.x;
+			// y is negative, so inequalities are flipped
+			if rel_min.z*ray.direction.y>dz&&dz>rel_max.z*ray.direction.y
+			 &&rel_min.x*ray.direction.y>dx&&dx>rel_max.x*ray.direction.y{
+				let t=rel_max.y/ray.direction.y;
+				hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
+			}
+		},
+		Ordering::Equal=>(),
+		Ordering::Greater=>{
+			let rel_min=aabb.min()-ray.origin;
+			let rel_max=aabb.max()-ray.origin;
+			let dz=rel_min.y*ray.direction.z;
+			let dx=rel_min.y*ray.direction.x;
+			// y is positive, so inequalities are normal
+			if rel_min.z*ray.direction.y<dz&&dz<rel_max.z*ray.direction.y
+			 &&rel_min.x*ray.direction.y<dx&&dx<rel_max.x*ray.direction.y{
+				let t=rel_min.y/ray.direction.y;
+				hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
+			}
+		},
+	}
+	hit
 }
 
 pub enum RecursiveContent<N,L>{
@@ -171,7 +160,7 @@ impl<L> BvhNode<L>{
 					child.populate_nodes(collector,nodes,ray,start_time,f);
 				}else{
 					// Am I an upcoming superstar?
-					if let Some(t)=ray.intersect_aabb(&child.aabb){
+					if let Some(t)=intersect_aabb(ray,&child.aabb){
 						if start_time.lt_ratio(t)&&t.lt_ratio(collector.time()){
 							nodes.insert(t,child);
 						}
@@ -212,7 +201,7 @@ impl<L> BvhNode<L>{
 				// break open the node and predict collisions with the child nodes
 				RecursiveContent::Branch(children)=>for child in children{
 					// Am I an upcoming superstar?
-					if let Some(t)=ray.intersect_aabb(&child.aabb){
+					if let Some(t)=intersect_aabb(ray,&child.aabb){
 						if t<collector.time(){
 							nodes.insert(t,child);
 						}
diff --git a/lib/common/src/lib.rs b/lib/common/src/lib.rs
index 69a3501..e6364ba 100644
--- a/lib/common/src/lib.rs
+++ b/lib/common/src/lib.rs
@@ -1,5 +1,6 @@
 pub mod bvh;
 pub mod map;
+pub mod ray;
 pub mod run;
 pub mod aabb;
 pub mod model;
diff --git a/lib/common/src/ray.rs b/lib/common/src/ray.rs
new file mode 100644
index 0000000..fe16127
--- /dev/null
+++ b/lib/common/src/ray.rs
@@ -0,0 +1,20 @@
+use ratio_ops::ratio::Ratio;
+use crate::integer::{self,Planar64,Planar64Vec3};
+
+pub struct Ray{
+	pub origin:Planar64Vec3,
+	pub direction:Planar64Vec3,
+}
+impl Ray{
+	pub fn extrapolate<Num,Den,N1,T1>(&self,t:Ratio<Num,Den>)->Planar64Vec3
+	where
+		Num:Copy,
+		Den:Copy,
+		Num:core::ops::Mul<Planar64,Output=N1>,
+		Planar64:core::ops::Mul<Den,Output=N1>,
+		N1:integer::Divide<Den,Output=T1>,
+		T1:integer::Fix<Planar64>,
+	{
+		self.origin+self.direction.map(|elem|(t*elem).divide().fix())
+	}
+}