Skip to main content

obj/
obj.rs

1use rusterix::prelude::*;
2use std::path::Path;
3use std::time::Instant;
4use theframework::*;
5use vek::{Mat4, Vec2, Vec3, Vec4};
6
7fn main() {
8    let demo = ObjDemo::new();
9    let app = TheApp::new();
10
11    () = app.run(Box::new(demo));
12}
13
14// This example uses raw draw calls into rusterix, bypassing the engine API.
15
16pub struct ObjDemo {
17    camera: D3OrbitCamera,
18    scene: Scene,
19    assets: Assets,
20    start_time: Instant,
21}
22
23impl TheTrait for ObjDemo {
24    fn new() -> Self
25    where
26        Self: Sized,
27    {
28        let scene = Scene::from_static(
29            vec![Batch2D::from_rectangle(0.0, 0.0, 200.0, 200.0)],
30            vec![
31                Batch3D::from_obj(Path::new("examples/teapot.obj"))
32                    .source(PixelSource::StaticTileIndex(0))
33                    .repeat_mode(RepeatMode::RepeatXY)
34                    .transform(Mat4::scaling_3d(Vec3::new(0.35, -0.35, 0.35)))
35                    .with_computed_normals(),
36            ],
37        )
38        .lights(vec![
39            Light::new(LightType::Point)
40                .with_intensity(1.0)
41                .with_color([1.0, 1.0, 0.95])
42                .compile(),
43        ])
44        .background(Box::new(VGrayGradientShader::new()));
45
46        let assets = Assets::default().textures(vec![Tile::from_texture(Texture::from_image(
47            Path::new("images/logo.png"),
48        ))]);
49
50        let mut camera = D3OrbitCamera::new();
51        camera.set_parameter_f32("distance", 1.5);
52
53        Self {
54            camera,
55            scene,
56            start_time: Instant::now(),
57            assets,
58        }
59    }
60
61    fn draw(&mut self, pixels: &mut [u8], ctx: &mut TheContext) {
62        let _start = get_time();
63
64        // Animate light in circle around Y-axis
65        let elapsed = self.start_time.elapsed().as_secs_f32() * 1.5;
66        self.scene.lights[0].position = Vec3::new(2.0 * elapsed.cos(), 0.8, 2.0 * elapsed.sin());
67
68        // Set it up
69        Rasterizer::setup(
70            None,
71            self.camera.view_matrix(),
72            self.camera
73                .projection_matrix(ctx.width as f32, ctx.height as f32),
74        )
75        .ambient(Vec4::broadcast(0.8))
76        .rasterize(
77            &mut self.scene,
78            pixels,     // Destination buffer
79            ctx.width,  // Destination buffer width
80            ctx.height, // Destination buffer height
81            60,         // Tile size
82            &self.assets,
83        );
84
85        let _stop = get_time();
86        // println!("Execution time: {:?} ms.", _stop - _start);
87    }
88
89    // Hover event
90    fn hover(&mut self, x: f32, y: f32, ctx: &mut TheContext) -> bool {
91        self.camera.set_parameter_vec2(
92            "from_normalized",
93            Vec2::new(x / ctx.width as f32, y / ctx.height as f32),
94        );
95        true
96    }
97
98    // Query if the widget needs a redraw, we redraw at max speed (which is not necessary)
99    fn update(&mut self, _ctx: &mut TheContext) -> bool {
100        true
101    }
102
103    fn window_title(&self) -> String {
104        "Rusterix OBJ Demo".to_string()
105    }
106}
107
108fn get_time() -> u128 {
109    #[cfg(target_arch = "wasm32")]
110    {
111        web_sys::window().unwrap().performance().unwrap().now() as u128
112    }
113    #[cfg(not(target_arch = "wasm32"))]
114    {
115        let stop = std::time::SystemTime::now()
116            .duration_since(std::time::UNIX_EPOCH)
117            .expect("Time went backwards");
118        stop.as_millis()
119    }
120}