Add types from cgmath
This commit is contained in:
parent
11e1623dad
commit
9d99347bbf
6 changed files with 693 additions and 1 deletions
120
src/frustum.rs
Normal file
120
src/frustum.rs
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2013 The Lmath Developers. For a full listing of the authors,
|
||||
// refer to the AUTHORS file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use mat::Mat4;
|
||||
use plane::Plane;
|
||||
use point::Point3;
|
||||
|
||||
mod num_macros;
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub struct Frustum<T> {
|
||||
left: Plane<T>,
|
||||
right: Plane<T>,
|
||||
bottom: Plane<T>,
|
||||
top: Plane<T>,
|
||||
near: Plane<T>,
|
||||
far: Plane<T>,
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub struct FrustumPoints<T> {
|
||||
near_top_left: Point3<T>,
|
||||
near_top_right: Point3<T>,
|
||||
near_bottom_left: Point3<T>,
|
||||
near_bottom_right: Point3<T>,
|
||||
far_top_left: Point3<T>,
|
||||
far_top_right: Point3<T>,
|
||||
far_bottom_left: Point3<T>,
|
||||
far_bottom_right: Point3<T>,
|
||||
}
|
||||
|
||||
impl<T:Copy + Real> Frustum<T> {
|
||||
/// Constructs a frustum
|
||||
pub fn from_planes(left: Plane<T>, right: Plane<T>,
|
||||
bottom: Plane<T>, top: Plane<T>,
|
||||
near: Plane<T>, far: Plane<T>) -> Frustum<T> {
|
||||
Frustum {
|
||||
left: left,
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
top: top,
|
||||
near: near,
|
||||
far: far,
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts frustum planes from a projection matrix
|
||||
pub fn from_matrix(mat: Mat4<T>) -> Frustum<T> {
|
||||
Frustum {
|
||||
left: Plane::from_vec4(mat.row(3).add_v(&mat.row(0)).normalize()),
|
||||
right: Plane::from_vec4(mat.row(3).sub_v(&mat.row(0)).normalize()),
|
||||
bottom: Plane::from_vec4(mat.row(3).add_v(&mat.row(1)).normalize()),
|
||||
top: Plane::from_vec4(mat.row(3).sub_v(&mat.row(1)).normalize()),
|
||||
near: Plane::from_vec4(mat.row(3).add_v(&mat.row(2)).normalize()),
|
||||
far: Plane::from_vec4(mat.row(3).sub_v(&mat.row(2)).normalize()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base() -> Frustum<T> {
|
||||
Frustum {
|
||||
left: Plane::from_abcd( one!(T), zero!(T), zero!(T), one!(T)),
|
||||
right: Plane::from_abcd(-one!(T), zero!(T), zero!(T), one!(T)),
|
||||
bottom: Plane::from_abcd( zero!(T), one!(T), zero!(T), one!(T)),
|
||||
top: Plane::from_abcd( zero!(T), -one!(T), zero!(T), one!(T)),
|
||||
near: Plane::from_abcd( zero!(T), zero!(T), -one!(T), one!(T)),
|
||||
far: Plane::from_abcd( zero!(T), zero!(T), one!(T), one!(T)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Copy + Real + ApproxEq<T>> Frustum<T> {
|
||||
/// Computes where the frustum planes intersect to form corners and returns
|
||||
/// a struct containing the eight resulting position vectors.
|
||||
pub fn to_points(&self) -> FrustumPoints<T> {
|
||||
FrustumPoints {
|
||||
near_top_left: self.near.intersection_3pl(&self.top, &self.left).unwrap(),
|
||||
near_top_right: self.near.intersection_3pl(&self.top, &self.right).unwrap(),
|
||||
near_bottom_left: self.near.intersection_3pl(&self.bottom, &self.left).unwrap(),
|
||||
near_bottom_right: self.near.intersection_3pl(&self.bottom, &self.right).unwrap(),
|
||||
far_top_left: self.far.intersection_3pl(&self.top, &self.left).unwrap(),
|
||||
far_top_right: self.far.intersection_3pl(&self.top, &self.right).unwrap(),
|
||||
far_bottom_left: self.far.intersection_3pl(&self.bottom, &self.left).unwrap(),
|
||||
far_bottom_right: self.far.intersection_3pl(&self.bottom, &self.right).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Copy + Eq + ApproxEq<T>> ApproxEq<T> for Frustum<T> {
|
||||
#[inline]
|
||||
pub fn approx_epsilon() -> T {
|
||||
ApproxEq::approx_epsilon::<T,T>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn approx_eq(&self, other: &Frustum<T>) -> bool {
|
||||
self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn approx_eq_eps(&self, other: &Frustum<T>, epsilon: &T) -> bool {
|
||||
self.left.approx_eq_eps(&other.left, epsilon) &&
|
||||
self.right.approx_eq_eps(&other.right, epsilon) &&
|
||||
self.bottom.approx_eq_eps(&other.bottom, epsilon) &&
|
||||
self.top.approx_eq_eps(&other.top, epsilon) &&
|
||||
self.near.approx_eq_eps(&other.near, epsilon) &&
|
||||
self.far.approx_eq_eps(&other.far, epsilon)
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
author = "Brendan Zabarauskas",
|
||||
url = "https://github.com/bjz/lmath-rs")];
|
||||
|
||||
#[comment = "A generic linear algebra library."];
|
||||
#[comment = "A mathematics library for computer graphics."];
|
||||
#[license = "ASL2"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
|
@ -29,4 +29,8 @@ pub mod mat;
|
|||
pub mod quat;
|
||||
pub mod vec;
|
||||
|
||||
pub mod frustum;
|
||||
pub mod plane;
|
||||
pub mod point;
|
||||
pub mod projection;
|
||||
pub mod ray;
|
||||
|
|
187
src/plane.rs
Normal file
187
src/plane.rs
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Copyright 2013 The Lmath Developers. For a full listing of the authors,
|
||||
// refer to the AUTHORS file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub use dim::Dimensional;
|
||||
use mat::Mat3;
|
||||
use point::Point3;
|
||||
use ray::Ray3;
|
||||
use vec::{Vec3, Vec4};
|
||||
|
||||
mod num_macros;
|
||||
mod dim_macros;
|
||||
|
||||
/// A plane formed from the equation: `Ax + Bx + Cx + D = 0`
|
||||
///
|
||||
/// # Fields
|
||||
///
|
||||
/// - `n`: the normal of the plane where:
|
||||
/// - `n.x`: corresponds to `A` in the plane equation
|
||||
/// - `n.y`: corresponds to `B` in the plane equation
|
||||
/// - `n.z`: corresponds to `C` in the plane equation
|
||||
/// - `d`: the distance value, corresponding to `D` in the plane equation
|
||||
#[deriving(Eq)]
|
||||
pub struct Plane<T> {
|
||||
norm: Vec3<T>,
|
||||
dist: T,
|
||||
}
|
||||
|
||||
impl_dimensional!(Plane, T, 4)
|
||||
impl_dimensional_fns!(Plane, T, 4)
|
||||
impl_swap!(Plane)
|
||||
impl_approx!(Plane)
|
||||
|
||||
impl<T:Copy + Real> Plane<T> {
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `a`: the `x` component of the normal
|
||||
/// - `b`: the `y` component of the normal
|
||||
/// - `c`: the `z` component of the normal
|
||||
/// - `d`: the plane's distance value
|
||||
pub fn from_abcd(a: T, b: T, c: T, d: T) -> Plane<T> {
|
||||
Plane {
|
||||
norm: Vec3::new(a, b, c),
|
||||
dist: d,
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a plane from a normal vector `n` and a distance `d`
|
||||
pub fn from_nd(norm: Vec3<T>, dist: T) -> Plane<T> {
|
||||
Plane { norm: norm, dist: dist }
|
||||
}
|
||||
|
||||
/// Construct a plane from the components of a four-dimensional vector
|
||||
pub fn from_vec4(vec: Vec4<T>) -> Plane<T> {
|
||||
Plane::from_abcd(vec.x, vec.y, vec.z, vec.w)
|
||||
}
|
||||
|
||||
/// Compute the distance from the plane to the point
|
||||
pub fn distance(&self, pos: &Point3<T>) -> T {
|
||||
self.norm.dot(&**pos) + self.dist
|
||||
}
|
||||
|
||||
/// Computes the point at which `ray` intersects the plane
|
||||
pub fn intersection_r(&self, _ray: &Ray3<T>) -> Point3<T> {
|
||||
fail!(~"not yet implemented")
|
||||
}
|
||||
|
||||
/// Returns `true` if the ray intersects the plane
|
||||
pub fn intersects(&self, _ray: &Ray3<T>) -> bool {
|
||||
fail!(~"not yet implemented")
|
||||
}
|
||||
|
||||
/// Returns `true` if `pos` is located behind the plane - otherwise it returns `false`
|
||||
pub fn contains(&self, pos: &Point3<T>) -> bool {
|
||||
self.distance(pos) < zero!(T)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Copy + Real + ApproxEq<T>> Plane<T> {
|
||||
/// Constructs a plane that passes through the the three points `a`, `b` and `c`
|
||||
pub fn from_3p(a: Point3<T>,
|
||||
b: Point3<T>,
|
||||
c: Point3<T>) -> Option<Plane<T>> {
|
||||
// create two vectors that run parallel to the plane
|
||||
let v0 = (*b).sub_v(&*a);
|
||||
let v1 = (*c).sub_v(&*a);
|
||||
// find the vector that is perpendicular to v1 and v2
|
||||
let mut norm = v0.cross(&v1);
|
||||
|
||||
if norm.approx_eq(&Vec3::zero()) {
|
||||
None
|
||||
} else {
|
||||
// compute the normal and the distance to the plane
|
||||
norm.normalize_self();
|
||||
let dist = -a.dot(&norm);
|
||||
|
||||
Some(Plane::from_nd(norm, dist))
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the ray created from the two-plane intersection of `self` and `other`
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// - `Some(r)`: The ray `r` where the planes intersect.
|
||||
/// - `None`: No valid intersection was found. The planes are probably parallel.
|
||||
pub fn intersection_2pl(&self, other: &Plane<T>) -> Option<Ray3<T>> {
|
||||
let ray_dir = self.norm.cross(&other.norm);
|
||||
|
||||
if ray_dir.approx_eq(&Vec3::zero::<T>()) {
|
||||
None // the planes are parallel
|
||||
} else {
|
||||
// The end-point of the ray is at the three-plane intersection between
|
||||
// `self`, `other`, and a tempory plane positioned at the origin
|
||||
do Plane::from_nd(ray_dir, zero!(T)).intersection_3pl(self, other).map |ray_pos| {
|
||||
Ray3 {
|
||||
pos: *ray_pos,
|
||||
dir: ray_dir,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the three-plane intersection between `self`, `other_a` and `other_b`.
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// - `Some(p)`: The position vector `p` where the planes intersect.
|
||||
/// - `None`: No valid intersection was found. The normals of the three
|
||||
/// planes are probably coplanar.
|
||||
pub fn intersection_3pl(&self, other_a: &Plane<T>, other_b: &Plane<T>) -> Option<Point3<T>> {
|
||||
let mx = Mat3::new(self.norm.x, other_a.norm.x, other_b.norm.x,
|
||||
self.norm.y, other_a.norm.y, other_b.norm.y,
|
||||
self.norm.z, other_a.norm.z, other_b.norm.z);
|
||||
do mx.inverse().map |m| {
|
||||
Point3(m.mul_v(&Vec3::new(self.dist, other_a.dist, other_b.dist)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToStr for Plane<T> {
|
||||
pub fn to_str(&self) -> ~str {
|
||||
fmt!("%?x + %?y + %?z + %? = 0", self.norm.x, self.norm.y, self.norm.z, self.dist)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use plane::*;
|
||||
use point::*;
|
||||
|
||||
#[test]
|
||||
fn test_from_3p() {
|
||||
assert_eq!(Plane::from_3p(Point3::new(5f, 0f, 5f),
|
||||
Point3::new(5f, 5f, 5f),
|
||||
Point3::new(5f, 0f, -1f)), Some(Plane::from_abcd(-1f, 0f, 0f, 5f)));
|
||||
|
||||
assert_eq!(Plane::from_3p(Point3::new(0f, 5f, -5f),
|
||||
Point3::new(0f, 5f, 0f),
|
||||
Point3::new(0f, 5f, 5f)), None); // The points are parallel
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plane_intersection_3pl() {
|
||||
let p0 = Plane::from_abcd(1.0, 0.0, 0.0, 1.0);
|
||||
let p1 = Plane::from_abcd(0.0, -1.0, 0.0, 2.0);
|
||||
let p2 = Plane::from_abcd(0.0, 0.0, 1.0, 1.0);
|
||||
|
||||
assert_eq!(p0.intersection_3pl(&p1, &p2).unwrap(), Point3::new(1.0, -2.0, 1.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(Plane::from_abcd(1.0, 2.0, 3.0, 4.0).to_str(), ~"1x + 2y + 3z + 4 = 0");
|
||||
}
|
||||
}
|
105
src/point.rs
Normal file
105
src/point.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2013 The Lmath Developers. For a full listing of the authors,
|
||||
// refer to the AUTHORS file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use dim::Dimensional;
|
||||
use vec::{Vec2, Vec3};
|
||||
|
||||
mod dim_macros;
|
||||
|
||||
/// A geometric point
|
||||
pub trait Point<T,V>: Eq + ApproxEq<T> + ToStr {
|
||||
pub fn translate(&self, offset: &V) -> Self;
|
||||
pub fn distance(&self, other: &Self) -> T;
|
||||
}
|
||||
|
||||
/// A two-dimensional point
|
||||
#[deriving(Eq)]
|
||||
pub struct Point2<T>(Vec2<T>);
|
||||
|
||||
impl_dimensional!(Point2, T, 2)
|
||||
impl_dimensional_fns!(Point2, T, 2)
|
||||
impl_approx!(Point2)
|
||||
|
||||
impl<T> Point2<T> {
|
||||
pub fn new(x: T, y: T) -> Point2<T> {
|
||||
Point2(Vec2::new(x, y))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Copy + Real> Point<T,Vec2<T>> for Point2<T> {
|
||||
pub fn translate(&self, offset: &Vec2<T>) -> Point2<T> {
|
||||
Point2(self.add_v(offset))
|
||||
}
|
||||
|
||||
pub fn distance(&self, other: &Point2<T>) -> T {
|
||||
(**self).distance(&**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToStr for Point2<T> {
|
||||
pub fn to_str(&self) -> ~str {
|
||||
fmt!("[%?, %?]", self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
/// A three-dimensional point
|
||||
#[deriving(Eq)]
|
||||
pub struct Point3<T>(Vec3<T>);
|
||||
|
||||
impl_dimensional!(Point3, T, 3)
|
||||
impl_dimensional_fns!(Point3, T, 3)
|
||||
impl_approx!(Point3)
|
||||
|
||||
impl<T> Point3<T> {
|
||||
pub fn new(x: T, y: T, z: T) -> Point3<T> {
|
||||
Point3(Vec3::new(x, y, z))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Copy + Real> Point<T,Vec3<T>> for Point3<T> {
|
||||
pub fn translate(&self, offset: &Vec3<T>) -> Point3<T> {
|
||||
Point3(self.add_v(offset))
|
||||
}
|
||||
|
||||
pub fn distance(&self, other: &Point3<T>) -> T {
|
||||
(**self).distance(&**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToStr for Point3<T> {
|
||||
pub fn to_str(&self) -> ~str {
|
||||
fmt!("[%?, %?, %?]", self.x, self.y, self.z)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_point2 {
|
||||
use point::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(Point2::new(1, 2).to_str(), ~"[1, 2]");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_point3 {
|
||||
use point::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(Point3::new(1, 2, 3).to_str(), ~"[1, 2, 3]");
|
||||
}
|
||||
}
|
|
@ -13,7 +13,9 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use frustum::Frustum;
|
||||
use mat::Mat4;
|
||||
use plane::Plane;
|
||||
|
||||
mod num_macros;
|
||||
|
||||
|
@ -97,3 +99,230 @@ pub fn ortho<T:Copy + Real>(left: T, right: T, bottom: T, top: T, near: T, far:
|
|||
c2r0, c2r1, c2r2, c2r3,
|
||||
c3r0, c3r1, c3r2, c3r3)
|
||||
}
|
||||
|
||||
pub trait Projection<T> {
|
||||
pub fn if_valid<U:Copy>(&self, f: &fn() -> U) -> Result<U, ~str>;
|
||||
pub fn to_mat4(&self) -> Result<Mat4<T>, ~str>;
|
||||
pub fn to_frustum(&self) -> Result<Frustum<T>, ~str>;
|
||||
}
|
||||
|
||||
/// A symmetrical perspective projection based on a field-of-view angle
|
||||
#[deriving(Eq)]
|
||||
pub struct PerspectiveFOV<T> {
|
||||
fovy: T, //radians
|
||||
aspect: T,
|
||||
near: T,
|
||||
far: T,
|
||||
}
|
||||
|
||||
impl<T:Copy + Real> PerspectiveFOV<T> {
|
||||
pub fn to_perspective(&self) -> Result<Perspective<T>, ~str> {
|
||||
do self.if_valid {
|
||||
let angle = self.fovy / two!(T);
|
||||
let ymax = self.near * angle.tan();
|
||||
let xmax = ymax * self.aspect;
|
||||
|
||||
Perspective {
|
||||
left: -xmax,
|
||||
right: xmax,
|
||||
bottom: -ymax,
|
||||
top: ymax,
|
||||
near: self.near,
|
||||
far: self.far,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Copy + Real> Projection<T> for PerspectiveFOV<T> {
|
||||
pub fn if_valid<U:Copy>(&self, f: &fn() -> U) -> Result<U, ~str> {
|
||||
let frac_pi_2: T = Real::frac_pi_2();
|
||||
cond! (
|
||||
(self.fovy < zero!(T)) { Err(fmt!("The vertical field of view cannot be below zero, found: %?", self.fovy)) }
|
||||
(self.fovy > frac_pi_2) { Err(fmt!("The vertical field of view cannot be greater than a half turn, found: %?", self.fovy)) }
|
||||
(self.aspect < zero!(T)) { Err(fmt!("The aspect ratio cannot be below zero, found: %?", self.aspect)) }
|
||||
(self.near < zero!(T)) { Err(fmt!("The near plane distance cannot be below zero, found: %?", self.near)) }
|
||||
(self.far < zero!(T)) { Err(fmt!("The far plane distance cannot be below zero, found: %?", self.far)) }
|
||||
(self.far < self.near) { Err(fmt!("The far plane cannot be closer than the near plane, found: far: %?, near: %?", self.far, self.near)) }
|
||||
_ { Ok(f()) }
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_mat4(&self) -> Result<Mat4<T>, ~str> {
|
||||
do self.to_perspective().chain |proj| { proj.to_mat4() }
|
||||
}
|
||||
|
||||
pub fn to_frustum(&self) -> Result<Frustum<T>, ~str> {
|
||||
do self.to_perspective().chain |proj| { proj.to_frustum() }
|
||||
}
|
||||
}
|
||||
|
||||
/// A perspective projection with arbitrary left/right/bottom/top distances
|
||||
#[deriving(Eq)]
|
||||
pub struct Perspective<T> {
|
||||
left: T,
|
||||
right: T,
|
||||
bottom: T,
|
||||
top: T,
|
||||
near: T,
|
||||
far: T,
|
||||
}
|
||||
|
||||
impl<T:Copy + Real> Projection<T> for Perspective<T> {
|
||||
pub fn if_valid<U:Copy>(&self, f: &fn() -> U) -> Result<U, ~str> {
|
||||
cond! (
|
||||
(self.left > self.right) { Err(fmt!("`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right)) }
|
||||
(self.bottom > self.top) { Err(fmt!("`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top)) }
|
||||
(self.near > self.far) { Err(fmt!("`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far)) }
|
||||
_ { Ok(f()) }
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_mat4(&self) -> Result<Mat4<T>, ~str> {
|
||||
do self.if_valid {
|
||||
let c0r0 = (two!(T) * self.near) / (self.right - self.left);
|
||||
let c0r1 = zero!(T);
|
||||
let c0r2 = zero!(T);
|
||||
let c0r3 = zero!(T);
|
||||
|
||||
let c1r0 = zero!(T);
|
||||
let c1r1 = (two!(T) * self.near) / (self.top - self.bottom);
|
||||
let c1r2 = zero!(T);
|
||||
let c1r3 = zero!(T);
|
||||
|
||||
let c2r0 = (self.right + self.left) / (self.right - self.left);
|
||||
let c2r1 = (self.top + self.bottom) / (self.top - self.bottom);
|
||||
let c2r2 = -(self.far + self.near) / (self.far - self.near);
|
||||
let c2r3 = -one!(T);
|
||||
|
||||
let c3r0 = zero!(T);
|
||||
let c3r1 = zero!(T);
|
||||
let c3r2 = -(two!(T) * self.far * self.near) / (self.far - self.near);
|
||||
let c3r3 = zero!(T);
|
||||
|
||||
Mat4::new(c0r0, c0r1, c0r2, c0r3,
|
||||
c1r0, c1r1, c1r2, c1r3,
|
||||
c2r0, c2r1, c2r2, c2r3,
|
||||
c3r0, c3r1, c3r2, c3r3)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_frustum(&self) -> Result<Frustum<T>, ~str> {
|
||||
do self.if_valid {
|
||||
/*
|
||||
|
||||
<---- l --->|<--- r ----->
|
||||
+-----------+-----------+ ^
|
||||
\ | / |
|
||||
\ | / |
|
||||
\ + | + / |
|
||||
\ / Nl | Nr \ / |
|
||||
\/ | \/ |
|
||||
left \ | / right f
|
||||
plane \ | / plane |
|
||||
⟨Nl,Dl⟩ \ | / ⟨Nr,Dr⟩ |
|
||||
\θl|θr/ |
|
||||
\ | / |
|
||||
\|/ |
|
||||
+ v
|
||||
|
||||
θl = tan⁻¹(l/f)
|
||||
|
||||
+
|
||||
/ Nl
|
||||
/
|
||||
/
|
||||
\ | /
|
||||
\θl| /
|
||||
\ | /
|
||||
\|/ θl
|
||||
+- - - -
|
||||
\
|
||||
|
||||
Nl = ⟨cos(θl), 0, sin(θl)⟩
|
||||
|
||||
left plane = ⟨Nl, 0⟩
|
||||
= ⟨cos(θl), 0, sin(θl), 0⟩
|
||||
|
||||
*/
|
||||
|
||||
let theta_l = (self.left / self.far).atan();
|
||||
let theta_r = (self.right / self.far).atan();
|
||||
let theta_b = (self.bottom / self.far).atan();
|
||||
let theta_t = (self.top / self.far).atan();
|
||||
|
||||
Frustum {
|
||||
left: Plane::from_abcd(theta_l.cos(), zero!(T), theta_l.sin(), zero!(T)),
|
||||
right: Plane::from_abcd(theta_r.cos(), zero!(T), theta_r.sin(), zero!(T)),
|
||||
bottom: Plane::from_abcd(zero!(T), theta_b.cos(), theta_b.sin(), zero!(T)),
|
||||
top: Plane::from_abcd(zero!(T), theta_t.cos(), theta_t.sin(), zero!(T)),
|
||||
near: Plane::from_abcd(zero!(T), zero!(T), -one!(T), -self.near),
|
||||
far: Plane::from_abcd(zero!(T), zero!(T), one!(T), self.far),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An orthographic projection with arbitrary left/right/bottom/top distances
|
||||
#[deriving(Eq)]
|
||||
pub struct Ortho<T> {
|
||||
left: T,
|
||||
right: T,
|
||||
bottom: T,
|
||||
top: T,
|
||||
near: T,
|
||||
far: T,
|
||||
}
|
||||
|
||||
impl<T:Copy + Real> Projection<T> for Ortho<T> {
|
||||
pub fn if_valid<U:Copy>(&self, f: &fn() -> U) -> Result<U, ~str> {
|
||||
cond! (
|
||||
(self.left > self.right) { Err(fmt!("`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right)) }
|
||||
(self.bottom > self.top) { Err(fmt!("`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top)) }
|
||||
(self.near > self.far) { Err(fmt!("`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far)) }
|
||||
_ { Ok(f()) }
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_mat4(&self) -> Result<Mat4<T>, ~str> {
|
||||
do self.if_valid {
|
||||
let c0r0 = two!(T) / (self.right - self.left);
|
||||
let c0r1 = zero!(T);
|
||||
let c0r2 = zero!(T);
|
||||
let c0r3 = zero!(T);
|
||||
|
||||
let c1r0 = zero!(T);
|
||||
let c1r1 = two!(T) / (self.top - self.bottom);
|
||||
let c1r2 = zero!(T);
|
||||
let c1r3 = zero!(T);
|
||||
|
||||
let c2r0 = zero!(T);
|
||||
let c2r1 = zero!(T);
|
||||
let c2r2 = -two!(T) / (self.far - self.near);
|
||||
let c2r3 = -one!(T);
|
||||
|
||||
let c3r0 = -(self.right + self.left) / (self.right - self.left);
|
||||
let c3r1 = -(self.top + self.bottom) / (self.top - self.bottom);
|
||||
let c3r2 = -(self.far + self.near) / (self.far - self.near);
|
||||
let c3r3 = one!(T);
|
||||
|
||||
Mat4::new(c0r0, c0r1, c0r2, c0r3,
|
||||
c1r0, c1r1, c1r2, c1r3,
|
||||
c2r0, c2r1, c2r2, c2r3,
|
||||
c3r0, c3r1, c3r2, c3r3)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_frustum(&self) -> Result<Frustum<T>, ~str> {
|
||||
do self.if_valid {
|
||||
Frustum {
|
||||
left: Plane::from_abcd(one!(T), zero!(T), zero!(T), self.left),
|
||||
right: Plane::from_abcd(-one!(T), zero!(T), zero!(T), self.right),
|
||||
bottom: Plane::from_abcd(zero!(T), one!(T), zero!(T), self.bottom),
|
||||
top: Plane::from_abcd(zero!(T), -one!(T), zero!(T), self.top),
|
||||
near: Plane::from_abcd(zero!(T), zero!(T), -one!(T), self.near),
|
||||
far: Plane::from_abcd(zero!(T), zero!(T), one!(T), self.far),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
47
src/ray.rs
Normal file
47
src/ray.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2013 The Lmath Developers. For a full listing of the authors,
|
||||
// refer to the AUTHORS file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use vec::Vec3;
|
||||
use point::Point3;
|
||||
|
||||
/// A three-dimensional ray
|
||||
///
|
||||
/// # Fields
|
||||
///
|
||||
/// - `pos`: the endpoint of the ray
|
||||
/// - `dir`: the direction vector
|
||||
#[deriving(Eq)]
|
||||
pub struct Ray3<T> {
|
||||
pos: Point3<T>,
|
||||
dir: Vec3<T>,
|
||||
}
|
||||
|
||||
impl<T:Copy + Eq + ApproxEq<T>> ApproxEq<T> for Ray3<T> {
|
||||
#[inline]
|
||||
pub fn approx_epsilon() -> T {
|
||||
ApproxEq::approx_epsilon::<T,T>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn approx_eq(&self, other: &Ray3<T>) -> bool {
|
||||
self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn approx_eq_eps(&self, other: &Ray3<T>, epsilon: &T) -> bool {
|
||||
self.pos.approx_eq_eps(&other.pos, epsilon) &&
|
||||
self.dir.approx_eq_eps(&other.dir, epsilon)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue