summaryrefslogtreecommitdiff
path: root/engine/src/rendering/backend/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/rendering/backend/opengl')
-rw-r--r--engine/src/rendering/backend/opengl/graphics_mesh.rs185
1 files changed, 139 insertions, 46 deletions
diff --git a/engine/src/rendering/backend/opengl/graphics_mesh.rs b/engine/src/rendering/backend/opengl/graphics_mesh.rs
index 6d5c248..a1c903b 100644
--- a/engine/src/rendering/backend/opengl/graphics_mesh.rs
+++ b/engine/src/rendering/backend/opengl/graphics_mesh.rs
@@ -1,3 +1,5 @@
+use std::hint::cold_path;
+
use opengl_bindings::buffer::{Buffer as GlBuffer, Usage as GlBufferUsage};
use opengl_bindings::vertex_array::{
AttributeFormat as GlVertexArrayAttributeFormat,
@@ -8,15 +10,20 @@ use opengl_bindings::vertex_array::{
};
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::MeshUsage;
+const VERTEX_BUF_BINDING_INDEX: u32 = 0;
+
#[derive(Debug)]
pub struct GraphicsMesh
{
/// Vertex and index buffer has to live as long as the vertex array
vertex_buffer: GlBuffer<u8>,
+ vertex_attr_props: Vec<MeshVertexAttrProperties>,
+ last_used_vertex_attr_cnt: u32,
pub index_buffer: Option<GlBuffer<u32>>,
pub element_cnt: u32,
pub vertex_arr: GlVertexArray,
@@ -29,7 +36,6 @@ impl GraphicsMesh
current_context: &GlCurrentContextWithFns,
mesh: &Mesh,
mesh_usage: MeshUsage,
- vertex_desc: &ShaderVertexDescription,
) -> Result<Self, Error>
{
let buffer_usage = mesh_usage_to_gl_buffer_usage(mesh_usage);
@@ -41,11 +47,9 @@ impl GraphicsMesh
.store(current_context, mesh.vertex_buf().as_bytes(), buffer_usage)
.map_err(Error::StoreVerticesFailed)?;
- let vertex_buf_binding_index = 0;
-
if let Err(err) = vertex_arr.bind_vertex_buffer(
current_context,
- vertex_buf_binding_index,
+ VERTEX_BUF_BINDING_INDEX,
&vertex_buffer,
GlVertexArrayVertexBufferSpec {
offset: 0,
@@ -69,48 +73,6 @@ impl GraphicsMesh
}
}
- for vertex_attr_props in mesh.vertex_buf().vertex_attr_props() {
- let vertex_field_desc = vertex_desc
- .fields
- .iter()
- .find(|vertex_field_desc| {
- *vertex_field_desc.name == vertex_attr_props.name
- })
- .unwrap();
-
- let attrib_index: u32 =
- vertex_field_desc.varying_input_offset.try_into().unwrap();
-
- vertex_arr.enable_attrib(current_context, attrib_index);
-
- vertex_arr.set_attrib_format(
- current_context,
- attrib_index,
- match &vertex_attr_props.ty {
- VertexAttrType::Float32 => GlVertexArrayAttributeFormat {
- data_type: GlVertexArrayDataType::Float,
- count: 1,
- normalized: false,
- offset: vertex_attr_props.byte_offset.try_into().unwrap(),
- },
- VertexAttrType::Float32Array { length } => {
- GlVertexArrayAttributeFormat {
- data_type: GlVertexArrayDataType::Float,
- count: (*length).try_into().unwrap(),
- normalized: false,
- offset: vertex_attr_props.byte_offset.try_into().unwrap(),
- }
- }
- },
- );
-
- vertex_arr.set_attrib_vertex_buf_binding(
- current_context,
- attrib_index,
- vertex_buf_binding_index,
- );
- }
-
if let Some(indices) = mesh.indices() {
let index_buffer = GlBuffer::new(current_context);
@@ -122,6 +84,8 @@ impl GraphicsMesh
return Ok(Self {
vertex_buffer: vertex_buffer,
+ vertex_attr_props: mesh.vertex_buf().vertex_attr_props().to_vec(),
+ last_used_vertex_attr_cnt: 0,
index_buffer: Some(index_buffer),
element_cnt: indices
.len()
@@ -133,6 +97,8 @@ impl GraphicsMesh
Ok(Self {
vertex_buffer: vertex_buffer,
+ vertex_attr_props: mesh.vertex_buf().vertex_attr_props().to_vec(),
+ last_used_vertex_attr_cnt: 0,
index_buffer: None,
element_cnt: mesh
.vertex_buf()
@@ -185,6 +151,113 @@ impl GraphicsMesh
Ok(())
}
+ pub fn update_vertex_attrs_for_shader(
+ &mut self,
+ curr_gl_ctx: &GlCurrentContextWithFns,
+ shader_vertex_desc: &ShaderVertexDescription,
+ ) -> Result<(), VertexAttrsUpdatingError>
+ {
+ let vertex_field_desc_cnt = u32::try_from(shader_vertex_desc.fields.len())
+ .expect("Shader has too many vertex fields. Count does not fit into u32");
+
+ if self.last_used_vertex_attr_cnt > vertex_field_desc_cnt {
+ for index in vertex_field_desc_cnt..self.last_used_vertex_attr_cnt {
+ self.vertex_arr.disable_attrib(curr_gl_ctx, index);
+ }
+ }
+
+ let mut used_vertex_attr_cnt = 0u32;
+
+ let mut last_attr_index: Option<u32> = None;
+
+ for vertex_attr_props in &self.vertex_attr_props {
+ let Some(vertex_field_desc) =
+ shader_vertex_desc.fields.iter().find(|vertex_field_desc| {
+ *vertex_field_desc.name == vertex_attr_props.name
+ })
+ else {
+ continue;
+ };
+
+ let attrib_index: u32 =
+ vertex_field_desc.varying_input_offset.try_into().unwrap();
+
+ if let Some(last_attr_index) = last_attr_index {
+ if last_attr_index.wrapping_add(1) != attrib_index {
+ cold_path();
+ return Err(
+ VertexAttrsUpdatingError::VertexAttrIndicesNotConsecutive,
+ );
+ }
+ } else if attrib_index != 0 {
+ cold_path();
+ return Err(VertexAttrsUpdatingError::FirstVertexAttrIndexNotZero {
+ vertex_attr_name: vertex_attr_props.name.to_string().into_boxed_str(),
+ unexpected_index: attrib_index,
+ });
+ }
+
+ last_attr_index = Some(attrib_index);
+
+ self.vertex_arr.enable_attrib(curr_gl_ctx, attrib_index);
+
+ self.vertex_arr.set_attrib_format(
+ curr_gl_ctx,
+ attrib_index,
+ match &vertex_attr_props.ty {
+ VertexAttrType::Float32 => GlVertexArrayAttributeFormat {
+ data_type: GlVertexArrayDataType::Float,
+ count: 1,
+ normalized: false,
+ offset: vertex_attr_props.byte_offset.try_into().unwrap(),
+ },
+ VertexAttrType::Float32Array { length } => {
+ GlVertexArrayAttributeFormat {
+ data_type: GlVertexArrayDataType::Float,
+ count: (*length).try_into().unwrap(),
+ normalized: false,
+ offset: vertex_attr_props.byte_offset.try_into().unwrap(),
+ }
+ }
+ },
+ );
+
+ self.vertex_arr.set_attrib_vertex_buf_binding(
+ curr_gl_ctx,
+ attrib_index,
+ VERTEX_BUF_BINDING_INDEX,
+ );
+
+ used_vertex_attr_cnt += 1;
+ }
+
+ self.last_used_vertex_attr_cnt = used_vertex_attr_cnt;
+
+ if used_vertex_attr_cnt as usize != shader_vertex_desc.fields.len() {
+ cold_path();
+
+ return Err(VertexAttrsUpdatingError::MissingVertexAttrs(
+ shader_vertex_desc
+ .fields
+ .iter()
+ .filter_map(|vertex_field_desc| {
+ if self
+ .vertex_attr_props
+ .iter()
+ .any(|prop| prop.name == *vertex_field_desc.name)
+ {
+ return None;
+ }
+
+ Some(vertex_field_desc.name.clone())
+ })
+ .collect(),
+ ));
+ }
+
+ Ok(())
+ }
+
pub fn destroy(&mut self, curr_gl_ctx: &GlCurrentContextWithFns)
{
self.vertex_arr.delete(curr_gl_ctx);
@@ -206,6 +279,26 @@ pub enum Error
StoreIndicesFailed(#[source] opengl_bindings::buffer::Error),
}
+#[derive(Debug, thiserror::Error)]
+pub enum VertexAttrsUpdatingError
+{
+ #[error("Mesh is missing vertex attribute(s) required by shader: {0:?}")]
+ MissingVertexAttrs(Vec<Box<str>>),
+
+ #[error("Shader's vertex attribute indices are not consecutive")]
+ VertexAttrIndicesNotConsecutive,
+
+ #[error(
+ "Shader's first vertex attribute ({vertex_attr_name}) index is not 0, is {}",
+ unexpected_index
+ )]
+ FirstVertexAttrIndexNotZero
+ {
+ vertex_attr_name: Box<str>,
+ unexpected_index: u32,
+ },
+}
+
fn mesh_usage_to_gl_buffer_usage(mesh_usage: MeshUsage) -> GlBufferUsage
{
match mesh_usage {