use crate::{ buffer::{Buffer, BufferRef, Target}, error::Error, misc::{BindGuard, Bindable}, }; /* TransformFeedback */ pub struct TransformFeedback { id: gl::GLuint, buffers: Vec, } impl TransformFeedback { pub fn builder() -> Builder { Builder::default() } pub fn id(&self) -> gl::GLuint { self.id } pub fn buffers(&self) -> &[T] { &self.buffers } pub fn buffers_mut(&mut self) -> &mut [T] { &mut self.buffers } } impl Drop for TransformFeedback { fn drop(&mut self) { gl::delete_transform_feedbacks(1, &self.id); } } impl Bindable for TransformFeedback { fn bind(&self) { gl::bind_transform_feedback(gl::TRANSFORM_FEEDBACK, self.id); } fn unbind(&self) { gl::bind_transform_feedback(gl::TRANSFORM_FEEDBACK, 0); } } /* Builder */ pub struct Builder { bindings: Vec>, } impl Builder where for<'a> &'a T: BufferRef, { pub fn bind_buffer(mut self, index: gl::GLuint, buffer: T) -> Result, Error> { for binding in &self.bindings { if binding.index == index { return Err(Error::TransformFeedbackIndexAlreadyInUse(index)); } } let binding = Binding { buffer, index }; self.bindings.push(binding); Ok(self) } pub fn build(self) -> Result, Error> { let mut id = 0; Error::checked(|| gl::create_transform_feedbacks(1, &mut id))?; let mut transform_feedback = TransformFeedback { id, buffers: Vec::new(), }; let guard = BindGuard::new(&transform_feedback); let mut buffers = Vec::new(); for binding in self.bindings { Error::checked(|| { binding .buffer .as_ref() .bind_buffer_base(Target::TransformFeedbackBuffer, binding.index) })?; buffers.push(binding.buffer); } drop(guard); transform_feedback.buffers = buffers; Ok(transform_feedback) } } impl Default for Builder { fn default() -> Self { Self { bindings: Vec::new(), } } } /* Binding */ struct Binding { buffer: T, index: gl::GLuint, }