scene_viewer/
scene_viewer.rs1use std::time::Instant;
13
14use ponko::*;
15
16fn extent(world: &mut World) -> (Vec3, f32) {
18 let (mut min, mut max) = (Vec3::splat(f32::MAX), Vec3::splat(f32::MIN));
19 world.query::<(&Transform3D, &Model)>().for_each(|(t, _)| {
20 min = min.min(t.position);
21 max = max.max(t.position);
22 });
23 if min.x > max.x {
24 return (Vec3::ZERO, 10.0);
25 }
26 ((min + max) * 0.5, (max - min).max_element().max(10.0))
27}
28
29fn camera_from_env() -> Option<(Vec3, f32, f32)> {
30 let v: Vec<f32> = std::env::var("CAMERA")
31 .ok()?
32 .split(',')
33 .map(|n| n.trim().parse().ok())
34 .collect::<Option<_>>()?;
35 let [x, y, z, yaw, pitch] = v[..] else { return None };
36 Some((vec3(x, y, z), yaw.to_radians(), pitch.to_radians()))
37}
38
39fn main() {
40 let scene = std::env::var("SCENE").unwrap_or_else(|_| {
41 eprintln!("say which scene: SCENE=town/Town.json (a file under assets/)");
42 std::process::exit(2);
43 });
44 if std::env::var("HEADLESS").is_ok() {
45 Game::new("scene viewer", 1, 1).run_headless(0, |ctx| {
46 let start = Instant::now();
47 ctx.load_scene(&scene).unwrap_or_else(|e| panic!("{e}"));
48 let models = ctx.world.query::<&Model>().iter().count();
49 let (middle, size) = extent(&mut ctx.world);
50 println!(
51 "{scene}: {models} models in {:.2} s, around {middle} across {size:.0} m",
52 start.elapsed().as_secs_f32()
53 );
54 });
55 return;
56 }
57 let shot = std::env::var("SHOT").ok();
58 let (mut yaw, mut pitch) = (0.0f32, -0.3f32);
59 Game::new("Crabby Engine: scene viewer", 1280, 720)
60 .system(move |ctx: &mut Ctx| {
61 if ctx.key_pressed(Key::Escape) {
62 ctx.quit();
63 }
64 let dt = ctx.dt();
65 if ctx.frame() == 1 {
66 let (y, x, _) = ctx.camera3d.rotation.to_euler(glam::EulerRot::YXZ);
67 (yaw, pitch) = (y, x);
68 }
69 let turn = 1.2 * dt;
70 if ctx.key_down(Key::Left) {
71 yaw += turn;
72 }
73 if ctx.key_down(Key::Right) {
74 yaw -= turn;
75 }
76 if ctx.key_down(Key::Up) {
77 pitch = (pitch + turn).min(1.5);
78 }
79 if ctx.key_down(Key::Down) {
80 pitch = (pitch - turn).max(-1.5);
81 }
82 let rotation = Quat::from_rotation_y(yaw) * Quat::from_rotation_x(pitch);
83 let speed = if ctx.key_down(Key::LeftShift) { 120.0 } else { 20.0 } * dt;
84 let mut go = Vec3::ZERO;
85 for (key, way) in [
86 (Key::W, Vec3::NEG_Z),
87 (Key::S, Vec3::Z),
88 (Key::A, Vec3::NEG_X),
89 (Key::D, Vec3::X),
90 ] {
91 if ctx.key_down(key) {
92 go += rotation * way;
93 }
94 }
95 if ctx.key_down(Key::E) {
96 go += Vec3::Y;
97 }
98 if ctx.key_down(Key::Q) {
99 go -= Vec3::Y;
100 }
101 ctx.camera3d.position += go * speed;
102 ctx.camera3d.rotation = rotation;
103 if ctx.frame() == 300
104 && let Some(path) = &shot
105 {
106 ctx.save_screenshot(path);
107 }
108 if ctx.frame() == 302 && shot.is_some() {
109 ctx.quit();
110 }
111 })
112 .run(move |ctx| {
113 ctx.load_scene(&scene).unwrap_or_else(|e| panic!("{e}"));
114 ctx.lighting.sun_direction = Sky::sun_direction_at(15.0);
115 ctx.lighting.shadow_distance = 400.0;
116 ctx.camera3d.far = 3000.0;
117 ctx.post.bloom = 0.05;
118 let (middle, size) = extent(&mut ctx.world);
119 let (at, yaw, pitch) =
120 camera_from_env().unwrap_or((middle + vec3(0.0, size * 0.25, size * 0.4), 0.0, -0.5));
121 ctx.camera3d.position = at;
122 ctx.camera3d.rotation = Quat::from_rotation_y(yaw) * Quat::from_rotation_x(pitch);
123 });
124}