summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine/res/default_shader.slang6
-rw-r--r--engine/res/imgui_shader.slang6
-rw-r--r--engine/src/file_format/wavefront/obj.rs15
-rw-r--r--engine/src/mesh.rs5
-rw-r--r--engine/src/mesh/cube.rs15
-rw-r--r--engine/src/mesh/vertex_buffer.rs51
-rw-r--r--engine/src/rendering/backend/opengl/graphics_mesh.rs29
-rw-r--r--engine/src/rendering/shader.rs120
-rw-r--r--engine/src/ui/dear_imgui.rs19
-rw-r--r--engine/src/util.rs45
10 files changed, 234 insertions, 77 deletions
diff --git a/engine/res/default_shader.slang b/engine/res/default_shader.slang
index 62b01f7..7da164c 100644
--- a/engine/res/default_shader.slang
+++ b/engine/res/default_shader.slang
@@ -224,9 +224,9 @@ struct VertexStageOutput
struct Vertex
{
- float3 pos;
- float2 texture_coords;
- float3 normal;
+ float3 pos : STD_POSITION;
+ float2 texture_coords : STD_UV;
+ float3 normal : STD_NORMAL;
};
struct Fragment
diff --git a/engine/res/imgui_shader.slang b/engine/res/imgui_shader.slang
index 2bdd718..29ad9bf 100644
--- a/engine/res/imgui_shader.slang
+++ b/engine/res/imgui_shader.slang
@@ -1,8 +1,8 @@
struct Vertex
{
- float3 pos;
- float4 color;
- float2 texture_coords;
+ float3 pos : STD_POSITION;
+ float4 color : STD_COLOR;
+ float2 texture_coords : STD_UV;
};
struct VertexData
diff --git a/engine/src/file_format/wavefront/obj.rs b/engine/src/file_format/wavefront/obj.rs
index ebbbe45..3fcb17b 100644
--- a/engine/src/file_format/wavefront/obj.rs
+++ b/engine/src/file_format/wavefront/obj.rs
@@ -17,8 +17,9 @@ use crate::mesh::vertex_buffer::{
NamedVertexAttr,
VertexAttrInfo,
VertexBuffer as MeshVertexBuffer,
+ VertexLabel,
};
-use crate::mesh::{Mesh, VertexAttrType, POSITION_VERTEX_ATTRIB_NAME};
+use crate::mesh::{Mesh, VertexAttrType};
use crate::util::try_option;
use crate::vector::{Vec2, Vec3};
@@ -90,15 +91,15 @@ impl Obj
let mut vertex_buf = MeshVertexBuffer::with_capacity(
&[
VertexAttrInfo {
- name: POSITION_VERTEX_ATTRIB_NAME.into(),
+ label: VertexLabel::Position,
ty: VertexAttrType::Float32Array { length: 3 },
},
VertexAttrInfo {
- name: "texture_coords".into(),
+ label: VertexLabel::Uv,
ty: VertexAttrType::Float32Array { length: 2 },
},
VertexAttrInfo {
- name: "normal".into(),
+ label: VertexLabel::Normal,
ty: VertexAttrType::Float32Array { length: 3 },
},
],
@@ -170,15 +171,15 @@ impl Obj
vertex_buf.push((
NamedVertexAttr {
- name: POSITION_VERTEX_ATTRIB_NAME,
+ label: VertexLabel::Position,
value: pos.into_array(),
},
NamedVertexAttr {
- name: "texture_coords",
+ label: VertexLabel::Uv,
value: texture_pos.into_array(),
},
NamedVertexAttr {
- name: "normal",
+ label: VertexLabel::Normal,
value: normal.into_array(),
},
));
diff --git a/engine/src/mesh.rs b/engine/src/mesh.rs
index 9aa1f80..82e2877 100644
--- a/engine/src/mesh.rs
+++ b/engine/src/mesh.rs
@@ -1,12 +1,11 @@
use std::alloc::Layout;
+use crate::mesh::vertex_buffer::VertexLabel;
use crate::vector::Vec3;
pub mod cube;
pub mod vertex_buffer;
-pub const POSITION_VERTEX_ATTRIB_NAME: &str = "pos";
-
#[derive(Debug, Clone)]
pub struct Mesh
{
@@ -58,7 +57,7 @@ impl Mesh
{
let mut pos_iter = self
.vertex_buf()
- .iter::<[f32; 3]>(POSITION_VERTEX_ATTRIB_NAME)
+ .iter::<[f32; 3]>(VertexLabel::Position)
.map(|vertex_pos| Vec3::from(*vertex_pos))
.into_iter();
diff --git a/engine/src/mesh/cube.rs b/engine/src/mesh/cube.rs
index 61d1e26..a89466a 100644
--- a/engine/src/mesh/cube.rs
+++ b/engine/src/mesh/cube.rs
@@ -7,8 +7,9 @@ use crate::mesh::vertex_buffer::{
NamedVertexAttr,
VertexAttrInfo,
VertexBuffer as MeshVertexBuffer,
+ VertexLabel,
};
-use crate::mesh::{Mesh, VertexAttrType, POSITION_VERTEX_ATTRIB_NAME};
+use crate::mesh::{Mesh, VertexAttrType};
use crate::vector::{Vec2, Vec3};
builder! {
@@ -98,15 +99,15 @@ impl Data
let mut vertex_buf = MeshVertexBuffer::with_capacity(
&[
VertexAttrInfo {
- name: POSITION_VERTEX_ATTRIB_NAME.into(),
+ label: VertexLabel::Position,
ty: VertexAttrType::Float32Array { length: 3 },
},
VertexAttrInfo {
- name: "texture_coords".into(),
+ label: VertexLabel::Uv,
ty: VertexAttrType::Float32Array { length: 2 },
},
VertexAttrInfo {
- name: "normal".into(),
+ label: VertexLabel::Normal,
ty: VertexAttrType::Float32Array { length: 3 },
},
],
@@ -156,15 +157,15 @@ impl Data
vertex_buf.push((
NamedVertexAttr {
- name: POSITION_VERTEX_ATTRIB_NAME,
+ label: VertexLabel::Position,
value: vertex_pos.into_array(),
},
NamedVertexAttr {
- name: "texture_coords",
+ label: VertexLabel::Uv,
value: vertex_uv.into_array(),
},
NamedVertexAttr {
- name: "normal",
+ label: VertexLabel::Normal,
value: vertex_normal.into_array(),
},
));
diff --git a/engine/src/mesh/vertex_buffer.rs b/engine/src/mesh/vertex_buffer.rs
index 9d77270..4df3ffc 100644
--- a/engine/src/mesh/vertex_buffer.rs
+++ b/engine/src/mesh/vertex_buffer.rs
@@ -30,9 +30,9 @@ impl<const LEN: usize> VertexAttrValue for [f32; LEN]
}
#[derive(Debug)]
-pub struct NamedVertexAttr<'name, Value: VertexAttrValue>
+pub struct NamedVertexAttr<Value: VertexAttrValue>
{
- pub name: &'name str,
+ pub label: VertexLabel,
pub value: Value,
}
@@ -40,7 +40,7 @@ pub struct NamedVertexAttr<'name, Value: VertexAttrValue>
#[non_exhaustive]
pub struct VertexAttrProperties
{
- pub name: Cow<'static, str>,
+ pub label: VertexLabel,
pub ty: VertexAttrType,
pub layout: Layout,
pub byte_offset: usize,
@@ -49,10 +49,20 @@ pub struct VertexAttrProperties
#[derive(Debug)]
pub struct VertexAttrInfo
{
- pub name: Cow<'static, str>,
+ pub label: VertexLabel,
pub ty: VertexAttrType,
}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum VertexLabel
+{
+ Position,
+ Normal,
+ Uv,
+ Color,
+ Other(Cow<'static, str>),
+}
+
#[derive(Debug, Clone, Default)]
pub struct VertexBuffer
{
@@ -67,8 +77,8 @@ impl VertexBuffer
{
let mut vertex_attr_props = vertex_attrs
.iter()
- .map(|VertexAttrInfo { name, ty }| VertexAttrProperties {
- name: name.clone(),
+ .map(|VertexAttrInfo { label, ty }| VertexAttrProperties {
+ label: label.clone(),
ty: ty.clone(),
layout: ty.layout(),
byte_offset: 0,
@@ -78,10 +88,9 @@ impl VertexBuffer
let mut vertex_layout = Layout::new::<()>();
for VertexAttrProperties {
- name: _,
- ty: _,
layout: vertex_attr_layout,
byte_offset: vertex_attr_byte_offset,
+ ..
} in &mut vertex_attr_props
{
let (new_struct_layout, byte_offset) =
@@ -100,10 +109,7 @@ impl VertexBuffer
}
}
- pub fn push<'name, VertexAttrs: NamedVertexAttrs<'name>>(
- &mut self,
- vertex: VertexAttrs,
- )
+ pub fn push<VertexAttrs: NamedVertexAttrs>(&mut self, vertex: VertexAttrs)
{
assert_eq!(
self.vertex_attr_props.len(),
@@ -119,11 +125,11 @@ impl VertexBuffer
let vertex_attrs = vertex.vertex_attrs();
- for (vertex_attr_name, vertex_attr_bytes, vertex_attr_ty) in vertex_attrs {
+ for (vertex_label, vertex_attr_bytes, vertex_attr_ty) in vertex_attrs {
let vertex_attr_props = self
.vertex_attr_props
.iter()
- .find(|vertex_attr_props| vertex_attr_props.name == vertex_attr_name)
+ .find(|vertex_attr_props| &vertex_attr_props.label == vertex_label)
.unwrap();
assert_eq!(vertex_attr_ty, vertex_attr_props.ty);
@@ -170,13 +176,13 @@ impl VertexBuffer
pub fn iter<VertexAttr: VertexAttrValue>(
&self,
- vertex_attr_name: &str,
+ vertex_label: VertexLabel,
) -> Iter<'_, VertexAttr>
{
let vertex_attr_props = self
.vertex_attr_props
.iter()
- .find(|vertex_attr_props| vertex_attr_props.name == vertex_attr_name)
+ .find(|vertex_attr_props| vertex_attr_props.label == vertex_label)
.unwrap();
assert_eq!(VertexAttr::ty(), vertex_attr_props.ty);
@@ -217,18 +223,19 @@ impl<'a, VertexAttr: VertexAttrValue> Iterator for Iter<'a, VertexAttr>
}
}
-pub trait NamedVertexAttrs<'name>
+pub trait NamedVertexAttrs
{
fn vertex_attr_cnt(&self) -> usize;
- fn vertex_attrs(&self) -> impl Iterator<Item = (&'name str, &[u8], VertexAttrType)>;
+ fn vertex_attrs(&self)
+ -> impl Iterator<Item = (&VertexLabel, &[u8], VertexAttrType)>;
}
macro_rules! impl_named_vertex_attrs {
($cnt: tt) => {
seq!(I in 0..$cnt {
- impl<'name, #(VertexAttr~I: VertexAttrValue,)*>
- NamedVertexAttrs<'name> for (#(NamedVertexAttr<'name, VertexAttr~I>,)*)
+ impl<#(VertexAttr~I: VertexAttrValue,)*>
+ NamedVertexAttrs for (#(NamedVertexAttr<VertexAttr~I>,)*)
{
fn vertex_attr_cnt(&self) -> usize
{
@@ -236,10 +243,10 @@ macro_rules! impl_named_vertex_attrs {
}
fn vertex_attrs(&self)
- -> impl Iterator<Item = (&'name str, &[u8], VertexAttrType)>
+ -> impl Iterator<Item = (&VertexLabel, &[u8], VertexAttrType)>
{
[#(
- (self.I.name, self.I.value.as_bytes(), VertexAttr~I::ty()),
+ (&self.I.label, self.I.value.as_bytes(), VertexAttr~I::ty()),
)*].into_iter()
}
}
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<Box<str>>),
+ #[error(
+ "Mesh is missing equivalent vertex attribute(s) for shader's vertex inputs: {}",
+ DisplaySlice::new(.0)
+ )]
+ MissingVertexAttrs(Vec<VertexInputSemName>),
}
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::<VertexInputSemName>::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("<unnamed>")
- .to_string();
+ let name = var_input.var_layout.name().unwrap_or("<unnamed>");
+
+ 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<str>,
+ 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<str>),
+}
+
+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)]
diff --git a/engine/src/ui/dear_imgui.rs b/engine/src/ui/dear_imgui.rs
index bcdefa1..8f58ff6 100644
--- a/engine/src/ui/dear_imgui.rs
+++ b/engine/src/ui/dear_imgui.rs
@@ -36,12 +36,9 @@ use crate::mesh::vertex_buffer::{
NamedVertexAttr as MeshNamedVertexAttr,
VertexAttrInfo as MeshVertexAttrInfo,
VertexBuffer as MeshVertexBuffer,
+ VertexLabel,
};
-use crate::mesh::{
- Mesh,
- VertexAttrType as MeshVertexAttrType,
- POSITION_VERTEX_ATTRIB_NAME,
-};
+use crate::mesh::{Mesh, VertexAttrType as MeshVertexAttrType};
use crate::projection::{
ClipVolume as ProjectionClipVolume,
Orthographic as OrthographicProjection,
@@ -393,15 +390,15 @@ fn initialize_context(
.vertices(MeshVertexBuffer::with_capacity(
&[
MeshVertexAttrInfo {
- name: POSITION_VERTEX_ATTRIB_NAME.into(),
+ label: VertexLabel::Position,
ty: MeshVertexAttrType::Float32Array { length: 3 },
},
MeshVertexAttrInfo {
- name: "color".into(),
+ label: VertexLabel::Color,
ty: MeshVertexAttrType::Float32Array { length: 4 },
},
MeshVertexAttrInfo {
- name: "texture_coords".into(),
+ label: VertexLabel::Uv,
ty: MeshVertexAttrType::Float32Array { length: 2 },
},
],
@@ -726,15 +723,15 @@ fn add_drawing_render_pass(
for vertex in draw_list.vtx_buffer() {
mesh.vertex_buf_mut().push((
MeshNamedVertexAttr::<[f32; 3]> {
- name: POSITION_VERTEX_ATTRIB_NAME,
+ label: VertexLabel::Position,
value: [vertex.pos[0], vertex.pos[1], 0.0],
},
MeshNamedVertexAttr {
- name: "color",
+ label: VertexLabel::Color,
value: vertex.rgba().map(|elem| (elem as f32) / 255.0),
},
MeshNamedVertexAttr {
- name: "texture_coords",
+ label: VertexLabel::Uv,
value: vertex.uv,
},
));
diff --git a/engine/src/util.rs b/engine/src/util.rs
index bd69734..688778b 100644
--- a/engine/src/util.rs
+++ b/engine/src/util.rs
@@ -1,4 +1,4 @@
-use std::fmt::Debug;
+use std::fmt::{Debug, Display};
use crate::ecs::util::VecExt;
@@ -161,6 +161,49 @@ impl<T> OptionExt<T> for Option<T>
}
}
+pub struct DisplaySlice<'a, Item>
+{
+ slice: &'a [Item],
+}
+
+impl<'a, Item> DisplaySlice<'a, Item>
+{
+ pub fn new(slice: &'a [Item]) -> Self
+ {
+ Self { slice }
+ }
+}
+
+impl<Item> Display for DisplaySlice<'_, Item>
+where
+ Item: Display,
+{
+ fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
+ {
+ let Some(first_item) = self.slice.first() else {
+ return formatter.write_str("<empty>");
+ };
+
+ write!(formatter, "{first_item}")?;
+
+ if self.slice.len() == 1 {
+ return Ok(());
+ }
+
+ for item in &self.slice[1..self.slice.len() - 1] {
+ write!(formatter, ", {item}")?;
+ }
+
+ let Some(last_item) = self.slice.last() else {
+ unreachable!();
+ };
+
+ write!(formatter, " & {last_item}")?;
+
+ Ok(())
+ }
+}
+
macro_rules! try_option {
($expr: expr) => {
match $expr {