1use num_traits::cast;
17use num_traits::Zero;
18
19use structure::Angle;
20
21use angle::Rad;
22use matrix::Matrix4;
23use num::BaseFloat;
24
25pub fn perspective<S: BaseFloat, A: Into<Rad<S>>>(
31 fovy: A,
32 aspect: S,
33 near: S,
34 far: S,
35) -> Matrix4<S> {
36 PerspectiveFov {
37 fovy: fovy.into(),
38 aspect: aspect,
39 near: near,
40 far: far,
41 }
42 .into()
43}
44
45pub fn frustum<S: BaseFloat>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Matrix4<S> {
51 Perspective {
52 left: left,
53 right: right,
54 bottom: bottom,
55 top: top,
56 near: near,
57 far: far,
58 }
59 .into()
60}
61
62pub fn ortho<S: BaseFloat>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Matrix4<S> {
68 Ortho {
69 left: left,
70 right: right,
71 bottom: bottom,
72 top: top,
73 near: near,
74 far: far,
75 }
76 .into()
77}
78
79#[derive(Copy, Clone, Debug, PartialEq)]
81#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
82#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
83pub struct PerspectiveFov<S> {
84 pub fovy: Rad<S>,
85 pub aspect: S,
86 pub near: S,
87 pub far: S,
88}
89
90impl<S: BaseFloat> PerspectiveFov<S> {
91 pub fn to_perspective(&self) -> Perspective<S> {
92 let two: S = cast(2).unwrap();
93 let angle = self.fovy / two;
94 let ymax = self.near * Rad::tan(angle);
95 let xmax = ymax * self.aspect;
96
97 Perspective {
98 left: -xmax,
99 right: xmax,
100 bottom: -ymax,
101 top: ymax,
102 near: self.near.clone(),
103 far: self.far.clone(),
104 }
105 }
106}
107
108impl<S: BaseFloat> From<PerspectiveFov<S>> for Matrix4<S> {
109 fn from(persp: PerspectiveFov<S>) -> Matrix4<S> {
110 assert!(
111 persp.fovy > Rad::zero(),
112 "The vertical field of view cannot be below zero, found: {:?}",
113 persp.fovy
114 );
115 assert!(
116 persp.fovy < Rad::turn_div_2(),
117 "The vertical field of view cannot be greater than a half turn, found: {:?}",
118 persp.fovy
119 );
120
121 assert!(
122 abs_diff_ne!(persp.aspect.abs(), S::zero()),
123 "The absolute aspect ratio cannot be zero, found: {:?}",
124 persp.aspect.abs()
125 );
126 assert!(
127 persp.near > S::zero(),
128 "The near plane distance cannot be below zero, found: {:?}",
129 persp.near
130 );
131 assert!(
132 persp.far > S::zero(),
133 "The far plane distance cannot be below zero, found: {:?}",
134 persp.far
135 );
136 assert!(
137 abs_diff_ne!(persp.far, persp.near),
138 "The far plane and near plane are too close, found: far: {:?}, near: {:?}",
139 persp.far,
140 persp.near
141 );
142
143 let two: S = cast(2).unwrap();
144 let f = Rad::cot(persp.fovy / two);
145
146 let c0r0 = f / persp.aspect;
147 let c0r1 = S::zero();
148 let c0r2 = S::zero();
149 let c0r3 = S::zero();
150
151 let c1r0 = S::zero();
152 let c1r1 = f;
153 let c1r2 = S::zero();
154 let c1r3 = S::zero();
155
156 let c2r0 = S::zero();
157 let c2r1 = S::zero();
158 let c2r2 = (persp.far + persp.near) / (persp.near - persp.far);
159 let c2r3 = -S::one();
160
161 let c3r0 = S::zero();
162 let c3r1 = S::zero();
163 let c3r2 = (two * persp.far * persp.near) / (persp.near - persp.far);
164 let c3r3 = S::zero();
165
166 #[cfg_attr(rustfmt, rustfmt_skip)]
167 Matrix4::new(
168 c0r0, c0r1, c0r2, c0r3,
169 c1r0, c1r1, c1r2, c1r3,
170 c2r0, c2r1, c2r2, c2r3,
171 c3r0, c3r1, c3r2, c3r3,
172 )
173 }
174}
175
176#[derive(Copy, Clone, Debug, PartialEq)]
178#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
179pub struct Perspective<S> {
180 pub left: S,
181 pub right: S,
182 pub bottom: S,
183 pub top: S,
184 pub near: S,
185 pub far: S,
186}
187
188impl<S: BaseFloat> From<Perspective<S>> for Matrix4<S> {
189 fn from(persp: Perspective<S>) -> Matrix4<S> {
190 assert!(
191 persp.left <= persp.right,
192 "`left` cannot be greater than `right`, found: left: {:?} right: {:?}",
193 persp.left,
194 persp.right
195 );
196 assert!(
197 persp.bottom <= persp.top,
198 "`bottom` cannot be greater than `top`, found: bottom: {:?} top: {:?}",
199 persp.bottom,
200 persp.top
201 );
202 assert!(
203 persp.near <= persp.far,
204 "`near` cannot be greater than `far`, found: near: {:?} far: {:?}",
205 persp.near,
206 persp.far
207 );
208
209 let two: S = cast(2i8).unwrap();
210
211 let c0r0 = (two * persp.near) / (persp.right - persp.left);
212 let c0r1 = S::zero();
213 let c0r2 = S::zero();
214 let c0r3 = S::zero();
215
216 let c1r0 = S::zero();
217 let c1r1 = (two * persp.near) / (persp.top - persp.bottom);
218 let c1r2 = S::zero();
219 let c1r3 = S::zero();
220
221 let c2r0 = (persp.right + persp.left) / (persp.right - persp.left);
222 let c2r1 = (persp.top + persp.bottom) / (persp.top - persp.bottom);
223 let c2r2 = -(persp.far + persp.near) / (persp.far - persp.near);
224 let c2r3 = -S::one();
225
226 let c3r0 = S::zero();
227 let c3r1 = S::zero();
228 let c3r2 = -(two * persp.far * persp.near) / (persp.far - persp.near);
229 let c3r3 = S::zero();
230
231 #[cfg_attr(rustfmt, rustfmt_skip)]
232 Matrix4::new(
233 c0r0, c0r1, c0r2, c0r3,
234 c1r0, c1r1, c1r2, c1r3,
235 c2r0, c2r1, c2r2, c2r3,
236 c3r0, c3r1, c3r2, c3r3,
237 )
238 }
239}
240
241#[derive(Copy, Clone, Debug, PartialEq)]
243#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
244pub struct Ortho<S> {
245 pub left: S,
246 pub right: S,
247 pub bottom: S,
248 pub top: S,
249 pub near: S,
250 pub far: S,
251}
252
253impl<S: BaseFloat> From<Ortho<S>> for Matrix4<S> {
254 fn from(ortho: Ortho<S>) -> Matrix4<S> {
255 let two: S = cast(2).unwrap();
256
257 let c0r0 = two / (ortho.right - ortho.left);
258 let c0r1 = S::zero();
259 let c0r2 = S::zero();
260 let c0r3 = S::zero();
261
262 let c1r0 = S::zero();
263 let c1r1 = two / (ortho.top - ortho.bottom);
264 let c1r2 = S::zero();
265 let c1r3 = S::zero();
266
267 let c2r0 = S::zero();
268 let c2r1 = S::zero();
269 let c2r2 = -two / (ortho.far - ortho.near);
270 let c2r3 = S::zero();
271
272 let c3r0 = -(ortho.right + ortho.left) / (ortho.right - ortho.left);
273 let c3r1 = -(ortho.top + ortho.bottom) / (ortho.top - ortho.bottom);
274 let c3r2 = -(ortho.far + ortho.near) / (ortho.far - ortho.near);
275 let c3r3 = S::one();
276
277 #[cfg_attr(rustfmt, rustfmt_skip)]
278 Matrix4::new(
279 c0r0, c0r1, c0r2, c0r3,
280 c1r0, c1r1, c1r2, c1r3,
281 c2r0, c2r1, c2r2, c2r3,
282 c3r0, c3r1, c3r2, c3r3,
283 )
284 }
285}