summaryrefslogtreecommitdiff
path: root/engine/src/rendering/backend/opengl/graphics_mesh.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-06-01 17:15:28 +0200
committerHampusM <hampus@hampusmat.com>2026-06-01 17:15:28 +0200
commitcce08a8557f41f792074cc46c1a7f8e8213e3b2d (patch)
tree15dbc519bcf68d8317e9fe103507e8f32cfb5de8 /engine/src/rendering/backend/opengl/graphics_mesh.rs
parent0ec6a59505d8dbc6f2c1534c0ac5a7b1d7f17967 (diff)
refactor(engine): make gl renderer a rendering backendHEADmaster
Diffstat (limited to 'engine/src/rendering/backend/opengl/graphics_mesh.rs')
-rw-r--r--engine/src/rendering/backend/opengl/graphics_mesh.rs216
1 files changed, 216 insertions, 0 deletions
diff --git a/engine/src/rendering/backend/opengl/graphics_mesh.rs b/engine/src/rendering/backend/opengl/graphics_mesh.rs
new file mode 100644
index 0000000..4933197
--- /dev/null
+++ b/engine/src/rendering/backend/opengl/graphics_mesh.rs
@@ -0,0 +1,216 @@
+use opengl_bindings::buffer::{Buffer as GlBuffer, Usage as GlBufferUsage};
+use opengl_bindings::vertex_array::{
+ AttributeFormat as GlVertexArrayAttributeFormat,
+ BindVertexBufferError as GlVertexArrayBindVertexBufferError,
+ DataType as GlVertexArrayDataType,
+ VertexArray as GlVertexArray,
+ VertexBufferSpec as GlVertexArrayVertexBufferSpec,
+};
+use opengl_bindings::MaybeCurrentContextWithFns as GlCurrentContextWithFns;
+
+use crate::mesh::{Mesh, VertexAttrType};
+use crate::rendering::MeshUsage;
+use crate::shader::VertexDescription as ShaderVertexDescription;
+
+#[derive(Debug)]
+pub struct GraphicsMesh
+{
+ /// Vertex and index buffer has to live as long as the vertex array
+ vertex_buffer: GlBuffer<u8>,
+ pub index_buffer: Option<GlBuffer<u32>>,
+ pub element_cnt: u32,
+ pub vertex_arr: GlVertexArray,
+}
+
+impl GraphicsMesh
+{
+ #[tracing::instrument(skip_all)]
+ pub fn new(
+ 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);
+
+ let vertex_arr = GlVertexArray::new(current_context);
+ let vertex_buffer = GlBuffer::new(current_context);
+
+ vertex_buffer
+ .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_buffer,
+ GlVertexArrayVertexBufferSpec {
+ offset: 0,
+ vertex_size: mesh.vertex_buf().vertex_size(),
+ },
+ ) {
+ match err {
+ GlVertexArrayBindVertexBufferError::OffsetValueTooLarge {
+ value: _,
+ max_value: _,
+ } => unreachable!(),
+ GlVertexArrayBindVertexBufferError::VertexSizeValueTooLarge {
+ value,
+ max_value,
+ } => {
+ panic!(
+ "Size of vertex ({}) is too large. Must be less than {max_value}",
+ value
+ );
+ }
+ }
+ }
+
+ 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);
+
+ index_buffer
+ .store(current_context, indices, buffer_usage)
+ .map_err(Error::StoreIndicesFailed)?;
+
+ vertex_arr.bind_element_buffer(current_context, &index_buffer);
+
+ return Ok(Self {
+ vertex_buffer: vertex_buffer,
+ index_buffer: Some(index_buffer),
+ element_cnt: indices
+ .len()
+ .try_into()
+ .expect("Mesh index count does not fit into a 32-bit unsigned int"),
+ vertex_arr,
+ });
+ }
+
+ Ok(Self {
+ vertex_buffer: vertex_buffer,
+ index_buffer: None,
+ element_cnt: mesh
+ .vertex_buf()
+ .len()
+ .try_into()
+ .expect("Mesh vertex count does not fit into a 32-bit unsigned int"),
+ vertex_arr,
+ })
+ }
+
+ pub fn update(
+ &mut self,
+ current_context: &GlCurrentContextWithFns,
+ mesh: &Mesh,
+ mesh_usage: MeshUsage,
+ ) -> Result<(), Error>
+ {
+ let buffer_usage = mesh_usage_to_gl_buffer_usage(mesh_usage);
+
+ self.vertex_buffer
+ .store(current_context, mesh.vertex_buf().as_bytes(), buffer_usage)
+ .map_err(Error::StoreVerticesFailed)?;
+
+ if let Some(indices) = mesh.indices() {
+ let index_buffer = self
+ .index_buffer
+ .get_or_insert_with(|| GlBuffer::new(current_context));
+
+ index_buffer
+ .store(current_context, indices, buffer_usage)
+ .map_err(Error::StoreIndicesFailed)?;
+
+ self.vertex_arr
+ .bind_element_buffer(current_context, &index_buffer);
+
+ self.element_cnt = indices
+ .len()
+ .try_into()
+ .expect("Mesh index count does not fit into a 32-bit unsigned int");
+
+ return Ok(());
+ }
+
+ self.element_cnt = mesh
+ .vertex_buf()
+ .len()
+ .try_into()
+ .expect("Mesh vertex count does not fit into a 32-bit unsigned int");
+
+ Ok(())
+ }
+
+ pub fn destroy(&mut self, curr_gl_ctx: &GlCurrentContextWithFns)
+ {
+ self.vertex_arr.delete(curr_gl_ctx);
+ self.vertex_buffer.delete(curr_gl_ctx);
+
+ if let Some(index_buffer) = &self.index_buffer {
+ index_buffer.delete(curr_gl_ctx);
+ }
+ }
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum Error
+{
+ #[error("Failed to store vertices in vertex buffer")]
+ StoreVerticesFailed(#[source] opengl_bindings::buffer::Error),
+
+ #[error("Failed to store indices in index buffer")]
+ StoreIndicesFailed(#[source] opengl_bindings::buffer::Error),
+}
+
+fn mesh_usage_to_gl_buffer_usage(mesh_usage: MeshUsage) -> GlBufferUsage
+{
+ match mesh_usage {
+ MeshUsage::Stream => GlBufferUsage::Stream,
+ MeshUsage::Static => GlBufferUsage::Static,
+ MeshUsage::Dynamic => GlBufferUsage::Dynamic,
+ }
+}