glium/
macros.rs

1//! Defines useful macros for glium usage.
2
3/// Calls the `assert_no_error` method on a `glium::Display` instance
4/// with file and line number information.
5///
6/// Aside from the first argument which must be the display,
7/// the arguments of this macro match the `println!` macro.
8///
9/// ## Example
10/// ```ignore rust
11/// assert_no_gl_error!(my_display);
12/// assert_no_gl_error!(my_display, "custom message");
13/// assert_no_gl_error!(my_display, "custom format {}", 5);
14/// ```
15#[macro_export]
16macro_rules! assert_no_gl_error {
17    ($display: expr) => {
18        {
19            let message = format!("{}:{}", file!(), line!());
20            $display.assert_no_error(Some(&message[..]));
21        }
22    };
23    ($display: expr, $msg: expr) => {
24        {
25            let message = format!("{}:{}  {}", file!(), line!(), $msg);
26            $display.assert_no_error(Some(&message[..]));
27        }
28    };
29    ($display: expr, $fmt: expr, $($arg:tt)+) => {
30        {
31            let message = format!(concat!("{}:{} ", $fmt), file!(), line!(), $($arg)+);
32            $display.assert_no_error(Some(&message[..]));
33        }
34    }
35}
36
37/// Returns an implementation-defined type which implements the `Uniform` trait.
38///
39/// ## Example
40///
41/// ```rust
42/// # use glium::uniform;
43/// # fn main() {
44/// let uniforms = uniform! {
45///     color: [1.0, 1.0, 0.0, 1.0],
46///     some_value: 12i32
47/// };
48/// # }
49/// ```
50#[macro_export]
51macro_rules! uniform {
52    () => {
53        $crate::uniforms::EmptyUniforms
54    };
55
56    ($field:ident: $value:expr) => {
57        $crate::uniforms::UniformsStorage::new(stringify!($field), $value)
58    };
59
60    ($field1:ident: $value1:expr, $($field:ident: $value:expr),+) => {
61        {
62            let uniforms = $crate::uniforms::UniformsStorage::new(stringify!($field1), $value1);
63            $(
64                let uniforms = uniforms.add(stringify!($field), $value);
65            )+
66            uniforms
67        }
68    };
69
70    ($($field:ident: $value:expr),*,) => {
71        $crate::uniform!($($field: $value),*)
72    };
73}
74
75/// Returns a Dynamic Uniforms Container to which values can be added later.
76///
77/// ## Example
78///
79/// ```rust
80/// # #[macro_use] extern crate glium;
81/// # use glium::uniform;
82/// # fn main(){
83///     let mut uniforms = dynamic_uniform!{
84///         color: &[1.0, 1.0, 0.0, 1.0],
85///         some_value: &12i32,
86///     };
87///
88///     uniforms.add("another_value", &1.5f32);
89/// # }
90/// ```
91///
92///
93#[macro_export]
94macro_rules! dynamic_uniform{
95    () => {
96        $crate::uniforms::DynamicUniforms::new()
97    };
98
99    ($($field:ident: $value:expr), *,) => {
100        {
101            let mut tmp = $crate::uniforms::DynamicUniforms::new();
102            $(
103                tmp.add(stringify!($field), $value);
104            )*
105            tmp
106        }
107    };
108}
109
110/// Implements the `glium::vertex::Vertex` trait for the given type.
111///
112/// The parameters must be the name of the struct and the names of its fields.
113///
114/// ## Safety
115///
116/// You must not use this macro on any struct with fields that cannot be zeroed.
117///
118/// ## Example
119///
120/// ```
121/// # use glium::implement_vertex;
122/// # fn main() {
123/// #[derive(Copy, Clone)]
124/// struct Vertex {
125///     position: [f32; 3],
126///     tex_coords: [f32; 2],
127/// }
128///
129/// implement_vertex!(Vertex, position, tex_coords);
130/// # }
131/// ```
132///
133/// ## Naming convention
134///
135/// If not using the location option, when it comes to using to using your vertex array in a shader you must make sure that all your attribute variables *match* the field names in the struct you are calling calling this macro for.
136///
137/// So, if you have a `vertex_position` attribute/input in your shader, a field named `vertex_position` must be present in the struct. Otherwise the drawing functions will panic.
138///
139/// ## Normalize option
140///
141/// You can specify a normalize option for attributes.
142/// ```
143/// # #[derive(Clone, Copy)]
144/// # struct Vertex {
145/// #     position: [f32; 2],
146/// #     tex_coords: [f32; 2],
147/// # }
148/// # use glium::implement_vertex;
149/// # fn main() {
150/// implement_vertex!(Vertex, position normalize(false), tex_coords normalize(false));
151/// # }
152/// ```
153/// ## Location option
154///
155/// You can specify a location option for attributes.
156/// ```
157/// # #[derive(Clone, Copy)]
158/// # struct Vertex {
159/// #     position: [f32; 2],
160/// #     tex_coords: [f32; 2],
161/// # }
162/// # use glium::implement_vertex;
163/// # fn main() {
164/// implement_vertex!(Vertex, position location(0), tex_coords location(1));
165/// # }
166/// ```
167#[macro_export]
168macro_rules! implement_vertex {
169    ($struct_name:ident, $($field_name:ident),+) => (
170        impl $struct_name {
171            const BINDINGS: $crate::vertex::VertexFormat = &[
172                $(
173                    (
174                        std::borrow::Cow::Borrowed(stringify!($field_name)),
175                        $crate::__glium_offset_of!($struct_name, $field_name),
176                        -1,
177                        {
178                            const fn attr_type_of_val<T: $crate::vertex::Attribute>(_: Option<&T>)
179                                -> $crate::vertex::AttributeType
180                            {
181                                <T as $crate::vertex::Attribute>::TYPE
182                            }
183                            let field_option = match None::<&$struct_name> {
184                                Some(v) => Some(&v.$field_name),
185                                None => None
186                            };
187                            attr_type_of_val(field_option)
188                        },
189                        false
190                    )
191                ),+
192            ];
193        }
194
195        impl $crate::vertex::Vertex for $struct_name {
196            #[inline]
197            fn build_bindings() -> $crate::vertex::VertexFormat {
198                Self::BINDINGS
199            }
200        }
201    );
202
203    ($struct_name:ident, $($field_name:ident normalize($should_normalize:expr)),+) => {
204        impl $struct_name {
205            const BINDINGS: $crate::vertex::VertexFormat = &[
206                $(
207                    (
208                        std::borrow::Cow::Borrowed(stringify!($field_name)),
209                        $crate::__glium_offset_of!($struct_name, $field_name),
210                        -1,
211                        {
212                            const fn attr_type_of_val<T: $crate::vertex::Attribute>(_: Option<&T>)
213                                -> $crate::vertex::AttributeType
214                            {
215                                <T as $crate::vertex::Attribute>::TYPE
216                            }
217                            let field_option = match None::<&$struct_name> {
218                                Some(v) => Some(&v.$field_name),
219                                None => None
220                            };
221                            attr_type_of_val(field_option)
222                        },
223                        {
224                            $should_normalize
225                        }
226                    )
227                ),+
228            ];
229        }
230        impl $crate::vertex::Vertex for $struct_name {
231            #[inline]
232            fn build_bindings() -> $crate::vertex::VertexFormat {
233                Self::BINDINGS
234            }
235        }
236    };
237
238    ($struct_name:ident, $($field_name:ident location($location:expr)),+) => {
239        impl $struct_name {
240            const BINDINGS: $crate::vertex::VertexFormat = &[
241                $(
242                    (
243                        std::borrow::Cow::Borrowed(stringify!($field_name)),
244                        $crate::__glium_offset_of!($struct_name, $field_name),
245                        {
246                            $location
247                        },
248                        {
249                            const fn attr_type_of_val<T: $crate::vertex::Attribute>(_: Option<&T>)
250                                -> $crate::vertex::AttributeType
251                            {
252                                <T as $crate::vertex::Attribute>::TYPE
253                            }
254                            let field_option = match None::<&$struct_name> {
255                                Some(v) => Some(&v.$field_name),
256                                None => None
257                            };
258                            attr_type_of_val(field_option)
259                        },
260                        false
261                    )
262                ),+
263            ];
264        }
265
266        impl $crate::vertex::Vertex for $struct_name {
267            #[inline]
268            fn build_bindings() -> $crate::vertex::VertexFormat {
269                Self::BINDINGS
270            }
271        }
272    };
273
274    ($struct_name:ident, $($field_name:ident),+,) => (
275        $crate::implement_vertex!($struct_name, $($field_name),+);
276    );
277}
278
279/// Implements the `glium::buffer::Content` trait for the given type.
280///
281/// Contrary to the other similar macros, this one doesn't require you pass the list of parameters.
282///
283/// **Only use this macro on structs.** Using it with anything else will result in a segfault.
284///
285/// ## Example
286///
287/// ```
288/// # use glium::implement_buffer_content;
289/// # fn main() {
290/// struct Data {
291///     data: [u32]
292/// }
293///
294/// implement_buffer_content!(Data);
295/// # }
296/// ```
297///
298#[macro_export]
299// TODO: this whole macro is ultra dangerous
300macro_rules! implement_buffer_content {
301    (__as_item $i:item) => {$i};
302
303    (__impl $struct_name:ident [$($gs:tt)*]) => {
304        implement_buffer_content! { __as_item
305            unsafe impl<$($gs)*> $crate::buffer::Content for $struct_name<$($gs)*> {
306                type Owned = Box<$struct_name<$($gs)*>>;
307
308                #[inline]
309                unsafe fn read<F, E>(size: usize, f: F) -> ::std::result::Result<Box<$struct_name<$($gs)*>>, E>
310                              where F: FnOnce(&mut $struct_name<$($gs)*>) -> ::std::result::Result<(), E>
311                {
312                    use std::mem;
313
314                    assert!(<$struct_name as $crate::buffer::Content>::is_size_suitable(size));
315
316                    let mut storage: Vec<u8> = Vec::with_capacity(size);
317                    unsafe { storage.set_len(size) };
318                    let storage = storage.into_boxed_slice();
319                    let mut storage: Box<$struct_name<$($gs)*>> = unsafe { mem::transmute(storage) };
320
321                    f(&mut storage)?;
322                    Ok(storage)
323                }
324
325                #[inline]
326                fn get_elements_size() -> usize {
327                    use std::mem;
328
329                    let fake_ptr: &$struct_name = unsafe { mem::transmute((0usize, 0usize)) };
330                    mem::size_of_val(fake_ptr)
331                }
332
333                #[inline]
334                fn to_void_ptr(&self) -> *const () {
335                    use std::mem;
336                    let (ptr, _): (*const (), usize) = unsafe { mem::transmute(self) };
337                    ptr
338                }
339
340                #[inline]
341                fn ref_from_ptr(ptr: *mut (), size: usize) -> Option<*mut $struct_name<$($gs)*>> {
342                    use std::mem;
343
344                    let fake_ptr: &$struct_name = unsafe { mem::transmute((0usize, 0usize)) };
345                    let min_size = mem::size_of_val(fake_ptr);
346
347                    let fake_ptr: &$struct_name = unsafe { mem::transmute((0usize, 1usize)) };
348                    let step = mem::size_of_val(fake_ptr) - min_size;
349
350                    if size < min_size {
351                        return None;
352                    }
353
354                    let variadic = size - min_size;
355                    if variadic % step != 0 {
356                        return None;
357                    }
358
359                    Some(unsafe { mem::transmute((ptr, (variadic / step) as usize)) })
360                }
361
362                #[inline]
363                fn is_size_suitable(size: usize) -> bool {
364                    use std::mem;
365
366                    let fake_ptr: &$struct_name = unsafe { mem::transmute((0usize, 0usize)) };
367                    let min_size = mem::size_of_val(fake_ptr);
368
369                    let fake_ptr: &$struct_name = unsafe { mem::transmute((0usize, 1usize)) };
370                    let step = mem::size_of_val(fake_ptr) - min_size;
371
372                    size > min_size && (size - min_size) % step == 0
373                }
374            }
375        }
376    };
377
378    ($struct_name:ident,) => (
379        $crate::implement_buffer_content!($struct_name);
380    );
381
382    ($struct_name:ident) => (
383        $crate::implement_buffer_content!(__impl $struct_name []);
384    );
385
386    ($struct_name:ident <$t1:tt>) => (
387        $crate::implement_buffer_content!(__impl $struct_name [$t1]);
388    );
389}
390
391/// Implements the `glium::uniforms::UniformBlock` trait for the given type.
392///
393/// The parameters must be the name of the struct and the names of its fields.
394///
395/// ## Example
396///
397/// ```
398/// # use glium::implement_uniform_block;
399/// # fn main() {
400/// #[derive(Copy, Clone)]
401/// struct Vertex {
402///     value1: [f32; 3],
403///     value2: [f32; 2],
404/// }
405///
406/// implement_uniform_block!(Vertex, value1, value2);
407/// # }
408/// ```
409///
410#[macro_export]
411macro_rules! implement_uniform_block {
412    (__as_item $i:item) => {$i};
413
414    (__impl $struct_name:ident [$($gs:tt)*], $($field_name:ident),+) => (
415        implement_uniform_block! { __as_item
416            impl<$($gs)*> $crate::uniforms::UniformBlock for $struct_name<$($gs)*> {
417                fn matches(layout: &$crate::program::BlockLayout, base_offset: usize)
418                           -> ::std::result::Result<(), $crate::uniforms::LayoutMismatchError>
419                {
420                    use std::mem;
421                    use $crate::program::BlockLayout;
422                    use $crate::uniforms::LayoutMismatchError;
423
424                    if let &BlockLayout::Struct { ref members } = layout {
425                        // checking that each member exists in the input struct
426                        for &(ref name, _) in members {
427                            if $(name != stringify!($field_name) &&)+ true {
428                                return Err(LayoutMismatchError::MissingField {
429                                    name: name.clone(),
430                                });
431                            }
432                        }
433
434                        fn matches_from_ty<T: $crate::uniforms::UniformBlock + ?Sized>(_: Option<&T>,
435                            layout: &$crate::program::BlockLayout, base_offset: usize)
436                            -> ::std::result::Result<(), $crate::uniforms::LayoutMismatchError>
437                        {
438                            <T as $crate::uniforms::UniformBlock>::matches(layout, base_offset)
439                        }
440
441                        // checking that each field of the input struct is correct in the reflection
442                        $(
443                            let reflected_ty = members.iter().find(|&&(ref name, _)| {
444                                                                        name == stringify!($field_name)
445                                                                   });
446                            let reflected_ty = match reflected_ty {
447                                Some(t) => &t.1,
448                                None => return Err(LayoutMismatchError::MissingField {
449                                    name: stringify!($field_name).to_owned(),
450                                })
451                            };
452
453                            let input_offset = mem::offset_of!($struct_name, $field_name);
454                            let dummy_field = None::<&$struct_name>.map(|v| &v.$field_name);
455
456                            match matches_from_ty(dummy_field, reflected_ty, input_offset) {
457                                Ok(_) => (),
458                                Err(e) => return Err(LayoutMismatchError::MemberMismatch {
459                                    member: stringify!($field_name).to_owned(),
460                                    err: Box::new(e),
461                                })
462                            };
463                        )+
464
465                        Ok(())
466
467                    } else {
468                        Err(LayoutMismatchError::LayoutMismatch {
469                            expected: layout.clone(),
470                            obtained: <Self as $crate::uniforms::UniformBlock>::build_layout(base_offset),
471                        })
472                    }
473                }
474
475                fn build_layout(base_offset: usize) -> $crate::program::BlockLayout {
476                    use $crate::program::BlockLayout;
477
478                    fn layout_from_ty<T: $crate::uniforms::UniformBlock + ?Sized>(_: Option<&T>, base_offset: usize)
479                                                                         -> BlockLayout
480                    {
481                        <T as $crate::uniforms::UniformBlock>::build_layout(base_offset)
482                    }
483
484                    BlockLayout::Struct {
485                        members: vec![
486                            $(
487                                (
488                                    stringify!($field_name).to_owned(),
489                                    {
490                                        let offset = $crate::__glium_offset_of!($struct_name, $field_name);
491                                        let field_option = None::<&$struct_name>.map(|v| &v.$field_name);
492                                        layout_from_ty(field_option, offset + base_offset)
493                                    }
494                                ),
495                            )+
496                        ],
497                    }
498                }
499            }
500        }
501    );
502
503    ($struct_name:ident, $($field_name:ident),+,) => (
504        $crate::implement_uniform_block!($struct_name, $($field_name),+);
505    );
506
507    ($struct_name:ident, $($field_name:ident),+) => (
508        $crate::implement_uniform_block!(__impl $struct_name [], $($field_name),+);
509    );
510
511    ($struct_name:ident<$l:tt>, $($field_name:ident),+) => (
512        $crate::implement_uniform_block!(__impl $struct_name [$l], $($field_name),+);
513    );
514}
515
516/// Builds a program depending on the GLSL version supported by the backend.
517///
518/// This is implemented with successive calls to `is_glsl_version_supported()`.
519///
520/// Returns a `glium::program::ProgramChooserCreationError`.
521///
522/// ## Example
523///
524/// ```no_run
525/// use glium::program;
526/// # use glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
527/// # fn example<T>(display: glium::Display<T>) where T: SurfaceTypeTrait + ResizeableSurface {
528/// let program = program!(&display,
529///     300 => {
530///         vertex: r#"
531///             #version 300
532///
533///             void main() {
534///                 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
535///             }
536///         "#,
537///         fragment: r#"
538///             #version 300
539///
540///             out vec4 color;
541///             void main() {
542///                 color = vec4(1.0, 1.0, 0.0, 1.0);
543///             }
544///         "#,
545///     },
546///     110 => {
547///         vertex: r#"
548///             #version 110
549///
550///             void main() {
551///                 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
552///             }
553///         "#,
554///         fragment: r#"
555///             #version 110
556///
557///             void main() {
558///                 gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
559///             }
560///         "#,
561///     },
562///     300 es => {
563///         vertex: r#"
564///             #version 110
565///
566///             void main() {
567///                 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
568///             }
569///         "#,
570///         fragment: r#"
571///             #version 110
572///
573///             void main() {
574///                 gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
575///             }
576///         "#,
577///     },
578/// );
579/// # }
580/// ```
581///
582#[macro_export]
583macro_rules! program {
584    ($facade:expr,) => (
585        Err($crate::program::ProgramChooserCreationError::NoVersion)
586    );
587
588    ($facade:expr,,$($rest:tt)*) => (
589        $crate::program!($facade,$($rest)*)
590    );
591
592    ($facade:expr, $num:tt => $($rest:tt)*) => (
593        {
594            let context = $crate::backend::Facade::get_context($facade);
595            let version = program!(_parse_num_gl $num);
596            $crate::program!(_inner, context, version, $($rest)*)
597        }
598    );
599
600    ($facade:expr, $num:tt es => $($rest:tt)*) => (
601        {
602            let context = $crate::backend::Facade::get_context($facade);
603            let version = program!(_parse_num_gles $num);
604            $crate::program!(_inner, context, version, $($rest)*)
605        }
606    );
607
608    (_inner, $context:ident, $vers:ident, {$($ty:ident:$src:expr),+}$($rest:tt)*) => (
609        if $context.is_glsl_version_supported(&$vers) {
610            let __vertex_shader: &str = "";
611            let __tessellation_control_shader: Option<&str> = None;
612            let __tessellation_evaluation_shader: Option<&str> = None;
613            let __geometry_shader: Option<&str> = None;
614            let __fragment_shader: &str = "";
615            let __outputs_srgb: bool = true;
616            let __uses_point_size: bool = false;
617
618            $(
619                $crate::program!(_program_ty $ty, $src, __vertex_shader, __tessellation_control_shader,
620                         __tessellation_evaluation_shader, __geometry_shader, __fragment_shader,
621                         __outputs_srgb, __uses_point_size);
622            )+
623
624            let input = $crate::program::ProgramCreationInput::SourceCode {
625                vertex_shader: __vertex_shader,
626                tessellation_control_shader: __tessellation_control_shader,
627                tessellation_evaluation_shader: __tessellation_evaluation_shader,
628                geometry_shader: __geometry_shader,
629                fragment_shader: __fragment_shader,
630                transform_feedback_varyings: None,
631                outputs_srgb: __outputs_srgb,
632                uses_point_size: __uses_point_size,
633            };
634
635            $crate::program::Program::new($context, input)
636                           .map_err(|err| $crate::program::ProgramChooserCreationError::from(err))
637
638        } else {
639            $crate::program!($context, $($rest)*)
640        }
641    );
642
643    (_inner, $context:ident, $vers:ident, {$($ty:ident:$src:expr),+,}$($rest:tt)*) => (
644        $crate::program!(_inner, $context, $vers, {$($ty:$src),+} $($rest)*);
645    );
646
647    (_program_ty vertex, $src:expr, $vs:ident, $tcs:ident, $tes:ident, $gs:ident, $fs:ident, $srgb:ident, $ps:ident) => (
648        let $vs = $src;
649    );
650
651    (_program_ty tessellation_control, $src:expr, $vs:ident, $tcs:ident, $tes:ident, $gs:ident, $fs:ident, $srgb:ident, $ps:ident) => (
652        let $tcs = Some($src);
653    );
654
655    (_program_ty tessellation_evaluation, $src:expr, $vs:ident, $tcs:ident, $tes:ident, $gs:ident, $fs:ident, $srgb:ident, $ps:ident) => (
656        let $tes = Some($src);
657    );
658
659    (_program_ty geometry, $src:expr, $vs:ident, $tcs:ident, $tes:ident, $gs:ident, $fs:ident, $srgb:ident, $ps:ident) => (
660        let $gs = Some($src);
661    );
662
663    (_program_ty fragment, $src:expr, $vs:ident, $tcs:ident, $tes:ident, $gs:ident, $fs:ident, $srgb:ident, $ps:ident) => (
664        let $fs = $src;
665    );
666
667    (_program_ty point_size, $src:expr, $vs:ident, $tcs:ident, $tes:ident, $gs:ident, $fs:ident, $srgb:ident, $ps:ident) => (
668        let $ps = $src;
669    );
670
671    (_program_ty outputs_srgb, $src:expr, $vs:ident, $tcs:ident, $tes:ident, $gs:ident, $fs:ident, $srgb:ident, $ps:ident) => (
672        let $srgb = $src;
673    );
674
675    (_parse_num_gl $num:expr) => (
676        if $num == 100 {
677            $crate::Version($crate::Api::GlEs, 1, 0)
678        } else {
679            let num: u32 = $num;
680            $crate::Version($crate::Api::Gl, (num / 100) as u8, ((num % 100) / 10) as u8)
681        }
682    );
683
684    (_parse_num_gles $num:expr) => ({
685        let num: u32 = $num;
686        $crate::Version($crate::Api::GlEs, (num / 100) as u8, ((num % 100) / 10) as u8)
687    });
688}
689
690#[cfg(test)]
691mod tests {
692    #[test]
693    fn trailing_comma_impl_uniforms() {
694        let u = uniform!{ a: 5, b: 6, };
695    }
696
697    #[test]
698    fn trailing_comma_impl_vertex() {
699        #[derive(Copy, Clone)]
700        struct Foo {
701            pos: [f32; 2],
702        }
703
704        implement_vertex!(Foo, pos,);
705    }
706
707    #[test]
708    fn assert_no_error_macro() {
709        struct Dummy;
710        impl Dummy {
711            fn assert_no_error(&self, _: Option<&str>) { }
712        }
713
714        assert_no_gl_error!(Dummy);
715
716        assert_no_gl_error!(Dummy, "hi");
717
718        assert_no_gl_error!(Dummy, "{} {}", 1, 2);
719    }
720}