2018-04-17 10:45:44 +02:00
|
|
|
extern crate clap;
|
2018-02-23 15:22:48 +01:00
|
|
|
extern crate glium;
|
2018-04-17 10:45:44 +02:00
|
|
|
#[macro_use]
|
|
|
|
extern crate verbose_log;
|
2018-02-26 11:45:53 +01:00
|
|
|
extern crate model_converter;
|
2018-02-23 15:22:48 +01:00
|
|
|
|
2018-04-11 17:03:32 +02:00
|
|
|
use std::process::exit;
|
2018-04-17 10:45:44 +02:00
|
|
|
use std::time::{Instant, Duration};
|
2018-06-15 16:21:04 +02:00
|
|
|
use std::thread::sleep;
|
2018-04-17 10:45:44 +02:00
|
|
|
|
|
|
|
use clap::{App, Arg};
|
2018-04-11 17:03:32 +02:00
|
|
|
|
2018-02-23 15:22:48 +01:00
|
|
|
use glium::Display;
|
|
|
|
use glium::glutin;
|
2018-04-18 14:19:16 +02:00
|
|
|
use glium::glutin::{EventsLoop, WindowBuilder};
|
2018-02-23 15:22:48 +01:00
|
|
|
|
|
|
|
use glium::glutin::Event;
|
|
|
|
use glium::glutin::WindowEvent;
|
|
|
|
use glium::glutin::VirtualKeyCode;
|
|
|
|
|
2018-04-18 10:26:40 +02:00
|
|
|
use model_converter::scene::Scene;
|
2018-04-17 10:45:44 +02:00
|
|
|
use model_converter::math::bounding_box::BoundingBox3;
|
2018-04-10 15:13:35 +02:00
|
|
|
use model_converter::math::vector::Vector3;
|
2018-06-07 17:41:02 +02:00
|
|
|
use model_converter::parser::parse_file;
|
2018-02-27 11:42:35 +01:00
|
|
|
use model_converter::renderer::Renderer;
|
2018-04-18 14:19:16 +02:00
|
|
|
use model_converter::controls::{OrbitControls, FirstPersonControls};
|
2018-04-17 10:45:44 +02:00
|
|
|
use model_converter::camera::Camera;
|
|
|
|
|
|
|
|
fn as_millis(duration: Duration) -> u64 {
|
|
|
|
duration.as_secs() * 1_000 + (duration.subsec_nanos() as u64) / 1_000_000
|
|
|
|
}
|
2018-02-26 11:45:53 +01:00
|
|
|
|
2018-02-23 15:22:48 +01:00
|
|
|
fn main() {
|
|
|
|
|
2018-04-17 10:45:44 +02:00
|
|
|
let matches = App::new("3D Viewer")
|
|
|
|
.version("1.0")
|
|
|
|
.arg(Arg::with_name("input")
|
|
|
|
.short("i")
|
|
|
|
.long("input")
|
|
|
|
.value_name("FILES")
|
|
|
|
.takes_value(true)
|
|
|
|
.multiple(true)
|
|
|
|
.help("Input model files")
|
|
|
|
.required(true))
|
|
|
|
.arg(Arg::with_name("first person")
|
|
|
|
.short("f")
|
|
|
|
.long("first-person")
|
|
|
|
.help("Uses first person controls instead of orbit controls"))
|
|
|
|
.arg(Arg::with_name("verbose")
|
|
|
|
.short("v")
|
|
|
|
.long("verbose")
|
|
|
|
.help("Shows logs during the parsing of the model"))
|
|
|
|
.get_matches();
|
|
|
|
|
|
|
|
// Set verbose flag
|
2018-07-02 11:35:12 +02:00
|
|
|
verbose_log::set(matches.occurrences_of("verbose") > 0);
|
2018-04-17 10:45:44 +02:00
|
|
|
|
|
|
|
use std::f64::{MIN, MAX};
|
|
|
|
let mut bbox = BoundingBox3::new(
|
|
|
|
Vector3::new(MAX, MAX, MAX),
|
|
|
|
Vector3::new(MIN, MIN, MIN),
|
|
|
|
);
|
2018-04-11 17:03:32 +02:00
|
|
|
|
2018-04-17 10:45:44 +02:00
|
|
|
let mut models = vec![];
|
2018-04-11 17:03:32 +02:00
|
|
|
|
2018-04-17 10:45:44 +02:00
|
|
|
for input in matches.values_of("input").unwrap() {
|
2018-06-07 17:41:02 +02:00
|
|
|
match parse_file(&input) {
|
2018-04-17 10:45:44 +02:00
|
|
|
Ok(model) => {
|
2018-04-24 11:57:25 +02:00
|
|
|
if model.vertices.len() > 0 {
|
|
|
|
bbox = bbox.union(&model.bounding_box());
|
|
|
|
}
|
2018-04-17 10:45:44 +02:00
|
|
|
models.push((input.to_owned(), model))
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
eprintln!("Error while parsing file: {}", e);
|
|
|
|
exit(1);
|
|
|
|
},
|
2018-04-11 17:03:32 +02:00
|
|
|
}
|
|
|
|
}
|
2018-02-26 14:59:32 +01:00
|
|
|
|
2018-02-23 15:22:48 +01:00
|
|
|
let mut events_loop = EventsLoop::new();
|
2018-04-11 17:11:55 +02:00
|
|
|
let window = WindowBuilder::new().with_visibility(false);
|
2018-02-26 14:59:32 +01:00
|
|
|
let context = glutin::ContextBuilder::new().with_depth_buffer(24);
|
2018-02-23 15:22:48 +01:00
|
|
|
let display = Display::new(window, context, &events_loop).unwrap();
|
2018-04-11 17:11:55 +02:00
|
|
|
let mut renderer = Renderer::new(display);
|
2018-02-23 15:22:48 +01:00
|
|
|
|
2018-04-18 10:26:40 +02:00
|
|
|
let mut scene = Scene::new();
|
2018-04-17 10:45:44 +02:00
|
|
|
let mut before;
|
|
|
|
let mut duration;
|
|
|
|
|
|
|
|
for (name, mut model) in models {
|
|
|
|
log!("Scaling model {}...", name);
|
|
|
|
model.center_and_scale_from_box(&bbox);
|
|
|
|
|
|
|
|
log!("\nBuilding textures for model {}...", name);
|
|
|
|
|
|
|
|
before = Instant::now();
|
|
|
|
model.build_textures(&renderer);
|
|
|
|
duration = Instant::now().duration_since(before);
|
|
|
|
|
|
|
|
log!(" done in {}ms.\nBuilding vertex buffers for model {}...",
|
|
|
|
as_millis(duration) ,name);
|
2018-02-23 15:22:48 +01:00
|
|
|
|
2018-04-17 10:45:44 +02:00
|
|
|
before = Instant::now();
|
|
|
|
model.build_vertex_buffers(&renderer);
|
|
|
|
duration = Instant::now().duration_since(before);
|
|
|
|
|
2018-04-18 10:26:40 +02:00
|
|
|
scene.emplace(model);
|
2018-04-17 10:45:44 +02:00
|
|
|
logln!(" done in {}ms.\nFinished", as_millis(duration));
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut closed = false;
|
2018-02-26 11:45:53 +01:00
|
|
|
|
2018-04-10 15:13:35 +02:00
|
|
|
let mut camera = Camera::new(
|
|
|
|
Vector3::new( 0.0, 0.0, 0.0),
|
|
|
|
Vector3::new( 0.0, 0.0, 0.0),
|
|
|
|
Vector3::new( 0.0, 1.0, 0.0),
|
|
|
|
);
|
2018-02-26 14:59:32 +01:00
|
|
|
|
2018-04-17 10:45:44 +02:00
|
|
|
camera.z_near = 0.0001;
|
2018-04-12 17:23:40 +02:00
|
|
|
|
2018-04-17 10:59:17 +02:00
|
|
|
let mut controls: Box<Controls> = if matches.is_present("first person") {
|
2018-04-17 10:45:44 +02:00
|
|
|
Box::new(FirstPersonControls::new())
|
|
|
|
} else {
|
|
|
|
Box::new(OrbitControls::new(
|
|
|
|
Vector3::new(0.0, 0.0, 0.0),
|
|
|
|
1.0,
|
|
|
|
&mut camera
|
|
|
|
))
|
|
|
|
};
|
2018-02-23 15:22:48 +01:00
|
|
|
|
2018-04-11 17:11:55 +02:00
|
|
|
renderer.show();
|
|
|
|
|
2018-04-17 10:45:44 +02:00
|
|
|
use model_converter::controls::Controls;
|
2018-06-15 16:21:04 +02:00
|
|
|
|
|
|
|
let mut before = Instant::now();
|
|
|
|
|
2018-04-10 15:13:35 +02:00
|
|
|
while !closed {
|
2018-02-27 11:42:35 +01:00
|
|
|
|
2018-04-10 15:13:35 +02:00
|
|
|
events_loop.poll_events(|ev| {
|
2018-02-23 15:22:48 +01:00
|
|
|
|
2018-04-12 17:23:40 +02:00
|
|
|
controls.manage_event(&ev, &mut camera, &renderer);
|
2018-02-23 15:22:48 +01:00
|
|
|
|
|
|
|
match ev {
|
|
|
|
// Close window
|
|
|
|
Event::WindowEvent {
|
|
|
|
event: WindowEvent::Closed, ..
|
|
|
|
} => closed = true,
|
|
|
|
|
|
|
|
// Escape key
|
|
|
|
Event::WindowEvent {
|
|
|
|
event: WindowEvent::KeyboardInput {
|
|
|
|
input: glutin::KeyboardInput {
|
|
|
|
virtual_keycode: Some(VirtualKeyCode::Escape), ..
|
|
|
|
}, ..
|
|
|
|
}, ..
|
|
|
|
} => closed = true,
|
|
|
|
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
});
|
2018-04-10 15:13:35 +02:00
|
|
|
|
2018-04-12 17:23:40 +02:00
|
|
|
controls.update(&mut camera, &renderer);
|
2018-04-17 10:45:44 +02:00
|
|
|
renderer.render(&scene, &camera);
|
2018-06-15 16:21:04 +02:00
|
|
|
let elapsed = as_millis(Instant::now().duration_since(before));
|
2018-04-10 15:13:35 +02:00
|
|
|
|
2018-06-15 16:21:04 +02:00
|
|
|
if elapsed < 20 {
|
|
|
|
sleep(Duration::from_millis(20 - elapsed));
|
|
|
|
}
|
|
|
|
|
|
|
|
before = Instant::now();
|
2018-02-23 15:22:48 +01:00
|
|
|
}
|
|
|
|
}
|