doppler/src/mesh.rs

229 lines
6.6 KiB
Rust

#![allow(dead_code)]
#![allow(non_snake_case)]
use std::ffi::CString;
use std::mem::size_of;
use std::os::raw::c_void;
use std::ptr;
use cgmath::prelude::*;
use cgmath::{Vector2, Vector3};
use gl;
use crate::shader::Shader;
// NOTE: without repr(C) the compiler may reorder the fields or use different padding/alignment than C.
// Depending on how you pass the data to OpenGL, this may be bad. In this case it's not strictly
// necessary though because of the `offset!` macro used below in setupMesh()
#[repr(C)]
#[derive(Clone, Debug)]
pub struct Vertex {
// position
pub position: Vector3<f32>,
// normal
pub normal: Vector3<f32>,
// texCoords
pub text_coords: Vector2<f32>,
// tangent
pub tangent: Vector3<f32>,
// bitangent
pub bitangent: Vector3<f32>,
}
impl Default for Vertex {
fn default() -> Self {
Vertex {
position: Vector3::zero(),
normal: Vector3::zero(),
text_coords: Vector2::zero(),
tangent: Vector3::zero(),
bitangent: Vector3::zero(),
}
}
}
#[derive(Clone, Debug)]
pub struct Texture {
pub id: u32,
pub type_: String,
pub path: String,
}
impl Drop for Texture {
fn drop(&mut self) {
unsafe {
gl::DeleteTextures(1, &self.id);
}
}
}
#[derive(Clone, Debug)]
pub struct Mesh {
/* Mesh Data */
pub vertices: Vec<Vertex>,
pub indices: Vec<u32>,
pub textures: Vec<Texture>,
pub VAO: u32,
/* Render data */
VBO: u32,
EBO: u32,
}
impl Drop for Mesh {
fn drop(&mut self) {
unsafe {
gl::DeleteVertexArrays(1, &self.VAO);
gl::DeleteBuffers(1, &self.VBO);
gl::DeleteBuffers(1, &self.EBO);
}
}
}
impl Mesh {
pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>, textures: Vec<Texture>) -> Mesh {
let mut mesh = Mesh {
vertices,
indices,
textures,
VAO: 0,
VBO: 0,
EBO: 0,
};
// now that we have all the required data, set the vertex buffers and its attribute pointers.
unsafe { mesh.setupMesh() }
mesh
}
/// render the mesh
pub unsafe fn Draw(&self, shader: &Shader) {
// bind appropriate textures
let mut diffuseNr = 0;
let mut specularNr = 0;
let mut normalNr = 0;
let mut heightNr = 0;
for (i, texture) in self.textures.iter().enumerate() {
gl::ActiveTexture(gl::TEXTURE0 + i as u32); // active proper texture unit before binding
// retrieve texture number (the N in diffuse_textureN)
let name = &texture.type_;
let number = match name.as_str() {
"texture_diffuse" => {
diffuseNr += 1;
diffuseNr
}
"texture_specular" => {
specularNr += 1;
specularNr
}
"texture_normal" => {
normalNr += 1;
normalNr
}
"texture_height" => {
heightNr += 1;
heightNr
}
_ => panic!("unknown texture type"),
};
// now set the sampler to the correct texture unit
let sampler = CString::new(format!("{}{}", name, number)).unwrap();
gl::Uniform1i(
gl::GetUniformLocation(shader.id, sampler.as_ptr()),
i as i32,
);
// and finally bind the texture
gl::BindTexture(gl::TEXTURE_2D, texture.id);
}
// draw mesh
gl::BindVertexArray(self.VAO);
gl::DrawElements(
gl::TRIANGLES,
self.indices.len() as i32,
gl::UNSIGNED_INT,
ptr::null(),
);
gl::BindVertexArray(0);
// always good practice to set everything back to defaults once configured.
gl::ActiveTexture(gl::TEXTURE0);
}
unsafe fn setupMesh(&mut self) {
// create buffers/arrays
gl::GenVertexArrays(1, &mut self.VAO);
gl::GenBuffers(1, &mut self.VBO);
gl::GenBuffers(1, &mut self.EBO);
gl::BindVertexArray(self.VAO);
// load data into vertex buffers
gl::BindBuffer(gl::ARRAY_BUFFER, self.VBO);
// A great thing about structs with repr(C) is that their memory layout is sequential for all its items.
// The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which
// again translates to 3/2 floats which translates to a byte array.
let size = (self.vertices.len() * size_of::<Vertex>()) as isize;
let data = &self.vertices[0] as *const Vertex as *const c_void;
gl::BufferData(gl::ARRAY_BUFFER, size, data, gl::STATIC_DRAW);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.EBO);
let size = (self.indices.len() * size_of::<u32>()) as isize;
let data = &self.indices[0] as *const u32 as *const c_void;
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, size, data, gl::STATIC_DRAW);
// set the vertex attribute pointers
let size = size_of::<Vertex>() as i32;
// vertex Positions
gl::EnableVertexAttribArray(0);
gl::VertexAttribPointer(
0,
3,
gl::FLOAT,
gl::FALSE,
size,
offset_of!(Vertex, position) as *const c_void,
);
// vertex normals
gl::EnableVertexAttribArray(1);
gl::VertexAttribPointer(
1,
3,
gl::FLOAT,
gl::FALSE,
size,
offset_of!(Vertex, normal) as *const c_void,
);
// vertex texture coords
gl::EnableVertexAttribArray(2);
gl::VertexAttribPointer(
2,
2,
gl::FLOAT,
gl::FALSE,
size,
offset_of!(Vertex, text_coords) as *const c_void,
);
// vertex tangent
gl::EnableVertexAttribArray(3);
gl::VertexAttribPointer(
3,
3,
gl::FLOAT,
gl::FALSE,
size,
offset_of!(Vertex, tangent) as *const c_void,
);
// vertex bitangent
gl::EnableVertexAttribArray(4);
gl::VertexAttribPointer(
4,
3,
gl::FLOAT,
gl::FALSE,
size,
offset_of!(Vertex, bitangent) as *const c_void,
);
gl::BindVertexArray(0);
}
}