wisp_storybook/stories/
s_transform_nesting.rs1use glam::Vec2;
4use wisp::application::Application;
5use wisp::{Container, Sprite, Stage, Texture};
6
7use crate::story::Story;
8
9pub fn story() -> Story {
10 Story {
11 id: "transform-nesting",
12 category: "Scene Graph",
13 title: "Nested transforms",
14 milestone: "M0.7 / M0.8",
15 writeup: include_str!("writeups/transform_nesting.md"),
16 build,
17 tick: Some(tick),
18 }
19}
20
21fn build(app: &Application, stage: &mut Stage) {
22 let red = solid_texture(app, [255, 100, 100, 255]);
24 let green = solid_texture(app, [100, 255, 100, 255]);
25 let blue = solid_texture(app, [100, 180, 255, 255]);
26
27 let outer = Container::default();
29 let outer_id = stage.add_child(stage.root(), outer).expect("outer");
30 add_orbiters(stage, outer_id, &red, 0.55, 6);
31
32 let mid = Container::default();
34 let mid_id = stage.add_child(outer_id, mid).expect("mid");
35 add_orbiters(stage, mid_id, &green, 0.35, 4);
36
37 let inner = Container::default();
39 let inner_id = stage.add_child(mid_id, inner).expect("inner");
40 add_orbiters(stage, inner_id, &blue, 0.18, 3);
41}
42
43fn solid_texture(app: &Application, rgba: [u8; 4]) -> Texture {
44 let mut bytes = Vec::with_capacity(4 * 4 * 4);
45 for _ in 0..(4 * 4) {
46 bytes.extend_from_slice(&rgba);
47 }
48 Texture::from_rgba(app, 4, 4, &bytes)
49}
50
51fn add_orbiters(stage: &mut Stage, parent: wisp::NodeId, texture: &Texture, radius: f32, n: u8) {
52 for i in 0..n {
53 let theta = std::f32::consts::TAU * f32::from(i) / f32::from(n);
54 let mut sprite = Sprite::from_texture(texture.clone()).with_anchor(Vec2::splat(0.5));
55 sprite.container.transform.position = Vec2::new(theta.cos() * radius, theta.sin() * radius);
56 sprite.container.transform.scale = Vec2::splat(0.08);
57 let _ = stage.add_child(parent, sprite);
58 }
59}
60
61fn tick(stage: &mut Stage, t: f32) {
62 let root_children: Vec<_> = stage
64 .get(stage.root())
65 .map(|n| n.container().children().collect())
66 .unwrap_or_default();
67 let Some(outer_id) = root_children.first().copied() else {
68 return;
69 };
70 set_rotation(stage, outer_id, t * 0.3);
71
72 let mid_children: Vec<_> = stage
73 .get(outer_id)
74 .map(|n| n.container().children().collect())
75 .unwrap_or_default();
76 if let Some(mid_id) = mid_children.iter().next_back().copied() {
78 set_rotation(stage, mid_id, t * -0.7);
79 let inner_children: Vec<_> = stage
80 .get(mid_id)
81 .map(|n| n.container().children().collect())
82 .unwrap_or_default();
83 if let Some(inner_id) = inner_children.iter().next_back().copied() {
84 set_rotation(stage, inner_id, t * 1.3);
85 }
86 }
87}
88
89fn set_rotation(stage: &mut Stage, id: wisp::NodeId, angle: f32) {
90 if let Some(node) = stage.get_mut(id) {
91 node.container_mut().transform.rotation = angle;
92 }
93}