use crate::{
geom::Vertex,
math::{Color4, vec::ProjVec3},
};
use super::raster::Frag;
pub trait VertexShader<In, Uni> {
type Output;
fn shade_vertex(&self, vertex: In, uniform: Uni) -> Self::Output;
}
pub trait FragmentShader<Var> {
fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4>;
}
impl<F, In, Out, Uni> VertexShader<In, Uni> for F
where
F: Fn(In, Uni) -> Out,
{
type Output = Out;
fn shade_vertex(&self, vertex: In, uniform: Uni) -> Out {
self(vertex, uniform)
}
}
impl<F, Var, Out> FragmentShader<Var> for F
where
F: Fn(Frag<Var>) -> Out,
Out: Into<Option<Color4>>,
{
fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4> {
self(frag).into()
}
}
pub fn new<Vs, Fs, Vtx, Var, Uni>(vs: Vs, fs: Fs) -> Shader<Vs, Fs>
where
Vs: VertexShader<Vtx, Uni, Output = Vertex<ProjVec3, Var>>,
Fs: FragmentShader<Var>,
{
Shader::new(vs, fs)
}
#[derive(Copy, Clone)]
pub struct Shader<Vs, Fs> {
pub vertex_shader: Vs,
pub fragment_shader: Fs,
}
impl<Vs, Fs> Shader<Vs, Fs> {
pub const fn new<In, Uni, Pos, Attr>(vs: Vs, fs: Fs) -> Self
where
Vs: VertexShader<In, Uni, Output = Vertex<Pos, Attr>>,
Fs: FragmentShader<Attr>,
{
Self {
vertex_shader: vs,
fragment_shader: fs,
}
}
}
impl<In, Vs, Fs, Uni> VertexShader<In, Uni> for Shader<Vs, Fs>
where
Vs: VertexShader<In, Uni>,
{
type Output = Vs::Output;
fn shade_vertex(&self, vertex: In, uniform: Uni) -> Self::Output {
self.vertex_shader.shade_vertex(vertex, uniform)
}
}
impl<Vs, Fs, Var> FragmentShader<Var> for Shader<Vs, Fs>
where
Fs: FragmentShader<Var>,
{
fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4> {
self.fragment_shader.shade_fragment(frag)
}
}