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