Last active
August 2, 2016 14:09
-
-
Save Cranc/f55fa1169fc55f71bbb2f8484c72b6ff to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use base::math::*; | |
use std::f64::consts::PI; | |
enum SIDE { | |
Top, | |
Bottom, | |
Left, | |
Right, | |
NearP, | |
FarP, | |
} | |
pub enum LOCATION { | |
Inside, | |
Outside, | |
Intersect, | |
} | |
// f64 for high accuracy #makef64greatagain | |
const ANG2RAD: f64 = (PI / 180.); | |
struct Plane { | |
points: [Point3f; 3], | |
d: f32, | |
normal: Vector3f, | |
} | |
impl Plane { | |
// is used to create plane with dummy values | |
// use setPoint3fs for right initialization | |
pub fn new() -> Plane { | |
Plane { | |
points: [Point3f::new(0., 0., 0.), Point3f::new(1., 1., 1.), Point3f::new(3., 2., 2.)], | |
d: 0., | |
normal: Vector3f::new(0., 1., -1.), | |
} | |
} | |
pub fn set_point3fs(&mut self, x: Vector3f, y: Vector3f, z: Vector3f) { | |
self.points[0] = Point3f { | |
x: x.x, | |
y: x.y, | |
z: x.z, | |
}; | |
self.points[1] = Point3f { | |
x: y.x, | |
y: y.y, | |
z: y.z, | |
}; | |
self.points[2] = Point3f { | |
x: z.x, | |
y: z.y, | |
z: z.z, | |
}; | |
let xy = y - x; | |
let xz = z - x; | |
self.normal = xy.cross(xz).normalize(); | |
self.d = -(self.normal.x * self.points[0].x + self.normal.y * self.points[0].y + | |
self.normal.z * self.points[0].z); | |
} | |
pub fn distance(&self, p: &Point3f) -> f32 { | |
let top = self.normal.x * p.x + self.normal.y * p.y + self.normal.z * p.z + self.d; | |
let c = |x| x * x; | |
let bottom = (c(self.normal.x) + c(self.normal.y) + c(self.normal.z)).sqrt(); | |
top / bottom | |
} | |
} | |
pub struct Frustum { | |
planes: [Plane; 6], | |
angle: f32, | |
ratio: f32, | |
near: f32, | |
far: f32, | |
nearheight: f32, | |
nearwidth: f32, | |
farheight: f32, | |
farwidth: f32, | |
} | |
impl Frustum { | |
// initialization stuff contains dummys use | |
// set_cam_internals and set_cam_def to initialize the frustum | |
pub fn new() -> Frustum { | |
let ps = | |
[Plane::new(), Plane::new(), Plane::new(), Plane::new(), Plane::new(), Plane::new()]; | |
Frustum { | |
planes: ps, | |
angle: 0.0, | |
ratio: 0.75, | |
near: 10.0, | |
far: 300.0, | |
nearheight: 800.0, | |
nearwidth: 600.0, | |
farheight: 1920.0, | |
farwidth: 1080.0, | |
} | |
} | |
pub fn set_cam_internals(&mut self, angle: f32, ratio: f32, near: f32, far: f32) { | |
self.angle = angle; | |
self.ratio = ratio; | |
self.near = near; | |
self.far = far; | |
let tan: f32 = ((ANG2RAD * self.angle as f64 * 0.5).tan()) as f32; | |
self.nearheight = self.near * tan; | |
self.nearwidth = self.nearheight * ratio; | |
self.farheight = self.far * tan; | |
self.farwidth = self.farheight * ratio; | |
} | |
// camera pos is a vector to use operators like | |
// -/+ (no ops for point3f - vector3f) | |
// note replace with more efficent later on | |
pub fn set_cam_def(&mut self, pos: Point3f, look_at: Vector3f, up: Vector3f) { | |
// axis cause we all want them | |
let camera_pos = Vector3f::new(pos.x, pos.y, pos.z); | |
let z = (camera_pos - look_at).normalize(); | |
let x = (up.cross(z)).normalize(); | |
let y = (z.cross(x)).normalize(); | |
// calc center of [insert near/far plane joke here] | |
let c = { | |
|x: f32| (camera_pos - z) * (x) | |
}; | |
let nc = c(self.near); | |
let fc = c(self.far); | |
// 4 corners of Frustum near plane | |
let ntl = nc + y * self.nearheight - x * self.nearwidth; | |
let ntr = nc + y * self.nearheight + x * self.nearwidth; | |
let nbl = nc - y * self.nearheight - x * self.nearwidth; | |
let nbr = nc - y * self.nearheight + x * self.nearwidth; | |
// 4 corners of Frustum far plane | |
let ftl = fc + y * self.farheight - x * self.farwidth; | |
let ftr = fc + y * self.farheight + x * self.farwidth; | |
let fbl = fc - y * self.farheight - x * self.farwidth; | |
let fbr = fc - y * self.farheight + x * self.farwidth; | |
// set planes points are given counter clockwise | |
let mut c = |s, x, y, z| self.planes[s as usize].set_point3fs(x, y, z); | |
c(SIDE::Top, ntr, ntl, ftl); | |
c(SIDE::Bottom, nbl, nbr, fbr); | |
c(SIDE::Left, ntl, nbl, fbl); | |
c(SIDE::Right, nbr, ntr, fbr); | |
c(SIDE::NearP, ntl, ntr, nbr); | |
c(SIDE::FarP, ftr, ftl, fbl); | |
} | |
pub fn point_in_frustum(&self, p: &Point3f) -> LOCATION { | |
// If a point is inside the frustum it must be on the right | |
// side of every plane. | |
for i in 0..6 { | |
if self.planes[i].distance(p) < 0.0 { | |
return LOCATION::Outside; | |
} | |
} | |
LOCATION::Inside | |
} | |
pub fn sphere_in_frustum(&self) { | |
// TODO if needed | |
} | |
pub fn box_in_frustum(&self, points: [&Point3f; 8]) -> LOCATION { | |
// If one of the corner points is inside we box needs to be rendered so INSIDE | |
let mut ins; | |
let mut out; | |
for i in 0..6 { | |
ins = 0; | |
out = 0; | |
for k in 0..8 { | |
if self.planes[i].distance(points[k]) < 0. { | |
out += 1; | |
if ins != 0 { | |
break; | |
} | |
} else { | |
ins += 1; | |
if out != 0 { | |
break; | |
} | |
} | |
} | |
// no point inside plane ... OUTSIDE | |
if ins == 0 { | |
return LOCATION::Outside; | |
} else if out != 0 { | |
return LOCATION::Intersect; | |
} | |
} | |
LOCATION::Inside | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment