diff --git a/src/main.rs b/src/main.rs index 19b5ffc..ce1f1d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,14 +4,16 @@ extern crate glium; #[macro_use] extern crate load_file; -use std::fs; use glium::texture::SrgbTexture2d; use phf::phf_map; +use std::fs; use std::io::Cursor; use std::time::Instant; +use glium::vertex::VertexBufferAny; #[allow(unused_imports)] use glium::{glutin, Surface}; +use crate::support::CHUNK_SIZE; mod support; @@ -421,28 +423,28 @@ fn main() { let structures_folder = "Extensions/LemnosLife/Map/Common/Structures/"; let paths = fs::read_dir(structures_folder).unwrap(); - let mut structures_vertex_buffer = vec![]; + let mut structures_vertex_buffer: Vec<(usize, VertexBufferAny)> = vec![]; for path in paths { - let path = path - .unwrap() - .path(); - let file_path = path - .to_str() - .unwrap(); + let path = path.unwrap().path(); + let file_path = path.to_str().unwrap(); if file_path.ends_with(".obj") { - print!("path: {:?}", file_path); - structures_vertex_buffer.push(support::load_wavefront( - &display, - load_bytes!(&format!("../{}", file_path)), + let file = file_path.replace(structures_folder, ""); + println!("{}", file); + structures_vertex_buffer.push(( + file + .replace(".obj", "") + .parse() + .unwrap(), + support::load_wavefront(&display, load_bytes!(&format!("../{}", file_path))), )) } } - let structures_vertex_buffer = support::load_wavefront( - &display, - load_bytes!(&format!("../{}/24.obj", structures_folder)), - ); + let mut structures_per_instance: Vec> = Vec::with_capacity(926); // As the maximum structure id is 925. + for _ in 0..=925 { + structures_per_instance.push(vec![]); + } let structures_program = program!(&display, 140 => { @@ -472,16 +474,48 @@ fn main() { ) .unwrap(); - let per_instance = vec![ - PerInstance { - w_position: (0.0, 0.0, 0.0), - w_rotation: 0.0, - }, - PerInstance { - w_position: (1.0, 0.0, 0.0), - w_rotation: 0.0, - }, - ]; + let objects_folder = "Extensions/LemnosLife/Map/Altis/Objects/"; + let paths = fs::read_dir(objects_folder).unwrap(); + + for path in paths { + let path = path.unwrap().path(); + let file_path = path.to_str().unwrap(); + let file = file_path.replace(objects_folder, ""); + println!("{}", file); + let file_name = file.replace(".objects", ""); + let file_name_parts: Vec<&str> = file_name.split(' ').collect(); + + let objects_contents = fs::read_to_string(file_path).unwrap_or_else(|_| panic!("Unable to load {} file!", file_path)); + + let chunk = [0, 1].map(|file_name_parts_index| { + file_name_parts[file_name_parts_index] + .parse::() + .unwrap() + * (CHUNK_SIZE as f32) + }); + + let objects_lines: Vec<&str> = objects_contents.split('\n').collect(); + + let (mut offset_x, mut offset_y) = (0.0, 0.0); + for object_line in objects_lines { + let object_line_parts: Vec<&str> = object_line.split(' ').collect(); + if object_line_parts.len() == 2 { + offset_x = object_line_parts[0].parse::().unwrap() * 100.0 + chunk[0]; + offset_y = object_line_parts[1].parse::().unwrap() * 100.0 + chunk[1]; + } else { + let structure_id: usize = object_line_parts[0].parse().unwrap(); + let x: f32 = object_line_parts[1].parse().unwrap(); + let y: f32 = object_line_parts[2].parse().unwrap(); + let z = object_line_parts[3].parse().unwrap(); + let rotation = object_line_parts[4].parse().unwrap(); + let structure_per_instance: &mut Vec = structures_per_instance.get_mut(structure_id).unwrap(); + structure_per_instance.push(PerInstance { + w_position: (offset_x + x, z, offset_y + y), + w_rotation: rotation, + }); + } + } + } // the main loop support::start_loop(event_loop, move |events| { @@ -513,6 +547,7 @@ fn main() { }; // That way we *load* far too many textures per structure but until haven't treated http://gitea.lemnoslife.com:3006/Benjamin_Loison/LemnosLife_Rust/issues/6#issuecomment-240, can't do better. + // Except if we proceed with a disjunction on the number of textures used in a structure which is 8, thanks to `find Extensions/LemnosLife/Map/Common/Structures/ -name '*.obj' -exec sh -c 'grep -o usemtl {} | wc -l' \; | sort -n | tail -1`. let structures_uniforms = uniform! { persp_matrix: camera.get_perspective(), view_matrix: camera.get_view(), @@ -609,10 +644,8 @@ fn main() { }; let mut structures_params = ground_params.clone(); - structures_params.blend = glium::draw_parameters::Blend::alpha_blending(); - - let per_instance_buffer = - glium::vertex::VertexBuffer::new(&display, &per_instance).unwrap(); + structures_params.blend = glium::draw_parameters::Blend::alpha_blending(); // Could disable per opaque structure to optimize. + // Doesn't seem to apply transparency from a structure instance to the other. // drawing a frame let start = Instant::now(); @@ -628,15 +661,26 @@ fn main() { ) .unwrap(); - target - .draw( - (&structures_vertex_buffer, per_instance_buffer.per_instance().unwrap()), - &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList), - &structures_program, - &structures_uniforms, - &structures_params, - ) - .unwrap(); + for (structure_id, structure_vertex_buffer) in &structures_vertex_buffer { + let structure_per_instance = &structures_per_instance[*structure_id]; + if !structure_per_instance.is_empty() { + let structure_per_instance_buffer = + glium::vertex::VertexBuffer::new(&display, structure_per_instance).unwrap(); + + target + .draw( + ( + structure_vertex_buffer, + structure_per_instance_buffer.per_instance().unwrap(), + ), + &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList), + &structures_program, + &structures_uniforms, + &structures_params, + ) + .unwrap(); + } + } target.finish().unwrap(); let duration = start.elapsed(); diff --git a/src/support/camera.rs b/src/support/camera.rs index a8b25a8..efa61f0 100644 --- a/src/support/camera.rs +++ b/src/support/camera.rs @@ -20,8 +20,7 @@ impl CameraState { CameraState { aspect_ratio: 1_024.0 / 768.0, // The second coordinate is for the altitude. - //position: (3_646.41, 12.3622, 13_113.7), - position: (0.0, 0.0, 0.0), + position: (3_646.41, 12.3622, 13_113.7), direction: (0.0, 0.0, -1.0), moving_up: false, moving_left: false, diff --git a/src/support/mod.rs b/src/support/mod.rs index d5f6874..738c6e6 100644 --- a/src/support/mod.rs +++ b/src/support/mod.rs @@ -77,7 +77,7 @@ fn get_altitude(height_columns: &[&str], columns_index: usize) -> f32 { const SEABED_ALTITUDE: f32 = -100.0; // seabed altitude - biggest drop * tiles in a chunk * (chunks in a row - 1) const ALTITUDE_BETWEEN_CHUNKS: f32 = SEABED_ALTITUDE - 16.17 * 250.0 * 30.0; -const CHUNK_SIZE: u32 = 1_000; +pub const CHUNK_SIZE: u32 = 1_000; /// Returns a vertex buffer that should be rendered as `TrianglesList`. pub fn load_ground(display: &Display) -> VertexBufferAny { @@ -220,9 +220,11 @@ pub fn load_wavefront(display: &Display, data: &[u8]) -> VertexBufferAny { obj::SimplePolygon(indices) => { for v in indices.iter().take(3) { let position = data.position[v.0]; + let position = [position[0], position[2], position[1]]; let texture_coordinates = data.texture[v.1.unwrap()]; - let texture_index = if let obj::ObjMaterial::Ref(texture) = group.material.as_ref().unwrap() + let texture_index = if let obj::ObjMaterial::Ref(texture) = + group.material.as_ref().unwrap() { STRUCTURES_TEXTURES_REVERSED[texture] } else { @@ -238,9 +240,11 @@ pub fn load_wavefront(display: &Display, data: &[u8]) -> VertexBufferAny { for i in [0, 2, 3] { let v = indices[i]; let position = data.position[v.0]; + let position = [position[0], position[2], position[1]]; let texture_coordinates = data.texture[v.1.unwrap()]; - let texture_index = if let obj::ObjMaterial::Ref(texture) = group.material.as_ref().unwrap() + let texture_index = if let obj::ObjMaterial::Ref(texture) = + group.material.as_ref().unwrap() { STRUCTURES_TEXTURES_REVERSED[texture] } else {