use std::ffi::{c_void, CStr, CString}; pub mod buffer; mod err; pub mod shader; pub mod texture; mod types; mod update_uniform; use crate::buffer::{Attributes, StaticBufferNonIndexed}; use buffer::StaticBuffer; pub use buffer::{VertexData, VertexDataCollection}; #[cfg(feature = "derive")] pub use eatgel_proc_macro::{ShaderData, VertexData}; pub use shader::ShaderData; use std::collections::HashMap; use std::mem::size_of; use std::ptr::null; pub use types::{amount_of, type_descriptor_of, type_of, TypeDescriptor, TypeResolver}; pub use update_uniform::*; pub struct GlContext { cache: HashMap>, clear_color: [f32; 4], } #[repr(u32)] #[derive(Debug, Copy, Clone)] enum Severity { Low = gl::DEBUG_SEVERITY_LOW, Medium = gl::DEBUG_SEVERITY_MEDIUM, High = gl::DEBUG_SEVERITY_HIGH, Notification = gl::DEBUG_SEVERITY_NOTIFICATION, } impl From for Severity { fn from(x: u32) -> Self { match x { gl::DEBUG_SEVERITY_LOW => Severity::Low, gl::DEBUG_SEVERITY_MEDIUM => Severity::Medium, gl::DEBUG_SEVERITY_HIGH => Severity::High, _ => Severity::Notification, } } } extern "system" fn gl_message_callback( _source: u32, _error_type: u32, _id: u32, severity: u32, _length: i32, message: *const i8, _user_data: *mut c_void, ) { unsafe { println!( "Message ({:?}): {:?}", Severity::from(severity), CStr::from_ptr(message) ); } } impl GlContext { pub fn new(f: F) -> Self where F: FnMut(&'static str) -> *const c_void, { gl::load_with(f); unsafe { gl::Enable(gl::DEBUG_OUTPUT); gl::DebugMessageCallback(Some(gl_message_callback), null()) } GlContext { cache: HashMap::new(), clear_color: [0., 0., 0., 0.], } } pub fn set_clear_color(&mut self, red: f32, green: f32, blue: f32, alpha: f32) { self.clear_color = [red, green, blue, alpha]; } pub fn clear(&self) { unsafe { gl::ClearColor( self.clear_color[0], self.clear_color[1], self.clear_color[2], self.clear_color[3], ); gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); } } pub fn get_uniform_location(&self, program_id: u32, name: &str) -> i32 { let name = CString::new(name).expect("Failed creating CString from &str"); unsafe { gl::GetUniformLocation(program_id, name.as_ptr()) } } pub fn register_uniforms(&mut self, program_id: u32, uniforms: &[&str]) { let mut ids = vec![]; for name in uniforms { unsafe { ids.push(gl::GetUniformLocation( program_id, CString::new(name.to_string()) .expect("Nul character in uniform name") .as_ptr(), )) } } self.cache.insert(program_id, ids.into_boxed_slice()); } pub fn get_uniform_location_by_index(&self, program_id: u32, index: usize) -> i32 { self.cache.get(&program_id).map(|x| x[index]).unwrap_or(-1) } unsafe fn create_attribs(&self, attributes: &Attributes) { let mut index = 0; for attribute in &attributes.attributes { gl::VertexAttribPointer( index, attribute.amount as i32, attribute.gl_type, gl::FALSE, attribute.stride as i32, attribute.offset as *const c_void, ); gl::EnableVertexAttribArray(index); index += 1; } } pub fn create_static_buffer_non_indexed, D: VertexData>( &self, buffer: C, ) -> StaticBufferNonIndexed { let attributes = buffer.create_ptr(false, None); let mut vbo = 0; let mut vao = 0; unsafe { gl::GenVertexArrays(1, &mut vao); gl::GenBuffers(1, &mut vbo); gl::BindVertexArray(vao); gl::BindBuffer(gl::ARRAY_BUFFER, vbo); gl::BufferData( gl::ARRAY_BUFFER, attributes.size as isize, attributes.as_ptr(), gl::STATIC_DRAW, ); self.create_attribs(&attributes) } StaticBufferNonIndexed { vao, elements: attributes.elements, attributes: attributes.attributes, } } pub fn create_static_buffer, D: VertexData>( &self, buffer: C, indices: &[u32], ) -> StaticBuffer { let attributes = buffer.create_ptr(false, None); let mut vbo = 0; let mut vao = 0; let mut ebo = 0; unsafe { gl::GenVertexArrays(1, &mut vao); gl::GenBuffers(1, &mut vbo); gl::GenBuffers(1, &mut ebo); gl::BindVertexArray(vao); gl::BindBuffer(gl::ARRAY_BUFFER, vbo); gl::BufferData( gl::ARRAY_BUFFER, attributes.size as isize, attributes.as_ptr(), gl::STATIC_DRAW, ); self.create_attribs(&attributes); gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo); gl::BufferData( gl::ELEMENT_ARRAY_BUFFER, (size_of::() * indices.len()) as isize, indices.as_ptr() as *const c_void, gl::STATIC_DRAW, ); } StaticBuffer { vao, ebo, indices: indices.len(), attributes: attributes.attributes, } } }