diff --git a/src/graphics.rs b/src/graphics.rs index 5150a67d..af6d9312 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -1,3 +1,4 @@ +use std::os::raw::c_void; use std::{ffi::CString, mem}; mod texture; @@ -1703,14 +1704,14 @@ pub enum Usage { Stream, } -fn gl_buffer_target(buffer_type: &BufferType) -> GLenum { +fn gl_buffer_target(buffer_type: BufferType) -> GLenum { match buffer_type { BufferType::VertexBuffer => GL_ARRAY_BUFFER, BufferType::IndexBuffer => GL_ELEMENT_ARRAY_BUFFER, } } -fn gl_usage(usage: &Usage) -> GLenum { +fn gl_usage(usage: Usage) -> GLenum { match usage { Usage::Immutable => GL_STATIC_DRAW, Usage::Dynamic => GL_DYNAMIC_DRAW, @@ -1727,6 +1728,37 @@ pub struct Buffer { } impl Buffer { + fn new( + ctx: &mut Context, + index_type: Option, + buffer_type: BufferType, + usage: Usage, + size: usize, + data: *const c_void, + ) -> Buffer { + let gl_target = gl_buffer_target(buffer_type); + let gl_usage = gl_usage(usage); + let mut gl_buf: u32 = 0; + + unsafe { + glGenBuffers(1, &mut gl_buf as *mut _); + ctx.cache.store_buffer_binding(gl_target); + ctx.cache.bind_buffer(gl_target, gl_buf, index_type); + glBufferData(gl_target, size as _, std::ptr::null() as *const _, gl_usage); + if !data.is_null() { + glBufferSubData(gl_target, 0, size as _, data); + } + ctx.cache.restore_buffer_binding(gl_target); + } + + Buffer { + gl_buf, + buffer_type, + size, + index_type, + } + } + /// Create an immutable buffer resource object. /// ```ignore /// #[repr(C)] @@ -1749,26 +1781,46 @@ impl Buffer { None }; - let gl_target = gl_buffer_target(&buffer_type); - let gl_usage = gl_usage(&Usage::Immutable); - let size = mem::size_of_val(data); - let mut gl_buf: u32 = 0; + Self::new( + ctx, + index_type, + buffer_type, + Usage::Immutable, + mem::size_of_val(data), + data.as_ptr() as *const _, + ) + } - unsafe { - glGenBuffers(1, &mut gl_buf as *mut _); - ctx.cache.store_buffer_binding(gl_target); - ctx.cache.bind_buffer(gl_target, gl_buf, index_type); - glBufferData(gl_target, size as _, std::ptr::null() as *const _, gl_usage); - glBufferSubData(gl_target, 0, size as _, data.as_ptr() as *const _); - ctx.cache.restore_buffer_binding(gl_target); - } + /// Create a dynamic buffer resource object. + /// ```ignore + /// #[repr(C)] + /// struct Vertex { + /// pos: Vec2, + /// uv: Vec2, + /// } + /// let vertices: [Vertex; 4] = [ + /// Vertex { pos : Vec2 { x: -0.5, y: -0.5 }, uv: Vec2 { x: 0., y: 0. } }, + /// Vertex { pos : Vec2 { x: 0.5, y: -0.5 }, uv: Vec2 { x: 1., y: 0. } }, + /// Vertex { pos : Vec2 { x: 0.5, y: 0.5 }, uv: Vec2 { x: 1., y: 1. } }, + /// Vertex { pos : Vec2 { x: -0.5, y: 0.5 }, uv: Vec2 { x: 0., y: 1. } }, + /// ]; + /// let buffer = Buffer::dynamic(ctx, BufferType::VertexBuffer, &vertices); + /// ``` + pub fn dynamic(ctx: &mut Context, buffer_type: BufferType, data: &[T]) -> Buffer { + let index_type = if buffer_type == BufferType::IndexBuffer { + Some(IndexType::for_type::()) + } else { + None + }; - Buffer { - gl_buf, - buffer_type, - size, + Self::new( + ctx, index_type, - } + buffer_type, + Usage::Dynamic, + mem::size_of_val(data), + data.as_ptr() as *const _, + ) } pub fn stream(ctx: &mut Context, buffer_type: BufferType, size: usize) -> Buffer { @@ -1778,46 +1830,27 @@ impl Buffer { None }; - let gl_target = gl_buffer_target(&buffer_type); - let gl_usage = gl_usage(&Usage::Stream); - let mut gl_buf: u32 = 0; - - unsafe { - glGenBuffers(1, &mut gl_buf as *mut _); - ctx.cache.store_buffer_binding(gl_target); - ctx.cache.bind_buffer(gl_target, gl_buf, None); - glBufferData(gl_target, size as _, std::ptr::null() as *const _, gl_usage); - ctx.cache.restore_buffer_binding(gl_target); - } - - Buffer { - gl_buf, + Self::new( + ctx, + index_type, buffer_type, + Usage::Stream, size, - index_type, - } + std::ptr::null(), + ) } pub fn index_stream(ctx: &mut Context, index_type: IndexType, size: usize) -> Buffer { - let gl_target = gl_buffer_target(&BufferType::IndexBuffer); - let gl_usage = gl_usage(&Usage::Stream); - let mut gl_buf: u32 = 0; - - unsafe { - glGenBuffers(1, &mut gl_buf as *mut _); - ctx.cache.store_buffer_binding(gl_target); - ctx.cache.bind_buffer(gl_target, gl_buf, None); - glBufferData(gl_target, size as _, std::ptr::null() as *const _, gl_usage); - ctx.cache.restore_buffer_binding(gl_target); - } - - Buffer { - gl_buf, - buffer_type: BufferType::IndexBuffer, + Self::new( + ctx, + Some(index_type), + BufferType::IndexBuffer, + Usage::Stream, size, - index_type: Some(index_type), - } + std::ptr::null(), + ) } + pub fn update(&self, ctx: &mut Context, data: &[T]) { if self.buffer_type == BufferType::IndexBuffer { assert!(self.index_type.is_some()); @@ -1828,7 +1861,7 @@ impl Buffer { assert!(size <= self.size); - let gl_target = gl_buffer_target(&self.buffer_type); + let gl_target = gl_buffer_target(self.buffer_type); ctx.cache.store_buffer_binding(gl_target); ctx.cache .bind_buffer(gl_target, self.gl_buf, self.index_type);