use cgmath;
use mint;
use hub::{Hub, SubNode};
use object;
use std::ops;
#[derive(Clone, Debug, PartialEq)]
pub enum ZRange {
Finite(ops::Range<f32>),
Infinite(ops::RangeFrom<f32>),
}
impl From<ops::Range<f32>> for ZRange {
fn from(range: ops::Range<f32>) -> ZRange {
ZRange::Finite(range)
}
}
impl From<ops::RangeFrom<f32>> for ZRange {
fn from(range: ops::RangeFrom<f32>) -> ZRange {
ZRange::Infinite(range)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Projection {
Orthographic(Orthographic),
Perspective(Perspective),
}
#[derive(Clone, Debug, PartialEq)]
pub struct Camera {
object: object::Base,
pub projection: Projection,
}
three_object!(Camera::object);
impl Camera {
pub(crate) fn new(hub: &mut Hub, projection: Projection) -> Self {
Camera {
object: hub.spawn(SubNode::Empty),
projection,
}
}
pub fn matrix(
&self,
aspect_ratio: f32,
) -> mint::ColumnMatrix4<f32> {
self.projection.matrix(aspect_ratio)
}
}
impl Projection {
pub fn orthographic<P>(
center: P,
extent_y: f32,
range: ops::Range<f32>,
) -> Self
where
P: Into<mint::Point2<f32>>,
{
let center = center.into();
Projection::Orthographic(Orthographic {
center,
extent_y,
range,
})
}
pub fn perspective<R>(
fov_y: f32,
range: R,
) -> Self
where
R: Into<ZRange>,
{
Projection::Perspective(Perspective {
fov_y,
zrange: range.into(),
})
}
pub fn matrix(
&self,
aspect_ratio: f32,
) -> mint::ColumnMatrix4<f32> {
match *self {
Projection::Orthographic(ref x) => x.matrix(aspect_ratio),
Projection::Perspective(ref x) => x.matrix(aspect_ratio),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Orthographic {
pub center: mint::Point2<f32>,
pub extent_y: f32,
pub range: ops::Range<f32>,
}
impl Orthographic {
pub fn matrix(
&self,
aspect_ratio: f32,
) -> mint::ColumnMatrix4<f32> {
let extent_x = aspect_ratio * self.extent_y;
cgmath::ortho(
self.center.x - extent_x,
self.center.x + extent_x,
self.center.y - self.extent_y,
self.center.y + self.extent_y,
self.range.start,
self.range.end,
).into()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Perspective {
pub fov_y: f32,
pub zrange: ZRange,
}
impl Perspective {
pub fn matrix(
&self,
aspect_ratio: f32,
) -> mint::ColumnMatrix4<f32> {
match self.zrange {
ZRange::Finite(ref range) => cgmath::perspective(
cgmath::Deg(self.fov_y),
aspect_ratio,
range.start,
range.end,
).into(),
ZRange::Infinite(ref range) => {
let m00 = 1.0 / (aspect_ratio * f32::tan(0.5 * self.fov_y));
let m11 = 1.0 / f32::tan(0.5 * self.fov_y);
let m22 = -1.0;
let m23 = -2.0 * range.start;
let m32 = -1.0;
let m = [
[m00, 0.0, 0.0, 0.0],
[0.0, m11, 0.0, 0.0],
[0.0, 0.0, m22, m23],
[0.0, 0.0, m32, 0.0],
];
m.into()
}
}
}
}