use std::{any::Any, ops::{Index, IndexMut}, rc::Rc};
use std::cell::{RefCell, Ref, RefMut};
use std::marker::PhantomData;
use std::ops::Range;
use crate::{components::Ty, geometry::{Geometry, Submesh}};
use super::allocator::{self, Creation, InternalCreation, Updater};
use densevec::{DenseVec, KeyedDenseVec};
use rin_gl::{self as gl, types::*};
use itertools::Either;
use rin_math::{Mat4, Pnt2};
use std::borrow::Cow;
use std::mem;
use std::any::TypeId;
use hashbrown::HashMap;
use rinecs::storage::SliceView;
#[cfg(not(feature="gl_continuous_allocator"))]
use glin::BufferRange;
#[cfg(feature="gl_continuous_allocator")]
use glin::buffer::Cast;
#[derive(Debug, Clone, Copy)]
pub struct BufferRef{
buffer: allocator::BufferRef,
dynamic: bool,
}
#[cfg(not(any(feature="gles", feature="webgl")))]
pub const fn storage_static_flags() -> GLbitfield{
0
}
#[cfg(not(any(feature="gles", feature="webgl")))]
#[cfg(feature="gl_persistent_map")]
pub const fn storage_dynamic_flags() -> GLbitfield{
gl::MAP_WRITE_BIT | gl::MAP_PERSISTENT_BIT | gl::MAP_COHERENT_BIT
}
#[cfg(not(any(feature="gles", feature="webgl")))]
#[cfg(not(feature="gl_persistent_map"))]
pub const fn storage_dynamic_flags() -> GLbitfield{
gl::DYNAMIC_STORAGE_BIT
}
pub const fn buffer_static_usage() -> GLenum{
gl::STATIC_DRAW
}
pub const fn buffer_dynamic_usage() -> GLenum{
gl::DYNAMIC_DRAW
}
#[cfg(not(any(feature="gles", feature="webgl")))]
#[cfg(feature="gl_persistent_map")]
fn map_flags() -> gl::MapWriteFlags{
if storage_dynamic_flags() & gl::MAP_COHERENT_BIT != 0 {
gl::MapWriteFlags::COHERENT
}else{
gl::MapWriteFlags::empty()
}
}
pub fn model_normal_formats() -> Vec<glin::attributes::Format>{
vec![
gl::attributes::MatFormat{
name: Cow::Borrowed("model"),
location: 5,
cols: 4,
rows: 4,
offset_in_vertex: 0,
}.into_row_formats(),
gl::attributes::MatFormat{
name: Cow::Borrowed("normal"),
location: 9,
cols: 4,
rows: 4,
offset_in_vertex: 16 * mem::size_of::<f32>(),
}.into_row_formats(),
].into_iter()
.flat_map(|f| f)
.collect::<Vec<_>>()
}
pub fn model_format() -> Vec<glin::attributes::Format>{
gl::attributes::MatFormat{
name: Cow::Borrowed("model"),
location: 5,
cols: 4,
rows: 4,
offset_in_vertex: 0,
}.into_row_formats()
}
pub fn material_offsets_format() -> glin::attributes::Format{
gl::attributes::Format{
name: Cow::Borrowed("material_offset"),
location: 4,
num_coords: 1,
src_type: glin::attributes::Type::U32,
dst_type: glin::attributes::Type::U32,
normalize: false,
offset_in_vertex: 0,
}
}
#[cfg(feature="gl_continuous_allocator")]
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct VaoId{
dynamic: bool,
indices: bool,
vertex_type_id: TypeId,
}
#[cfg(not(feature="gl_continuous_allocator"))]
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct VaoId{
dynamic: bool,
vertices: allocator::BufferRef,
indices: Option<allocator::BufferRef>,
vertex_type_id: TypeId,
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
struct VaoModelBufferId{
vao_id: VaoId,
buffer_id: u32,
}
#[cfg(feature="gl_continuous_allocator")]
#[derive(Clone, Debug)]
pub struct VaoRange{
indices_range: Option<allocator::BufferRef>,
vertices_range: allocator::BufferRef,
subrange: Option<Range<usize>>,
vao_id: VaoId,
}
#[cfg(not(feature="gl_continuous_allocator"))]
#[derive(Clone, Debug)]
pub struct VaoRange{
subrange: Option<Range<usize>>,
vao_id: VaoId,
}
impl VaoRange{
pub fn vao_id(&self) -> VaoId{
self.vao_id
}
#[cfg(feature="gl_continuous_allocator")]
pub fn has_indices(&self) -> bool{
self.vao_id.indices
}
#[cfg(not(feature="gl_continuous_allocator"))]
pub fn has_indices(&self) -> bool{
self.vao_id.indices.is_some()
}
#[cfg(feature="gl_continuous_allocator")]
pub fn vertices_range(&self) -> allocator::BufferRef{
self.vertices_range
}
#[cfg(not(feature="gl_continuous_allocator"))]
pub fn vertices_range(&self) -> allocator::BufferRef{
self.vao_id.vertices
}
#[cfg(feature="gl_continuous_allocator")]
pub fn indices_range(&self) -> Option<allocator::BufferRef>{
self.indices_range
}
#[cfg(not(feature="gl_continuous_allocator"))]
pub fn indices_range(&self) -> Option<allocator::BufferRef>{
self.vao_id.indices
}
}
#[derive(Clone)]
pub struct VaoRangeInfo{
pub range: Range<usize>,
pub base_vertex: Option<i32>,
}
pub type IndexAllocator<B> = allocator::Allocator<B>;
pub struct VaoCache<T>{
vaos: HashMap<VaoId, glin::Vao>,
shadow_vaos: HashMap<VaoModelBufferId, glin::Vao>,
marker: PhantomData<T>,
}
impl<T> VaoCache<T>{
pub fn new() -> VaoCache<T>{
VaoCache{
vaos: HashMap::new(),
shadow_vaos: HashMap::new(),
marker: PhantomData,
}
}
pub fn vao<C,B,I>(&mut self,
gl: &C,
vao_id: VaoId,
vertex_buffer: &B,
indices_buffer: Option<&I>,
model_buffer: Either<&glin::SharedBuffer<Mat4>, &glin::SharedBuffer<(Mat4,Mat4)>>,
material_offsets_buffer: Option<&glin::SharedBuffer<u32>>) -> &mut glin::Vao
where C: glin::CreationContext,
T: 'static + glin::VertexFormat,
B: 'static + glin::BufferRange<T> + Clone,
I: 'static + glin::BufferRangeMut<glin::IndexT> + Clone,
{
let insert_new = ||{
let bindings = super::default_attribute_bindings();
let mut vao_builder = gl.new_vao()
.bindings_from(&bindings, vertex_buffer.clone());
vao_builder = match model_buffer {
Either::Left(model_buffer) => vao_builder
.instance_attributes_from(model_format(), model_buffer.clone(), 1),
Either::Right(model_normal_buffer) => vao_builder
.instance_attributes_from(model_normal_formats(), model_normal_buffer.clone(), 1),
};
if let Some(indices_buffer) = indices_buffer{
vao_builder = vao_builder.indices(indices_buffer.clone());
}
if let Some(offsets) = material_offsets_buffer{
let formats = material_offsets_format();
vao_builder = vao_builder.instance_attributes_from(formats, offsets.clone(), 1);
}
vao_builder.create().unwrap()
};
if let Either::Left(model_buffer) = model_buffer {
let buffer_id = model_buffer.id();
self.shadow_vaos.entry(VaoModelBufferId{
buffer_id,
vao_id,
}).or_insert_with(insert_new)
}else{
self.vaos.entry(vao_id).or_insert_with(insert_new)
}
}
}
pub trait AllocatorFlags{
fn static_flags() -> u32;
fn dynamic_flags() -> u32;
}
#[cfg(not(any(feature="gles", feature="webgl")))]
impl<T> AllocatorFlags for Allocator<T,glin::SharedBufferStorage<u8>>{
fn static_flags() -> u32{
storage_static_flags()
}
fn dynamic_flags() -> u32{
storage_dynamic_flags()
}
}
impl<T> AllocatorFlags for Allocator<T,glin::SharedBuffer<u8>>{
fn static_flags() -> u32{
buffer_static_usage()
}
fn dynamic_flags() -> u32{
buffer_dynamic_usage()
}
}
pub struct Allocator<T, B>{
static_allocator: Option<allocator::Allocator<B>>,
dynamic_allocator: Option<allocator::Allocator<B>>,
indices: Rc<RefCell<IndexAllocator<B>>>,
vaos_cache: VaoCache<T>,
bytes: usize,
}
impl<T, B> Allocator<T,B>{
pub fn new(bytes: usize, indices: Rc<RefCell<IndexAllocator<B>>>) -> Allocator<T,B>{
Allocator{
static_allocator: None,
dynamic_allocator: None,
indices,
vaos_cache: VaoCache::new(),
bytes,
}
}
}
#[cfg(not(feature="webgl"))]
pub trait BufferExt<T>: glin::BufferRange<T> +
glin::buffer::WithBackend +
glin::buffer::WithBackendMut +
glin::BufferRangeMut<T> +
glin::buffer::WithMapRange<T> +
glin::buffer::WithMapRangeMut<T>
{}
#[cfg(feature="webgl")]
pub trait BufferExt<T>: glin::BufferRange<T> +
glin::buffer::WithBackend +
glin::buffer::WithBackendMut +
glin::BufferRangeMut<T> +
allocator::MapRange<T>
{}
impl<T: 'static> BufferExt<T> for glin::Buffer<T>{}
impl<T: 'static> BufferExt<T> for glin::SharedBuffer<T>{}
#[cfg(not(any(feature="gles", feature="webgl")))]
impl<T: 'static> BufferExt<T> for glin::BufferStorage<T>{}
#[cfg(not(any(feature="gles", feature="webgl")))]
impl<T: 'static> BufferExt<T> for glin::SharedBufferStorage<T>{}
impl<T, B> Allocator<T,B>
where T: 'static + Clone + glin::VertexFormat,
allocator::Allocator<B>: InternalCreation<B> + Creation<B> + Updater,
B: 'static
+ Clone
+ BufferExt<u8>
+ glin::buffer::Cast<glin::IndexT>,
<B as glin::buffer::Cast<glin::IndexT>>::CastTo: 'static
+ glin::BufferRange<glin::IndexT>
+ glin::BufferRangeMut<glin::IndexT>
+ Clone,
Self: AllocatorFlags,
{
fn indices_allocator_mut(&mut self) -> RefMut<allocator::Allocator<B>>{
self.indices.borrow_mut()
}
fn indices_allocator(&self) -> Ref<allocator::Allocator<B>>{
self.indices.borrow()
}
fn vertices_static_allocator<C: glin::CreationContext>(&mut self, gl: &C) -> glin::Result<&mut allocator::Allocator<B>>{
let bytes = self.bytes;
Ok(self.static_allocator.get_or_insert_with(||{
let target = gl::ARRAY_BUFFER;
allocator::Allocator::new(gl, bytes, Self::static_flags(), target).unwrap()
}))
}
fn vertices_dynamic_allocator<C: glin::CreationContext>(&mut self, gl: &C) -> glin::Result<&mut allocator::Allocator<B>>{
let bytes = self.bytes;
Ok(self.dynamic_allocator.get_or_insert_with(||{
let target = gl::ARRAY_BUFFER;
allocator::Allocator::new(gl, bytes, Self::dynamic_flags(), target).unwrap()
}))
}
pub fn vertices_static<C: glin::CreationContext>(&mut self, gl: &C, data: &[T]) -> glin::Result<BufferRef>{
Ok(BufferRef{
buffer: self.vertices_static_allocator(gl)
.and_then(|allocator| allocator.from_data(gl, data))?,
dynamic: false,
})
}
pub fn vertices_dynamic<C: glin::CreationContext>(&mut self, gl: &C, data: &[T]) -> glin::Result<BufferRef>{
Ok(BufferRef{
buffer: self.vertices_dynamic_allocator(gl)
.and_then(|allocator| allocator.from_data(gl, data))?,
dynamic: true
})
}
pub fn indices_static<C: glin::CreationContext>(&mut self, gl: &C, data: &[glin::IndexT]) -> glin::Result<BufferRef>{
Ok(BufferRef{
buffer: self.indices_allocator_mut().from_data(gl, data)?,
dynamic: false,
})
}
#[cfg(feature="gl_continuous_allocator")]
fn get_vao<C>(&mut self,
gl: &C,
vao_id: VaoId,
model_buffer: Either<&glin::SharedBuffer<Mat4>, &glin::SharedBuffer<(Mat4,Mat4)>>,
material_offsets_buffer: Option<&glin::SharedBuffer<u32>>) -> glin::Result<&mut glin::Vao>
where C: glin::CreationContext ,
B: glin::buffer::Cast<T>,
<B as glin::buffer::Cast<T>>::CastTo: glin::BufferRange<T> + Clone,
{
let vertex_buffer = if vao_id.dynamic{
self.vertices_dynamic_allocator(gl).unwrap().full_buffer().clone()
}else{
self.vertices_static_allocator(gl).unwrap().full_buffer().clone()
};
let vertex_buffer = glin::buffer::cast::<T,_>(vertex_buffer);
let indices_buffer = if vao_id.indices{
let indices_buffer = self.indices_allocator().full_buffer().clone();
let indices_buffer = glin::buffer::cast::<glin::IndexT,_>(indices_buffer);
Some(indices_buffer)
}else{
None
};
let vao = self.vaos_cache.vao(gl,
vao_id,
&vertex_buffer,
indices_buffer.as_ref(),
model_buffer,
material_offsets_buffer);
#[cfg(not(any(feature="gles", feature="webgl")))]
vao.set_attribute_buffer_at(0, vertex_buffer)?;
if vao_id.indices {
vao.set_indices_buffer(indices_buffer.unwrap())
}
Ok(vao)
}
#[cfg(not(feature="gl_continuous_allocator"))]
fn get_vao<C>(&mut self,
gl: &C,
vao_id: VaoId,
model_buffer: Either<&glin::SharedBuffer<Mat4>, &glin::SharedBuffer<(Mat4,Mat4)>>,
material_offsets_buffer: Option<&glin::SharedBuffer<u32>>) -> glin::Result<&mut glin::Vao>
where C: glin::CreationContext ,
B: glin::buffer::Cast<T>,
<B as glin::buffer::Cast<T>>::CastTo: glin::BufferRange<T> + Clone,
{
let vertex_buffer = if vao_id.dynamic{
self.vertices_dynamic_allocator(gl).unwrap().buffer(&vao_id.vertices).clone()
}else{
self.vertices_static_allocator(gl).unwrap().buffer(&vao_id.vertices).clone()
};
let vertex_buffer = glin::buffer::cast::<T,_>(vertex_buffer);
let indices_buffer = if let Some(indices_ref) = vao_id.indices.as_ref(){
let indices_buffer = self.indices_allocator().buffer(indices_ref).clone();
let indices_buffer = glin::buffer::cast::<glin::IndexT,_>(indices_buffer);
Some(indices_buffer)
}else{
None
};
let vao = self.vaos_cache.vao(gl,
vao_id,
&vertex_buffer,
indices_buffer.as_ref(),
model_buffer,
material_offsets_buffer);
#[cfg(not(any(feature="gles", feature="webgl")))]
vao.set_attribute_buffer_at(0, vertex_buffer)?;
if let Some(indices_buffer) = indices_buffer {
vao.set_indices_buffer(indices_buffer)
}
Ok(vao)
}
pub fn vao<C>(&mut self,
gl: &C,
vao_id: VaoId,
model_normal_buffer: &glin::SharedBuffer<(Mat4, Mat4)>,
material_offsets_buffer: Option<&glin::SharedBuffer<u32>> ) -> glin::Result<&mut glin::Vao>
where C: glin::CreationContext,
B: glin::buffer::Cast<T>,
<B as glin::buffer::Cast<T>>::CastTo: glin::BufferRange<T> + Clone,
{
self.get_vao(gl, vao_id, Either::Right(model_normal_buffer), material_offsets_buffer)
}
pub fn shadow_vao<C>(&mut self,
gl: &C,
vao_id: VaoId,
model_buffer: &glin::SharedBuffer<Mat4>,
material_offsets_buffer: Option<&glin::SharedBuffer<u32>>
) -> glin::Result<&mut glin::Vao>
where C: glin::CreationContext,
B: glin::buffer::Cast<T>,
<B as glin::buffer::Cast<T>>::CastTo: glin::BufferRange<T> + Clone,
{
self.get_vao(gl, vao_id, Either::Left(model_buffer), material_offsets_buffer)
}
#[cfg(feature="gl_continuous_allocator")]
pub fn submesh_vaos(
&mut self,
gl: &gl::Renderer,
geometry: &Geometry<T>,
submeshes: Option<SliceView<Submesh>>,
dynamic: bool)
-> (Vec<VaoRange>, VaoRange, BufferRef, Option<BufferRef>)
{
let has_indices = !geometry.indices().is_empty();
let vao_id = VaoId{
dynamic,
indices: has_indices || submeshes.is_some(),
vertex_type_id: TypeId::of::<T>(),
};
let vertices_range;
let indices_range;
let ranges;
let full_range;
if dynamic{
vertices_range = self.vertices_dynamic(gl, geometry.vertices()).unwrap();
}else{
vertices_range = self.vertices_static(gl, geometry.vertices()).unwrap();
}
if has_indices || submeshes.is_some() {
if let Some(submeshes) = submeshes {
let indices_vec = if geometry.indices().is_empty(){
submeshes.iter().flat_map(|submesh|{
submesh.iter().cloned()
}).collect()
}else{
geometry.indices().clone()
};
let mut base_index = 0;
indices_range = Some(self.indices_static(gl, &indices_vec).unwrap());
ranges = submeshes.iter().map(|submesh| {
let range = VaoRange{
indices_range: indices_range.map(|i| i.buffer),
vertices_range: vertices_range.buffer,
subrange: Some(base_index .. base_index + submesh.len()),
vao_id,
};
base_index += submesh.len();
range
}).collect();
full_range = VaoRange{
indices_range: indices_range.map(|i| i.buffer),
vertices_range: vertices_range.buffer,
subrange: None,
vao_id,
};
}else{
indices_range = Some(self.indices_static(gl, geometry.indices()).unwrap());
full_range = VaoRange{
indices_range: indices_range.map(|i| i.buffer),
vertices_range: vertices_range.buffer,
subrange: None,
vao_id: vao_id,
};
ranges = vec![full_range.clone()];
}
}else{
full_range = VaoRange{
vertices_range: vertices_range.buffer,
indices_range: None,
subrange: None,
vao_id,
};
ranges = vec![full_range.clone()];
indices_range = None;
}
(ranges, full_range, vertices_range, indices_range)
}
#[cfg(not(feature="gl_continuous_allocator"))]
pub fn submesh_vaos(&mut self, gl: &gl::Renderer, geometry: &Geometry<T>, submeshes: Option<SliceView<Submesh>>, dynamic: bool) ->
(Vec<VaoRange>, VaoRange, BufferRef, Option<BufferRef>)
{
let has_indices = !geometry.indices().is_empty();
let vao_id;
let vertices_range;
let indices_range;
let ranges;
let full_range;
if dynamic{
vertices_range = self.vertices_dynamic(gl, geometry.vertices()).unwrap();
}else{
vertices_range = self.vertices_static(gl, geometry.vertices()).unwrap();
}
if has_indices || submeshes.is_some() {
if let Some(submeshes) = submeshes {
let indices_vec = if geometry.indices().is_empty(){
submeshes.iter().flat_map(|submesh|{
submesh.iter().cloned()
}).collect()
}else{
geometry.indices().clone()
};
let mut base_index = 0;
indices_range = Some(self.indices_static(gl, &indices_vec).unwrap());
vao_id = VaoId{
dynamic,
vertices: vertices_range.buffer,
indices: indices_range.map(|i| i.buffer),
vertex_type_id: TypeId::of::<T>(),
};
ranges = submeshes.iter().map(|submesh| {
let range = VaoRange{
subrange: Some(base_index .. base_index + submesh.len()),
vao_id,
};
base_index += submesh.len();
range
}).collect();
full_range = VaoRange{
subrange: None,
vao_id,
};
}else{
indices_range = Some(self.indices_static(gl, geometry.indices()).unwrap());
vao_id = VaoId{
dynamic,
vertices: vertices_range.buffer,
indices: indices_range.map(|i| i.buffer),
vertex_type_id: TypeId::of::<T>(),
};
full_range = VaoRange{
subrange: None,
vao_id: vao_id,
};
ranges = vec![full_range.clone()];
}
}else{
vao_id = VaoId{
dynamic,
vertices: vertices_range.buffer,
indices: None,
vertex_type_id: TypeId::of::<T>(),
};
full_range = VaoRange{
subrange: None,
vao_id,
};
ranges = vec![full_range.clone()];
indices_range = None;
}
(ranges, full_range, vertices_range, indices_range)
}
#[cfg(not(any(feature="gles", feature="webgl")))]
pub fn vao_range(&self, range: &VaoRange) -> VaoRangeInfo {
let vertex_buffer = if range.vao_id.dynamic{
self.dynamic_allocator.as_ref().unwrap().buffer(&range.vertices_range())
}else{
self.static_allocator.as_ref().unwrap().buffer(&range.vertices_range())
};
if range.has_indices() {
let base_vertex = (vertex_buffer.start() / mem::size_of::<T>()) as i32;
let indices = self.indices_allocator().buffer(range.indices_range().as_ref().unwrap()).clone();
let indices_range = if let Some(subrange) = range.subrange.as_ref(){
indices.start() / mem::size_of::<glin::IndexT>() + subrange.start ..
indices.start() / mem::size_of::<glin::IndexT>() + subrange.end
}else{
indices.start() / mem::size_of::<glin::IndexT>() ..
indices.end() / mem::size_of::<glin::IndexT>()
};
VaoRangeInfo{
range: indices_range,
base_vertex: Some(base_vertex),
}
}else{
let vertex_range = vertex_buffer.start() / mem::size_of::<T>() ..
vertex_buffer.end() / mem::size_of::<T>();
VaoRangeInfo{
range: vertex_range,
base_vertex: None,
}
}
}
#[cfg(any(feature="gles", feature="webgl"))]
pub fn vao_range<'v>(&self, range: &VaoRange, vao: &'v mut glin::Vao, primitive_type: GLenum) -> glin::vao::Range<'v>
where B: glin::buffer::Cast<T>,
<B as glin::buffer::Cast<T>>::CastTo: glin::BufferRange<T>
+ glin::buffer::WithBackend
+ allocator::MapRange<T>
+ Clone,
{
let vertex_buffer = if range.vao_id.dynamic{
self.dynamic_allocator.as_ref().unwrap().cast_buffer::<T>(&range.vertices_range())
}else{
self.static_allocator.as_ref().unwrap().cast_buffer::<T>(&range.vertices_range())
};
let range = if range.has_indices() {
vao.set_attribute_buffer_at(super::AttributeBufferIndex::Vertex as usize, vertex_buffer).unwrap();
let indices = self.indices_allocator().buffer(range.indices_range().as_ref().unwrap()).clone();
let stride = mem::size_of::<glin::IndexT>();
if let Some(subrange) = range.subrange.as_ref(){
indices.start() / stride + subrange.start .. indices.start() / stride + subrange.end
}else{
indices.start() / stride .. indices.end() / stride
}
}else{
let stride = mem::size_of::<T>();
vertex_buffer.start() / stride .. vertex_buffer.end() / stride
};
vao.range(range, primitive_type)
}
pub fn command(&self, range: &VaoRange, base_instance: u32, instance_count: u32) -> glin::DrawElementsIndirectCommand{
let vertex_buffer = if range.vao_id.dynamic{
self.dynamic_allocator.as_ref().unwrap().buffer(&range.vertices_range())
}else{
self.static_allocator.as_ref().unwrap().buffer(&range.vertices_range())
};
if range.has_indices() {
#[cfg(feature="gl_continuous_allocator")]
let indices: glin::buffer::Range<glin::IndexT,_,_> = self.indices_allocator()
.buffer(range.indices_range().as_ref().unwrap())
.clone()
.cast();
#[cfg(not(feature="gl_continuous_allocator"))]
let indices: <B as glin::buffer::Cast<glin::IndexT>>::CastTo = self.indices_allocator()
.buffer(range.indices_range().as_ref().unwrap())
.clone()
.cast();
let indices_range = if let Some(subrange) = range.subrange.as_ref(){
indices.start() + subrange.start .. indices.start() + subrange.end
}else{
indices.start() .. indices.end()
};
let count = indices_range.len() as u32;
let base_vertex = (vertex_buffer.start() / mem::size_of::<T>()) as u32;
glin::DrawElementsIndirectCommand{
count,
instance_count,
first_index: indices_range.start as u32,
base_vertex,
base_instance,
}
}else{
let vertex_range = vertex_buffer.start() / mem::size_of::<T>() ..
vertex_buffer.end() / mem::size_of::<T>();
glin::DrawElementsIndirectCommand{
count: vertex_range.len() as u32,
instance_count,
first_index: vertex_range.start as u32,
base_vertex: base_instance,
base_instance: 0,
}
}
}
#[cfg(feature="gl_continuous_allocator")]
pub fn dynamic_vertex_buffer_range(&self, range: &BufferRef) -> glin::buffer::Range<T, <B as glin::buffer::Cast<T>>::CastTo, <B as glin::buffer::Cast<T>>::CastTo>
where B: glin::buffer::Cast<T>
{
self.dynamic_allocator.as_ref().unwrap().buffer(&range.buffer).cast()
}
#[cfg(not(feature="gl_continuous_allocator"))]
pub fn dynamic_vertex_buffer_range(&self, range: &BufferRef) -> <B as glin::buffer::Cast<T>>::CastTo
where B: glin::buffer::Cast<T>
{
let allocator: &allocator::Allocator<B> = self.dynamic_allocator.as_ref().unwrap();
allocator.cast_buffer::<T>(&range.buffer)
}
pub fn update_vertex_buffer_range<C>(&mut self, gl: &C, range: &BufferRef, data: &[T]) -> glin::Result<()>
where C: glin::CreationContext
{
if range.dynamic {
self.dynamic_allocator.as_mut().unwrap().update_range(gl, &range.buffer, data)
}else{
self.static_allocator.as_mut().unwrap().update_range(gl, &range.buffer, data)
}
}
pub fn update_index_buffer_range<C>(&mut self, gl: &C, range: &BufferRef, data: &[glin::IndexT]) -> glin::Result<()>
where C: glin::CreationContext
{
self.indices_allocator_mut().update_range(gl, &range.buffer, data)
}
pub fn debug_draw(&self, gl: &gl::Renderer, pos: &Pnt2, w: f32, h: f32){
let mut pos = pos.clone();
if let Some(dyn_allocator) = self.dynamic_allocator.as_ref(){
dyn_allocator.gl_debug(gl, &pos, w, h);
pos.y += h + 10.;
}
if let Some(stc_allocator) = self.static_allocator.as_ref(){
stc_allocator.gl_debug(gl, &pos, w, h);
pos.y += h + 10.;
}
self.indices_allocator().gl_debug(gl, &pos, w, h);
}
pub fn vertex_buffer_range_len(&self, range: &BufferRef) -> usize{
if range.dynamic {
self.dynamic_allocator.as_ref().unwrap().buffer(&range.buffer).len()
}else{
self.static_allocator.as_ref().unwrap().buffer(&range.buffer).len()
}
}
pub fn index_buffer_range_len(&self, range: &BufferRef) -> usize{
self.indices_allocator().buffer(&range.buffer).len()
}
}
pub struct AllocatorHandle<V,B>(usize, PhantomData<V>, PhantomData<B>);
impl<V,B> Clone for AllocatorHandle<V,B> {
fn clone(&self) -> AllocatorHandle<V,B> {
AllocatorHandle(self.0, PhantomData, PhantomData)
}
}
impl<V,B> Copy for AllocatorHandle<V,B>{}
impl<V,B> PartialEq for AllocatorHandle<V,B> {
fn eq(&self, other: &AllocatorHandle<V,B>) -> bool {
self.0 == other.0
}
}
impl<V,B> Eq for AllocatorHandle<V,B>{}
impl<V, B> densevec::Key for AllocatorHandle<V, B> {
fn to_usize(self) -> usize {
self.0
}
fn from_usize(k: usize) -> Self {
AllocatorHandle(k, PhantomData, PhantomData)
}
}
pub struct AllocatorsIndex {
allocators: DenseVec<Box<dyn Any>>,
index: HashMap<TypeId, usize>,
}
impl AllocatorsIndex {
pub fn new() -> AllocatorsIndex {
AllocatorsIndex {
allocators: DenseVec::new(),
index: HashMap::new(),
}
}
pub fn add_allocator<V: 'static, B: 'static>(&mut self, allocator: Allocator<V,B>) -> AllocatorHandle<V,B> {
let handle = self.allocators.insert_key_gen(Box::new(allocator));
self.index.insert(TypeId::of::<V>(), handle);
AllocatorHandle(handle, PhantomData, PhantomData)
}
pub fn handle<V: 'static, B: 'static>(&self) -> Option<AllocatorHandle<V,B>> {
self.index.get(&TypeId::of::<V>()).map(|handle| AllocatorHandle(*handle, PhantomData, PhantomData))
}
pub fn by_type<V: 'static, B: 'static>(&self) -> Option<&Allocator<V,B>> {
self.handle::<V,B>().and_then(|handle| self.get(handle))
}
pub fn by_type_mut<V: 'static, B: 'static>(&mut self) -> Option<&mut Allocator<V,B>> {
self.handle::<V,B>().and_then(move |handle| self.get_mut(handle))
}
pub fn get<V: 'static, B: 'static>(&self, handle: AllocatorHandle<V,B>) -> Option<&Allocator<V,B>> {
self.allocators
.get(handle.0)
.and_then(|allocator| allocator.downcast_ref())
}
pub fn get_mut<V: 'static, B: 'static>(&mut self, handle: AllocatorHandle<V,B>) -> Option<&mut Allocator<V,B>> {
self.allocators
.get_mut(handle.0)
.and_then(|allocator| allocator.downcast_mut())
}
}
impl<V: 'static, B: 'static> Index<AllocatorHandle<V,B>> for AllocatorsIndex {
type Output = Allocator<V,B>;
fn index(&self, handle: AllocatorHandle<V,B>) -> &Allocator<V,B> {
self.allocators[handle.0].downcast_ref().unwrap()
}
}
impl<V: 'static, B: 'static> IndexMut<AllocatorHandle<V,B>> for AllocatorsIndex {
fn index_mut(&mut self, handle: AllocatorHandle<V,B>) -> &mut Allocator<V,B> {
self.allocators[handle.0].downcast_mut().unwrap()
}
}