use super::{Projection, CoordinateOrigin, CameraExt, Node, NodeRef};
use rin_math::{
Rect, Pnt3, Vec4, Mat4, one, vec4, Deg, Pnt2, Translation, Translation2, Translation3,
UnitQuaternion, Rotation3, Isometry3, Isometry2, vec3, Rotation2, ToVec
};
#[cfg(feature="gl")]
use glin::program::Uniform;
#[cfg(feature="gl")]
use glin::{self, uniforms, UniformsLocationCache2};
use log::warn;
#[cfg(feature="serialize")]
use serde_derive::{Serialize, Deserialize};
#[derive(Clone, Debug)]
#[cfg_attr(feature="gl", derive(UniformsLocationCache2))]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct Mvp{
#[cfg_attr(feature="gl", not_uniform)]
camera: CameraMatrices,
#[cfg_attr(feature="gl", not_uniform)]
model: ModelMatrices,
#[cfg_attr(feature="gl", uniform(name="modelViewProjectionMatrix"))]
projection_view_model: Mat4,
#[cfg_attr(feature="gl", uniform(name="modelViewMatrix"))]
view_model: Mat4,
}
impl Mvp{
pub fn from_parts(projection: Mat4,
view: Mat4,
camera_pos: Pnt3,
near_plane: f32,
far_plane: f32,
clip_plane: Vec4,
origin: CoordinateOrigin,
viewport: Rect<i32>) -> Mvp
{
let camera = CameraMatrices::from_parts(projection, view, camera_pos, near_plane, far_plane, clip_plane, origin, viewport);
let model: Mat4 = one();
Mvp{
projection_view_model: *camera.projection_view(),
view_model: *camera.view(),
camera,
model: ModelMatrices::from_model(model),
}
}
pub fn with_camera_viewport<C: CameraExt + ?Sized>(camera: &C, viewport: Rect<i32>) -> Mvp{
let camera = CameraMatrices::with_camera_viewport(camera, viewport);
let model: Mat4 = one();
Mvp{
projection_view_model: *camera.projection_view(),
view_model: *camera.view(),
camera,
model: ModelMatrices::from_model(model),
}
}
pub fn with_camera_viewport_clip_plane<C: CameraExt + ?Sized>(camera: &C, viewport: Rect<i32>, clip_plane: Vec4) -> Mvp{
let camera = CameraMatrices::with_camera_viewport_clip_plane(camera, viewport, clip_plane);
let model: Mat4 = one();
Mvp{
projection_view_model: *camera.projection_view(),
view_model: *camera.view(),
camera,
model: ModelMatrices::from_model(model),
}
}
pub fn ortho_top_left(viewport: Rect<i32>) -> Mvp{
Mvp::from(&Projection::new_ortho(viewport, CoordinateOrigin::TopLeft))
}
pub fn ortho_bottom_left(viewport: Rect<i32>) -> Mvp{
Mvp::from(&Projection::new_ortho(viewport, CoordinateOrigin::BottomLeft))
}
pub fn perspective_top_left(viewport: Rect<i32>, fov: Deg<f32>) -> Mvp{
Mvp::from(&Projection::new_perspective(viewport, fov, CoordinateOrigin::TopLeft))
}
pub fn perspective_bottom_left(viewport: Rect<i32>, fov: Deg<f32>) -> Mvp{
Mvp::from(&Projection::new_perspective(viewport, fov, CoordinateOrigin::BottomLeft))
}
pub fn for_model<M: Into<Model>>(&self, model: M) -> Mvp{
let model = ModelMatrices::from_model(model);
let view_model = self.view() * model.model();
let projection_view_model = self.projection() * view_model;
Mvp{
camera: self.camera,
model: model,
projection_view_model: projection_view_model,
view_model: view_model,
}
}
pub fn for_model_normal<M: Into<Model>>(&self, model: M, normal: &Mat4) -> Mvp{
let model = ModelMatrices::from_model_normal(model, normal);
let view_model = self.view() * model.model();
let projection_view_model = self.projection() * view_model;
Mvp{
camera: self.camera,
model: model,
projection_view_model: projection_view_model,
view_model: view_model,
}
}
pub fn projection(&self) -> &Mat4{
self.camera.projection()
}
pub fn view(&self) -> &Mat4{
self.camera.view()
}
pub fn model(&self) -> &Mat4{
self.model.model()
}
pub fn projection_view(&self) -> &Mat4{
self.camera.projection_view()
}
pub fn projection_view_model(&self) -> &Mat4{
&self.projection_view_model
}
pub fn view_model(&self) -> &Mat4{
&self.view_model
}
pub fn normal(&self) -> &Mat4{
self.model.normal()
}
pub fn origin(&self) -> CoordinateOrigin{
self.camera.origin()
}
pub fn viewport(&self) -> &Rect<i32>{
self.camera.viewport()
}
pub fn clip_plane(&self) -> &Vec4{
self.camera.clip_plane()
}
pub fn camera_position(&self) -> &Pnt3 {
self.camera.camera_position()
}
pub fn near_plane(&self) -> f32 {
self.camera.near_plane()
}
pub fn far_plane(&self) -> f32 {
self.camera.far_plane()
}
#[cfg(feature="gl")]
pub fn uniforms(&self) -> Vec<Uniform>{
uniforms!{
modelViewProjectionMatrix: *self.projection_view_model(),
viewProjectionMatrix: *self.projection_view(),
modelViewMatrix: *self.view_model(),
projectionMatrix: *self.projection(),
viewMatrix: *self.view(),
modelMatrix: *self.model(),
normalMatrix: *self.normal(),
u_camera: self.camera_position().to_vec(),
near_plane: self.near_plane(),
far_plane: self.far_plane(),
clip_plane: *self.clip_plane(),
viewport: *self.viewport(),
}
}
#[cfg(feature="gl")]
pub fn uniforms_cache(program: &glin::Program) -> UniformsLocationCache{
Mvp::from_program_non_strict(program)
}
#[cfg(feature="gl")]
pub fn model_uniforms_cache(program: &glin::Program) -> ModelUniformsCache{
ModelMatrices::uniforms_cache(program)
}
#[cfg(feature="gl")]
pub fn camera_uniforms_cache(program: &glin::Program) -> CameraUniformsCache{
CameraMatrices::uniforms_cache(program)
}
pub fn camera_matrices_id(&self) -> usize{
self.camera.id()
}
pub fn model_matrices_id(&self) -> usize{
self.model.id()
}
pub fn camera_matrices(&self) -> &CameraMatrices{
&self.camera
}
pub fn model_matrices(&self) -> &ModelMatrices{
&self.model
}
}
impl<'a> From<&'a Projection> for Mvp{
fn from(projection: &'a Projection) -> Mvp{
let camera = CameraMatrices::from(projection);
let model: Mat4 = one();
Mvp{
model: ModelMatrices::from_model(model),
projection_view_model: *camera.projection_view(),
view_model: *camera.view(),
camera,
}
}
}
impl From<CameraMatrices> for Mvp{
fn from(camera: CameraMatrices) -> Mvp{
let model: Mat4 = one();
Mvp{
model: ModelMatrices::from_model(model),
projection_view_model: *camera.projection_view(),
view_model: *camera.view(),
camera,
}
}
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug)]
pub struct Model{
mat: Mat4
}
impl Model{
pub fn new() -> Model{
Model{
mat: one()
}
}
pub fn matrix(&self) -> &Mat4{
&self.mat
}
}
impl From<Mat4> for Model{
fn from(mat: Mat4) -> Model{
Model{
mat
}
}
}
impl From<Node> for Model{
fn from(node: Node) -> Model{
Model{
mat: node.global_transformation()
}
}
}
impl<'a> From<&'a Mat4> for Model{
fn from(mat: &Mat4) -> Model{
Model{
mat: mat.clone()
}
}
}
impl<'a, N: NodeRef> From<&'a N> for Model{
fn from(node: &N) -> Model{
Model{
mat: node.global_transformation()
}
}
}
impl<'a> From<&'a Pnt3> for Model{
fn from(pos: &Pnt3) -> Model{
Mat4::from_columns(&[
vec4!(1., 0., 0., 0.),
vec4!(0., 1., 0., 0.),
vec4!(0., 0., 1., 0.),
vec4!(pos.to_vec(), 1.),
]).into()
}
}
impl<'a> From<&'a Pnt2> for Model{
fn from(pos: &Pnt2) -> Model{
Mat4::from_columns(&[
vec4!(1., 0., 0., 0.),
vec4!(0., 1., 0., 0.),
vec4!(0., 0., 1., 0.),
vec4!(pos.to_vec(), 0., 1.),
]).into()
}
}
impl<'a> From<&'a Translation3<f32>> for Model{
fn from(t: &Translation3<f32>) -> Model{
Model{
mat: t.to_homogeneous()
}
}
}
impl<'a> From<&'a Rotation3<f32>> for Model{
fn from(r: &Rotation3<f32>) -> Model{
Model{
mat: r.to_homogeneous()
}
}
}
impl<'a> From<&'a Isometry3<f32>> for Model{
fn from(i: &Isometry3<f32>) -> Model{
Model{
mat: i.to_homogeneous()
}
}
}
impl<'a> From<&'a UnitQuaternion<f32>> for Model{
fn from(q: &UnitQuaternion<f32>) -> Model{
Model{
mat: q.to_homogeneous()
}
}
}
impl<'a> From<&'a Translation2<f32>> for Model{
fn from(t: &Translation2<f32>) -> Model{
Model{
mat: Translation::from(vec3!(t.vector, 0.))
.to_homogeneous()
}
}
}
impl<'a> From<&'a Rotation2<f32>> for Model{
fn from(r: &Rotation2<f32>) -> Model{
let mat = r.to_homogeneous();
Model{
mat: Mat4::from_columns(&[
vec4!(mat.column(0), 0.),
vec4!(mat.column(1), 0.),
vec4!(mat.column(2), 0.),
vec4!(0., 0., 0., 1.),
])}
}
}
impl<'a> From<&'a Isometry2<f32>> for Model{
fn from(i: &Isometry2<f32>) -> Model{
let mat = i.to_homogeneous();
Model{
mat: Mat4::from_columns(&[
vec4!(mat.column(0), 0.),
vec4!(mat.column(1), 0.),
vec4!(mat.column(2), 0.),
vec4!(0., 0., 0., 1.),
])}
}
}
mod camera{
use super::{Projection, CoordinateOrigin, CameraExt};
use rin_math::{
Rect, Pnt3, Vec4, Mat4, vec4, Deg, Vec3, ToVec, AsPnt
};
#[cfg(feature="gl")]
use glin::program::Uniform;
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(feature="gl")]
use glin::{self, uniforms, UniformsLocationCache2};
use std::f32;
use log::warn;
#[cfg(feature="serialize")]
use serde_derive::{Serialize, Deserialize};
static mut NEXT_ID: AtomicUsize = AtomicUsize::new(0);
fn next_id() -> usize{
unsafe{
NEXT_ID.fetch_add(1, Ordering::Relaxed)
}
}
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[repr(C)]
pub struct Data{
projection: Mat4,
projection_view: Mat4,
view: Mat4,
clip_plane: Vec4,
viewport: Rect<i32>,
camera_pos: Vec3,
near_plane: f32,
far_plane: f32,
padding: [f32;3],
}
#[cfg(feature="gl")]
#[derive(Clone, Copy, Debug, UniformsLocationCache2)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct CameraMatrices{
#[uniform(name="projectionMatrix")]
projection: Mat4,
#[uniform(name="viewProjectionMatrix")]
projection_view: Mat4,
#[uniform(name="viewMatrix")]
view: Mat4,
#[uniform(name="u_camera")]
camera_pos: Vec3,
#[uniform(name="near_plane")]
near_plane: f32,
#[uniform(name="far_plane")]
far_plane: f32,
#[uniform(name="clip_plane")]
clip_plane: Vec4,
#[uniform(name="viewport")]
viewport: Rect<i32>,
#[not_uniform]
origin: CoordinateOrigin,
#[not_uniform]
id: usize,
}
#[cfg(not(any(feature="gl", feature="gles", feature="webgl")))]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug)]
pub struct CameraMatrices{
projection: Mat4,
view: Mat4,
projection_view: Mat4,
camera_pos: Vec3,
near_plane: f32,
far_plane: f32,
clip_plane: Vec4,
viewport: Rect<i32>,
origin: CoordinateOrigin,
id: usize,
}
impl CameraMatrices{
pub fn from_parts(projection: Mat4,
view: Mat4,
camera_pos: Pnt3,
near_plane: f32,
far_plane: f32,
clip_plane: Vec4,
origin: CoordinateOrigin,
viewport: Rect<i32>) -> CameraMatrices
{
let projection_view = projection * view;
CameraMatrices{
id: next_id(),
projection: projection,
view: view,
projection_view,
origin,
viewport,
camera_pos: camera_pos.to_vec(),
near_plane,
far_plane,
clip_plane: clip_plane,
}
}
pub fn with_camera_viewport<C: CameraExt + ?Sized>(camera: &C, viewport: Rect<i32>) -> CameraMatrices{
let projection = camera.projection();
let view = camera.view();
let projection_view = camera.projection_view();
CameraMatrices{
id: next_id(),
projection: projection,
view: view,
projection_view,
origin: CoordinateOrigin::CenterUp,
viewport,
camera_pos: camera.global_position().to_vec(),
near_plane: camera.near_clip(),
far_plane: camera.far_clip().unwrap_or(f32::INFINITY),
clip_plane: vec4!(0.),
}
}
pub fn with_camera_viewport_clip_plane<C: CameraExt + ?Sized>(camera: &C, viewport: Rect<i32>, clip_plane: Vec4) -> CameraMatrices{
let projection = camera.projection();
let view = camera.view();
let projection_view = camera.projection_view();
CameraMatrices{
id: next_id(),
projection: projection,
view: view,
projection_view,
origin: CoordinateOrigin::CenterUp,
viewport,
camera_pos: camera.global_position().to_vec(),
near_plane: camera.near_clip(),
far_plane: camera.far_clip().unwrap_or(f32::INFINITY),
clip_plane,
}
}
pub fn ortho_top_left(viewport: Rect<i32>) -> CameraMatrices{
CameraMatrices::from(&Projection::new_ortho(viewport, CoordinateOrigin::TopLeft))
}
pub fn ortho_bottom_left(viewport: Rect<i32>) -> CameraMatrices{
CameraMatrices::from(&Projection::new_ortho(viewport, CoordinateOrigin::BottomLeft))
}
pub fn perspective_top_left(viewport: Rect<i32>, fov: Deg<f32>) -> CameraMatrices{
CameraMatrices::from(&Projection::new_perspective(viewport, fov, CoordinateOrigin::TopLeft))
}
pub fn perspective_bottom_left(viewport: Rect<i32>, fov: Deg<f32>) -> CameraMatrices{
CameraMatrices::from(&Projection::new_perspective(viewport, fov, CoordinateOrigin::BottomLeft))
}
pub fn id(&self) -> usize{
self.id
}
pub fn projection(&self) -> &Mat4{
&self.projection
}
pub fn view(&self) -> &Mat4{
&self.view
}
pub fn projection_view(&self) -> &Mat4{
&self.projection_view
}
pub fn origin(&self) -> CoordinateOrigin{
self.origin
}
pub fn viewport(&self) -> &Rect<i32>{
&self.viewport
}
pub fn clip_plane(&self) -> &Vec4{
&self.clip_plane
}
pub fn camera_position(&self) -> &Pnt3 {
self.camera_pos.as_pnt()
}
pub fn near_plane(&self) -> f32 {
self.near_plane
}
pub fn far_plane(&self) -> f32 {
self.far_plane
}
pub fn set_clip_plane(&mut self, c: Vec4){
self.clip_plane = c;
}
#[cfg(feature="gl")]
pub fn uniforms(&self) -> Vec<Uniform>{
uniforms!{
viewProjectionMatrix: self.projection_view,
projectionMatrix: self.projection,
viewMatrix: self.view,
u_camera: self.camera_pos,
near_plane: self.near_plane,
far_plane: self.far_plane,
clip_plane: self.clip_plane,
viewport: self.viewport,
}
}
#[cfg(feature="gl")]
pub fn uniforms_cache(program: &glin::Program) -> UniformsLocationCache{
Self::from_program_non_strict(program)
}
pub fn data(&self) -> Data{
Data{
projection: self.projection,
projection_view: self.projection_view,
view: self.view,
clip_plane: self.clip_plane,
viewport: self.viewport,
camera_pos: self.camera_pos,
near_plane: self.near_plane,
far_plane: self.far_plane,
padding: [0.;3],
}
}
}
impl<'a,C: CameraExt + ?Sized> From<(&'a C, &'a Rect<i32>)> for CameraMatrices{
fn from(camera_viewport: (&C, &Rect<i32>)) -> CameraMatrices{
let (camera, viewport) = camera_viewport;
let projection = camera.projection();
let view = camera.view();
let projection_view = camera.projection_view();
CameraMatrices{
id: next_id(),
projection: projection,
view: view,
projection_view,
origin: CoordinateOrigin::CenterUp,
viewport: *viewport,
camera_pos: camera.global_position().to_vec(),
near_plane: camera.near_clip(),
far_plane: camera.far_clip().unwrap_or(f32::INFINITY),
clip_plane: vec4!(0.),
}
}
}
impl<'a> From<&'a Projection> for CameraMatrices{
fn from(projection: &'a Projection) -> CameraMatrices{
let (viewport, projection, view, camera_pos, (near_plane, far_plane), origin) = projection.into_parts();
let projection_view = projection * view;
CameraMatrices{
id: next_id(),
projection: projection,
view: view,
projection_view,
origin,
viewport,
camera_pos: camera_pos.to_vec(),
near_plane,
far_plane,
clip_plane: vec4!(0.),
}
}
}
}
pub use self::camera::CameraMatrices;
#[cfg(feature="gl")]
pub use self::camera::UniformsLocationCache as CameraUniformsCache;
pub use self::camera::Data as CameraData;
mod model{
use rin_math::{Mat4, FastInverse};
use rin_util::LazyUpdate;
#[cfg(feature="gl")]
use glin::program::Uniform;
use super::Model;
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(feature="gl")]
use glin::{self, uniforms, UniformsLocationCache2};
use std::mem::MaybeUninit;
use log::warn;
#[cfg(feature="serialize")]
use serde_derive::{Serialize, Deserialize};
static mut NEXT_ID: AtomicUsize = AtomicUsize::new(0);
fn next_id() -> usize{
unsafe{
NEXT_ID.fetch_add(1, Ordering::Relaxed)
}
}
#[cfg(feature="gl")]
#[derive(Clone, Debug, UniformsLocationCache2)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ModelMatrices{
#[uniform(name="modelMatrix")]
model: Mat4,
#[uniform(name="normalMatrix")]
normal: LazyUpdate<Mat4>,
#[not_uniform]
id: usize,
}
#[cfg(not(any(feature="gl", feature="gles", feature="webgl")))]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ModelMatrices{
model: Mat4,
normal: LazyUpdate<Mat4>,
id: usize,
}
impl ModelMatrices {
pub fn from_model<M: Into<Model>>(model: M) -> ModelMatrices{
let model: Model = model.into();
let model = model.matrix();
ModelMatrices{
id: next_id(),
model: *model,
normal: LazyUpdate::new_dirty(unsafe{ MaybeUninit::uninit().assume_init() }),
}
}
pub fn from_model_normal<M: Into<Model>>(model: M, normal: &Mat4) -> ModelMatrices{
let model: Model = model.into();
let model = model.matrix();
ModelMatrices{
id: next_id(),
model: *model,
normal: LazyUpdate::new(*normal),
}
}
pub fn id(&self) -> usize{
self.id
}
pub fn model(&self) -> &Mat4{
&self.model
}
pub fn normal(&self) -> &Mat4{
self.normal.update(|normal| *normal = self.model.fast_orthonormal_inverse().transpose());
&self.normal
}
#[cfg(feature="gl")]
pub fn uniforms(&self) -> Vec<Uniform>{
uniforms!{
modelMatrix: self.model,
normalMatrix: *self.normal(),
}
}
#[cfg(feature="gl")]
pub fn uniforms_cache(program: &glin::Program) -> UniformsLocationCache{
Self::from_program_non_strict(program)
}
}
}
pub use self::model::ModelMatrices;
#[cfg(feature="gl")]
pub use self::model::UniformsLocationCache as ModelUniformsCache;