Skip to main content

textured_cube/
textured_cube.rs

1//! # Textured Cube
2//!
3//! Demonstrates loading a PNG texture from disk and applying it to a rotating
4//! cube.  A second, untextured sphere is placed nearby so you can compare the
5//! two rendering modes side-by-side.
6//!
7//! The texture file must exist at `examples/assets/texture.png` relative to
8//! the workspace root.  The cube's vertex colour is `[1.0, 1.0, 1.0, 1.0]`
9//! (white) so the texture is displayed at full fidelity; tinting the colour
10//! changes the texture's hue.
11//!
12//! **Run:**
13//! ```sh
14//! cargo run --example textured_cube
15//! ```
16//!
17//! **Controls (editor mode):**
18//! | Key / mouse       | Action                          |
19//! |-------------------|---------------------------------|
20//! | Alt + left-drag   | Orbit camera                    |
21//! | Scroll wheel      | Zoom                            |
22//! | Middle-drag       | Pan                             |
23//! | W / A / S / D     | Fly camera                      |
24//! | T / R / E         | Translate / Rotate / Scale gizmo|
25//! | F                 | Focus on selected object        |
26//! | Escape            | Switch to play mode             |
27
28use vertra::camera::Camera;
29use vertra::geometry::Geometry;
30use vertra::objects::Object;
31use vertra::transform::Transform;
32use vertra::window::Window;
33
34const TEXTURE_PATH: &str = "examples/assets/texture.png";
35
36struct AppState {
37    cube_id: Option<usize>,
38}
39
40fn main() {
41    Window::new(AppState { cube_id: None })
42        .with_title("Textured Cube — Vertra")
43        .with_camera(
44            Camera::new()
45                .with_position([0.0, 2.5, -6.0])
46                .with_rotation(90.0, -15.0),
47        )
48        .on_startup(|state, scene, _| {
49            // ----------------------------------------------------------------
50            // 1.  Load the texture from disk.
51            //     The key must match the `texture_path` set on the object.
52            // ----------------------------------------------------------------
53            #[cfg(not(target_arch = "wasm32"))]
54            match scene.load_texture(TEXTURE_PATH) {
55                Ok(()) => println!("[info] Texture loaded: {TEXTURE_PATH}"),
56                Err(e) => eprintln!("[warn] {e}  – cube will render with vertex colour"),
57            }
58
59            // ----------------------------------------------------------------
60            // 2.  Textured cube (white vertex colour so the image shows cleanly)
61            // ----------------------------------------------------------------
62            let cube_id = scene.spawn(
63                Object {
64                    name: "Textured Cube".to_string(),
65                    str_id: "cube".to_string(),
66                    geometry: Some(Geometry::Cube { size: 2.0 }),
67                    // White vertex colour = texture displayed without tint.
68                    // Change this to tint the texture (e.g. [1.0, 0.5, 0.5, 1.0] = reddish).
69                    color: [1.0, 1.0, 1.0, 1.0],
70                    transform: Transform::from_position(0.0, 1.0, 0.0),
71                    texture_path: Some(TEXTURE_PATH.to_string()),
72                    ..Default::default()
73                },
74                None,
75            );
76            state.cube_id = Some(cube_id);
77        })
78        .on_update(|state, scene, ctx| {
79            // Slowly rotate the cube so all faces of the texture are visible.
80            if let Some(cube) = state.cube_id.and_then(|id| scene.world.get_mut(id)) {
81                cube.transform.rotation[1] += 40.0 * ctx.dt; // 40°/s around Y
82                cube.transform.rotation[0] += 15.0 * ctx.dt; // 15°/s around X
83            }
84        })
85        .create();
86}
87