use crate::base::Result;
use crate::three::load::{self, LoadStats, Model};
use crate::three::scene::{Camera, Light, Scene};
#[derive(Debug)]
pub struct QuickView {
pub model: Model,
pub camera: Camera,
pub light: Light,
pub stats: LoadStats,
}
impl QuickView {
pub fn scene(&self) -> Scene<'_> {
let mut scene = Scene::new(&self.model, self.camera);
scene.light = self.light;
scene.double_sided = true;
scene
}
pub fn look_from(&mut self, yaw: f32, pitch: f32) {
self.camera = self.model.fit_camera(yaw, pitch);
}
}
pub fn quick_view(path: impl AsRef<std::path::Path>) -> Result<QuickView> {
let (model, stats) = load::load_glb_with_stats(path)?;
let camera = model.fit_camera(0.6, 0.35);
Ok(QuickView {
model,
camera,
light: Light::default(),
stats,
})
}
pub fn quick_view_bytes(bytes: &[u8]) -> Result<QuickView> {
let (model, stats) = Model::load_with_stats(bytes)?;
let camera = model.fit_camera(0.6, 0.35);
Ok(QuickView {
model,
camera,
light: Light::default(),
stats,
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testing::glb_mutate;
use crate::three::raster::Framebuffer;
use crate::three::scene::SceneRenderer;
#[test]
fn quick_view_renders_in_five_lines() {
let view = quick_view_bytes(&glb_mutate::minimal_glb()).unwrap();
let mut fb = Framebuffer::new(64, 48);
SceneRenderer::new().render(&view.scene(), &mut fb);
assert!(fb.coverage() > 0.0, "framed camera must show the model");
assert!(view.stats.total > std::time::Duration::ZERO);
}
#[test]
fn quick_view_path_errors_name_the_file() {
let err = quick_view("/nonexistent/nope.glb").unwrap_err();
assert!(err.to_string().contains("nope.glb"), "{err}");
}
#[test]
fn look_from_reframes() {
let mut view = quick_view_bytes(&glb_mutate::minimal_glb()).unwrap();
let before = view.camera.yaw;
view.look_from(before + 1.0, 0.1);
assert!((view.camera.yaw - (before + 1.0)).abs() < 1e-6);
}
}