From c611ee62477564fbe532f51e8526bae2e82dae93 Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 13 Aug 2026 14:16:39 +0200 Subject: feat(engine): add standardized names for mesh vertex attrs & vertex shader input --- .../src/rendering/backend/opengl/graphics_mesh.rs | 29 +++-- engine/src/rendering/shader.rs | 120 +++++++++++++++++++-- 2 files changed, 129 insertions(+), 20 deletions(-) (limited to 'engine/src/rendering') diff --git a/engine/src/rendering/backend/opengl/graphics_mesh.rs b/engine/src/rendering/backend/opengl/graphics_mesh.rs index fba60c8..f6b7d56 100644 --- a/engine/src/rendering/backend/opengl/graphics_mesh.rs +++ b/engine/src/rendering/backend/opengl/graphics_mesh.rs @@ -12,8 +12,12 @@ use opengl_bindings::MaybeCurrentContextWithFns as GlCurrentContextWithFns; use crate::mesh::vertex_buffer::VertexAttrProperties as MeshVertexAttrProperties; use crate::mesh::{Mesh, VertexAttrType}; -use crate::rendering::shader::VertexDescription as ShaderVertexDescription; +use crate::rendering::shader::{ + VertexDescription as ShaderVertexDescription, + VertexInputSemName, +}; use crate::rendering::MeshUsage; +use crate::util::DisplaySlice; const VERTEX_BUF_BINDING_INDEX: u32 = 0; @@ -171,7 +175,9 @@ impl GraphicsMesh for vertex_attr_props in &self.vertex_attr_props { let Some(vertex_input_desc) = shader_vertex_desc.inputs.iter().find(|vertex_input_desc| { - *vertex_input_desc.name == vertex_attr_props.name + vertex_input_desc + .semantic_name + .matches_vertex_label(&vertex_attr_props.label) }) else { continue; @@ -221,15 +227,15 @@ impl GraphicsMesh .inputs .iter() .filter_map(|vertex_input_desc| { - if self - .vertex_attr_props - .iter() - .any(|prop| prop.name == *vertex_input_desc.name) - { + if self.vertex_attr_props.iter().any(|props| { + vertex_input_desc + .semantic_name + .matches_vertex_label(&props.label) + }) { return None; } - Some(vertex_input_desc.name.clone()) + Some(vertex_input_desc.semantic_name.clone()) }) .collect(), )); @@ -262,8 +268,11 @@ pub enum Error #[derive(Debug, thiserror::Error)] pub enum VertexAttrsUpdatingError { - #[error("Mesh is missing vertex attribute(s) required by shader: {0:?}")] - MissingVertexAttrs(Vec>), + #[error( + "Mesh is missing equivalent vertex attribute(s) for shader's vertex inputs: {}", + DisplaySlice::new(.0) + )] + MissingVertexAttrs(Vec), } fn mesh_usage_to_gl_buffer_usage(mesh_usage: MeshUsage) -> GlBufferUsage diff --git a/engine/src/rendering/shader.rs b/engine/src/rendering/shader.rs index 3142400..6f50a79 100644 --- a/engine/src/rendering/shader.rs +++ b/engine/src/rendering/shader.rs @@ -1,7 +1,7 @@ use std::any::type_name; use std::borrow::Cow; -use std::collections::HashMap; -use std::fmt::Debug; +use std::collections::{HashMap, HashSet}; +use std::fmt::{Debug, Display, Write}; use std::path::Path; use std::str::Utf8Error; use std::sync::Arc; @@ -34,10 +34,16 @@ use crate::ecs::pair::ChildOf; use crate::ecs::phase::{Phase, POST_UPDATE as POST_UPDATE_PHASE}; use crate::ecs::sole::Single; use crate::ecs::{declare_entity, pair, Component, Sole}; +use crate::mesh::vertex_buffer::VertexLabel; pub mod cursor; pub mod default; +pub const STD_VERTEX_INPUT_SEMANTIC_NAME_POSITION: &str = "STD_POSITION"; +pub const STD_VERTEX_INPUT_SEMANTIC_NAME_NORMAL: &str = "STD_NORMAL"; +pub const STD_VERTEX_INPUT_SEMANTIC_NAME_UV: &str = "STD_UV"; +pub const STD_VERTEX_INPUT_SEMANTIC_NAME_COLOR: &str = "STD_COLOR"; + #[derive(Debug, Clone, Component)] pub struct Shader { @@ -983,15 +989,31 @@ impl VertexDescription ); }); + let mut seen_inputs = HashSet::::new(); + Ok(Self { inputs: inputs .filter(|var_input| var_input.type_layout.kind() != TypeKind::Struct) .map(|var_input| { - let name = var_input - .var_layout - .name() - .unwrap_or("") - .to_string(); + let name = var_input.var_layout.name().unwrap_or(""); + + let semantic_name = + var_input.var_layout.semantic_name().ok_or_else(|| { + VertexDescriptionError::VertexInputMissingSemanticName { + name: name.to_owned(), + } + })?; + + let semantic_name = + VertexInputSemName::from_semantic_name(semantic_name); + + if seen_inputs.contains(&semantic_name) { + return Err( + VertexDescriptionError::VertexInputHasOccupiedSemanticName { + name: name.to_owned(), + }, + ); + } let scalar_type = match ( var_input.type_layout.kind(), @@ -1002,14 +1024,16 @@ impl VertexDescription _ => { return Err( VertexDescriptionError::UnsupportedVertexInputType { - name, + name: name.to_owned(), }, ); } }; + seen_inputs.insert(semantic_name.clone()); + Ok(VertexInputDescription { - name: name.into_boxed_str(), + semantic_name, index: var_input.index, type_kind: var_input.type_layout.kind(), scalar_type, @@ -1022,14 +1046,76 @@ impl VertexDescription } #[derive(Debug)] +#[non_exhaustive] pub struct VertexInputDescription { - pub name: Box, + pub semantic_name: VertexInputSemName, pub index: usize, pub type_kind: TypeKind, pub scalar_type: ScalarType, } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum VertexInputSemName +{ + Position, + Normal, + Uv, + Color, + Other(Box), +} + +impl VertexInputSemName +{ + fn from_semantic_name(semantic_name: &str) -> Self + { + match semantic_name { + STD_VERTEX_INPUT_SEMANTIC_NAME_POSITION => Self::Position, + STD_VERTEX_INPUT_SEMANTIC_NAME_NORMAL => Self::Normal, + STD_VERTEX_INPUT_SEMANTIC_NAME_UV => Self::Uv, + STD_VERTEX_INPUT_SEMANTIC_NAME_COLOR => Self::Color, + _ => Self::Other(semantic_name.to_lowercase().into_boxed_str()), + } + } + + pub fn matches_vertex_label(&self, vertex_label: &VertexLabel) -> bool + { + match (self, vertex_label) { + (Self::Position, VertexLabel::Position) + | (Self::Normal, VertexLabel::Normal) + | (Self::Uv, VertexLabel::Uv) + | (Self::Color, VertexLabel::Color) => true, + (Self::Other(other), VertexLabel::Other(other_vertex_label)) => { + **other == *other_vertex_label + } + _ => false, + } + } +} + +impl Display for VertexInputSemName +{ + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + match self { + Self::Position => { + formatter.write_str(STD_VERTEX_INPUT_SEMANTIC_NAME_POSITION) + } + Self::Normal => formatter.write_str(STD_VERTEX_INPUT_SEMANTIC_NAME_NORMAL), + Self::Uv => formatter.write_str(STD_VERTEX_INPUT_SEMANTIC_NAME_UV), + Self::Color => formatter.write_str(STD_VERTEX_INPUT_SEMANTIC_NAME_COLOR), + Self::Other(other) => { + for character in other.chars() { + formatter.write_char(character.to_ascii_uppercase())?; + } + + Ok(()) + } + } + } +} + #[derive(Debug, thiserror::Error)] pub enum VertexDescriptionError { @@ -1041,6 +1127,20 @@ pub enum VertexDescriptionError { name: String }, + + #[error("Vertex input '{name}' is missing a semantic name")] + VertexInputMissingSemanticName + { + name: String + }, + + #[error( + "Vertex input '{name}' has a semantic name already used by another vertex input" + )] + VertexInputHasOccupiedSemanticName + { + name: String + }, } #[derive(Debug, thiserror::Error)] -- cgit v1.2.3-18-g5258