use gl::types::*;
use attributes::{self, AttributeBufferBinding, DynVertexBufferBinding, VertexFormat, VertexBufferBinding};
use buffer::{BufferRange, BufferRangeMut};
use ::Result;
use mopa;
use state::StateRef;
use std::ops;
use std::marker::PhantomData;
use ::Error;
use ::ErrorKind;
use std::fmt::{self, Debug};
trait DynIndexBufferRangeMut: mopa::Any + BufferRangeMut<::IndexT>{}
mopafy!(DynIndexBufferRangeMut);
impl<B> DynIndexBufferRangeMut for B where B: 'static + BufferRangeMut<::IndexT>{}
pub struct Vao{
id: u32,
vertex_buffer_bindings: Vec<Box<dyn DynVertexBufferBinding>>,
attribute_buffer_bindings: Vec<(attributes::Format, usize)>,
indices: Option<Box<dyn DynIndexBufferRangeMut>>,
indices_enabled: bool,
state: StateRef,
}
impl PartialEq for Vao {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Debug for Vao{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result{
fmt.debug_struct("glin::Vao")
.field("id", &self.id)
.field("attribute_buffer_bindings", &self.attribute_buffer_bindings)
.finish()
}
}
impl Drop for Vao{
fn drop(&mut self) {
for (format, index) in self.attribute_buffer_bindings.iter(){
let vertex_binding = &*self.vertex_buffer_bindings[*index];
(format, vertex_binding).disable_for(self, self.state.state_mut(), self.state.capabilities());
}
unsafe{
self.state.DeleteVertexArrays(1, &self.id)
}
}
}
impl Eq for Vao {}
pub struct Builder{
vao: Vao,
}
impl Builder{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub(crate) fn new(gl: &StateRef) -> Builder{
let mut id = 0;
unsafe{
if gl.capabilities().supports_dsa(){
gl.CreateVertexArrays(1, &mut id);
}else{
gl.GenVertexArrays(1, &mut id);
}
}
Builder{
vao: Vao{
vertex_buffer_bindings: vec![],
attribute_buffer_bindings: vec![],
indices: None,
id: id,
indices_enabled: false,
state: gl.clone(),
},
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub(crate) fn new(gl: &StateRef) -> Builder{
let mut id = 0;
unsafe{
gl.GenVertexArrays(1, &mut id);
}
Builder{
vao: Vao{
vertex_buffer_bindings: vec![],
attribute_buffer_bindings: vec![],
indices: None,
id: id,
indices_enabled: false,
state: gl.clone(),
},
}
}
pub fn bindings_from<T, B, BI>(self, bindings: &BI, from: B) -> Builder
where T:'static + VertexFormat,
B: BufferRange<T> + 'static,
BI: attributes::Bindings,
{
let formats = T::attributes_formats(bindings);
self.attributes_from(formats, from)
}
pub fn attributes_from<T, B, I>(mut self, formats: I, from: B) -> Builder
where T:'static, B: BufferRange<T> + 'static,
I: Into<Vec<attributes::Format>>
{
let index = self.vao.vertex_buffer_bindings.len();
let vertex_binding = VertexBufferBinding{
index: index,
buffer: from,
divisor: 0,
marker: PhantomData,
};
vertex_binding.enable_for(&self.vao, self.vao.state.state_mut(), self.vao.state.capabilities());
let formats = formats.into();
for format in formats {
(&format, &vertex_binding).enable_for(&self.vao, self.vao.state.state_mut(), self.vao.state.capabilities());
let attr_vert_binding = (format, index);
self.vao.attribute_buffer_bindings.push(attr_vert_binding);
}
self.vao.vertex_buffer_bindings.push(Box::new(vertex_binding));
self
}
pub fn instance_bindings_from<T, B, BI>(self, bindings: &BI, from: B, divisor: usize) -> Builder
where T:'static,
T: VertexFormat,
B: BufferRange<T> + 'static,
BI: attributes::Bindings,{
let formats = T::attributes_formats(bindings);
self.instance_attributes_from(formats, from, divisor)
}
pub fn instance_attributes_from<T, B, I>(mut self, formats: I, from: B, divisor: usize) -> Builder
where T:'static,
B: BufferRange<T> + 'static,
I: Into<Vec<attributes::Format>> {
let index = self.vao.vertex_buffer_bindings.len();
let vertex_binding = VertexBufferBinding{
index: index,
buffer: from,
divisor,
marker: PhantomData,
};
vertex_binding.enable_for(&self.vao, self.vao.state.state_mut(), self.vao.state.capabilities());
let formats = formats.into();
for format in formats {
(&format, &vertex_binding).enable_for(&self.vao, self.vao.state.state_mut(), self.vao.state.capabilities());
let attr_vert_binding = (format, index);
self.vao.attribute_buffer_bindings.push(attr_vert_binding);
}
self.vao.vertex_buffer_bindings.push(Box::new(vertex_binding));
self
}
pub fn indices<B, I>(mut self, indices: I) -> Builder
where B: BufferRangeMut<::IndexT> + 'static,
I: Into<Option<B>>
{
self.vao.indices = indices.into().map(|i| Box::new(i) as Box<dyn DynIndexBufferRangeMut>);
if let Some(indices) = self.vao.indices.as_ref(){
indices.enable_for(&self.vao, self.vao.state.state_mut(), self.vao.state.capabilities());
self.vao.indices_enabled = true;
}
self
}
pub fn create(self) -> Result<Vao>{
if self.vao.id == 0{
Err(::Error::new(::ErrorKind::VaoCreationError, "Error creating vao"))
}else{
Ok(self.vao)
}
}
}
impl Vao{
pub fn id(&self) -> u32{
self.id
}
pub fn len(&self) -> usize{
self.vertex_buffer_bindings
.iter()
.filter_map(|buffer_binding|
if buffer_binding.divisor() == 0{
Some(buffer_binding.len())
}else{
None
})
.max()
.unwrap()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn range<R:InputRange>(&self, range: R, mode: GLenum) -> Range{
Range{
vao: self,
range: range.to_range(self),
mode: mode,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_vertex: None,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn range_base_vertex<R:InputRange>(&self, range: R, base_vertex: i32, mode: GLenum) -> Range{
Range{
vao: self,
range: range.to_range(self),
mode: mode,
base_vertex: Some(base_vertex),
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn range_base_instance<R:InputRange>(&self, range: R, base_instance: u32, mode: GLenum) -> Range{
Range{
vao: self,
range: range.to_range(self),
mode: mode,
base_vertex: None,
base_instance: Some(base_instance),
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn range_base_vertex_base_instance<R:InputRange>(
&self,
range: R,
base_vertex: i32,
base_instance: u32,
mode: GLenum) -> Range
{
Range{
vao: self,
range: range.to_range(self),
mode: mode,
base_vertex: Some(base_vertex),
base_instance: Some(base_instance),
}
}
pub fn full_range(&self, mode: GLenum) -> Range{
Range{
vao: self,
range: (..).to_range(self),
mode: mode,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_vertex: None,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn full_range_base_vertex(&self, base_vertex: i32, mode: GLenum) -> Range{
Range{
vao: self,
range: (..).to_range(self),
mode: mode,
base_vertex: Some(base_vertex),
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn full_range_base_instance(&self, base_instance: u32, mode: GLenum) -> Range{
Range{
vao: self,
range: (..).to_range(self),
mode: mode,
base_vertex: None,
base_instance: Some(base_instance),
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn full_range_base_vertex_base_instance(
&self,
base_vertex: i32,
base_instance: u32,
mode: GLenum) -> Range
{
Range{
vao: self,
range: (..).to_range(self),
mode: mode,
base_vertex: Some(base_vertex),
base_instance: Some(base_instance),
}
}
pub fn into_range<R:InputRange>(self, range: R, mode: GLenum) -> IntoRange{
IntoRange{
range: range.to_range(&self),
vao: self,
mode: mode,
base_vertex: None,
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_range_base_vertex<R:InputRange>(self, range: R, base_vertex: i32, mode: GLenum) -> IntoRange{
IntoRange{
range: range.to_range(&self),
vao: self,
mode: mode,
base_vertex: Some(base_vertex),
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_range_base_instance<R:InputRange>(self, range: R, base_instance: u32, mode: GLenum) -> IntoRange{
IntoRange{
range: range.to_range(&self),
vao: self,
mode: mode,
base_vertex: None,
base_instance: Some(base_instance),
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_range_base_vertex_base_instance<R:InputRange>(
self,
range: R,
base_vertex: i32,
base_instance: u32,
mode: GLenum) -> IntoRange
{
IntoRange{
range: range.to_range(&self),
vao: self,
mode: mode,
base_vertex: Some(base_vertex),
base_instance: Some(base_instance),
}
}
pub fn into_full_range(self, mode: GLenum) -> IntoRange{
IntoRange{
range: (..).to_range(&self),
mode: mode,
vao: self,
base_vertex: None,
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_full_range_base_vertex(self, base_vertex: i32, mode: GLenum) -> IntoRange{
IntoRange{
range: (..).to_range(&self),
mode: mode,
vao: self,
base_vertex: Some(base_vertex),
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_full_range_base_instance(self, base_instance: u32, mode: GLenum) -> IntoRange{
IntoRange{
range: (..).to_range(&self),
mode: mode,
vao: self,
base_vertex: None,
base_instance: Some(base_instance),
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_full_range_base_vertex_base_instance(
self,
base_vertex: i32,
base_instance: u32,
mode: GLenum) -> IntoRange
{
IntoRange{
range: (..).to_range(&self),
mode: mode,
vao: self,
base_vertex: Some(base_vertex),
base_instance: Some(base_instance),
}
}
pub fn enable(&mut self, attr_name: &str) -> Result<()>{
if let Some((format, index)) = self.attribute_buffer_bindings.iter()
.find(|(format, _)| format.name == attr_name)
{
let vertex_binding = &*self.vertex_buffer_bindings[*index];
vertex_binding.enable_for(self, self.state.state_mut(), self.state.capabilities());
(format, vertex_binding).enable_for(self, self.state.state_mut(), self.state.capabilities());
Ok(())
}else{
Err(::Error::new(::ErrorKind::AttributeNotFound, "Attribute not found"))
}
}
pub fn disable(&mut self, attr_name: &str) -> Result<()>{
if let Some((format, index)) = self.attribute_buffer_bindings.iter()
.find(|(format, _)| format.name == attr_name)
{
let vertex_binding = &*self.vertex_buffer_bindings[*index];
(format, vertex_binding).disable_for(self, self.state.state_mut(), self.state.capabilities());
Ok(())
}else{
Err(::Error::new(::ErrorKind::AttributeNotFound, "Attribute not found"))
}
}
pub fn enable_indices(&mut self){
if let Some(ref indices) = self.indices {
indices.enable_for(self, self.state.state_mut(), self.state.capabilities());
self.indices_enabled = true;
}
}
pub fn disable_indices(&mut self){
if let Some(ref indices) = self.indices{
indices.disable_for(self, self.state.state_mut(), self.state.capabilities());
}
self.indices_enabled = false;
}
pub fn buffer<T: 'static, B: BufferRange<T> + 'static>(&self, index: usize) -> Option<&B>{
let binding: Option<&VertexBufferBinding<T,B>> = self.vertex_buffer_bindings[index]
.downcast_ref();
binding.map(|binding| &binding.buffer)
}
pub fn buffer_mut<T: 'static, B: BufferRange<T> + 'static>(&mut self, index: usize) -> Option<&mut B>{
let binding: Option<&mut VertexBufferBinding<T,B>> = self.vertex_buffer_bindings[index]
.downcast_mut();
binding.map(|binding| &mut binding.buffer)
}
pub fn indices_buffer<B: BufferRangeMut<::IndexT> + 'static>(&self) -> Option<&B>{
self.indices.as_ref().and_then(|indices_buff| indices_buff.downcast_ref())
}
pub fn indices_buffer_mut<B: BufferRangeMut<::IndexT> + 'static>(&mut self) -> Option<&mut B>{
self.indices.as_mut().and_then(|indices_buff| indices_buff.downcast_mut())
}
pub fn set_indices_buffer<B: BufferRangeMut<::IndexT> + 'static>(&mut self, buffer: B){
self.indices = Some(Box::new(buffer));
self.enable_indices();
}
pub fn set_attributes_buffer<T,B,I>(&mut self, formats: I, buffer: B) -> Result<()>
where I: Into<Vec<attributes::Format>>,
T:'static,
B: BufferRange<T> + 'static,
{
let formats = formats.into();
let prev_vertex_bindings = formats.iter()
.filter_map(|format| self.attribute_buffer_bindings.iter().find(|binding| binding.0.location == format.location))
.map(|(_attr, vertex_buffer_binding)| *vertex_buffer_binding)
.collect::<Vec<_>>();
let (index, new) = if prev_vertex_bindings.is_empty(){
(self.vertex_buffer_bindings.len(), true)
}else if prev_vertex_bindings.len() == formats.len() && prev_vertex_bindings.iter().all(|v| *v == prev_vertex_bindings[0]){
(prev_vertex_bindings[0], false)
}else{
return Err(Error::new(ErrorKind::VaoCreationError, "Couldn't set attributes cause previous bindings are incompatible"));
};
let vertex_binding = VertexBufferBinding{
index: index,
buffer,
divisor: 0,
marker: PhantomData,
};
vertex_binding.enable_for(self, self.state.state_mut(), self.state.capabilities());
for format in formats {
(&format, &vertex_binding).enable_for(self, self.state.state_mut(), self.state.capabilities());
if new {
let attr_vert_binding = (format, index);
self.attribute_buffer_bindings.push(attr_vert_binding);
}
}
if new {
self.vertex_buffer_bindings.push(Box::new(vertex_binding));
}else{
self.vertex_buffer_bindings[index] = Box::new(vertex_binding);
}
Ok(())
}
pub fn set_instance_attributes_buffer<T,B,I>(&mut self, formats: I, buffer: B, divisor: usize) -> Result<()>
where I: Into<Vec<attributes::Format>>,
T:'static,
B: BufferRange<T> + 'static,
{
let formats = formats.into();
let prev_vertex_bindings = formats.iter()
.filter_map(|format| self.attribute_buffer_bindings.iter().find(|binding| binding.0.location == format.location))
.map(|(_attr, vertex_buffer_binding)| *vertex_buffer_binding)
.collect::<Vec<_>>();
let (index, new) = if prev_vertex_bindings.is_empty(){
(self.vertex_buffer_bindings.len(), true)
}else if prev_vertex_bindings.len() == formats.len() && prev_vertex_bindings.iter().all(|v| *v == prev_vertex_bindings[0]){
(prev_vertex_bindings[0], false)
}else{
return Err(Error::new(ErrorKind::VaoCreationError, "Couldn't set attributes cause previos bindings are incompatible"));
};
let vertex_binding = VertexBufferBinding{
index: index,
buffer,
divisor: divisor,
marker: PhantomData,
};
vertex_binding.enable_for(self, self.state.state_mut(), self.state.capabilities());
for format in formats {
(&format, &vertex_binding).enable_for(self, self.state.state_mut(), self.state.capabilities());
if new {
let attr_vert_binding = (format, index);
self.attribute_buffer_bindings.push(attr_vert_binding);
}
}
if new {
self.vertex_buffer_bindings.push(Box::new(vertex_binding));
}else{
self.vertex_buffer_bindings[index] = Box::new(vertex_binding);
}
Ok(())
}
pub fn set_attribute_buffer_at<T,B>(&mut self, index: usize, buffer: B) -> Result<()>
where T:'static,
B: BufferRange<T> + 'static,
{
let formats = self.attribute_buffer_bindings.iter()
.filter_map(|(format, i)| if *i == index {
Some(format)
}else{
None
});
let vertex_binding = VertexBufferBinding{
index,
buffer,
divisor: 0,
marker: PhantomData,
};
vertex_binding.enable_for(self, self.state.state_mut(), self.state.capabilities());
if !self.state.capabilities().supports_vertex_attrib_binding() {
for format in formats {
let attr_binding = (format, &vertex_binding);
attr_binding.enable_for(self, self.state.state_mut(), self.state.capabilities());
}
}
self.vertex_buffer_bindings[index] = Box::new(vertex_binding);
Ok(())
}
pub fn set_instance_attribute_buffer_at<T,B>(&mut self, index: usize, buffer: B, divisor: usize) -> Result<()>
where T:'static,
B: BufferRange<T> + 'static,
{
let formats = self.attribute_buffer_bindings.iter()
.filter_map(|(format, i)| if *i == index {
Some(format)
}else{
None
});
let vertex_binding = VertexBufferBinding{
index,
buffer,
divisor: divisor,
marker: PhantomData,
};
vertex_binding.enable_for(self, self.state.state_mut(), self.state.capabilities());
if !self.state.capabilities().supports_vertex_attrib_binding() {
for format in formats {
let attr_binding = (format, &vertex_binding);
attr_binding.enable_for(self, self.state.state_mut(), self.state.capabilities());
}
}
self.vertex_buffer_bindings[index] = Box::new(vertex_binding);
Ok(())
}
}
pub mod simple_vao {
use gl;
use gl::types::*;
use attributes::{self, VertexFormat, VertexBufferBinding};
use buffer::Buffer;
use context::{CreationProxy, CreationContext};
use ::Result;
use super::{Vao, InputRange, Range, IntoRange, VaoRange, VaoDraw};
use std::marker;
use std::rc::Rc;
use state::StateRef;
use std::fmt::{self, Debug};
pub struct SimpleVao<T>{
mode: GLenum,
vao: Vao,
marker: marker::PhantomData<T>,
context: Rc<CreationProxy>,
}
impl<T> Debug for SimpleVao<T>{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result{
fmt.debug_struct("glin::SimpleVao<T>")
.field("mode", &self.mode)
.field("vao", &self.vao)
.finish()
}
}
impl<T> PartialEq for SimpleVao<T> {
fn eq(&self, other: &Self) -> bool {
self.vao.id == other.vao.id
}
}
impl<T> Eq for SimpleVao<T> {}
pub struct Format<Vertex, I: Into<Option<Buffer<::IndexT>>>>{
pub buffer: Buffer<Vertex>,
pub attribute_formats: Vec<attributes::Format>,
pub indices: I,
pub mode: GLenum
}
pub struct Data<'a,T: 'a>{
pub vertices: &'a dyn AsRef<[T]>,
pub indices: &'a [::IndexT],
pub mode: GLenum,
}
pub struct Builder<'a>(pub(crate) &'a Rc<CreationProxy>, pub(crate) &'a StateRef);
impl<'a> Builder<'a>{
pub fn from_format<T: 'static, I: Into<Option<::Buffer<::IndexT>>>>(&self, format: Format<T, I>) -> Result<SimpleVao<T>>{
let vao = ::vao::Builder::new(&self.1)
.attributes_from(format.attribute_formats, format.buffer)
.indices::<::Buffer<::IndexT>, Option<::Buffer<::IndexT>>>(format.indices.into())
.create()?;
Ok(SimpleVao{
vao: vao,
mode: format.mode,
marker: marker::PhantomData,
context: self.0.clone(),
})
}
pub fn empty<T: 'static>(&self, attribute_formats: Vec<attributes::Format>, mode: GLenum) -> Result<SimpleVao<T>>{
self.from_format(Format{
buffer: self.0.new_buffer().empty_target(gl::ARRAY_BUFFER)?,
attribute_formats: attribute_formats,
indices: None,
mode: mode,
})
}
pub fn empty_from_bindings<T>(&self, bindings: &dyn attributes::Bindings, mode: GLenum) -> Result<SimpleVao<T>>
where T: 'static + VertexFormat
{
self.from_format(Format{
buffer: self.0.new_buffer().empty_target(gl::ARRAY_BUFFER)?,
attribute_formats: T::attributes_formats(bindings),
indices: None,
mode: mode,
})
}
pub fn from_data_bindings<'data, T, D>(
&self,
data: D,
bindings: &dyn attributes::Bindings,
usage: GLenum) -> Result<SimpleVao<T>>
where
T: 'static + attributes::VertexFormat,
D: Into<Data<'data,T>>
{
let data = data.into();
let buffer = self.0.new_buffer()
.from_data_target(data.vertices.as_ref(), usage, gl::ARRAY_BUFFER)?;
let indices = if !data.indices.is_empty(){
Some(self.0.new_buffer()
.from_data_target(data.indices, usage, gl::ELEMENT_ARRAY_BUFFER)?)
}else{
None
};
self.from_format(Format{
buffer: buffer,
attribute_formats: T::attributes_formats(bindings),
indices: indices,
mode: data.mode,
})
}
}
impl<T: 'static> SimpleVao<T>{
pub fn id(&self) -> u32{
self.vao.id
}
pub fn range<R:InputRange>(&self, range: R, mode: GLenum) -> Range{
Range{
vao: &self.vao,
range: range.to_range(self),
mode: mode,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_vertex: None,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn range_base_vertex<R:InputRange>(&self, range: R, base_vertex: i32, mode: GLenum) -> Range{
Range{
vao: &self.vao,
range: range.to_range(self),
mode: mode,
base_vertex: Some(base_vertex),
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn range_base_instance<R:InputRange>(&self, range: R, base_instance: u32, mode: GLenum) -> Range{
Range{
vao: &self.vao,
range: range.to_range(self),
mode: mode,
base_vertex: None,
base_instance: Some(base_instance),
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn range_base_vertex_base_instance<R:InputRange>(
&self,
range: R,
base_vertex: i32,
base_instance: u32,
mode: GLenum) -> Range
{
Range{
vao: &self.vao,
range: range.to_range(self),
mode: mode,
base_vertex: Some(base_vertex),
base_instance: Some(base_instance),
}
}
pub fn full_range(&self) -> Range{
Range{
vao: &self.vao,
range: (..).to_range(self),
mode: self.mode,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_vertex: None,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_instance: None
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn full_range_base_vertex(&self, base_vertex: i32) -> Range{
Range{
vao: &self.vao,
range: (..).to_range(self),
mode: self.mode,
base_vertex: Some(base_vertex),
base_instance: None
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn full_range_base_instance(&self, base_instance: u32) -> Range{
Range{
vao: &self.vao,
range: (..).to_range(self),
mode: self.mode,
base_vertex: None,
base_instance: Some(base_instance)
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn full_range_base_vertex_base_instance(
&self,
base_vertex: i32,
base_instance: u32) -> Range
{
Range{
vao: &self.vao,
range: (..).to_range(self),
mode: self.mode,
base_vertex: Some(base_vertex),
base_instance: Some(base_instance),
}
}
pub fn into_range<R:InputRange>(self, range: R) -> IntoRange{
IntoRange{
range: range.to_range(&self),
vao: self.vao,
mode: self.mode,
base_vertex: None,
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_range_base_vertex<R:InputRange>(self, range: R, base_vertex: i32) -> IntoRange{
IntoRange{
range: range.to_range(&self),
vao: self.vao,
mode: self.mode,
base_vertex: Some(base_vertex),
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_range_base_instance<R:InputRange>(self, range: R, base_instance: u32) -> IntoRange{
IntoRange{
range: range.to_range(&self),
vao: self.vao,
mode: self.mode,
base_vertex: None,
base_instance: Some(base_instance),
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_range_base_vertex_base_instance<R:InputRange>(
self,
range: R,
base_vertex: i32,
base_instance: u32) -> IntoRange
{
IntoRange{
range: range.to_range(&self),
vao: self.vao,
mode: self.mode,
base_vertex: Some(base_vertex),
base_instance: Some(base_instance),
}
}
pub fn into_full_range(self) -> IntoRange{
IntoRange{
range: (..).to_range(&self),
mode: self.mode,
vao: self.vao,
base_vertex: None,
base_instance: None,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_full_range_base_vertex(self, base_vertex: i32) -> IntoRange{
IntoRange{
range: (..).to_range(&self),
mode: self.mode,
vao: self.vao,
base_vertex: Some(base_vertex),
base_instance: None
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_full_range_base_instance(self, base_instance: u32) -> IntoRange{
IntoRange{
range: (..).to_range(&self),
mode: self.mode,
vao: self.vao,
base_vertex: None,
base_instance: Some(base_instance)
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn into_full_range_base_vertex_base_instance(
self,
base_vertex: i32,
base_instance: u32) -> IntoRange
{
IntoRange{
range: (..).to_range(&self),
mode: self.mode,
vao: self.vao,
base_vertex: Some(base_vertex),
base_instance: Some(base_instance),
}
}
pub fn buffer(&self) -> &Buffer<T>{
let binding: &VertexBufferBinding<T,Buffer<T>> = self.vao.vertex_buffer_bindings[0]
.downcast_ref()
.unwrap();
&binding.buffer
}
pub fn buffer_mut(&mut self) -> &mut Buffer<T>{
let binding: &mut VertexBufferBinding<T,Buffer<T>> = self.vao.vertex_buffer_bindings[0]
.downcast_mut()
.unwrap();
&mut binding.buffer
}
pub fn load<'a, D: Into<Data<'a,T>>>(&mut self, data: D, usage: GLenum){
let data = data.into();
self.load_vertices(data.vertices, usage);
if data.indices.is_empty(){
self.disable_indices();
}else{
self.load_indices(data.indices, usage).unwrap();
self.enable_indices();
}
self.set_mode(data.mode);
}
pub fn load_vertices<V: AsRef<[T]>>(&mut self, data: V, usage: GLenum){
self.buffer_mut().load(data.as_ref(), usage);
}
pub fn load_indices(&mut self, indices: &[::IndexT], usage: GLenum) -> Result<()>{
match self.vao.indices{
None => if !indices.is_empty(){
let indices_buff = self.context.new_buffer()
.from_data_target(indices, usage, gl::ELEMENT_ARRAY_BUFFER)?;
self.vao.indices = Some(Box::new(indices_buff));
self.vao.enable_indices();
},
Some(ref mut indices_buff) => {
let indices_buff: &mut Buffer<::IndexT> = indices_buff.downcast_mut().unwrap();
indices_buff.load(indices, usage);
}
}
Ok(())
}
pub fn update_vertices<V: AsRef<[T]>>(&mut self, data: V){
self.buffer_mut().update(data.as_ref());
}
pub fn update_indices(&mut self, indices: &[::IndexT]){
match self.vao.indices{
Some(ref mut buffer) => buffer.update(indices),
None => panic!("Trying to update indices buffer not allocated yet")
}
}
pub fn enable(&mut self, attr_name: &str) -> Result<()>{
self.vao.enable(attr_name)
}
pub fn disable(&mut self, attr_name: &str) -> Result<()>{
self.vao.disable(attr_name)
}
pub fn enable_indices(&mut self){
self.vao.enable_indices()
}
pub fn disable_indices(&mut self){
self.vao.disable_indices()
}
pub fn len(&self) -> usize{
self.buffer().len()
}
pub fn len_indices(&self) -> usize{
match self.vao.indices{
Some(ref indices) => indices.len(),
None => 0
}
}
pub fn is_empty(&self) -> bool{
self.buffer().is_empty()
}
pub fn mode(&self) -> GLenum{
self.mode
}
pub fn capacity(&self) -> usize{
self.buffer().capacity()
}
pub fn capacity_indices(&self) -> usize{
match self.vao.indices{
Some(ref indices) => indices.capacity(),
None => 0
}
}
pub fn set_mode(&mut self, mode: GLenum){
self.mode = mode;
}
pub fn into_vao(self) -> Vao{
self.vao
}
}
impl<'a, T> VaoRange for &'a SimpleVao<T>{
fn id(&self) -> GLuint{
self.vao.id
}
fn start(&self) -> usize{
0
}
fn end(&self) -> usize{
if self.has_indices() { self.num_indices() } else { self.num_vertices() }
}
fn count(&self) -> usize{
self.end() - self.start()
}
fn num_indices(&self) -> usize{
self.vao.indices.as_ref().map_or(0, |indices| indices.len())
}
fn num_vertices(&self) -> usize{
self.vao.vertex_buffer_bindings[0].len()
}
fn has_indices(&self) -> bool{
self.vao.indices.is_some() && self.vao.indices_enabled
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_vertex(&self) -> Option<i32>{
None
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_instance(&self) -> Option<u32>{
None
}
}
impl<'a, T> VaoRange for &'a mut SimpleVao<T>{
fn id(&self) -> GLuint{
self.vao.id
}
fn start(&self) -> usize{
0
}
fn end(&self) -> usize{
if self.has_indices() { self.num_indices() } else { self.num_vertices() }
}
fn count(&self) -> usize{
self.end() - self.start()
}
fn num_indices(&self) -> usize{
self.vao.indices.as_ref().map_or(0, |indices| indices.len())
}
fn num_vertices(&self) -> usize{
self.vao.vertex_buffer_bindings[0].len()
}
fn has_indices(&self) -> bool{
self.vao.indices.is_some() && self.vao.indices_enabled
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_vertex(&self) -> Option<i32>{
None
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_instance(&self) -> Option<u32>{
None
}
}
impl<'a, T> VaoDraw for &'a SimpleVao<T>{
fn mode(&self) -> GLenum{
self.mode
}
}
impl<'a, T> VaoDraw for &'a mut SimpleVao<T>{
fn mode(&self) -> GLenum{
self.mode
}
}
impl<'a> VaoRange for &'a Vao{
fn id(&self) -> GLuint{
self.id
}
fn start(&self) -> usize{
if self.has_indices() {
self.indices.as_ref().unwrap().start()
}else{
0
}
}
fn end(&self) -> usize{
if self.has_indices() {
self.indices.as_ref().unwrap().end()
}else{
self.num_vertices()
}
}
fn count(&self) -> usize{
self.end() - self.start()
}
fn num_indices(&self) -> usize{
self.indices.as_ref().map_or(0, |indices| indices.len())
}
fn num_vertices(&self) -> usize{
self.len()
}
fn has_indices(&self) -> bool{
self.indices.is_some() && self.indices_enabled
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_vertex(&self) -> Option<i32>{
None
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_instance(&self) -> Option<u32>{
None
}
}
}
pub trait InputRange{
fn to_range<R: VaoRange>(self, vao: R) -> ops::Range<usize>;
}
impl InputRange for ops::Range<usize>{
fn to_range<R: VaoRange>(self, vao: R) -> ops::Range<usize>{
assert!(vao.start() + self.start <= vao.start() + self.end);
assert!(vao.start() + self.end <= vao.end());
vao.start() + self.start .. vao.start() + self.end
}
}
impl InputRange for ops::RangeFrom<usize>{
fn to_range<R: VaoRange>(self, vao: R) -> ops::Range<usize>{
assert!(vao.start() + self.start <= vao.end());
vao.start() + self.start .. vao.end()
}
}
impl InputRange for ops::RangeTo<usize>{
fn to_range<R: VaoRange>(self, vao: R) -> ops::Range<usize>{
assert!(vao.start() + self.end <= vao.end());
vao.start() .. vao.start() + self.end
}
}
impl InputRange for ops::RangeFull{
fn to_range<R: VaoRange>(self, vao: R) -> ops::Range<usize>{
vao.start() .. vao.end()
}
}
pub trait VaoRange{
fn id(&self) -> GLuint;
fn start(&self) -> usize;
fn end(&self) -> usize;
fn count(&self) -> usize;
fn num_indices(&self) -> usize;
fn num_vertices(&self) -> usize;
fn has_indices(&self) -> bool;
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_vertex(&self) -> Option<i32>;
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_instance(&self) -> Option<u32>;
}
pub trait VaoDraw: VaoRange{
fn mode(&self) -> GLenum;
}
#[derive(Clone)]
pub struct Range<'a>{
vao: &'a Vao,
range: ops::Range<usize>,
mode: GLenum,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_vertex: Option<i32>,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_instance: Option<u32>,
}
impl<'a> VaoRange for Range<'a>{
fn id(&self) -> GLuint{
self.vao.id()
}
fn start(&self) -> usize{
self.range.start
}
fn end(&self) -> usize{
self.range.end
}
fn count(&self) -> usize{
self.range.len()
}
fn num_indices(&self) -> usize{
self.vao.indices.as_ref().map_or(0, |_indices| self.count())
}
fn num_vertices(&self) -> usize{
self.vao.len()
}
fn has_indices(&self) -> bool{
self.vao.indices.is_some() && self.vao.indices_enabled
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_vertex(&self) -> Option<i32>{
if self.vao.indices.is_some(){
self.base_vertex.or(Some(0))
}else{
self.base_vertex
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_instance(&self) -> Option<u32>{
self.base_instance
}
}
impl<'a> VaoDraw for Range<'a>{
fn mode(&self) -> GLenum{
self.mode
}
}
impl<'a> VaoRange for &'a Range<'a>{
fn id(&self) -> GLuint{
self.vao.id()
}
fn start(&self) -> usize{
self.range.start
}
fn end(&self) -> usize{
self.range.end
}
fn count(&self) -> usize{
self.range.len()
}
fn num_indices(&self) -> usize{
self.vao.indices.as_ref().map_or(0, |_indices| self.count())
}
fn num_vertices(&self) -> usize{
self.vao.len()
}
fn has_indices(&self) -> bool{
self.vao.indices.is_some() && self.vao.indices_enabled
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_vertex(&self) -> Option<i32>{
if self.vao.indices.is_some(){
self.base_vertex.or(Some(0))
}else{
self.base_vertex
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_instance(&self) -> Option<u32>{
self.base_instance
}
}
impl<'a> VaoDraw for &'a Range<'a>{
fn mode(&self) -> GLenum{
self.mode
}
}
impl<'a> VaoRange for &'a mut Range<'a>{
fn id(&self) -> GLuint{
self.vao.id()
}
fn start(&self) -> usize{
self.range.start
}
fn end(&self) -> usize{
self.range.end
}
fn count(&self) -> usize{
self.range.len()
}
fn num_indices(&self) -> usize{
self.vao.indices.as_ref().map_or(0, |_indices| self.count())
}
fn num_vertices(&self) -> usize{
self.vao.len()
}
fn has_indices(&self) -> bool{
self.vao.indices.is_some() && self.vao.indices_enabled
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_vertex(&self) -> Option<i32>{
if self.vao.indices.is_some(){
self.base_vertex.or(Some(0))
}else{
self.base_vertex
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_instance(&self) -> Option<u32>{
self.base_instance
}
}
impl<'a> VaoDraw for &'a mut Range<'a>{
fn mode(&self) -> GLenum{
self.mode
}
}
impl<'a> VaoRange for &'a dyn VaoDraw{
fn id(&self) -> GLuint{
(*self).id()
}
fn start(&self) -> usize{
(*self).start()
}
fn end(&self) -> usize{
(*self).end()
}
fn count(&self) -> usize{
(*self).count()
}
fn num_indices(&self) -> usize{
(*self).num_indices()
}
fn num_vertices(&self) -> usize{
(*self).num_vertices()
}
fn has_indices(&self) -> bool{
(*self).has_indices()
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_vertex(&self) -> Option<i32>{
(*self).base_vertex()
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_instance(&self) -> Option<u32>{
(*self).base_instance()
}
}
impl<'a> VaoDraw for &'a dyn VaoDraw{
fn mode(&self) -> GLenum{
(*self).mode()
}
}
#[derive(Debug)]
pub struct IntoRange{
vao: Vao,
range: ops::Range<usize>,
mode: GLenum,
base_vertex: Option<i32>,
base_instance: Option<u32>,
}
impl VaoRange for IntoRange{
fn id(&self) -> GLuint{
self.vao.id()
}
fn start(&self) -> usize{
self.range.start
}
fn end(&self) -> usize{
self.range.end
}
fn count(&self) -> usize{
self.range.len()
}
fn num_indices(&self) -> usize{
self.vao.indices.as_ref().map_or(0, |_indices| self.count())
}
fn num_vertices(&self) -> usize{
self.vao.len()
}
fn has_indices(&self) -> bool{
self.vao.indices.is_some() && self.vao.indices_enabled
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_vertex(&self) -> Option<i32>{
if self.vao.indices.is_some(){
self.base_vertex.or(Some(0))
}else{
self.base_vertex
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn base_instance(&self) -> Option<u32>{
self.base_instance
}
}
impl VaoDraw for IntoRange{
fn mode(&self) -> GLenum{
self.mode
}
}
impl IntoRange{
pub fn as_ref(&self) -> Range{
Range{
vao: &self.vao,
range: self.range.clone(),
mode: self.mode,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_vertex: self.base_vertex,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
base_instance: self.base_instance,
}
}
pub fn vao(&self) -> &Vao{
&self.vao
}
pub fn vao_mut(&mut self) -> &mut Vao{
&mut self.vao
}
pub fn into_vao(self) -> Vao{
self.vao
}
}