You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
5.7 KiB
Rust

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<u32, Box<[i32]>>,
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<u32> 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: 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<C: VertexDataCollection<D>, 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<C: VertexDataCollection<D>, 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::<u32>() * indices.len()) as isize,
indices.as_ptr() as *const c_void,
gl::STATIC_DRAW,
);
}
StaticBuffer {
vao,
ebo,
indices: indices.len(),
attributes: attributes.attributes,
}
}
}