Skip to main content

cube/
cube.rs

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