diff options
Diffstat (limited to 'engine/src/renderer')
-rw-r--r-- | engine/src/renderer/mod.rs | 79 | ||||
-rw-r--r-- | engine/src/renderer/vertex_array.rs | 62 | ||||
-rw-r--r-- | engine/src/renderer/vertex_buffers.rs | 83 |
3 files changed, 221 insertions, 3 deletions
diff --git a/engine/src/renderer/mod.rs b/engine/src/renderer/mod.rs index 9cd379d..3c42f93 100644 --- a/engine/src/renderer/mod.rs +++ b/engine/src/renderer/mod.rs @@ -1,10 +1,17 @@ -use std::ffi::{c_void, CString}; +use std::ffi::{c_float, c_void, CString}; +use std::mem::size_of; use std::process::abort; +use std::ptr::null; use glfw::WindowSize; +use crate::renderer::vertex_array::{PrimitiveKind, VertexArray}; +use crate::renderer::vertex_buffers::{BufferUsage, VertexBuffers}; use crate::vector::Vec2; +mod vertex_array; +mod vertex_buffers; + pub fn initialize(window: &glfw::Window) -> Result<(), Error> { gl::load_with(|symbol| { @@ -30,10 +37,51 @@ pub fn initialize(window: &glfw::Window) -> Result<(), Error> Ok(()) } -pub fn render() +pub fn render<'renderable>(renderables: impl IntoIterator<Item = &'renderable Renderable>) { unsafe { - gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); + gl::Clear(gl::COLOR_BUFFER_BIT); + } + + for renderable in renderables { + renderable.shader_program.activate(); + + renderable.vertex_arr.draw(PrimitiveKind::Triangles, 0, 3); + } +} + +pub struct Renderable +{ + shader_program: crate::shader::Program, + vertex_arr: VertexArray, +} + +impl Renderable +{ + pub fn new(shader_program: crate::shader::Program, vertices: &[f32]) -> Self + { + let vertex_arr = VertexArray::new(); + + vertex_arr.bind(); + + let vertex_buffer = VertexBuffers::<1>::new(); + + vertex_buffer + .store(0, vertices, BufferUsage::Static) + .unwrap(); + + vertex_attrib_ptr(0); + enable_vertex_attrib_array(0); + + unsafe { + gl::BindBuffer(gl::ARRAY_BUFFER, 0); + gl::BindVertexArray(0); + } + + Self { + shader_program, + vertex_arr, + } } } @@ -57,3 +105,28 @@ pub enum Error #[error("Failed to get window size")] GetWindowSizeFailed(#[source] glfw::Error), } + +fn vertex_attrib_ptr(index: usize) +{ + let stride = 3 * size_of::<c_float>(); + + unsafe { + #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)] + gl::VertexAttribPointer( + index as gl::types::GLuint, + 3, + gl::FLOAT, + gl::FALSE, + stride as gl::types::GLsizei, + null(), + ); + } +} + +fn enable_vertex_attrib_array(index: usize) +{ + unsafe { + #[allow(clippy::cast_possible_truncation)] + gl::EnableVertexAttribArray(index as gl::types::GLuint); + } +} diff --git a/engine/src/renderer/vertex_array.rs b/engine/src/renderer/vertex_array.rs new file mode 100644 index 0000000..e54f638 --- /dev/null +++ b/engine/src/renderer/vertex_array.rs @@ -0,0 +1,62 @@ +pub struct VertexArray +{ + array: gl::types::GLuint, +} + +impl VertexArray +{ + pub fn new() -> Self + { + let mut array = 0; + + unsafe { + gl::GenVertexArrays(1, &mut array); + } + + Self { array } + } + + pub fn draw(&self, primitive_kind: PrimitiveKind, start_index: u32, index_cnt: u32) + { + self.bind(); + + unsafe { + #[allow(clippy::cast_possible_wrap)] + gl::DrawArrays( + primitive_kind.into_gl(), + start_index as gl::types::GLint, + index_cnt as gl::types::GLsizei, + ); + } + } + + pub fn bind(&self) + { + unsafe { gl::BindVertexArray(self.array) } + } +} + +impl Drop for VertexArray +{ + fn drop(&mut self) + { + unsafe { + gl::DeleteVertexArrays(1, &self.array); + } + } +} + +pub enum PrimitiveKind +{ + Triangles, +} + +impl PrimitiveKind +{ + fn into_gl(self) -> gl::types::GLenum + { + match self { + Self::Triangles => gl::TRIANGLES, + } + } +} diff --git a/engine/src/renderer/vertex_buffers.rs b/engine/src/renderer/vertex_buffers.rs new file mode 100644 index 0000000..a6d1a2c --- /dev/null +++ b/engine/src/renderer/vertex_buffers.rs @@ -0,0 +1,83 @@ +use std::mem::size_of_val; + +pub struct VertexBuffers<const CNT: usize> +{ + buffers: [gl::types::GLuint; CNT], +} + +impl<const CNT: usize> VertexBuffers<CNT> +{ + pub fn new() -> Self + { + let mut buffers = [gl::types::GLuint::default(); CNT]; + + unsafe { + #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)] + gl::GenBuffers(CNT as gl::types::GLsizei, buffers.as_mut_ptr()); + }; + + Self { buffers } + } + + pub fn store( + &self, + buffer_index: usize, + vertices: &[f32], + usage: BufferUsage, + ) -> Option<()> + { + let buffer = *self.buffers.get(buffer_index)?; + + unsafe { + gl::BindBuffer(gl::ARRAY_BUFFER, buffer); + } + + unsafe { + #[allow(clippy::cast_possible_wrap)] + gl::BufferData( + gl::ARRAY_BUFFER, + size_of_val(vertices) as gl::types::GLsizeiptr, + vertices.as_ptr().cast(), + usage.into_gl(), + ); + } + + Some(()) + } +} + +impl<const CNT: usize> Drop for VertexBuffers<CNT> +{ + fn drop(&mut self) + { + #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)] + unsafe { + gl::DeleteBuffers(CNT as gl::types::GLsizei, self.buffers.as_ptr()); + } + } +} + +#[allow(dead_code)] +pub enum BufferUsage +{ + /// The buffer data is set only once and used by the GPU at most a few times. + Stream, + + /// The buffer data is set only once and used many times. + Static, + + /// The buffer data is changed a lot and used many times. + Dynamic, +} + +impl BufferUsage +{ + fn into_gl(self) -> gl::types::GLenum + { + match self { + Self::Stream => gl::STREAM_DRAW, + Self::Static => gl::STATIC_DRAW, + Self::Dynamic => gl::DYNAMIC_DRAW, + } + } +} |