From a8510376b4b68caf77faf7efbe6f05d22430dd7a Mon Sep 17 00:00:00 2001 From: amd64sucks Date: Sun, 12 Jun 2022 16:49:16 +0200 Subject: [PATCH] Added support for location binding in 'implement_vertex' (#2013) --- src/macros.rs | 59 ++++++++++++++++++++++++++++++++++++-- src/program/raw.rs | 2 +- src/vertex/format.rs | 2 +- src/vertex/mod.rs | 2 +- src/vertex_array_object.rs | 56 +++++++++++++++++++++++++++++------- 5 files changed, 106 insertions(+), 15 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index bdbec376206..48e03293c6f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -97,10 +97,28 @@ macro_rules! uniform { /// /// ## Naming convention /// -/// 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. +/// 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. /// -/// So, if you have a `vertex_position` atribute/input in your shader, a field named `vertex_position` must be present in the struct. Ohterwise the drawing functions will panic. +/// 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. /// +/// ## Normalize option +/// +/// You can specify a normalize option for attributes. +/// ``` +/// # use glium::implement_vertex; +/// # fn main() { +/// implement_vertex!(Vertex, position normalize(false), tex_coords normalize(false)); +/// # } +/// ``` +/// ## Location option +/// +/// You can specify a location option for attributes. +/// ``` +/// # use glium::implement_vertex; +/// # fn main() { +/// implement_vertex!(Vertex, position location(0), tex_coords location(1)); +/// # } +/// ``` #[macro_export] macro_rules! implement_vertex { ($struct_name:ident, $($field_name:ident),+) => ( @@ -116,6 +134,7 @@ macro_rules! implement_vertex { ( Cow::Borrowed(stringify!($field_name)), $crate::__glium_offset_of!($struct_name, $field_name), + -1, { // Obtain the type of the $field_name field of $struct_name and // call get_type on it. @@ -148,6 +167,7 @@ macro_rules! implement_vertex { ( Cow::Borrowed(stringify!($field_name)), $crate::__glium_offset_of!($struct_name, $field_name), + -1, { // Obtain the type of the $field_name field of $struct_name and // call get_type on it. @@ -169,6 +189,41 @@ macro_rules! implement_vertex { } }; + ($struct_name:ident, $($field_name:ident location($location:expr)),+) => { + impl $crate::vertex::Vertex for $struct_name { + #[inline] + fn build_bindings() -> $crate::vertex::VertexFormat { + use std::borrow::Cow; + + // TODO: use a &'static [] if possible + + Cow::Owned(vec![ + $( + ( + Cow::Borrowed(stringify!($field_name)), + $crate::__glium_offset_of!($struct_name, $field_name), + { + $location + }, + { + // Obtain the type of the $field_name field of $struct_name and + // call get_type on it. + fn attr_type_of_val(_: Option<&T>) + -> $crate::vertex::AttributeType + { + ::get_type() + } + let field_option = None::<&$struct_name>.map(|v| &v.$field_name); + attr_type_of_val(field_option) + }, + false + ) + ),+ + ]) + } + } + }; + ($struct_name:ident, $($field_name:ident),+,) => ( $crate::implement_vertex!($struct_name, $($field_name),+); ); diff --git a/src/program/raw.rs b/src/program/raw.rs index 683dcc874d2..b98328da2b3 100644 --- a/src/program/raw.rs +++ b/src/program/raw.rs @@ -428,7 +428,7 @@ impl RawProgram { } for elem in buf.elements.iter() { - if format.iter().find(|e| e.1 == elem.offset && e.2 == elem.ty) + if format.iter().find(|e| e.1 == elem.offset && e.3 == elem.ty) .is_none() { return false; diff --git a/src/vertex/format.rs b/src/vertex/format.rs index 0cf5fc82d1e..84a7e5ba927 100644 --- a/src/vertex/format.rs +++ b/src/vertex/format.rs @@ -410,7 +410,7 @@ impl AttributeType { /// third element is the type and the fourth element indicates whether /// or not the element should use fixed-point normalization when /// binding in a VAO. -pub type VertexFormat = Cow<'static, [(Cow<'static, str>, usize, AttributeType, bool)]>; +pub type VertexFormat = Cow<'static, [(Cow<'static, str>, usize, i32, AttributeType, bool)]>; unsafe impl Attribute for i8 { #[inline] diff --git a/src/vertex/mod.rs b/src/vertex/mod.rs index 19e25da36ea..3b5ccb48d1d 100644 --- a/src/vertex/mod.rs +++ b/src/vertex/mod.rs @@ -290,7 +290,7 @@ pub trait Vertex: Copy + Sized { fn is_supported(caps: &C) -> bool where C: CapabilitiesSource { let format = Self::build_bindings(); - for &(_, _, ref ty, _) in format.iter() { + for &(_, _, _, ref ty, _) in format.iter() { if !ty.is_supported(caps) { return false; } diff --git a/src/vertex_array_object.rs b/src/vertex_array_object.rs index 46eab5992f5..6490e7c6e82 100644 --- a/src/vertex_array_object.rs +++ b/src/vertex_array_object.rs @@ -259,10 +259,22 @@ impl VertexArrayObject { { // checking the attributes types for &(_, ref bindings, _, _, _) in vertex_buffers { - for &(ref name, _, ty, _) in bindings.iter() { - let attribute = match program.get_attribute(Borrow::::borrow(name)) { - Some(a) => a, - None => continue + for &(ref name, _, location, ty, _) in bindings.iter() { + let attribute = match location { + -1 => { + // No location specified in Vertex Format. Check name instead + match program.get_attribute(Borrow::::borrow(name)) { + Some(a) => a, + None => continue, + } + } + _ => { + match program.attributes().into_iter() + .find(|(_, a)| a.location == location) { + Some((_, a)) => a, + None => continue, + } + } }; if ty.get_num_components() != attribute.ty.get_num_components() || @@ -274,11 +286,23 @@ impl VertexArrayObject { } } + // checking for duplicate attribute locations + for &(_, ref bindings, _, _, _) in vertex_buffers { + for (i, bi) in bindings.iter().enumerate() { + for (o, bo) in bindings.iter().enumerate() { + if i != o && bi.2 == bo.2 { + panic!("The program attribute `{}` has the same binding location as program attribute `{}` (binding location {})", + bi.0, bo.0, bi.2) + } + } + } + } + // checking for missing attributes - for (&ref name, _) in program.attributes() { + for (&ref name, attribute) in program.attributes() { let mut found = false; for &(_, ref bindings, _, _, _) in vertex_buffers { - if bindings.iter().any(|&(ref n, _, _, _)| n == name) { + if bindings.iter().any(|&(ref n, _, location, _, _)| (location != -1 && location == attribute.location) || n == name) { found = true; break; } @@ -520,12 +544,24 @@ unsafe fn bind_attribute(ctxt: &mut CommandContext<'_>, program: &Program, } // binding attributes - for &(ref name, offset, ty, normalize) in bindings.iter() { + for &(ref name, offset, location, ty, normalize) in bindings.iter() { let (data_type, elements_count, instances_count) = vertex_binding_type_to_gl(ty); - let attribute = match program.get_attribute(Borrow::::borrow(name)) { - Some(a) => a, - None => continue + let attribute = match location { + -1 => { + // No location specified in Vertex Format. Check name instead + match program.get_attribute(Borrow::::borrow(name)) { + Some(a) => a, + None => continue, + } + } + _ => { + match program.attributes().into_iter() + .find(|(_, a)| a.location == location) { + Some((_, a)) => a, + None => continue, + } + } }; if attribute.location != -1 {