hexga_graphics 0.0.11-beta.53

The default graphic renderer of hexga_engine.
Documentation
use super::*;

// Based on https://docs.rs/macroquad/latest/macroquad/camera/index.html
pub trait ICamera<F = float>: GetMatrix<F, 4, 4>
where
    F: Float,
{
    fn have_depth(&self) -> bool;
    //fn viewport(&self) -> Option<Rect2i>;

    fn camera(&self) -> CameraOf<F>
    {
        CameraOf {
            matrix: self.matrix(),
            depth: self.have_depth(),
        }
    }

    /*
    fn push(&self) where Camera : CastFrom<CameraOf<F>>, Self:Sized
    {
        Cam.push_cam(self);
    }
    fn pop(&self) where Camera : CastFrom<CameraOf<F>>, Self:Sized
    {
        Cam.pop_cam();
    }
    fn scope<S>(&self, scope:S) where S: FnOnce(), Camera : CastFrom<CameraOf<F>>, Self:Sized
    {
        Cam.scope_cam(self, scope);
    }*/
}

pub type Camera3D = Camera3DOf<float>;

#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Camera3DOf<F>
where
    F: Float,
{
    pub position: Vector3<F>,
    pub target: Vector3<F>,
    pub up: Vector3<F>,
    pub perspective: CameraPerspectiveOf<F>,
    pub viewport: Option<Rect2i>,
}

/*
impl<F> Default for Camera3DOf<F> where F:Float
{
    fn default() -> Self {
        Self { position: Vector3::ZERO.with_z(one()), target: zero(), up: Vector3::Y, perspective: ___(), viewport: None }
    }
}
*/
impl<F> GetMatrix<F, 4, 4> for Camera3DOf<F>
where
    F: Float,
{
    fn matrix(&self) -> Matrix<F, 4, 4> { self.matrix() }
}

pub type CameraPerspective = CameraPerspectiveOf<float>;

#[derive(Clone, Copy, PartialEq, Debug)]
pub struct CameraPerspectiveOf<F>
where
    F: Float,
{
    pub aspect: F,
    pub fovy: AngleOf<F>,
    pub znear: F,
    pub zfar: F,
}
/*
impl<F> Default for CameraPerspectiveOf<F> where F:Float
{
    fn default() -> Self
    {
        Self { aspect: (16. / 9.).cast_into(), fovy: AngleOf::from_degree(F::cast_from(45.)), znear: F::cast_from(0.1), zfar: F::cast_from(100.0) }
    }
}*/
impl<F> From<CameraPerspectiveOf<F>> for Matrix4<F>
where
    F: Float,
{
    // Based on https://docs.rs/cgmath/latest/src/cgmath/projection.rs.html#108
    fn from(p: CameraPerspectiveOf<F>) -> Self
    {
        debug_assert!(p.fovy > AngleOf::ZERO && p.fovy < AngleOf::HALF);
        debug_assert!(p.aspect != F::ZERO);
        debug_assert!(p.znear > F::ZERO && p.zfar > F::ZERO && p.zfar != p.znear);

        let two = F::TWO;
        let f = (p.fovy / two).cot();

        let m00 = f / p.aspect;
        let m11 = f;
        let m22 = (p.zfar + p.znear) / (p.znear - p.zfar);
        let m23 = -F::ONE;
        let m32 = (two * p.zfar * p.znear) / (p.znear - p.zfar);

        Matrix4::from_col(Vector4::new(
            Vector4::new(m00, F::ZERO, F::ZERO, F::ZERO),
            Vector4::new(F::ZERO, m11, F::ZERO, F::ZERO),
            Vector4::new(F::ZERO, F::ZERO, m22, m23),
            Vector4::new(F::ZERO, F::ZERO, m32, F::ZERO),
        ))
    }
}

/*
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Projection
{
    Perspective,
    Orthographics,
}*/

impl<F> Camera3DOf<F>
where
    F: Float,
{
    fn matrix(&self) -> Matrix4<F>
    {
        // https://sotrh.github.io/learn-wgpu/beginner/tutorial6-uniforms/#a-perspective-camera
        let view: Matrix<F, 4, 4> = Matrix4::<F>::look_at_rh(self.position, self.target, self.up);
        let proj = Matrix4::<F>::from(self.perspective);
        return Self::OPENGL_TO_WGPU_MATRIX * proj * view;
    }

    pub(crate) const OPENGL_TO_WGPU_MATRIX: Matrix4<F> = Matrix4::from_col(vector4(
        vector4(F::ONE, F::ZERO, F::ZERO, F::ZERO),
        vector4(F::ZERO, F::ONE, F::ZERO, F::ZERO),
        vector4(F::ZERO, F::ZERO, F::HALF, F::ZERO),
        vector4(F::ZERO, F::ZERO, F::HALF, F::ONE),
    ));
}

impl<F> ICamera<F> for Camera3DOf<F>
where
    F: Float,
{
    fn have_depth(&self) -> bool { true }
}

pub type Camera = CameraOf<float>;

#[derive(Clone, Copy, PartialEq)]
pub struct CameraOf<F>
{
    pub matrix: Matrix4<F>,
    pub depth: bool,
}
impl<F> Debug for CameraOf<F>
where
    F: Debug,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
    {
        f.debug_struct("Camera")
            .field("matrix", &self.matrix)
            .field("depth", &self.depth)
            .finish()
    }
}
impl<T> MapIntern for CameraOf<T>
{
    type Item = T;
    fn map_intern<F>(mut self, f: F) -> Self
    where
        F: FnMut(Self::Item) -> Self::Item,
    {
        self.matrix = self.matrix.map_intern(f);
        self
    }
}
impl<T> Map for CameraOf<T>
{
    type WithType<R> = CameraOf<R>;

    fn map<R, F>(self, f: F) -> Self::WithType<R>
    where
        F: FnMut(Self::Item) -> R,
    {
        Self::WithType {
            matrix: self.matrix.map(f),
            depth: self.depth,
        }
    }
}

impl<F> GetPosition<F, 3> for CameraOf<F>
where
    F: Float,
{
    fn pos(&self) -> Vector<F, 3> { self.matrix.pos() }
}
impl<F> SetPosition<F, 3> for CameraOf<F>
where
    F: Float,
{
    fn set_pos(&mut self, pos: Vector<F, 3>) -> &mut Self
    {
        self.matrix.set_pos(pos);
        self
    }
}
impl<F> GetScale<F, 3> for CameraOf<F>
where
    F: Float,
{
    fn scale(&self) -> Vector<F, 3> { self.matrix.scale() }
}
impl<F> SetScale<F, 3> for CameraOf<F>
where
    F: Float,
{
    fn set_scale(&mut self, scale: Vector<F, 3>) -> &mut Self
    {
        self.matrix.set_scale(scale);
        self
    }
}
impl<F> RotateX<F> for CameraOf<F>
where
    F: Float,
{
    fn rotate_x(&mut self, angle: AngleOf<F>) -> &mut Self
    {
        self.matrix.rotate_x(angle);
        self
    }
}
impl<F> RotateY<F> for CameraOf<F>
where
    F: Float,
{
    fn rotate_y(&mut self, angle: AngleOf<F>) -> &mut Self
    {
        self.matrix.rotate_y(angle);
        self
    }
}
impl<F> RotateZ<F> for CameraOf<F>
where
    F: Float,
{
    fn rotate_z(&mut self, angle: AngleOf<F>) -> &mut Self
    {
        self.matrix.rotate_z(angle);
        self
    }
}
impl<F> GetMatrix<F, 4, 4> for CameraOf<F>
where
    F: Float,
{
    fn matrix(&self) -> Matrix<F, 4, 4> { self.matrix }
}
impl<F> SetMatrix<F, 4, 4> for CameraOf<F>
where
    F: Float,
{
    fn set_matrix(&mut self, matrix: Matrix<F, 4, 4>) -> &mut Self
    {
        self.matrix = matrix;
        self
    }
}

impl<F> CameraOf<F>
where
    F: Float,
{
    pub const CAMERA_2D: Self = Self {
        matrix: Matrix4::IDENTITY,
        depth: false,
    };
    pub const CAMERA_3D: Self = Self {
        matrix: Matrix4::IDENTITY,
        depth: true,
    };

    pub fn new() -> Self { Self::___() }

    pub fn with_matrix(self, matrix: Matrix4<F>) -> Self { Self { matrix, ..self } }
    pub fn with_depth(self, depth: bool) -> Self { Self { depth, ..self } }
}
impl<F> Default for CameraOf<F>
where
    F: Float,
{
    fn default() -> Self { Self::CAMERA_3D }
}
impl<F> ICamera<F> for CameraOf<F>
where
    F: Float,
{
    fn have_depth(&self) -> bool { self.depth }
}