1use std::mem::size_of;
2use std::os::raw::c_void;
3use std::path::Path;
4use std::ptr;
5use std::rc::Rc;
6
7use gl;
8use gl::types::GLenum;
9use gltf;
10use log::{warn, debug};
11
12use crate::render::math::*;
13use crate::render::{Material, Root};
14use crate::shader::*;
15use crate::importdata::ImportData;
16
17#[derive(Debug)]
18pub struct Vertex {
19 pub position: Vector3,
20 pub normal: Vector3,
21 pub tangent: Vector4,
22 pub tex_coord_0: Vector2,
23 pub tex_coord_1: Vector2,
24 pub color_0: Vector4,
25 pub joints_0: [u16; 4],
26 pub weights_0: Vector4,
27}
28
29impl Default for Vertex {
30 fn default() -> Self {
31 Vertex {
32 position: Vector3::zero(),
33 normal: Vector3::zero(),
34 tangent: Vector4::zero(),
35 tex_coord_0: Vector2::zero(),
36 tex_coord_1: Vector2::zero(),
37 color_0: Vector4::zero(),
38 joints_0: [0; 4],
39 weights_0: Vector4::zero(),
40 }
41 }
42}
43
44#[derive(Clone, Debug)]
45pub struct Texture {
46 pub id: u32,
47 pub type_: String,
48 pub path: String,
49}
50
51pub struct Primitive {
52 pub bounds: Aabb3,
53
54 vao: u32,
55 vbo: u32,
56 num_vertices: u32,
57
58 ebo: Option<u32>,
59 num_indices: u32,
60
61 mode: GLenum,
62
63 material: Rc<Material>,
64
65 pbr_shader: Rc<PbrShader>,
66
67 }
69
70impl Primitive {
71 pub fn new(
72 bounds: Aabb3,
73 vertices: &[Vertex],
74 indices: Option<Vec<u32>>,
75 mode: GLenum,
76 material: Rc<Material>,
77 shader: Rc<PbrShader>,
78 ) -> Primitive {
79 let num_indices = indices.as_ref().map(|i| i.len()).unwrap_or(0);
80 let mut prim = Primitive {
81 bounds,
82 num_vertices: vertices.len() as u32,
83 num_indices: num_indices as u32,
84 vao: 0, vbo: 0, ebo: None,
85 mode,
86 material,
87 pbr_shader: shader,
88 };
89
90 unsafe { prim.setup_primitive(vertices, indices) }
92 prim
93 }
94
95 pub fn from_gltf(
96 g_primitive: &gltf::Primitive<'_>,
97 primitive_index: usize,
98 mesh_index: usize,
99 root: &mut Root,
100 imp: &ImportData,
101 base_path: &Path) -> Primitive
102 {
103 let buffers = &imp.buffers;
104 let reader = g_primitive.reader(|buffer| Some(&buffers[buffer.index()]));
105 let positions = {
106 let iter = reader
107 .read_positions()
108 .unwrap_or_else(||
109 panic!("primitives must have the POSITION attribute (mesh: {}, primitive: {})",
110 mesh_index, primitive_index)
111 );
112 iter.collect::<Vec<_>>()
113 };
114
115 let bounds = g_primitive.bounding_box();
116 let bounds = Aabb3 {
117 min: bounds.min.into(),
118 max: bounds.max.into()
119 };
120
121 let mut vertices: Vec<Vertex> = positions
122 .into_iter()
123 .map(|position| {
124 Vertex {
125 position: Vector3::from(position),
126 ..Vertex::default()
127 }
128 }).collect();
129
130 let mut shader_flags = ShaderFlags::empty();
131
132 if let Some(normals) = reader.read_normals() {
134 for (i, normal) in normals.enumerate() {
135 vertices[i].normal = Vector3::from(normal);
136 }
137 shader_flags |= ShaderFlags::HAS_NORMALS;
138 }
139 else {
140 debug!("Found no NORMALs for primitive {} of mesh {} \
141 (flat normal calculation not implemented yet)", primitive_index, mesh_index);
142 }
143
144 if let Some(tangents) = reader.read_tangents() {
146 for (i, tangent) in tangents.enumerate() {
147 vertices[i].tangent = Vector4::from(tangent);
148 }
149 shader_flags |= ShaderFlags::HAS_TANGENTS;
150 }
151 else {
152 debug!("Found no TANGENTS for primitive {} of mesh {} \
153 (tangent calculation not implemented yet)", primitive_index, mesh_index);
154 }
155
156 let mut tex_coord_set = 0;
158 while let Some(tex_coords) = reader.read_tex_coords(tex_coord_set) {
159 if tex_coord_set > 1 {
160 warn!("Ignoring texture coordinate set {}, \
161 only supporting 2 sets at the moment. (mesh: {}, primitive: {})",
162 tex_coord_set, mesh_index, primitive_index);
163 tex_coord_set += 1;
164 continue;
165 }
166 for (i, tex_coord) in tex_coords.into_f32().enumerate() {
167 match tex_coord_set {
168 0 => vertices[i].tex_coord_0 = Vector2::from(tex_coord),
169 1 => vertices[i].tex_coord_1 = Vector2::from(tex_coord),
170 _ => unreachable!()
171 }
172 }
173 shader_flags |= ShaderFlags::HAS_UV;
174 tex_coord_set += 1;
175 }
176
177 if let Some(colors) = reader.read_colors(0) {
179 let colors = colors.into_rgba_f32();
180 for (i, c) in colors.enumerate() {
181 vertices[i].color_0 = c.into();
182 }
183 shader_flags |= ShaderFlags::HAS_COLORS;
184 }
185 if reader.read_colors(1).is_some() {
186 warn!("Ignoring further color attributes, only supporting COLOR_0. (mesh: {}, primitive: {})",
187 mesh_index, primitive_index);
188 }
189
190 if let Some(joints) = reader.read_joints(0) {
191 for (i, joint) in joints.into_u16().enumerate() {
192 vertices[i].joints_0 = joint;
193 }
194 }
195 if reader.read_joints(1).is_some() {
196 warn!("Ignoring further joint attributes, only supporting JOINTS_0. (mesh: {}, primitive: {})",
197 mesh_index, primitive_index);
198 }
199
200 if let Some(weights) = reader.read_weights(0) {
201 for (i, weights) in weights.into_f32().enumerate() {
202 vertices[i].weights_0 = weights.into();
203 }
204 }
205 if reader.read_weights(1).is_some() {
206 warn!("Ignoring further weight attributes, only supporting WEIGHTS_0. (mesh: {}, primitive: {})",
207 mesh_index, primitive_index);
208 }
209
210 let indices = reader
211 .read_indices()
212 .map(|read_indices| {
213 read_indices.into_u32().collect::<Vec<_>>()
214 });
215
216 let mode = g_primitive.mode().as_gl_enum();
224
225 let g_material = g_primitive.material();
226
227 let mut material = None;
228 if let Some(mat) = root.materials.iter().find(|m| (***m).index == g_material.index()) {
229 material = Rc::clone(mat).into()
230 }
231
232 if material.is_none() { let mat = Rc::new(Material::from_gltf(&g_material, root, imp, base_path));
234 root.materials.push(Rc::clone(&mat));
235 material = Some(mat);
236 };
237 let material = material.unwrap();
238 shader_flags |= material.shader_flags();
239
240 let mut new_shader = false; let shader =
242 if let Some(shader) = root.shaders.get(&shader_flags) {
243 Rc::clone(shader)
244 }
245 else {
246 new_shader = true;
247 PbrShader::new(shader_flags).into()
248
249 };
250 if new_shader {
251 root.shaders.insert(shader_flags, Rc::clone(&shader));
252 }
253
254 Primitive::new(bounds, &vertices, indices, mode, material, shader)
255 }
256
257 pub unsafe fn draw(&self, model_matrix: &Matrix4, mvp_matrix: &Matrix4, camera_position: &Vector3) {
259 if self.material.double_sided {
262 gl::Disable(gl::CULL_FACE);
263 } else {
264 gl::Enable(gl::CULL_FACE);
265 }
266
267 if self.mode == gl::POINTS {
268 gl::PointSize(10.0);
269 }
270
271 self.configure_shader(model_matrix, mvp_matrix, camera_position);
272
273 gl::BindVertexArray(self.vao);
275 if self.ebo.is_some() {
276 gl::DrawElements(self.mode, self.num_indices as i32, gl::UNSIGNED_INT, ptr::null());
277 }
278 else {
279 gl::DrawArrays(self.mode, 0, self.num_vertices as i32)
280 }
281
282 gl::BindVertexArray(0);
283 gl::ActiveTexture(gl::TEXTURE0);
284
285 if self.material.alpha_mode != gltf::material::AlphaMode::Opaque {
286 let shader = &self.pbr_shader.shader;
287
288 gl::Disable(gl::BLEND);
289 shader.set_float(self.pbr_shader.uniforms.u_AlphaBlend, 0.0);
290 if self.material.alpha_mode == gltf::material::AlphaMode::Mask {
291 shader.set_float(self.pbr_shader.uniforms.u_AlphaCutoff, 0.0);
292 }
293 }
294 }
295
296 unsafe fn configure_shader(&self, model_matrix: &Matrix4,
297 mvp_matrix: &Matrix4, camera_position: &Vector3)
298 {
299 let mat = &self.material;
301 let shader = &self.pbr_shader.shader;
302 let uniforms = &self.pbr_shader.uniforms;
303 self.pbr_shader.shader.use_program();
304
305 shader.set_mat4(uniforms.u_ModelMatrix, model_matrix);
307 shader.set_mat4(uniforms.u_MVPMatrix, mvp_matrix);
308 shader.set_vector3(uniforms.u_Camera, camera_position);
309
310 if mat.alpha_mode != gltf::material::AlphaMode::Opaque {
312 gl::Enable(gl::BLEND);
314 gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
315 shader.set_float(uniforms.u_AlphaBlend, 1.0);
316
317 if mat.alpha_mode == gltf::material::AlphaMode::Mask {
318 shader.set_float(uniforms.u_AlphaCutoff, mat.alpha_cutoff);
319 }
320 }
321
322 shader.set_vector4(uniforms.u_BaseColorFactor, &mat.base_color_factor);
324 if let Some(ref base_color_texture) = mat.base_color_texture {
325 gl::ActiveTexture(gl::TEXTURE0);
326 gl::BindTexture(gl::TEXTURE_2D, base_color_texture.id);
327 shader.set_int(uniforms.u_BaseColorTexCoord, base_color_texture.tex_coord as i32);
328 }
329 if let Some(ref normal_texture) = mat.normal_texture {
330 gl::ActiveTexture(gl::TEXTURE1);
331 gl::BindTexture(gl::TEXTURE_2D, normal_texture.id);
332 shader.set_int(uniforms.u_NormalTexCoord, normal_texture.tex_coord as i32);
333 shader.set_float(uniforms.u_NormalScale, mat.normal_scale.unwrap_or(1.0));
334 }
335 if let Some(ref emissive_texture) = mat.emissive_texture {
336 gl::ActiveTexture(gl::TEXTURE2);
337 gl::BindTexture(gl::TEXTURE_2D, emissive_texture.id);
338 shader.set_int(uniforms.u_EmissiveTexCoord, emissive_texture.tex_coord as i32);
339 shader.set_vector3(uniforms.u_EmissiveFactor, &mat.emissive_factor);
340 }
341
342 if let Some(ref mr_texture) = mat.metallic_roughness_texture {
343 gl::ActiveTexture(gl::TEXTURE3);
344 gl::BindTexture(gl::TEXTURE_2D, mr_texture.id);
345 shader.set_int(uniforms.u_MetallicRoughnessTexCoord, mr_texture.tex_coord as i32);
346 }
347 shader.set_vec2(uniforms.u_MetallicRoughnessValues,
348 mat.metallic_factor, mat.roughness_factor);
349
350 if let Some(ref occlusion_texture) = mat.occlusion_texture {
351 gl::ActiveTexture(gl::TEXTURE4);
352 gl::BindTexture(gl::TEXTURE_2D, occlusion_texture.id);
353 shader.set_int(uniforms.u_OcclusionTexCoord, occlusion_texture.tex_coord as i32);
354 shader.set_float(uniforms.u_OcclusionStrength, mat.occlusion_strength);
355 }
356 }
357
358 unsafe fn setup_primitive(&mut self, vertices: &[Vertex], indices: Option<Vec<u32>>) {
359 gl::GenVertexArrays(1, &mut self.vao);
361 gl::GenBuffers(1, &mut self.vbo);
362 if indices.is_some() {
363 let mut ebo = 0;
364 gl::GenBuffers(1, &mut ebo);
365 self.ebo = Some(ebo);
366 }
367
368 gl::BindVertexArray(self.vao);
369 gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
371 let size = (vertices.len() * size_of::<Vertex>()) as isize;
372 let data = &vertices[0] as *const Vertex as *const c_void;
373 gl::BufferData(gl::ARRAY_BUFFER, size, data, gl::STATIC_DRAW);
374
375 if let Some(ebo) = self.ebo {
376 let indices = indices.unwrap();
377 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
378 let size = (indices.len() * size_of::<u32>()) as isize;
379 let data = &indices[0] as *const u32 as *const c_void;
380 gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, size, data, gl::STATIC_DRAW);
381 }
382
383 let size = size_of::<Vertex>() as i32;
385 gl::EnableVertexAttribArray(0);
387 gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, position) as *const c_void);
388 gl::EnableVertexAttribArray(1);
390 gl::VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, normal) as *const c_void);
391 gl::EnableVertexAttribArray(2);
393 gl::VertexAttribPointer(2, 4, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tangent) as *const c_void);
394 gl::EnableVertexAttribArray(3);
396 gl::VertexAttribPointer(3, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tex_coord_0) as *const c_void);
397 gl::EnableVertexAttribArray(4);
399 gl::VertexAttribPointer(4, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tex_coord_1) as *const c_void);
400 gl::EnableVertexAttribArray(5);
402 gl::VertexAttribPointer(5, 4, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, color_0) as *const c_void);
403 gl::EnableVertexAttribArray(6);
405 gl::VertexAttribPointer(6, 4, gl::UNSIGNED_SHORT, gl::FALSE, size, offset_of!(Vertex, joints_0) as *const c_void);
407 gl::EnableVertexAttribArray(7);
409 gl::VertexAttribPointer(7, 4, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, weights_0) as *const c_void);
410
411 gl::BindVertexArray(0);
412 }
413}