use buffer::{self, Buffer, BufferType};
use uniforms::{AsUniformValue, UniformValue, UniformBlock};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::sync::mpsc::Sender;
use backend::Facade;
use GlObject;
use BufferExt;
use gl;
use sync;
use version::Version;
use version::Api;
#[derive(Debug)]
pub struct UniformBuffer<T> {
buffer: TypelessUniformBuffer,
marker: PhantomData<T>,
}
#[derive(Debug)]
pub struct TypelessUniformBuffer {
buffer: Buffer,
}
impl<T> UniformBuffer<T> where T: Copy + Send + 'static {
#[cfg(feature = "gl_uniform_blocks")]
pub fn new<F>(facade: &F, data: T) -> UniformBuffer<T> where F: Facade {
UniformBuffer::new_if_supported(facade, data).unwrap()
}
pub fn new_if_supported<F>(facade: &F, data: T) -> Option<UniformBuffer<T>> where F: Facade {
if facade.get_context().get_version() < &Version(Api::Gl, 3, 1) &&
!facade.get_context().get_extensions().gl_arb_uniform_buffer_object
{
None
} else {
let buffer = Buffer::new(facade, &[data], BufferType::UniformBuffer, true).unwrap();
Some(UniformBuffer {
buffer: TypelessUniformBuffer {
buffer: buffer,
},
marker: PhantomData,
})
}
}
pub fn upload(&mut self, data: T) {
self.buffer.buffer.upload(0, &[data])
}
pub fn map<'a>(&'a mut self) -> Mapping<'a, T> {
Mapping(self.buffer.buffer.map(0, 1))
}
#[cfg(feature = "gl_read_buffer")]
pub fn read(&self) -> T {
self.buffer.buffer.read().into_iter().next().unwrap()
}
pub fn read_if_supported(&self) -> Option<T> {
let res = self.buffer.buffer.read_if_supported();
res.map(|res| res.into_iter().next().unwrap())
}
}
impl<T> GlObject for UniformBuffer<T> {
type Id = gl::types::GLuint;
fn get_id(&self) -> gl::types::GLuint {
self.buffer.get_id()
}
}
impl GlObject for TypelessUniformBuffer {
type Id = gl::types::GLuint;
fn get_id(&self) -> gl::types::GLuint {
self.buffer.get_id()
}
}
impl<T> BufferExt for UniformBuffer<T> {
fn add_fence(&self) -> Option<Sender<sync::LinearSyncFence>> {
self.buffer.add_fence()
}
}
impl BufferExt for TypelessUniformBuffer {
fn add_fence(&self) -> Option<Sender<sync::LinearSyncFence>> {
self.buffer.add_fence()
}
}
pub struct Mapping<'a, T>(buffer::Mapping<'a, T>);
impl<'a, T> Deref for Mapping<'a, T> {
type Target = T;
fn deref<'b>(&'b self) -> &'b T {
self.0.deref().get(0).unwrap()
}
}
impl<'a, T> DerefMut for Mapping<'a, T> {
fn deref_mut<'b>(&'b mut self) -> &'b mut T {
self.0.deref_mut().get_mut(0).unwrap()
}
}
impl<'a, T> AsUniformValue for &'a UniformBuffer<T> where T: UniformBlock {
fn as_uniform_value(&self) -> UniformValue {
UniformValue::Block(&self.buffer, <T as UniformBlock>::matches)
}
}