use byteorder::{ByteOrder, LittleEndian}; use std::collections::*; use std::convert::TryInto; use std::ffi::c_void; use crate::gpu_buffers::*; use crate::iqm; // Takes ownership of mesh stuff in an opaque way that's abstract // from the IQM model. IQM is zero-copy, but this is not. // Since it's opaque, I can drop in a VBO/IBO setup when I'm not lazy. pub struct RenderableMesh { first_triangle: usize, num_triangles: i32, pub name: Vec , } pub struct RenderableModel { num_pos: usize, num_uv: usize, num_normal: usize, vertexes: VertexBuffer, indexes: IndexBuffer, pub meshes: Vec , } unsafe fn vertex_attrib_pointer (id: Option , num_coords: i32, float_offset: usize) { 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, (float_offset * 4) as *const u8 as *const c_void); } } impl RenderableModel { pub fn from_iqm (model: &iqm::Model) -> RenderableModel { let pos_bytes = model.get_vertex_slice (iqm::types::POSITION); let uv_bytes = model.get_vertex_slice (iqm::types::TEXCOORD); let normal_bytes = model.get_vertex_slice (iqm::types::NORMAL); let num_pos = pos_bytes.len () / 4; let num_uv = uv_bytes.len () / 4; let num_normal = normal_bytes.len () / 4; let num_vertexes = num_pos / 3; assert_eq! (num_vertexes * 2, num_uv); assert_eq! (num_vertexes * 3, num_normal); let mut vertex_vec = vec! [0.0; num_pos + num_uv + num_normal]; LittleEndian::read_f32_into (pos_bytes, &mut vertex_vec [0..num_pos]); LittleEndian::read_f32_into (uv_bytes, &mut vertex_vec [num_pos..num_pos + num_uv]); LittleEndian::read_f32_into (normal_bytes, &mut vertex_vec [num_pos + num_uv..num_pos + num_uv + num_normal]); let vertexes = VertexBuffer::from_slice (&vertex_vec); let index_slice = model.get_all_indexes (); let indexes = IndexBuffer::from_slice (index_slice); let max_index: usize = indexes.max ().try_into ().unwrap (); assert! (max_index * 3 < num_pos); assert! (max_index * 2 < num_uv); assert! (max_index * 3 < num_normal); let meshes = model.meshes.iter ().enumerate () .map (|(i, mesh)| RenderableMesh { first_triangle: mesh.first_triangle.try_into ().unwrap (), num_triangles: mesh.num_triangles.try_into ().unwrap (), name: model.get_mesh_name (i).to_owned (), }) .collect (); Self { num_pos, num_uv, num_normal, vertexes, indexes, meshes, } } pub fn draw (&self, attrs: &HashMap >, mesh_num: usize) { let mesh = &self.meshes [mesh_num]; self.vertexes.bind (); self.indexes.bind (); unsafe { vertex_attrib_pointer (attrs ["pos"], 3, 0); vertex_attrib_pointer (attrs ["uv"], 2, self.num_pos); vertex_attrib_pointer (attrs ["normal"], 3, self.num_pos + self.num_uv); gl::DrawRangeElements (gl::TRIANGLES, 0, self.indexes.max (), mesh.num_triangles * 3, gl::UNSIGNED_INT, (mesh.first_triangle * 3 * 4) as *const u8 as *const c_void); } } pub fn num_meshes (&self) -> usize { self.meshes.len () } }