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
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,
|
|
}
|
|
}
|
|
}
|