use std;
use math_utils as math;
use glium;
use crate::{Camera2d, Camera3d};
use crate::render::params;
#[derive(Debug)]
pub struct Viewport {
rect : glium::Rect,
camera2d : Option <Camera2d>,
camera3d : Option <Camera3d>
}
pub struct Builder {
rect : glium::Rect,
camera_2d : bool,
camera_3d : bool,
orthographic_3d : Option <f32>,
pose_3d : Option <math::Pose3 <f32>>,
position_2d : Option <math::Point2 <f32>>,
zoom_2d : Option <f32>
}
impl Viewport {
pub fn new (rect : glium::Rect) -> Self {
assert!(rect.width <= std::u16::MAX as u32);
assert!(rect.height <= std::u16::MAX as u32);
Viewport {
rect,
camera2d: Some (Camera2d::new (rect.width as u16, rect.height as u16)),
camera3d: Some (Camera3d::new (rect.width as u16, rect.height as u16))
}
}
pub fn with_pose_3d (
rect : glium::Rect,
pose : math::Pose3 <f32>
) -> Self {
assert!(rect.width <= std::u16::MAX as u32);
assert!(rect.height <= std::u16::MAX as u32);
Viewport {
rect,
camera2d: Some (Camera2d::new (rect.width as u16, rect.height as u16)),
camera3d: Some (Camera3d::with_pose (
rect.width as u16, rect.height as u16,
pose
))
}
}
pub fn rect (&self) -> &glium::Rect {
&self.rect
}
pub fn camera2d (&self) -> Option <&Camera2d> {
self.camera2d.as_ref()
}
pub fn camera3d (&self) -> Option <&Camera3d> {
self.camera3d.as_ref()
}
pub fn set_rect (&mut self, rect : glium::Rect) {
assert!(rect.width <= std::u16::MAX as u32);
assert!(rect.height <= std::u16::MAX as u32);
self.rect = rect;
self.camera2d.as_mut().map (|camera2d|
camera2d.set_viewport_dimensions (rect.width as u16, rect.height as u16));
self.camera3d.as_mut().map (|camera3d|
camera3d.set_viewport_dimensions (rect.width as u16, rect.height as u16));
}
pub fn camera2d_set_position (&mut self, position : math::Point2 <f32>) {
self.camera2d.as_mut().unwrap().set_position (position)
}
pub fn camera2d_set_zoom (&mut self, zoom : f32) {
self.camera2d.as_mut().unwrap().set_zoom (zoom)
}
pub fn camera2d_move_local (&mut self, dx : f32, dy : f32) {
self.camera2d.as_mut().unwrap().move_local (dx, dy)
}
pub fn camera2d_move_origin_to_bottom_left (&mut self) {
self.camera2d.as_mut().unwrap().move_origin_to_bottom_left()
}
pub fn camera3d_set_position (&mut self, position : math::Point3 <f32>) {
self.camera3d.as_mut().unwrap().set_position (position)
}
pub fn camera3d_set_orientation (&mut self,
orientation : math::Rotation3 <f32>
) {
self.camera3d.as_mut().unwrap().set_orientation (orientation)
}
pub fn camera3d_look_at (&mut self, target : math::Point3 <f32>) {
self.camera3d.as_mut().unwrap().look_at (target)
}
pub fn camera3d_move_local_xy (&mut self, dx : f32, dy : f32, dz : f32) {
self.camera3d.as_mut().unwrap().move_local_xy (dx, dy, dz)
}
pub fn camera3d_rotate (&mut self,
dyaw : math::Rad <f32>, dpitch : math::Rad <f32>, droll : math::Rad <f32>
) {
self.camera3d.as_mut().unwrap().rotate (dyaw, dpitch, droll)
}
pub fn camera3d_scale_fovy_or_zoom (&mut self, zoom : f32) {
self.camera3d.as_mut().unwrap().scale_fovy_or_zoom (zoom)
}
#[allow(mismatched_lifetime_syntaxes)]
pub fn draw_parameters (&self) -> glium::DrawParameters {
glium::DrawParameters {
viewport: Some (self.rect),
.. Default::default()
}
}
#[allow(mismatched_lifetime_syntaxes)]
pub fn draw_parameters_blend_invert (&self) -> glium::DrawParameters {
glium::DrawParameters {
blend: params::BLEND_FUNC_INVERT_COLOR,
.. self.draw_parameters()
}
}
}
impl Builder {
#[inline]
pub fn new (rect : glium::Rect) -> Self {
Builder {
rect,
camera_2d: true,
camera_3d: true,
orthographic_3d: None,
pose_3d: None,
position_2d: None,
zoom_2d: None
}
}
pub fn with_camera_2d (self, camera_2d : bool) -> Self {
Builder { camera_2d, .. self }
}
pub fn with_camera_3d (self, camera_3d : bool) -> Self {
Builder { camera_3d, .. self }
}
pub fn with_zoom_2d (self, zoom : f32) -> Self {
Builder { zoom_2d: Some (zoom), .. self }
}
pub fn with_position_2d (self, position_2d : math::Point2 <f32>) -> Self {
Builder { position_2d: Some (position_2d), .. self }
}
pub fn orthographic_3d (self, zoom : f32) -> Self {
Builder { orthographic_3d: Some (zoom), .. self }
}
pub fn with_pose_3d (self, pose_3d : math::Pose3 <f32>) -> Self {
Builder { pose_3d: Some (pose_3d), .. self }
}
#[inline]
pub fn build (self) -> Viewport {
let mut viewport = if let Some (pose_3d) = self.pose_3d {
Viewport::with_pose_3d (self.rect, pose_3d)
} else {
Viewport::new (self.rect)
};
if self.camera_2d {
if let Some (position) = self.position_2d {
viewport.camera2d.as_mut().unwrap().set_position (position);
}
if let Some (zoom) = self.zoom_2d {
viewport.camera2d.as_mut().unwrap().set_zoom (zoom);
}
} else {
let _ = viewport.camera2d.take();
}
if self.camera_3d {
if let Some (zoom) = self.orthographic_3d {
viewport.camera3d.as_mut().unwrap().to_orthographic (zoom);
}
} else {
let _ = viewport.camera3d.take();
}
viewport
}
}
#[cfg(test)]
mod tests {
use super::*;
use glium;
#[test]
fn viewport_matrices() {
let viewport = Viewport::new (
glium::Rect { left: 0, bottom: 0, width: 1600, height: 900 }
);
let (transform_view_matrix, projection_ortho_matrix) =
viewport.camera2d().unwrap().view_ortho_mats();
println!("transform view matrix:\n{:#?}", transform_view_matrix);
println!("projection ortho matrix:\n{:#?}", projection_ortho_matrix);
}
}