1#[macro_export]
10macro_rules! def_programs {
11 (
15 SHADERS [
16 $($shader:ident, $sourcepath:expr),*
17 ]
18 PROGRAMS [
19 $(
20 program $program:ident {
21 vertex_shader: $vert_shader:ident
22 $(tessellation_control_shader: $tess_ctrl_shader:ident
23 tessellation_evaluation_shader: $tess_eval_shader:ident)*
24 $(geometry_shader: $geom_shader:ident)*
25 fragment_shader: $frag_shader:ident
26 }
27 )*
28 ]
29
30 ) => {
31
32 $crate::def_programs!{
33 @def_shaders
34 $($shader, $sourcepath),*
35 }
36
37 $crate::def_programs!{
38 @def_programs
39 SHADERS [ $($shader),* ]
40 PROGRAMS [
41 $(
42 program $program {
43 vertex_shader: $vert_shader
44 $(tessellation_control_shader: $tess_ctrl_shader
45 tessellation_evaluation_shader: $tess_eval_shader)*
46 $(geometry_shader: $geom_shader)*
47 fragment_shader: $frag_shader
48 }
49 )*
50 ]
51 }
52 };
53
54 ( @def_programs
58 SHADERS [ $($shader:ident),* ]
59 PROGRAMS [
60 $(
61 program $program:ident {
62 vertex_shader: $vert_shader:ident
63 $(tessellation_control_shader: $tess_ctrl_shader:ident
64 tessellation_evaluation_shader: $tess_eval_shader:ident)*
65 $(geometry_shader: $geom_shader:ident)*
66 fragment_shader: $frag_shader:ident
67 }
68 )*
69 ]
70 ) => {
71 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd,
72 $crate::num_derive::FromPrimitive, $crate::num_derive::ToPrimitive,
73 $crate::enum_iterator::Sequence)]
74 pub enum ProgramId {
75 $($program),*
76 }
77
78 impl ProgramId {
79 pub fn index (self) -> usize {
80 self as usize
81 }
82 fn create_program (&self,
83 glium_facade : &$crate::glium::backend::Facade,
84 shaders : &$crate::vec_map::VecMap <String>
85 ) -> $crate::glium::Program {
86 match *self {
87 $(
88 ProgramId::$program => {
89 let vertex_shader
90 = shaders.get (ShaderId::$vert_shader as usize).unwrap().as_str();
91 let tessellation_control_shader
92 = $crate::def_programs!(
93 @option_shader shaders [$($tess_ctrl_shader)*]);
94 let tessellation_evaluation_shader
95 = $crate::def_programs!(
96 @option_shader shaders [$($tess_eval_shader)*]);
97 let geometry_shader
98 = $crate::def_programs!(
99 @option_shader shaders [$($geom_shader)*]);
100 let fragment_shader
101 = shaders.get (ShaderId::$frag_shader as usize).unwrap().as_str();
102 $crate::glium::Program::new (
103 glium_facade,
104 $crate::glium::program::ProgramCreationInput::SourceCode {
105 vertex_shader,
106 tessellation_control_shader,
107 tessellation_evaluation_shader,
108 geometry_shader,
109 fragment_shader,
110 transform_feedback_varyings: None,
111 outputs_srgb: true,
112 uses_point_size: false
113 }
114 ).unwrap()
115 }
116 )*
117 }
118 }
119 }
120
121 pub fn build_programs (glium_facade : &$crate::glium::backend::Facade) ->
122 Result <$crate::vec_map::VecMap <$crate::glium::Program>, std::io::Error>
123 {
124 log::debug!("building shader programs...");
125
126 let shaders = load_shaders()?;
127 let mut programs = $crate::vec_map::VecMap::new();
128 for program_id in ProgramId::iter_variants() {
129 let pid = program_id as usize;
130 assert!(
131 programs.insert (pid, program_id.create_program (glium_facade, &shaders)
132 ).is_none());
133 }
134
135 log::debug!("...building shader programs");
136 Ok (programs)
137 }
138 };
139
140 (
144 @def_shaders $($shader:ident, $sourcepath:expr),*
145 ) => {
146
147 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd,
148 $crate::num_derive::FromPrimitive, $crate::num_derive::ToPrimitive,
149 $crate::enum_iterator::Sequence)]
150 pub enum ShaderId {
151 $($shader),*
152 }
153
154 impl ShaderId {
155 pub fn load_source (&self) -> Result <String, std::io::Error> {
156 use std::io::Read;
157 let mut source_file = std::fs::File::open (self.sourcepath())?;
158 let mut source_string = std::string::String::new();
159 let _ = source_file.read_to_string (&mut source_string).unwrap();
160 Ok (source_string)
161 }
162
163 pub fn sourcepath (&self) -> &'static str {
164 match *self {
165 $(ShaderId::$shader => $sourcepath),*
166 }
167 }
168 }
169
170 pub fn load_shaders()
171 -> Result <$crate::vec_map::VecMap <String>, std::io::Error>
172 {
173 let mut shaders = $crate::vec_map::VecMap::new();
174 for shader_id in ShaderId::iter_variants() {
175 let source_string = shader_id.load_source()?;
176 let sid = shader_id as usize;
177 assert!{ shaders.insert (sid, source_string).is_none() }
178 }
179 Ok (shaders)
180 }
181
182 };
183
184 (@option_shader $shaders:ident [$shader_id:ident]) => {
188 Some ($shaders.get (ShaderId::$shader_id as usize).unwrap().as_str())
189 };
190
191 (@option_shader $shaders:ident []) => { None };
195
196} #[macro_export]
210macro_rules! def_programs_include {
211 ( SHADERS [
215 $($shader:ident, $sourcepath:expr),*
216 ]
217 PROGRAMS [
218 $(
219 program $program:ident {
220 vertex_shader: $vert_shader:ident
221 $(tessellation_control_shader: $tess_ctrl_shader:ident
222 tessellation_evaluation_shader: $tess_eval_shader:ident)*
223 $(geometry_shader: $geom_shader:ident)*
224 fragment_shader: $frag_shader:ident
225 }
226 )*
227 ]
228 ) => {
229 $crate::def_programs_include!{
230 @def_shaders
231 $($shader, $sourcepath),*
232 }
233 $crate::def_programs_include!{
234 @def_programs
235 SHADERS [ $($shader),* ]
236 PROGRAMS [
237 $(
238 program $program {
239 vertex_shader: $vert_shader
240 $(tessellation_control_shader: $tess_ctrl_shader
241 tessellation_evaluation_shader: $tess_eval_shader)*
242 $(geometry_shader: $geom_shader)*
243 fragment_shader: $frag_shader
244 }
245 )*
246 ]
247 }
248 };
249
250 ( @def_programs
254 SHADERS [ $($shader:ident),* ]
255 PROGRAMS [
256 $(
257 program $program:ident {
258 vertex_shader: $vert_shader:ident
259 $(tessellation_control_shader: $tess_ctrl_shader:ident
260 tessellation_evaluation_shader: $tess_eval_shader:ident)*
261 $(geometry_shader: $geom_shader:ident)*
262 fragment_shader: $frag_shader:ident
263 }
264 )*
265 ]
266 ) => {
267 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd,
268 $crate::strum::EnumCount, $crate::strum::EnumIter,
269 $crate::strum::FromRepr)]
270 #[repr(u16)]
271 pub enum ProgramId {
272 $($program),*
273 }
274
275 impl ProgramId {
276 pub fn index (self) -> usize {
277 self as usize
278 }
279 fn create_program (&self,
280 glium_facade : &dyn $crate::glium::backend::Facade,
281 shaders : &$crate::vec_map::VecMap <&'static str>
282 ) -> $crate::glium::Program {
283 log::debug!(name:?=self; "create shader program");
284 match *self {
285 $(
286 ProgramId::$program => {
287 let vertex_shader
288 = shaders.get (ShaderId::$vert_shader as usize).unwrap();
289 let tessellation_control_shader = $crate::def_programs_include!(
290 @option_shader shaders [$($tess_ctrl_shader)*]);
291 let tessellation_evaluation_shader = $crate::def_programs_include!(
292 @option_shader shaders [$($tess_eval_shader)*]);
293 let geometry_shader = $crate::def_programs_include!(
294 @option_shader shaders [$($geom_shader)*]);
295 let fragment_shader
296 = shaders.get (ShaderId::$frag_shader as usize).unwrap();
297 $crate::glium::Program::new (
298 glium_facade,
299 $crate::glium::program::ProgramCreationInput::SourceCode {
300 vertex_shader,
301 tessellation_control_shader,
302 tessellation_evaluation_shader,
303 geometry_shader,
304 fragment_shader,
305 transform_feedback_varyings: None,
306 outputs_srgb: true,
307 uses_point_size: false
308 }
309 ).unwrap()
310 }
311 )*
312 }
313 }
314 }
315
316 pub fn build_programs (
317 glium_facade : &dyn $crate::glium::backend::Facade
318 ) -> Result
319 <$crate::vec_map::VecMap <$crate::glium::Program>, std::io::Error>
320 {
321 use $crate::strum::IntoEnumIterator;
322 log::debug!("building shader programs...");
323 let shaders = load_shaders()?;
324 let mut programs = $crate::vec_map::VecMap::new();
325 for program_id in ProgramId::iter() {
326 let pid = program_id as usize;
327 assert!(
328 programs.insert (pid, program_id.create_program (glium_facade, &shaders)
329 ).is_none());
330 }
331
332 log::debug!("...building shader programs");
333 Ok (programs)
334 }
335 };
336
337 (
341 @def_shaders $($shader:ident, $sourcepath:expr),*
342 ) => {
343 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd,
344 $crate::strum::EnumCount, $crate::strum::EnumIter,
345 $crate::strum::FromRepr)]
346 #[repr(u16)]
347 pub enum ShaderId {
348 $($shader),*
349 }
350 impl ShaderId {
351 pub fn source_str (&self) -> &'static str {
352 match *self {
353 $(
354 ShaderId::$shader => include_str!($sourcepath)
355 ),*
356 }
357 }
358 pub fn sourcepath (&self) -> &'static str {
359 match *self {
360 $(ShaderId::$shader => $sourcepath),*
361 }
362 }
363 }
364 pub fn load_shaders()
365 -> Result <$crate::vec_map::VecMap <&'static str>, std::io::Error>
366 {
367 use $crate::strum::IntoEnumIterator;
368 let mut shaders = $crate::vec_map::VecMap::new();
369 for shader_id in ShaderId::iter() {
370 let source_str = shader_id.source_str();
371 let sid = shader_id as usize;
372 assert!(shaders.insert (sid, source_str).is_none());
373 }
374 Ok (shaders)
375 }
376 };
377
378 (@option_shader $shaders:ident [$shader_id:ident]) => {
382 Some (*$shaders.get (ShaderId::$shader_id as usize).unwrap())
383 };
384
385 (@option_shader $shaders:ident []) => { None };
389
390}