1use primback::prelude::*;
2
3struct AnimationApp {
4 linear_pos: Animated<Vec3>,
5 exp_pos: Animated<Vec3>,
6 spring_pos: Animated<Vec3>,
7 target_pos: Vec3,
8 timer: f32,
9 rng: Random,
10}
11
12impl PrimbackApp for AnimationApp {
13 fn init(&mut self, update_ctx: &mut UpdateContext) {
14 let camera = Camera::look_at(vec3(0.0, 4.0, 8.0), vec3(0.0, 1.0, 0.0), Vec3::Y);
15 update_ctx.set_camera(camera);
16
17 let light = Light {
18 direction: vec3(0.5, -1.0, -0.5).normalize(),
19 color: Color::new(1.0, 1.0, 1.0),
20 ambient: Color::new(0.3, 0.3, 0.35),
21 };
22 update_ctx.set_light(light);
23 }
24
25 fn update(&mut self, update_ctx: &mut UpdateContext) {
26 if update_ctx.is_key_pressed(KeyCode::Escape) {
27 update_ctx.exit();
28 }
29
30 let dt = update_ctx.delta_time();
31 self.timer += dt;
32
33 if self.timer >= 2.5 {
35 self.timer = 0.0;
36 let x = self.rng.range(-4.0, 4.0);
38 let z = self.rng.range(-2.0, 2.0);
39 self.target_pos = vec3(x, 1.0, z);
40
41 self.linear_pos.set_target(self.target_pos);
43 self.exp_pos.set_target(self.target_pos);
44 self.spring_pos.set_target(self.target_pos);
45
46 update_ctx.play_synth(Synth::click());
48 }
49
50 self.linear_pos.update(dt);
52 self.exp_pos.update(dt);
53 self.spring_pos.update(dt);
54 }
55
56 fn draw(&mut self, draw_ctx: &mut DrawContext) {
57 draw_ctx.clear(Color::new(0.07, 0.07, 0.09));
58
59 draw_ctx.draw_shape(
61 Shape::plane(),
62 Transform::new_position(vec3(0.0, 0.0, 0.0)).scale(vec3(12.0, 1.0, 8.0)),
63 Color::new(0.12, 0.12, 0.14),
64 );
65
66 draw_ctx.draw_shape(
68 Shape::sphere().radius(0.15),
69 Transform::new_position(self.target_pos),
70 Color::new(0.9, 0.1, 0.1),
71 );
72
73 let linear_val = self.linear_pos.current();
78 draw_ctx.draw_shape(
79 Shape::sphere().radius(0.4),
80 Transform::new_position(vec3(linear_val.x, linear_val.y + 0.5, linear_val.z)),
81 Color::new(0.8, 0.2, 0.8),
82 );
83 if let Some(screen_pos) = draw_ctx.camera().world_to_screen(
85 vec3(linear_val.x, linear_val.y + 1.2, linear_val.z),
86 draw_ctx.render_size(),
87 ) {
88 let label = Text::new("Linear").scale(1.0);
89 let size = draw_ctx.measure_text(&label);
90 draw_ctx.draw_text(
91 label,
92 RectTransform::new_position(screen_pos - vec2(size.x * 0.5, 0.0)),
93 Color::new(0.8, 0.2, 0.8),
94 );
95 }
96
97 let exp_val = self.exp_pos.current();
99 draw_ctx.draw_shape(
100 Shape::sphere().radius(0.4),
101 Transform::new_position(vec3(exp_val.x, exp_val.y, exp_val.z)),
102 Color::new(0.9, 0.7, 0.1),
103 );
104 if let Some(screen_pos) = draw_ctx.camera().world_to_screen(
105 vec3(exp_val.x, exp_val.y + 0.7, exp_val.z),
106 draw_ctx.render_size(),
107 ) {
108 let label = Text::new("Exp").scale(1.0);
109 let size = draw_ctx.measure_text(&label);
110 draw_ctx.draw_text(
111 label,
112 RectTransform::new_position(screen_pos - vec2(size.x * 0.5, 0.0)),
113 Color::new(0.9, 0.7, 0.1),
114 );
115 }
116
117 let spring_val = self.spring_pos.current();
119 draw_ctx.draw_shape(
120 Shape::sphere().radius(0.4),
121 Transform::new_position(vec3(spring_val.x, spring_val.y - 0.5, spring_val.z)),
122 Color::new(0.1, 0.7, 0.8),
123 );
124 if let Some(screen_pos) = draw_ctx.camera().world_to_screen(
125 vec3(spring_val.x, spring_val.y + 0.2, spring_val.z),
126 draw_ctx.render_size(),
127 ) {
128 let label = Text::new("Spring").scale(1.0);
129 let size = draw_ctx.measure_text(&label);
130 draw_ctx.draw_text(
131 label,
132 RectTransform::new_position(screen_pos - vec2(size.x * 0.5, 0.0)),
133 Color::new(0.1, 0.7, 0.8),
134 );
135 }
136
137 draw_ctx.draw_text(
139 Text::new("Interpolation Comparison Demo").scale(1.0),
140 RectTransform::new_position(vec2(15.0, 15.0)),
141 Color::WHITE,
142 );
143 draw_ctx.draw_text(
144 Text::new("Comparing Linear vs Exponential vs Spring dynamics").scale(1.0),
145 RectTransform::new_position(vec2(15.0, 35.0)),
146 Color::new(0.6, 0.6, 0.7),
147 );
148 }
149}
150
151fn main() {
152 let config = PrimbackConfig {
153 window_title: "Primback - Animation Demo".to_string(),
154 ..Default::default()
155 };
156
157 let start_pos = vec3(-3.0, 1.0, 0.0);
158
159 let linear_pos = Animated::new(start_pos, AnimationMode::linear().speed(3.0));
161 let exp_pos = Animated::new(start_pos, AnimationMode::exp().speed(4.0));
162 let spring_pos = Animated::new(
163 start_pos,
164 AnimationMode::spring().stiffness(40.0).damping(5.0),
165 );
166
167 Primback::run(
168 config,
169 AnimationApp {
170 linear_pos,
171 exp_pos,
172 spring_pos,
173 target_pos: start_pos,
174 timer: 2.0, rng: Random::new_random(),
176 },
177 );
178}