#[macro_export]
macro_rules! def_programs {
(
SHADERS [
$($shader:ident, $sourcepath:expr),*
]
PROGRAMS [
$(
program $program:ident {
vertex_shader: $vert_shader:ident
$(tessellation_control_shader: $tess_ctrl_shader:ident
tessellation_evaluation_shader: $tess_eval_shader:ident)*
$(geometry_shader: $geom_shader:ident)*
fragment_shader: $frag_shader:ident
}
)*
]
) => {
$crate::def_programs!{
@def_shaders
$($shader, $sourcepath),*
}
$crate::def_programs!{
@def_programs
SHADERS [ $($shader),* ]
PROGRAMS [
$(
program $program {
vertex_shader: $vert_shader
$(tessellation_control_shader: $tess_ctrl_shader
tessellation_evaluation_shader: $tess_eval_shader)*
$(geometry_shader: $geom_shader)*
fragment_shader: $frag_shader
}
)*
]
}
};
( @def_programs
SHADERS [ $($shader:ident),* ]
PROGRAMS [
$(
program $program:ident {
vertex_shader: $vert_shader:ident
$(tessellation_control_shader: $tess_ctrl_shader:ident
tessellation_evaluation_shader: $tess_eval_shader:ident)*
$(geometry_shader: $geom_shader:ident)*
fragment_shader: $frag_shader:ident
}
)*
]
) => {
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd,
$crate::num_derive::FromPrimitive, $crate::num_derive::ToPrimitive,
$crate::enum_iterator::Sequence)]
pub enum ProgramId {
$($program),*
}
impl ProgramId {
pub fn index (self) -> usize {
self as usize
}
fn create_program (&self,
glium_facade : &$crate::glium::backend::Facade,
shaders : &$crate::vec_map::VecMap <String>
) -> $crate::glium::Program {
match *self {
$(
ProgramId::$program => {
let vertex_shader
= shaders.get (ShaderId::$vert_shader as usize).unwrap().as_str();
let tessellation_control_shader
= $crate::def_programs!(
@option_shader shaders [$($tess_ctrl_shader)*]);
let tessellation_evaluation_shader
= $crate::def_programs!(
@option_shader shaders [$($tess_eval_shader)*]);
let geometry_shader
= $crate::def_programs!(
@option_shader shaders [$($geom_shader)*]);
let fragment_shader
= shaders.get (ShaderId::$frag_shader as usize).unwrap().as_str();
$crate::glium::Program::new (
glium_facade,
$crate::glium::program::ProgramCreationInput::SourceCode {
vertex_shader,
tessellation_control_shader,
tessellation_evaluation_shader,
geometry_shader,
fragment_shader,
transform_feedback_varyings: None,
outputs_srgb: true,
uses_point_size: false
}
).unwrap()
}
)*
}
}
}
pub fn build_programs (glium_facade : &$crate::glium::backend::Facade) ->
Result <$crate::vec_map::VecMap <$crate::glium::Program>, std::io::Error>
{
log::debug!("building shader programs...");
let shaders = load_shaders()?;
let mut programs = $crate::vec_map::VecMap::new();
for program_id in ProgramId::iter_variants() {
let pid = program_id as usize;
assert!(
programs.insert (pid, program_id.create_program (glium_facade, &shaders)
).is_none());
}
log::debug!("...building shader programs");
Ok (programs)
}
};
(
@def_shaders $($shader:ident, $sourcepath:expr),*
) => {
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd,
$crate::num_derive::FromPrimitive, $crate::num_derive::ToPrimitive,
$crate::enum_iterator::Sequence)]
pub enum ShaderId {
$($shader),*
}
impl ShaderId {
pub fn load_source (&self) -> Result <String, std::io::Error> {
use std::io::Read;
let mut source_file = std::fs::File::open (self.sourcepath())?;
let mut source_string = std::string::String::new();
let _ = source_file.read_to_string (&mut source_string).unwrap();
Ok (source_string)
}
pub fn sourcepath (&self) -> &'static str {
match *self {
$(ShaderId::$shader => $sourcepath),*
}
}
}
pub fn load_shaders()
-> Result <$crate::vec_map::VecMap <String>, std::io::Error>
{
let mut shaders = $crate::vec_map::VecMap::new();
for shader_id in ShaderId::iter_variants() {
let source_string = shader_id.load_source()?;
let sid = shader_id as usize;
assert!{ shaders.insert (sid, source_string).is_none() }
}
Ok (shaders)
}
};
(@option_shader $shaders:ident [$shader_id:ident]) => {
Some ($shaders.get (ShaderId::$shader_id as usize).unwrap().as_str())
};
(@option_shader $shaders:ident []) => { None };
}
#[macro_export]
macro_rules! def_programs_include {
( SHADERS [
$($shader:ident, $sourcepath:expr),*
]
PROGRAMS [
$(
program $program:ident {
vertex_shader: $vert_shader:ident
$(tessellation_control_shader: $tess_ctrl_shader:ident
tessellation_evaluation_shader: $tess_eval_shader:ident)*
$(geometry_shader: $geom_shader:ident)*
fragment_shader: $frag_shader:ident
}
)*
]
) => {
$crate::def_programs_include!{
@def_shaders
$($shader, $sourcepath),*
}
$crate::def_programs_include!{
@def_programs
SHADERS [ $($shader),* ]
PROGRAMS [
$(
program $program {
vertex_shader: $vert_shader
$(tessellation_control_shader: $tess_ctrl_shader
tessellation_evaluation_shader: $tess_eval_shader)*
$(geometry_shader: $geom_shader)*
fragment_shader: $frag_shader
}
)*
]
}
};
( @def_programs
SHADERS [ $($shader:ident),* ]
PROGRAMS [
$(
program $program:ident {
vertex_shader: $vert_shader:ident
$(tessellation_control_shader: $tess_ctrl_shader:ident
tessellation_evaluation_shader: $tess_eval_shader:ident)*
$(geometry_shader: $geom_shader:ident)*
fragment_shader: $frag_shader:ident
}
)*
]
) => {
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd,
$crate::strum::EnumCount, $crate::strum::EnumIter,
$crate::strum::FromRepr)]
#[repr(u16)]
pub enum ProgramId {
$($program),*
}
impl ProgramId {
pub const fn index (self) -> usize {
self as usize
}
fn create_program (&self,
glium_facade : &dyn $crate::glium::backend::Facade,
shaders : &$crate::vec_map::VecMap <&'static str>
) -> $crate::glium::Program {
log::debug!(name:?=self; "create shader program");
match *self {
$(
ProgramId::$program => {
let vertex_shader
= shaders.get (ShaderId::$vert_shader as usize).unwrap();
let tessellation_control_shader = $crate::def_programs_include!(
@option_shader shaders [$($tess_ctrl_shader)*]);
let tessellation_evaluation_shader = $crate::def_programs_include!(
@option_shader shaders [$($tess_eval_shader)*]);
let geometry_shader = $crate::def_programs_include!(
@option_shader shaders [$($geom_shader)*]);
let fragment_shader
= shaders.get (ShaderId::$frag_shader as usize).unwrap();
$crate::glium::Program::new (
glium_facade,
$crate::glium::program::ProgramCreationInput::SourceCode {
vertex_shader,
tessellation_control_shader,
tessellation_evaluation_shader,
geometry_shader,
fragment_shader,
transform_feedback_varyings: None,
outputs_srgb: true,
uses_point_size: false
}
).unwrap()
}
)*
}
}
}
pub fn build_programs (
glium_facade : &dyn $crate::glium::backend::Facade
) -> Result
<$crate::vec_map::VecMap <$crate::glium::Program>, std::io::Error>
{
use $crate::strum::IntoEnumIterator;
log::debug!("building shader programs...");
let shaders = load_shaders()?;
let mut programs = $crate::vec_map::VecMap::new();
for program_id in ProgramId::iter() {
let pid = program_id as usize;
assert!(
programs.insert (pid, program_id.create_program (glium_facade, &shaders)
).is_none());
}
log::debug!("...building shader programs");
Ok (programs)
}
};
(
@def_shaders $($shader:ident, $sourcepath:expr),*
) => {
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd,
$crate::strum::EnumCount, $crate::strum::EnumIter,
$crate::strum::FromRepr)]
#[repr(u16)]
pub enum ShaderId {
$($shader),*
}
impl ShaderId {
pub const fn source_str (&self) -> &'static str {
match *self {
$(
ShaderId::$shader => include_str!($sourcepath)
),*
}
}
pub const fn sourcepath (&self) -> &'static str {
match *self {
$(ShaderId::$shader => $sourcepath),*
}
}
}
pub fn load_shaders()
-> Result <$crate::vec_map::VecMap <&'static str>, std::io::Error>
{
use $crate::strum::IntoEnumIterator;
let mut shaders = $crate::vec_map::VecMap::new();
for shader_id in ShaderId::iter() {
let source_str = shader_id.source_str();
let sid = shader_id as usize;
assert!(shaders.insert (sid, source_str).is_none());
}
Ok (shaders)
}
};
(@option_shader $shaders:ident [$shader_id:ident]) => {
Some (*$shaders.get (ShaderId::$shader_id as usize).unwrap())
};
(@option_shader $shaders:ident []) => { None };
}