forked from bwasty/learn-opengl-rs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodel.rs
140 lines (116 loc) · 4.62 KB
/
model.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#![allow(non_snake_case)]
#![allow(dead_code)]
use std::os::raw::c_void;
use std::path::Path;
use cgmath::{vec2, vec3};
use gl;
use image;
use image::DynamicImage::*;
use image::GenericImage;
use tobj;
use mesh::{ Mesh, Texture, Vertex };
use shader::Shader;
#[derive(Default)]
pub struct Model {
/* Model Data */
pub meshes: Vec<Mesh>,
pub textures_loaded: Vec<Texture>, // stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once.
directory: String,
}
impl Model {
/// constructor, expects a filepath to a 3D model.
pub fn new(path: &str) -> Model {
let mut model = Model::default();
model.loadModel(path);
model
}
pub fn Draw(&self, shader: &Shader) {
for mesh in &self.meshes {
unsafe { mesh.Draw(shader); }
}
}
// loads a model from file and stores the resulting meshes in the meshes vector.
fn loadModel(&mut self, path: &str) {
let path = Path::new(path);
// retrieve the directory path of the filepath
self.directory = path.parent().unwrap_or_else(|| Path::new("")).to_str().unwrap().into();
let obj = tobj::load_obj(path);
let (models, materials) = obj.unwrap();
for model in models {
let mesh = &model.mesh;
let num_vertices = mesh.positions.len() / 3;
// data to fill
let mut vertices: Vec<Vertex> = Vec::with_capacity(num_vertices);
let indices: Vec<u32> = mesh.indices.clone();
let (p, n, t) = (&mesh.positions, &mesh.normals, &mesh.texcoords);
for i in 0..num_vertices {
vertices.push(Vertex {
Position: vec3(p[i*3], p[i*3+1], p[i*3+2]),
Normal: vec3(n[i*3], n[i*3+1], n[i*3+2]),
TexCoords: vec2(t[i*2], t[i*2+1]),
..Vertex::default()
})
}
// process material
let mut textures = Vec::new();
if let Some(material_id) = mesh.material_id {
let material = &materials[material_id];
// 1. diffuse map
if !material.diffuse_texture.is_empty() {
let texture = self.loadMaterialTexture(&material.diffuse_texture, "texture_diffuse");
textures.push(texture);
}
// 2. specular map
if !material.specular_texture.is_empty() {
let texture = self.loadMaterialTexture(&material.specular_texture, "texture_specular");
textures.push(texture);
}
// 3. normal map
if !material.normal_texture.is_empty() {
let texture = self.loadMaterialTexture(&material.normal_texture, "texture_normal");
textures.push(texture);
}
// NOTE: no height maps
}
self.meshes.push(Mesh::new(vertices, indices, textures));
}
}
fn loadMaterialTexture(&mut self, path: &str, typeName: &str) -> Texture {
{
let texture = self.textures_loaded.iter().find(|t| t.path == path);
if let Some(texture) = texture {
return texture.clone();
}
}
let texture = Texture {
id: unsafe { TextureFromFile(path, &self.directory) },
type_: typeName.into(),
path: path.into()
};
self.textures_loaded.push(texture.clone());
texture
}
}
unsafe fn TextureFromFile(path: &str, directory: &str) -> u32 {
let filename = format!("{}/{}", directory, path);
let mut textureID = 0;
gl::GenTextures(1, &mut textureID);
let img = image::open(&Path::new(&filename)).expect("Texture failed to load");
let img = img.flipv();
let format = match img {
ImageLuma8(_) => gl::RED,
ImageLumaA8(_) => gl::RG,
ImageRgb8(_) => gl::RGB,
ImageRgba8(_) => gl::RGBA,
};
let data = img.raw_pixels();
gl::BindTexture(gl::TEXTURE_2D, textureID);
gl::TexImage2D(gl::TEXTURE_2D, 0, format as i32, img.width() as i32, img.height() as i32,
0, format, gl::UNSIGNED_BYTE, &data[0] as *const u8 as *const c_void);
gl::GenerateMipmap(gl::TEXTURE_2D);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
textureID
}