use super::*;
pub trait GlObjectTrait {
type Handle;
fn create_handle(value: u32) -> Self::Handle;
fn stuff(self) -> GlObjectType;
}
pub struct GlVertexBuffer {
pub buffer: GLuint,
pub size: usize,
pub _usage: crate::BufferUsage,
pub layout: &'static crate::VertexLayout,
}
impl GlObjectTrait for GlVertexBuffer {
type Handle = crate::VertexBuffer;
#[inline]
fn create_handle(value: u32) -> Self::Handle {
crate::VertexBuffer { value }
}
#[inline]
fn stuff(self) -> GlObjectType {
GlObjectType::VertexBuffer(self)
}
}
pub struct GlIndexBuffer {
pub buffer: GLuint,
pub size: usize,
pub _usage: crate::BufferUsage,
pub ty: crate::IndexType,
}
impl GlObjectTrait for GlIndexBuffer {
type Handle = crate::IndexBuffer;
#[inline]
fn create_handle(value: u32) -> Self::Handle {
crate::IndexBuffer { value }
}
#[inline]
fn stuff(self) -> GlObjectType {
GlObjectType::IndexBuffer(self)
}
}
#[allow(dead_code)]
pub struct GlActiveAttrib {
pub location: GLuint,
pub size: GLint,
pub ty: GLenum,
}
pub struct GlActiveUniform {
pub location: GLint,
pub array_size: GLint, pub ty: GLenum,
pub texture_unit: i8, }
pub struct GlShaderProgram {
pub program: GLuint,
pub attribs: HashMap<NameBuf, GlActiveAttrib>,
pub uniforms: HashMap<NameBuf, GlActiveUniform>,
}
impl GlObjectTrait for GlShaderProgram {
type Handle = crate::ShaderProgram;
#[inline]
fn create_handle(value: u32) -> Self::Handle {
crate::ShaderProgram { value }
}
#[inline]
fn stuff(self) -> GlObjectType {
GlObjectType::ShaderProgram(self)
}
}
pub struct GlTexture2D {
pub texture: GLuint,
pub info: crate::Texture2DInfo,
}
impl GlObjectTrait for GlTexture2D {
type Handle = crate::Texture2D;
#[inline]
fn create_handle(value: u32) -> Self::Handle {
crate::Texture2D { value }
}
#[inline]
fn stuff(self) -> GlObjectType {
GlObjectType::Texture2D(self)
}
}
pub struct GlObject {
pub ref_count: u32,
pub obj: GlObjectType,
}
impl GlObject {
pub fn release(&self) {
match &self.obj {
GlObjectType::VertexBuffer(buf) => {
gl_check!(gl::DeleteBuffers(1, &buf.buffer));
}
GlObjectType::IndexBuffer(buf) => {
gl_check!(gl::DeleteBuffers(1, &buf.buffer));
}
GlObjectType::ShaderProgram(shader) => {
shader::release(&shader);
}
GlObjectType::Texture2D(texture) => {
texture2d::release(&texture);
}
}
}
}
pub enum GlObjectType {
VertexBuffer(GlVertexBuffer),
IndexBuffer(GlIndexBuffer),
ShaderProgram(GlShaderProgram),
Texture2D(GlTexture2D),
}
pub struct ObjectMap {
objects: HashMap<u32, GlObject>,
last: u32,
}
impl ObjectMap {
pub fn new() -> ObjectMap {
ObjectMap {
objects: HashMap::new(),
last: 0,
}
}
pub fn get_type(&self, handle: crate::BaseObject) -> Option<crate::ObjectType> {
let Some(obj) = self.objects.get(&handle.value) else {
return None;
};
let obj_type = match obj.obj {
GlObjectType::VertexBuffer(_) => crate::ObjectType::VertexBuffer,
GlObjectType::IndexBuffer(_) => crate::ObjectType::IndexBuffer,
GlObjectType::ShaderProgram(_) => crate::ObjectType::ShaderProgram,
GlObjectType::Texture2D(_) => crate::ObjectType::Texture2D,
};
return Some(obj_type);
}
#[track_caller]
pub fn add_ref(&mut self, handle: crate::BaseObject) {
if handle == crate::BaseObject::INVALID {
return;
}
let Some(obj) = self.objects.get_mut(&handle.value) else {
panic!("Invalid object handle: {:?}", handle);
};
obj.ref_count += 1;
}
#[track_caller]
pub fn release(&mut self, handle: crate::BaseObject) -> u32 {
if handle == crate::BaseObject::INVALID {
return 0;
}
let hash_map::Entry::Occupied(mut entry) = self.objects.entry(handle.value) else {
panic!("Invalid object handle: {:?}", handle);
};
let obj = entry.get_mut();
if obj.ref_count == 0 {
panic!("Object released too many times: {:?}", handle);
}
obj.ref_count -= 1;
let ref_count = obj.ref_count;
if ref_count == 0 {
obj.release();
entry.remove();
}
ref_count
}
pub fn insert<T: GlObjectTrait>(&mut self, obj: T) -> T::Handle {
loop {
self.last = self.last.wrapping_add(1);
if !self.objects.contains_key(&self.last) {
break;
}
}
let value = self.last;
self.objects.insert(value, GlObject { ref_count: 1, obj: obj.stuff() });
T::create_handle(value)
}
}
impl ObjectMap {
pub fn get_vertex_buffer(&self, handle: crate::VertexBuffer) -> Option<&GlVertexBuffer> {
let Some(object) = self.objects.get(&handle.value) else { return None };
let GlObjectType::VertexBuffer(ref buf) = object.obj else { return None };
return Some(buf);
}
pub fn get_index_buffer(&self, handle: crate::IndexBuffer) -> Option<&GlIndexBuffer> {
let Some(object) = self.objects.get(&handle.value) else { return None };
let GlObjectType::IndexBuffer(ref buf) = object.obj else { return None };
return Some(buf);
}
pub fn get_shader_program(&self, handle: crate::ShaderProgram) -> Option<&GlShaderProgram> {
let Some(object) = self.objects.get(&handle.value) else { return None };
let GlObjectType::ShaderProgram(ref shader) = object.obj else { return None };
return Some(shader);
}
pub fn get_texture2d(&self, handle: crate::Texture2D) -> Option<&GlTexture2D> {
let Some(object) = self.objects.get(&handle.value) else { return None };
let GlObjectType::Texture2D(ref texture) = object.obj else { return None };
return Some(texture);
}
pub fn get_texture2d_mut(&mut self, handle: crate::Texture2D) -> Option<&mut GlTexture2D> {
let Some(object) = self.objects.get_mut(&handle.value) else { return None };
let GlObjectType::Texture2D(ref mut texture) = object.obj else { return None };
return Some(texture);
}
}