110 lines
3.0 KiB
Rust
110 lines
3.0 KiB
Rust
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.
|
|
|
|
struct RenderableMesh {
|
|
first_triangle: usize,
|
|
num_triangles: i32,
|
|
}
|
|
|
|
pub struct RenderableModel {
|
|
num_pos: usize,
|
|
num_uv: usize,
|
|
num_normal: usize,
|
|
|
|
vertexes: VertexBuffer,
|
|
indexes: IndexBuffer,
|
|
|
|
meshes: Vec <RenderableMesh>,
|
|
}
|
|
|
|
unsafe fn vertex_attrib_pointer (id: Option <u32>, 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_
|
|
|
|
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 ()
|
|
.map (|mesh| RenderableMesh {
|
|
first_triangle: mesh.first_triangle.try_into ().unwrap (),
|
|
num_triangles: mesh.num_triangles.try_into ().unwrap (),
|
|
})
|
|
.collect ();
|
|
|
|
Self {
|
|
num_pos,
|
|
num_uv,
|
|
num_normal,
|
|
|
|
vertexes,
|
|
indexes,
|
|
meshes,
|
|
}
|
|
}
|
|
|
|
pub fn draw (&self, attrs: &HashMap <String, Option <u32>>, 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 ()
|
|
}
|
|
}
|