diff --git a/src/structs/iso.rs b/src/structs/iso.rs index e401fa7f..a96584ef 100644 --- a/src/structs/iso.rs +++ b/src/structs/iso.rs @@ -16,7 +16,7 @@ use structs::rot::{Rot2, Rot3}; use quickcheck::{Arbitrary, Gen}; -/// Two dimensional isometry. +/// Two dimensional **direct** isometry. /// /// This is the composition of a rotation followed by a translation. Vectors `Vec2` are not /// affected by the translational component of this transformation while points `Pnt2` are. @@ -30,7 +30,7 @@ pub struct Iso2 { pub translation: Vec2 } -/// Three dimensional isometry. +/// Three dimensional **direct** isometry. /// /// This is the composition of a rotation followed by a translation. Vectors `Vec3` are not /// affected by the translational component of this transformation while points `Pnt3` are. @@ -62,20 +62,40 @@ impl Iso3 { Iso3::new_with_rotmat(eye.as_vec().clone(), new_rotmat) } - /// Builds a look-at view matrix. + /// Builds a right-handed look-at view matrix. /// - /// This conforms to the common notion of "look-at" matrix from the computer graphics - /// community. Its maps the view direction `target - eye` to the **negative** `z` axis and the - /// `eye` to the origin. + /// This conforms to the common notion of right handed look-at matrix from the computer + /// graphics community. /// /// # Arguments /// * eye - The eye position. /// * target - The target position. - /// * up - The vertical view direction. It must not be to collinear to `eye - target`. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn new_look_at(eye: &Pnt3, target: &Pnt3, up: &Vec3) -> Iso3 { - let new_rotmat = Rot3::new_look_at(&(*target - *eye), up); - Iso3::new_with_rotmat(new_rotmat * (-*eye.as_vec()), new_rotmat) + pub fn look_at_rh(eye: &Pnt3, target: &Pnt3, up: &Vec3) -> Iso3 { + let rot = Rot3::look_at_rh(&(*target - *eye), up); + let trans = rot * (-*eye); + + Iso3::new_with_rotmat(trans.to_vec(), rot) + } + + /// Builds a left-handed look-at view matrix. + /// + /// This conforms to the common notion of left handed look-at matrix from the computer + /// graphics community. + /// + /// # Arguments + /// * eye - The eye position. + /// * target - The target position. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `target - eye`. + #[inline] + pub fn look_at_lh(eye: &Pnt3, target: &Pnt3, up: &Vec3) -> Iso3 { + let rot = Rot3::look_at_lh(&(*target - *eye), up); + let trans = rot * (-*eye); + + Iso3::new_with_rotmat(trans.to_vec(), rot) } } diff --git a/src/structs/ortho.rs b/src/structs/ortho.rs index e5018d2d..1bff6367 100644 --- a/src/structs/ortho.rs +++ b/src/structs/ortho.rs @@ -7,18 +7,24 @@ use quickcheck::{Arbitrary, Gen}; /// A 3D orthographic projection stored without any matrix. /// -/// Reading or modifying its individual properties is cheap but applying the transformation is costly. +/// This flips the `z` axis and maps a axis-aligned cube to the unit cube with corners varying from +/// `(-1, -1, -1)` to `(1, 1, 1)`. Reading or modifying its individual properties is cheap but +/// applying the transformation is costly. #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] pub struct Ortho3 { - width: N, - height: N, + left: N, + right: N, + bottom: N, + top: N, znear: N, zfar: N } /// A 3D orthographic projection stored as a 4D matrix. /// -/// Reading or modifying its individual properties is costly but applying the transformation is cheap. +/// This flips the `z` axis and maps a axis-aligned cube to the unit cube with corners varying from +/// `(-1, -1, -1)` to `(1, 1, 1)`. Reading or modifying its individual properties is costly but +/// applying the transformation is cheap. #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] pub struct OrthoMat3 { mat: Mat4 @@ -26,14 +32,16 @@ pub struct OrthoMat3 { impl Ortho3 { /// Creates a new 3D orthographic projection. - pub fn new(width: N, height: N, znear: N, zfar: N) -> Ortho3 { + pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Ortho3 { assert!(!::is_zero(&(zfar - znear))); - assert!(!::is_zero(&width)); - assert!(!::is_zero(&height)); + assert!(!::is_zero(&(left - right))); + assert!(!::is_zero(&(top - bottom))); Ortho3 { - width: width, - height: height, + left: left, + right: right, + bottom: bottom, + top: top, znear: znear, zfar: zfar } @@ -41,37 +49,51 @@ impl Ortho3 { /// Builds a 4D projection matrix (using homogeneous coordinates) for this projection. pub fn to_mat(&self) -> Mat4 { - self.to_ortho_mat().mat + self.to_persp_mat().mat } /// Build a `OrthoMat3` representing this projection. - pub fn to_ortho_mat(&self) -> OrthoMat3 { - OrthoMat3::new(self.width, self.height, self.znear, self.zfar) + pub fn to_persp_mat(&self) -> OrthoMat3 { + OrthoMat3::new(self.left, self.right, self.bottom, self.top, self.znear, self.zfar) } } #[cfg(feature="arbitrary")] impl Arbitrary for Ortho3 { fn arbitrary(g: &mut G) -> Ortho3 { - let width = reject(g, |x| !::is_zero(x)); - let height = reject(g, |x| !::is_zero(x)); - let znear = Arbitrary::arbitrary(g); - let zfar = reject(g, |&x: &N| !::is_zero(&(x - znear))); + let left = Arbitrary::arbitrary(g); + let right = reject(g, |x: &N| *x > left); + let bottom = Arbitrary::arbitrary(g); + let top = reject(g, |x: &N| *x > bottom); + let znear = Arbitrary::arbitrary(g); + let zfar = reject(g, |x: &N| *x > znear); Ortho3::new(width, height, znear, zfar) } } impl Ortho3 { - /// The width of the view cuboid. + /// The smallest x-coordinate of the view cuboid. #[inline] - pub fn width(&self) -> N { - self.width.clone() + pub fn left(&self) -> N { + self.left.clone() } - /// The height of the view cuboid. + /// The largest x-coordinate of the view cuboid. #[inline] - pub fn height(&self) -> N { - self.height.clone() + pub fn right(&self) -> N { + self.right.clone() + } + + /// The smallest y-coordinate of the view cuboid. + #[inline] + pub fn bottom(&self) -> N { + self.bottom.clone() + } + + /// The largest y-coordinate of the view cuboid. + #[inline] + pub fn top(&self) -> N { + self.top.clone() } /// The near plane offset of the view cuboid. @@ -86,27 +108,45 @@ impl Ortho3 { self.zfar.clone() } - /// Sets the width of the view cuboid. + /// Sets the smallest x-coordinate of the view cuboid. #[inline] - pub fn set_width(&mut self, width: N) { - self.width = width + pub fn set_left(&mut self, left: N) { + assert!(left < self.right, "The left corner must be farther than the right corner."); + self.left = left } - /// Sets the height of the view cuboid. + /// Sets the largest x-coordinate of the view cuboid. #[inline] - pub fn set_height(&mut self, height: N) { - self.height = height + pub fn set_right(&mut self, right: N) { + assert!(right > self.left, "The left corner must be farther than the right corner."); + self.right = right + } + + /// Sets the smallest y-coordinate of the view cuboid. + #[inline] + pub fn set_bottom(&mut self, bottom: N) { + assert!(bottom < self.top, "The top corner must be higher than the bottom corner."); + self.bottom = bottom + } + + /// Sets the largest y-coordinate of the view cuboid. + #[inline] + pub fn set_top(&mut self, top: N) { + assert!(top > self.bottom, "The top corner must be higher than the left corner."); + self.top = top } /// Sets the near plane offset of the view cuboid. #[inline] pub fn set_znear(&mut self, znear: N) { + assert!(znear < self.zfar, "The far plane must be farther than the near plane."); self.znear = znear } /// Sets the far plane offset of the view cuboid. #[inline] pub fn set_zfar(&mut self, zfar: N) { + assert!(zfar > self.znear, "The far plane must be farther than the near plane."); self.zfar = zfar } @@ -114,34 +154,47 @@ impl Ortho3 { #[inline] pub fn project_pnt(&self, p: &Pnt3) -> Pnt3 { // FIXME: optimize that - self.to_ortho_mat().project_pnt(p) + self.to_persp_mat().project_pnt(p) } /// Projects a vector. #[inline] pub fn project_vec(&self, p: &Vec3) -> Vec3 { // FIXME: optimize that - self.to_ortho_mat().project_vec(p) + self.to_persp_mat().project_vec(p) } } impl OrthoMat3 { - /// Creates a new orthographic projection matrix from the width, heihgt, znear and zfar planes of the view cuboid. - pub fn new(width: N, height: N, znear: N, zfar: N) -> OrthoMat3 { - assert!(!::is_zero(&(zfar - znear))); - assert!(!::is_zero(&width)); - assert!(!::is_zero(&height)); + /// Creates a new orthographic projection matrix. + pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> OrthoMat3 { + assert!(left < right, "The left corner must be farther than the right corner."); + assert!(bottom < top, "The top corner must be higher than the bottom corner."); + assert!(znear < zfar, "The far plane must be farther than the near plane."); let mat: Mat4 = ::one(); let mut res = OrthoMat3 { mat: mat }; - res.set_width(width); - res.set_height(height); + res.set_left_and_right(left, right); + res.set_bottom_and_top(bottom, top); res.set_znear_and_zfar(znear, zfar); res } + /// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view. + pub fn new_with_fov(aspect: N, vfov: N, znear: N, zfar: N) -> OrthoMat3 { + assert!(znear < zfar, "The far plane must be farther than the near plane."); + assert!(!::is_zero(&aspect)); + + let _1: N = ::one(); + let _2 = _1 + _1; + let width = zfar * (vfov / _2).tan(); + let height = width / aspect; + + OrthoMat3::new(-width / _2, width / _2, -height / _2, height / _2, znear, zfar) + } + /// Creates a new orthographic matrix from a 4D matrix. /// /// This is unsafe because the input matrix is not checked to be a orthographic projection. @@ -158,42 +211,68 @@ impl OrthoMat3 { &self.mat } - /// The width of the view cuboid. + /// The smallest x-coordinate of the view cuboid. #[inline] - pub fn width(&self) -> N { - >::from(2.0) / self.mat.m11 + pub fn left(&self) -> N { + (-::one::() - self.mat.m14) / self.mat.m11 } - /// The height of the view cuboid. + /// The largest x-coordinate of the view cuboid. #[inline] - pub fn height(&self) -> N { - >::from(2.0) / self.mat.m22 + pub fn right(&self) -> N { + (::one::() - self.mat.m14) / self.mat.m11 + } + + /// The smallest y-coordinate of the view cuboid. + #[inline] + pub fn bottom(&self) -> N { + (-::one::() - self.mat.m24) / self.mat.m22 + } + + /// The largest y-coordinate of the view cuboid. + #[inline] + pub fn top(&self) -> N { + (::one::() - self.mat.m24) / self.mat.m22 } /// The near plane offset of the view cuboid. #[inline] pub fn znear(&self) -> N { - (self.mat.m34 + ::one()) / self.mat.m33 + (::one::() + self.mat.m34) / self.mat.m33 } /// The far plane offset of the view cuboid. #[inline] pub fn zfar(&self) -> N { - (self.mat.m34 - ::one()) / self.mat.m33 + (-::one::() + self.mat.m34) / self.mat.m33 } - /// Sets the width of the view cuboid. + /// Sets the smallest x-coordinate of the view cuboid. #[inline] - pub fn set_width(&mut self, width: N) { - assert!(!::is_zero(&width)); - self.mat.m11 = >::from(2.0) / width; + pub fn set_left(&mut self, left: N) { + let right = self.right(); + self.set_left_and_right(left, right); } - /// Sets the height of the view cuboid. + /// Sets the largest x-coordinate of the view cuboid. #[inline] - pub fn set_height(&mut self, height: N) { - assert!(!::is_zero(&height)); - self.mat.m22 = >::from(2.0) / height; + pub fn set_right(&mut self, right: N) { + let left = self.left(); + self.set_left_and_right(left, right); + } + + /// Sets the smallest y-coordinate of the view cuboid. + #[inline] + pub fn set_bottom(&mut self, bottom: N) { + let top = self.top(); + self.set_bottom_and_top(bottom, top); + } + + /// Sets the largest y-coordinate of the view cuboid. + #[inline] + pub fn set_top(&mut self, top: N) { + let bottom = self.bottom(); + self.set_bottom_and_top(bottom, top); } /// Sets the near plane offset of the view cuboid. @@ -210,6 +289,22 @@ impl OrthoMat3 { self.set_znear_and_zfar(znear, zfar); } + /// Sets the view cuboid coordinates along the `x` axis. + #[inline] + pub fn set_left_and_right(&mut self, left: N, right: N) { + assert!(left < right, "The left corner must be farther than the right corner."); + self.mat.m11 = >::from(2.0) / (right - left); + self.mat.m14 = -(right + left) / (right - left); + } + + /// Sets the view cuboid coordinates along the `y` axis. + #[inline] + pub fn set_bottom_and_top(&mut self, bottom: N, top: N) { + assert!(bottom < top, "The top corner must be higher than the bottom corner."); + self.mat.m22 = >::from(2.0) / (top - bottom); + self.mat.m24 = -(top + bottom) / (top - bottom); + } + /// Sets the near and far plane offsets of the view cuboid. #[inline] pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) { @@ -222,8 +317,8 @@ impl OrthoMat3 { #[inline] pub fn project_pnt(&self, p: &Pnt3) -> Pnt3 { Pnt3::new( - self.mat.m11 * p.x, - self.mat.m22 * p.y, + self.mat.m11 * p.x + self.mat.m14, + self.mat.m22 * p.y + self.mat.m24, self.mat.m33 * p.z + self.mat.m34 ) } @@ -251,7 +346,7 @@ impl OrthoMat3 { impl Arbitrary for OrthoMat3 { fn arbitrary(g: &mut G) -> OrthoMat3 { let x: Ortho3 = Arbitrary::arbitrary(g); - x.to_ortho_mat() + x.to_persp_mat() } } diff --git a/src/structs/persp.rs b/src/structs/persp.rs index af9289cd..b9d70dda 100644 --- a/src/structs/persp.rs +++ b/src/structs/persp.rs @@ -7,18 +7,22 @@ use quickcheck::{Arbitrary, Gen}; /// A 3D perspective projection stored without any matrix. /// -/// Reading or modifying its individual properties is cheap but applying the transformation is costly. +/// This maps a frustrum cube to the unit cube with corners varying from `(-1, -1, -1)` to +/// `(1, 1, 1)`. Reading or modifying its individual properties is cheap but applying the +/// transformation is costly. #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] pub struct Persp3 { aspect: N, - fov: N, + fovy: N, znear: N, zfar: N } /// A 3D perspective projection stored as a 4D matrix. /// -/// Reading or modifying its individual properties is costly but applying the transformation is cheap. +/// This maps a frustrum to the unit cube with corners varying from `(-1, -1, -1)` to +/// `(1, 1, 1)`. Reading or modifying its individual properties is costly but applying the +/// transformation is cheap. #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] pub struct PerspMat3 { mat: Mat4 @@ -26,13 +30,13 @@ pub struct PerspMat3 { impl Persp3 { /// Creates a new 3D perspective projection. - pub fn new(aspect: N, fov: N, znear: N, zfar: N) -> Persp3 { + pub fn new(aspect: N, fovy: N, znear: N, zfar: N) -> Persp3 { assert!(!::is_zero(&(zfar - znear))); assert!(!::is_zero(&aspect)); Persp3 { aspect: aspect, - fov: fov, + fovy: fovy, znear: znear, zfar: zfar } @@ -45,7 +49,7 @@ impl Persp3 { /// Build a `PerspMat3` representing this projection. pub fn to_persp_mat(&self) -> PerspMat3 { - PerspMat3::new(self.aspect, self.fov, self.znear, self.zfar) + PerspMat3::new(self.aspect, self.fovy, self.znear, self.zfar) } } @@ -66,10 +70,10 @@ impl Persp3 { self.aspect.clone() } - /// Gets the field of view of the view frustrum. + /// Gets the y field of view of the view frustrum. #[inline] - pub fn fov(&self) -> N { - self.fov.clone() + pub fn fovy(&self) -> N { + self.fovy.clone() } /// Gets the near plane offset of the view frustrum. @@ -92,12 +96,12 @@ impl Persp3 { self.aspect = aspect; } - /// Sets the field of view of the view frustrum. + /// Sets the y field of view of the view frustrum. /// /// This method does not build any matrix. #[inline] - pub fn set_fov(&mut self, fov: N) { - self.fov = fov; + pub fn set_fovy(&mut self, fovy: N) { + self.fovy = fovy; } /// Sets the near plane offset of the view frustrum. @@ -132,19 +136,19 @@ impl Persp3 { } impl PerspMat3 { - /// Creates a new persepctive matrix from the aspect ratio, field of view, and near/far planes. - pub fn new(aspect: N, fov: N, znear: N, zfar: N) -> PerspMat3 { + /// Creates a new perspective matrix from the aspect ratio, y field of view, and near/far planes. + pub fn new(aspect: N, fovy: N, znear: N, zfar: N) -> PerspMat3 { assert!(!::is_zero(&(znear - zfar))); assert!(!::is_zero(&aspect)); let mat: Mat4 = ::one(); let mut res = PerspMat3 { mat: mat }; - res.set_fov(fov); + res.set_fovy(fovy); res.set_aspect(aspect); res.set_znear_and_zfar(znear, zfar); res.mat.m44 = ::zero(); - res.mat.m43 = ::one(); + res.mat.m43 = -::one::(); res } @@ -168,12 +172,12 @@ impl PerspMat3 { /// Gets the `width / height` aspect ratio of the view frustrum. #[inline] pub fn aspect(&self) -> N { - -self.mat.m22 / self.mat.m11 + self.mat.m22 / self.mat.m11 } - /// Gets the field of view of the view frustrum. + /// Gets the y field of view of the view frustrum. #[inline] - pub fn fov(&self) -> N { + pub fn fovy(&self) -> N { let _1: N = ::one(); let _2 = _1 + _1; @@ -185,7 +189,7 @@ impl PerspMat3 { pub fn znear(&self) -> N { let _1: N = ::one(); let _2 = _1 + _1; - let ratio = (self.mat.m33 + _1) / (self.mat.m33 - _1); + let ratio = (-self.mat.m33 + _1) / (-self.mat.m33 - _1); self.mat.m34 / (_2 * ratio) - self.mat.m34 / _2 } @@ -195,29 +199,29 @@ impl PerspMat3 { pub fn zfar(&self) -> N { let _1: N = ::one(); let _2 = _1 + _1; - let ratio = (self.mat.m33 + _1) / (self.mat.m33 - _1); + let ratio = (-self.mat.m33 + _1) / (-self.mat.m33 - _1); (self.mat.m34 - ratio * self.mat.m34) / _2 } - // FIXME: add a method to retriev znear and zfar at once ? + // FIXME: add a method to retrieve znear and zfar simultaneously? /// Updates this projection matrix with a new `width / height` aspect ratio of the view /// frustrum. #[inline] pub fn set_aspect(&mut self, aspect: N) { assert!(!::is_zero(&aspect)); - self.mat.m11 = -self.mat.m22 / aspect; + self.mat.m11 = self.mat.m22 / aspect; } - /// Updates this projection with a new field of view of the view frustrum. + /// Updates this projection with a new y field of view of the view frustrum. #[inline] - pub fn set_fov(&mut self, fov: N) { + pub fn set_fovy(&mut self, fovy: N) { let _1: N = ::one(); let _2 = _1 + _1; let old_m22 = self.mat.m22.clone(); - self.mat.m22 = _1 / (fov / _2).tan(); + self.mat.m22 = _1 / (fovy / _2).tan(); self.mat.m11 = self.mat.m11 * (self.mat.m22 / old_m22); } @@ -241,7 +245,7 @@ impl PerspMat3 { let _1: N = ::one(); let _2 = _1 + _1; - self.mat.m33 = -(zfar + znear) / (znear - zfar); + self.mat.m33 = (zfar + znear) / (znear - zfar); self.mat.m34 = zfar * znear * _2 / (znear - zfar); } @@ -249,7 +253,7 @@ impl PerspMat3 { #[inline] pub fn project_pnt(&self, p: &Pnt3) -> Pnt3 { let _1: N = ::one(); - let inv_denom = _1 / p.z; + let inv_denom = -_1 / p.z; Pnt3::new( self.mat.m11 * p.x * inv_denom, self.mat.m22 * p.y * inv_denom, @@ -261,7 +265,7 @@ impl PerspMat3 { #[inline] pub fn project_vec(&self, p: &Vec3) -> Vec3 { let _1: N = ::one(); - let inv_denom = _1 / p.z; + let inv_denom = -_1 / p.z; Vec3::new( self.mat.m11 * p.x * inv_denom, self.mat.m22 * p.y * inv_denom, diff --git a/src/structs/rot.rs b/src/structs/rot.rs index cd1c77ce..40ef54de 100644 --- a/src/structs/rot.rs +++ b/src/structs/rot.rs @@ -218,19 +218,36 @@ impl Rot3 { } } - /// Builds a look-at view matrix with no translational component. + + /// Builds a right-handed look-at view matrix without translation. /// - /// This conforms to the common notion of "look-at" matrix from the computer graphics community. - /// Its maps the view direction `dir` to the **negative** `z` axis. + /// This conforms to the common notion of right handed look-at matrix from the computer + /// graphics community. /// /// # Arguments - /// * dir - The view direction. - /// * up - The vertical direction. The only requirement of this parameter is to not be - /// collinear to `dir`. + /// * eye - The eye position. + /// * target - The target position. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn new_look_at(dir: &Vec3, up: &Vec3) -> Rot3 { + pub fn look_at_rh(dir: &Vec3, up: &Vec3) -> Rot3 { Rot3::new_observer_frame(&(-*dir), up).inv().unwrap() } + + /// Builds a left-handed look-at view matrix without translation. + /// + /// This conforms to the common notion of left handed look-at matrix from the computer + /// graphics community. + /// + /// # Arguments + /// * eye - The eye position. + /// * target - The target position. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `target - eye`. + #[inline] + pub fn look_at_lh(dir: &Vec3, up: &Vec3) -> Rot3 { + Rot3::new_observer_frame(&(*dir), up).inv().unwrap() + } } impl> diff --git a/tests/transforms.rs b/tests/transforms.rs index 3b7ec6cb..8db23131 100644 --- a/tests/transforms.rs +++ b/tests/transforms.rs @@ -2,8 +2,8 @@ extern crate nalgebra as na; extern crate rand; use rand::random; -use na::{Pnt2, Pnt3, Vec2, Vec3, Vec1, Rot2, Rot3, Persp3, PerspMat3, Ortho3, OrthoMat3, Iso2, - Iso3, Sim2, Sim3, BaseFloat, Transform}; +use na::{Pnt2, Pnt3, Vec2, Vec3, Vec1, Rot2, Rot3, Persp3, PerspMat3, Ortho3, OrthoMat3, + Iso2, Iso3, Sim2, Sim3, BaseFloat, Transform}; #[test] fn test_rotation2() { @@ -71,25 +71,27 @@ fn test_rot2_angle_between() { #[test] -fn test_look_at_iso3() { +fn test_look_at_rh_iso3() { for _ in 0usize .. 10000 { let eye = random::>(); let target = random::>(); let up = random::>(); - let viewmat = Iso3::new_look_at(&eye, &target, &up); + let viewmat = Iso3::look_at_rh(&eye, &target, &up); - assert_eq!(&(viewmat * eye), &na::orig()); + let origin: Pnt3 = na::orig(); + assert_eq!(&(viewmat * eye), &origin); assert!(na::approx_eq(&na::normalize(&(viewmat * (target - eye))), &-Vec3::z())); } } #[test] -fn test_look_at_rot3() { +fn test_look_at_rh_rot3() { for _ in 0usize .. 10000 { let dir = random::>(); let up = random::>(); - let viewmat = Rot3::new_look_at(&dir, &up); + let viewmat = Rot3::look_at_rh(&dir, &up); + println!("found: {}", viewmat * dir); assert!(na::approx_eq(&na::normalize(&(viewmat * dir)), &-Vec3::z())); } } @@ -124,16 +126,16 @@ fn test_persp() { let mut pm = PerspMat3::new(42.0f64, 0.5, 1.5, 10.0); assert!(p.to_mat() == pm.to_mat()); assert!(p.aspect() == 42.0); - assert!(p.fov() == 0.5); + assert!(p.fovy() == 0.5); assert!(p.znear() == 1.5); assert!(p.zfar() == 10.0); assert!(na::approx_eq(&pm.aspect(), &42.0)); - assert!(na::approx_eq(&pm.fov(), &0.5)); + assert!(na::approx_eq(&pm.fovy(), &0.5)); assert!(na::approx_eq(&pm.znear(), &1.5)); assert!(na::approx_eq(&pm.zfar(), &10.0)); - p.set_fov(0.1); - pm.set_fov(0.1); + p.set_fovy(0.1); + pm.set_fovy(0.1); assert!(na::approx_eq(&p.to_mat(), pm.as_mat())); p.set_znear(24.0); @@ -149,52 +151,60 @@ fn test_persp() { assert!(na::approx_eq(&p.to_mat(), pm.as_mat())); assert!(p.aspect() == 23.0); - assert!(p.fov() == 0.1); + assert!(p.fovy() == 0.1); assert!(p.znear() == 24.0); assert!(p.zfar() == 61.0); assert!(na::approx_eq(&pm.aspect(), &23.0)); - assert!(na::approx_eq(&pm.fov(), &0.1)); + assert!(na::approx_eq(&pm.fovy(), &0.1)); assert!(na::approx_eq(&pm.znear(), &24.0)); assert!(na::approx_eq(&pm.zfar(), &61.0)); } #[test] fn test_ortho() { - let mut p = Ortho3::new(42.0f64, 0.5, 1.5, 10.0); - let mut pm = OrthoMat3::new(42.0f64, 0.5, 1.5, 10.0); + let mut p = Ortho3::new(-0.3, 5.2, -3.9, -1.0, 1.5, 10.0); + let mut pm = OrthoMat3::new(-0.3, 5.2, -3.9, -1.0, 1.5, 10.0); assert!(p.to_mat() == pm.to_mat()); - assert!(p.width() == 42.0); - assert!(p.height() == 0.5); + assert!(p.left() == -0.3); + assert!(p.right() == 5.2); + assert!(p.bottom() == -3.9); + assert!(p.top() == -1.0); assert!(p.znear() == 1.5); assert!(p.zfar() == 10.0); - assert!(na::approx_eq(&pm.width(), &42.0)); - assert!(na::approx_eq(&pm.height(), &0.5)); + assert!(na::approx_eq(&pm.left(), &-0.3)); + assert!(na::approx_eq(&pm.right(), &5.2)); + assert!(na::approx_eq(&pm.bottom(), &-3.9)); + assert!(na::approx_eq(&pm.top(), &-1.0)); assert!(na::approx_eq(&pm.znear(), &1.5)); assert!(na::approx_eq(&pm.zfar(), &10.0)); - p.set_width(0.1); - pm.set_width(0.1); + p.set_left(0.1); + pm.set_left(0.1); assert!(na::approx_eq(&p.to_mat(), pm.as_mat())); - p.set_znear(24.0); - pm.set_znear(24.0); + p.set_right(10.1); + pm.set_right(10.1); + assert!(na::approx_eq(&p.to_mat(), pm.as_mat())); + + p.set_top(24.0); + pm.set_top(24.0); + assert!(na::approx_eq(&p.to_mat(), pm.as_mat())); + + p.set_bottom(-23.0); + pm.set_bottom(-23.0); assert!(na::approx_eq(&p.to_mat(), pm.as_mat())); p.set_zfar(61.0); pm.set_zfar(61.0); assert!(na::approx_eq(&p.to_mat(), pm.as_mat())); - p.set_height(23.0); - pm.set_height(23.0); + p.set_znear(21.0); + pm.set_znear(21.0); assert!(na::approx_eq(&p.to_mat(), pm.as_mat())); - assert!(p.height() == 23.0); - assert!(p.width() == 0.1); - assert!(p.znear() == 24.0); + assert!(p.znear() == 21.0); assert!(p.zfar() == 61.0); - assert!(na::approx_eq(&pm.height(), &23.0)); - assert!(na::approx_eq(&pm.width(), &0.1)); - assert!(na::approx_eq(&pm.znear(), &24.0)); + assert!(na::approx_eq(&pm.znear(), &21.0)); assert!(na::approx_eq(&pm.zfar(), &61.0)); }