shadiertoy 0.1.0

A shadertoy rip-off.
Documentation
/// Define the format of the data you're passing to the shader.
///
/// There are three common types of data link:
///
/// - `RenderTarget`, for the color buffer.
/// - `Global`, for global variables.
/// - `TextureSampler`, for textures.
///
/// ```
/// # #[macro_use] extern crate shadiertoy;
/// #
/// pipeline!(globals {
///     time: Global<f32>,
///     color: RenderTarget,
///     resolution: Global<[f32; 2]>,
/// });
/// ```
#[macro_export]
macro_rules! pipeline {{
    $module:ident {
        $( $field:ident: $ty:ty, )*
    }
} => {

pub mod $module {
   #![allow(non_snake_case, unused_imports)]

    use $crate::{Global, RenderTarget, TextureSampler};
    use $crate::gfx::pso::{DataLink, DataBind, Descriptor, InitError, RawDataSet, AccessInfo, PipelineInit, PipelineData};

    #[derive(Clone, Debug, PartialEq)]
    pub struct Data<'a> {
        $( pub $field: &'a <$ty as DataBind<$crate::R>>::Data, )*
    }

    #[derive(Clone, Debug, Hash, PartialEq)]
    pub struct Meta {
        $( $field: $ty, )*
    }

    #[derive(Clone, Debug, PartialEq)]
    pub struct Init<'a> {
        $( pub $field: <$ty as DataLink<'a>>::Init, )*
    }

    impl<'a> PipelineInit for Init<'a> {
        type Meta = Meta;
        fn link_to<'s>(&self, desc: &mut Descriptor, info: &'s $crate::gfx::ProgramInfo)
                   -> ::std::result::Result<Self::Meta, InitError<&'s str>>
        {
            let mut meta = Meta {
                $( $field: <$ty as DataLink<'a>>::new(), )*
            };

            let mut _num_vb = 0;

            $(
                if let Some(d) = meta.$field.link_vertex_buffer(_num_vb, &self.$field) {
                    assert!(meta.$field.is_active());
                    desc.vertex_buffers[_num_vb as usize] = Some(d);
                    _num_vb += 1;
                }
            )*

            for at in &info.vertex_attributes {
                $(
                    match meta.$field.link_input(at, &self.$field) {
                        Some(Ok(d)) => {
                            assert!(meta.$field.is_active());
                            desc.attributes[at.slot as usize] = Some(d);
                            continue;
                        },
                        Some(Err(fm)) => return Err(
                            InitError::VertexImport(&at.name, Some(fm))
                        ),
                        None => (),
                    }
                )*
                return Err(InitError::VertexImport(&at.name, None));
            }

            for cb in &info.constant_buffers {
                $(
                    match meta.$field.link_constant_buffer(cb, &self.$field) {
                        Some(Ok(d)) => {
                            assert!(meta.$field.is_active());
                            desc.constant_buffers[cb.slot as usize] = Some(d);
                            continue;
                        },
                        Some(Err(e)) => return Err(
                            InitError::ConstantBuffer(&cb.name, Some(e))
                        ),
                        None => (),
                    }
                )*
                return Err(InitError::ConstantBuffer(&cb.name, None));
            }

            for gc in &info.globals {
                $(
                    match meta.$field.link_global_constant(gc, &self.$field) {
                        Some(Ok(())) => {
                            assert!(meta.$field.is_active());
                            continue;
                        },
                        Some(Err(e)) => return Err(
                            InitError::GlobalConstant(&gc.name, Some(e))
                        ),
                        None => (),
                    }
                )*
                return Err(InitError::GlobalConstant(&gc.name, None));
            }

            for srv in &info.textures {
                $(
                    match meta.$field.link_resource_view(srv, &self.$field) {
                        Some(Ok(d)) => {
                            assert!(meta.$field.is_active());
                            desc.resource_views[srv.slot as usize] = Some(d);
                            continue;
                        },
                        Some(Err(_)) => return Err(
                            InitError::ResourceView(&srv.name, Some(()))
                        ),
                        None => (),
                    }
                )*
                return Err(InitError::ResourceView(&srv.name, None));
            }

            for uav in &info.unordereds {
                $(
                    match meta.$field.link_unordered_view(uav, &self.$field) {
                        Some(Ok(d)) => {
                            assert!(meta.$field.is_active());
                            desc.unordered_views[uav.slot as usize] = Some(d);
                            continue;
                        },
                        Some(Err(_)) => return Err(
                            InitError::UnorderedView(&uav.name, Some(()))
                        ),
                        None => (),
                    }
                )*

                return Err(InitError::UnorderedView(&uav.name, None));
            }

            for sm in &info.samplers {
                $(
                    match meta.$field.link_sampler(sm, &self.$field) {
                        Some(d) => {
                            assert!(meta.$field.is_active());
                            desc.samplers[sm.slot as usize] = Some(d);
                            continue;
                        },
                        None => (),
                    }
                )*

                return Err(InitError::Sampler(&sm.name, None));
            }

            for out in &info.outputs {
                $(
                    match meta.$field.link_output(out, &self.$field) {
                        Some(Ok(d)) => {
                            assert!(meta.$field.is_active());
                            desc.color_targets[out.slot as usize] = Some(d);
                            continue;
                        },
                        Some(Err(fm)) => return Err(
                            InitError::PixelExport(&out.name, Some(fm))
                        ),
                        None => (),
                    }
                )*

                return Err(InitError::PixelExport(&out.name, None));
            }

            if !info.knows_outputs {
                use $crate::gfx::shade::core as s;

                let mut out = s::OutputVar {
                    name: String::new(),
                    slot: 0,
                    base_type: s::BaseType::F32,
                    container: s::ContainerType::Vector(4),
                };

                $(
                    match meta.$field.link_output(&out, &self.$field) {
                        Some(Ok(d)) => {
                            assert!(meta.$field.is_active());
                            desc.color_targets[out.slot as usize] = Some(d);
                            out.slot += 1;
                        },
                        Some(Err(fm)) => return Err(
                            InitError::PixelExport(&"!known", Some(fm))
                        ),
                        None => (),
                    }
                )*
            }

            for _ in 0..1 {
                $(
                    if let Some(d) = meta.$field.link_depth_stencil(&self.$field) {
                        assert!(meta.$field.is_active());
                        desc.depth_stencil = Some(d);
                    }

                    if meta.$field.link_scissor() {
                        assert!(meta.$field.is_active());
                        desc.scissor = true;
                    }
                )*
            }

            Ok(meta)
        }
    }

    impl<'a> PipelineData<$crate::R> for Data<'a> {
        type Meta = Meta;
        fn bake_to(&self,
                   out: &mut RawDataSet<$crate::R>,
                   meta: &Self::Meta,
                   man: &mut $crate::gfx::handle::Manager<$crate::R>,
                   access: &mut AccessInfo<$crate::R>) {
            $(
                meta.$field.bind_to(out, self.$field, man, access);
            )*
        }
    }

    impl Default for Init<'static> {
        fn default() -> Self {
            Init {
                $( $field: stringify!($field), )*
            }
        }
    }

    pub fn new() -> Init<'static> {
        Default::default()
    }
}

}}