use std::ffi::c_void;
#[derive(Clone, Copy)]
pub enum VertexAttribType {
Float,
Float2,
Float3,
Float4,
Mat3,
Mat4,
Int,
Int2,
Int3,
Int4,
Uint,
Byte,
}
pub fn vertex_attrib_type_gl(vtype: &VertexAttribType) -> u32 {
match vtype {
VertexAttribType::Float => gl::FLOAT,
VertexAttribType::Float2 => gl::FLOAT,
VertexAttribType::Float3 => gl::FLOAT,
VertexAttribType::Float4 => gl::FLOAT,
VertexAttribType::Mat3 => gl::FLOAT,
VertexAttribType::Mat4 => gl::FLOAT,
VertexAttribType::Int => gl::INT,
VertexAttribType::Int2 => gl::INT,
VertexAttribType::Int3 => gl::INT,
VertexAttribType::Int4 => gl::INT,
VertexAttribType::Uint => gl::UNSIGNED_INT,
VertexAttribType::Byte => gl::BYTE,
}
}
pub fn vertex_attrib_type_size(vtype: &VertexAttribType) -> u32 {
match vtype {
VertexAttribType::Float => 4,
VertexAttribType::Float2 => 4 * 2,
VertexAttribType::Float3 => 4 * 3,
VertexAttribType::Float4 => 4 * 4,
VertexAttribType::Mat3 => 4 * 3 * 3,
VertexAttribType::Mat4 => 4 * 4 * 4,
VertexAttribType::Int => 4,
VertexAttribType::Int2 => 4 * 2,
VertexAttribType::Int3 => 4 * 3,
VertexAttribType::Int4 => 4 * 4,
VertexAttribType::Uint => 4,
VertexAttribType::Byte => 1,
}
}
pub fn vertex_attrib_type_count(vtype: &VertexAttribType) -> u32 {
match vtype {
VertexAttribType::Float => 1,
VertexAttribType::Float2 => 2,
VertexAttribType::Float3 => 3,
VertexAttribType::Float4 => 4,
VertexAttribType::Mat3 => 3 * 3,
VertexAttribType::Mat4 => 4 * 4,
VertexAttribType::Int => 1,
VertexAttribType::Int2 => 2,
VertexAttribType::Int3 => 3,
VertexAttribType::Int4 => 4,
VertexAttribType::Uint => 1,
VertexAttribType::Byte => 1,
}
}
pub struct VertexAttrib {
pub size: u32,
pub offset: u32,
pub vtype: VertexAttribType,
pub normalize: bool,
pub name: String,
}
impl VertexAttrib {
pub fn new(vtype: VertexAttribType, normalize: bool, name: String) -> Self {
Self {
size: vertex_attrib_type_size(&vtype),
offset: 0,
vtype,
normalize,
name,
}
}
}
pub fn submit_vertex_attribs(vertex_attribs: &mut Vec<VertexAttrib>) {
let mut stride = 0;
let mut offset = 0;
for attrib in vertex_attribs.iter_mut() {
attrib.offset += offset;
offset += attrib.size;
stride += attrib.size;
}
let mut i = 0;
for attrib in vertex_attribs {
if vertex_attrib_type_gl(&attrib.vtype) == gl::FLOAT {
unsafe {
gl::VertexAttribPointer(
i,
vertex_attrib_type_count(&attrib.vtype) as i32,
vertex_attrib_type_gl(&attrib.vtype),
attrib.normalize as u8,
stride as i32,
attrib.offset as *const std::ffi::c_void,
);
}
} else {
unsafe {
gl::VertexAttribIPointer(
i,
vertex_attrib_type_count(&attrib.vtype) as i32,
vertex_attrib_type_gl(&attrib.vtype),
stride as i32,
attrib.offset as *const std::ffi::c_void,
);
}
}
unsafe {
gl::EnableVertexAttribArray(i);
}
i += 1;
}
}
fn gen_vao() -> u32 {
let mut vao: u32 = 0;
unsafe { gl::GenVertexArrays(1, &mut vao) }
vao
}
fn gen_buffer() -> u32 {
let mut buffer: u32 = 0;
unsafe { gl::GenBuffers(1, &mut buffer) }
buffer
}
pub fn calc_bytes_size<T>(v: &Vec<T>) -> usize {
v.len() * std::mem::size_of::<T>()
}
pub struct VertexArray {
pub id: u32,
}
impl VertexArray {
pub fn new() -> Self {
Self { id: gen_vao() }
}
pub fn bind(&self) {
unsafe {
gl::BindVertexArray(self.id);
}
}
pub fn unbind(&self) {
unsafe {
gl::BindVertexArray(0);
}
}
}
pub struct VertexBuffer {
pub id: u32,
}
impl VertexBuffer {
pub fn new<T>(size: isize, vertices: Option<&Vec<T>>) -> Self {
let _self = Self { id: gen_buffer() };
_self.bind();
if let Some(vertices) = vertices {
unsafe {
gl::BufferData(
gl::ARRAY_BUFFER,
size,
vertices.as_ptr() as *const std::ffi::c_void,
gl::STATIC_DRAW,
);
}
} else {
unsafe {
gl::BufferData(gl::ARRAY_BUFFER, size, std::ptr::null(), gl::DYNAMIC_DRAW);
}
}
_self
}
pub fn send_data<T>(&self, size: isize, offset: isize, vertices: &Vec<T>) {
unsafe {
self.bind();
gl::BufferSubData(
gl::ARRAY_BUFFER,
offset,
size,
vertices.as_ptr() as *const std::ffi::c_void,
);
}
}
pub fn bind(&self) {
unsafe {
gl::BindBuffer(gl::ARRAY_BUFFER, self.id);
}
}
pub fn unbind(&self) {
unsafe {
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
}
}
}
pub struct IndexBuffer {
pub id: u32,
}
impl IndexBuffer {
pub fn new(size: isize, indices: Option<&Vec<i32>>) -> Self {
let _self = Self { id: gen_buffer() };
_self.bind();
if let Some(indices) = indices {
unsafe {
gl::BufferData(
gl::ELEMENT_ARRAY_BUFFER,
size,
indices.as_ptr() as *const std::ffi::c_void,
gl::STATIC_DRAW,
);
}
} else {
unsafe {
gl::BufferData(
gl::ELEMENT_ARRAY_BUFFER,
size,
std::ptr::null(),
gl::DYNAMIC_DRAW,
);
}
}
_self
}
pub fn send_data(&self, size: isize, offset: isize, indices: &Vec<i32>) {
unsafe {
self.bind();
gl::BufferSubData(
gl::ELEMENT_ARRAY_BUFFER,
offset,
size,
indices.as_ptr() as *const std::ffi::c_void,
);
}
}
pub fn bind(&self) {
unsafe {
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.id);
}
}
pub fn unbind(&self) {
unsafe {
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
}
}
}
pub struct UniforBuffer {
pub id: u32,
pub slot: u32,
}
impl UniforBuffer {
pub fn new(size: isize, binding: u32) -> Self {
let _self = Self {
id: gen_buffer(),
slot: binding,
};
unsafe {
gl::BufferData(gl::UNIFORM_BUFFER, size, std::ptr::null(), gl::DYNAMIC_DRAW);
gl::BindBufferBase(gl::UNIFORM_BUFFER, _self.slot, _self.id);
}
_self
}
pub fn send_data(&self, data: *const c_void, size: isize, offset: isize) {
unsafe {
gl::BindBufferBase(gl::UNIFORM_BUFFER, self.slot, self.id);
gl::BufferSubData(gl::UNIFORM_BUFFER, offset, size, data);
}
}
}
impl Drop for VertexArray {
fn drop(&mut self) {
unsafe { gl::DeleteVertexArrays(1, &self.id) }
}
}
impl Drop for VertexBuffer {
fn drop(&mut self) {
unsafe { gl::DeleteBuffers(1, &self.id) }
}
}
impl Drop for IndexBuffer {
fn drop(&mut self) {
unsafe { gl::DeleteBuffers(1, &self.id) }
}
}
impl Drop for UniforBuffer {
fn drop(&mut self) {
unsafe { gl::DeleteBuffers(1, &self.id) }
}
}