// Trivial wrappers around GLESv2 C functions that should be safe use byteorder::{LittleEndian, ReadBytesExt}; use glam::{Mat4, Vec3, Vec4}; use std::collections::*; use std::convert::TryInto; use std::cmp; use std::io::Cursor; use std::ffi::c_void; use crate::iqm; pub fn clear_color (r: f32, g: f32, b: f32, a: f32) { unsafe { gl::ClearColor (1.0f32, 1.0f32, 1.0f32, 1.0f32); } } pub fn clear (flags: u32) { unsafe { gl::Clear (flags); } } pub fn disable (constant: u32) { unsafe { gl::Disable (constant); } } pub fn enable (constant: u32) { unsafe { gl::Enable (constant); } } pub fn enable_vertex_attrib_array (id: Option ) { if let Some (id) = id { // Are safety checks really needed here? unsafe { gl::EnableVertexAttribArray (id); } } } pub fn uniform_1i (uni: i32, x: i32) { unsafe { gl::Uniform1i (uni, x); } } pub fn uniform_3fv (uni: i32, v: &Vec3) { unsafe { gl::Uniform3fv (uni, 1, v as *const Vec3 as *const f32); } } pub fn uniform_4fv (uni: i32, v: &Vec4) { unsafe { gl::Uniform4fv (uni, 1, v as *const Vec4 as *const f32); } } pub fn uniform_matrix_4fv (uni: i32, m: &Mat4) { const FALSE_U8: u8 = 0; unsafe { gl::UniformMatrix4fv (uni, 1, FALSE_U8, m as *const Mat4 as *const f32); } } // More abstract stuff unsafe fn vertex_attrib_pointer (id: Option , num_coords: i32, slice: &[u8]) { const FALSE_U8: u8 = 0; const FLOAT_SIZE: i32 = 4; if let Some (id) = id { gl::VertexAttribPointer (id, num_coords, gl::FLOAT, FALSE_U8, FLOAT_SIZE * num_coords, &slice [0] as *const u8 as *const c_void); } } pub fn draw_model ( attrs: &HashMap >, model: &iqm::Model, mesh_number: usize ) { let index_slice: &[u8] = model.get_index_slice (mesh_number); let num_indexes = model.meshes [mesh_number].num_triangles * 3; unsafe { vertex_attrib_pointer (attrs ["pos"], 3, model.get_vertex_slice (0)); vertex_attrib_pointer (attrs ["uv"], 2, model.get_vertex_slice (1)); vertex_attrib_pointer (attrs ["normal"], 3, model.get_vertex_slice (2)); gl::DrawElements (gl::TRIANGLES, (num_indexes) as i32, gl::UNSIGNED_INT, &index_slice [0] as *const u8 as *const c_void); } } pub struct VertexBuffer { id: u32, len: usize, } impl VertexBuffer { pub fn from_slice (slice: &[u8]) -> Self { let id = { let mut id = 0; unsafe { gl::GenBuffers (1, &mut id); gl::BindBuffer (gl::ARRAY_BUFFER, id); gl::BufferData (gl::ARRAY_BUFFER, slice.len ().try_into ().unwrap (), &slice [0] as *const u8 as *const c_void, gl::STATIC_DRAW); } assert! (id != 0); id }; Self { id, len: slice.len (), } } pub fn bind (&self) { unsafe { gl::BindBuffer (gl::ARRAY_BUFFER, self.id); } } } impl Drop for VertexBuffer { fn drop (&mut self) { if self.id == 0 { return; } unsafe { gl::DeleteBuffers (1, &self.id); } self.id = 0; } } pub struct IndexBuffer { id: u32, len: usize, min: u32, max: u32, } impl IndexBuffer { pub fn from_slice (slice: &[u8]) -> Self { let mut rdr = Cursor::new (slice); let mut min = None; let mut max = None; assert_eq! (slice.len () % 4, 0); for _ in 0..slice.len () / 4 { let idx = rdr.read_u32:: ().unwrap (); min = match min { None => Some (idx), Some (min) => Some (cmp::min (min, idx)), }; max = match max { None => Some (idx), Some (max) => Some (cmp::max (max, idx)), }; } let id = { let mut id = 0; unsafe { gl::GenBuffers (1, &mut id); gl::BindBuffer (gl::ELEMENT_ARRAY_BUFFER, id); gl::BufferData (gl::ELEMENT_ARRAY_BUFFER, slice.len ().try_into ().unwrap (), &slice [0] as *const u8 as *const c_void, gl::STATIC_DRAW); } assert! (id != 0); id }; Self { id, len: slice.len () / 4, min: min.unwrap (), max: max.unwrap (), } } pub fn bind (&self) { unsafe { gl::BindBuffer (gl::ELEMENT_ARRAY_BUFFER, self.id); } } } impl Drop for IndexBuffer { fn drop (&mut self) { if self.id == 0 { return; } unsafe { gl::DeleteBuffers (1, &self.id); } self.id = 0; } }