model-converter/src/programs/viewer.rs

166 lines
4.6 KiB
Rust

extern crate clap;
extern crate glium;
#[macro_use]
extern crate verbose_log;
extern crate model_converter;
use std::process::exit;
use std::time::{Instant, Duration};
use clap::{App, Arg};
use glium::Display;
use glium::glutin;
use glium::glutin::{EventsLoop, WindowBuilder};
use glium::glutin::Event;
use glium::glutin::WindowEvent;
use glium::glutin::VirtualKeyCode;
use model_converter::scene::Scene;
use model_converter::math::bounding_box::BoundingBox3;
use model_converter::math::vector::Vector3;
use model_converter::parser::parse_file;
use model_converter::renderer::Renderer;
use model_converter::controls::{OrbitControls, FirstPersonControls};
use model_converter::camera::Camera;
fn as_millis(duration: Duration) -> u64 {
duration.as_secs() * 1_000 + (duration.subsec_nanos() as u64) / 1_000_000
}
fn main() {
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
verbose_log::log::VERBOSE.with(|verbose| {
*verbose.borrow_mut() = matches.occurrences_of("verbose") > 0;
});
use std::f64::{MIN, MAX};
let mut bbox = BoundingBox3::new(
Vector3::new(MAX, MAX, MAX),
Vector3::new(MIN, MIN, MIN),
);
let mut models = vec![];
for input in matches.values_of("input").unwrap() {
match parse_file(&input) {
Ok(model) => {
if model.vertices.len() > 0 {
bbox = bbox.union(&model.bounding_box());
}
models.push((input.to_owned(), model))
},
Err(e) => {
eprintln!("Error while parsing file: {}", e);
exit(1);
},
}
}
let mut events_loop = EventsLoop::new();
let window = WindowBuilder::new().with_visibility(false);
let context = glutin::ContextBuilder::new().with_depth_buffer(24);
let display = Display::new(window, context, &events_loop).unwrap();
let mut renderer = Renderer::new(display);
let mut scene = Scene::new();
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);
before = Instant::now();
model.build_vertex_buffers(&renderer);
duration = Instant::now().duration_since(before);
scene.emplace(model);
logln!(" done in {}ms.\nFinished", as_millis(duration));
}
let mut closed = false;
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),
);
camera.z_near = 0.0001;
let mut controls: Box<Controls> = if matches.is_present("first person") {
Box::new(FirstPersonControls::new())
} else {
Box::new(OrbitControls::new(
Vector3::new(0.0, 0.0, 0.0),
1.0,
&mut camera
))
};
renderer.show();
use model_converter::controls::Controls;
while !closed {
events_loop.poll_events(|ev| {
controls.manage_event(&ev, &mut camera, &renderer);
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,
_ => (),
}
});
controls.update(&mut camera, &renderer);
renderer.render(&scene, &camera);
}
}