Mercurial > touhou
comparison src/th06/anm0_vm.rs @ 641:a58103f2f264
Implement and use interpolators.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Sun, 07 Jul 2019 12:17:42 +0200 |
parents | 37d151fe000b |
children | 9e40bd5cc26d |
comparison
equal
deleted
inserted
replaced
640:37d151fe000b | 641:a58103f2f264 |
---|---|
7 Instruction, | 7 Instruction, |
8 }; | 8 }; |
9 use std::cell::RefCell; | 9 use std::cell::RefCell; |
10 use std::rc::Rc; | 10 use std::rc::Rc; |
11 | 11 |
12 #[derive(Debug, Clone)] | 12 #[derive(Debug, Clone, Copy, PartialEq)] |
13 struct Interpolator; | 13 enum Formula { |
14 Linear, | |
15 Power2, | |
16 InvertPower2, | |
17 } | |
18 | |
19 impl Formula { | |
20 fn apply(&self, x: f32) -> f32 { | |
21 match self { | |
22 Formula::Linear => x, | |
23 Formula::Power2 => x * x, | |
24 Formula::InvertPower2 => 2. * x - x * x, | |
25 } | |
26 } | |
27 } | |
28 | |
29 macro_rules! generate_interpolator { | |
30 ($name:ident, $n:tt) => { | |
31 #[derive(Debug, Clone)] | |
32 struct $name<T> { | |
33 start_values: [T; $n], | |
34 end_values: [T; $n], | |
35 start_frame: u16, | |
36 end_frame: u16, | |
37 formula: Formula, | |
38 } | |
39 | |
40 impl<T> $name<T> | |
41 where f32: From<T>, | |
42 T: From<f32>, | |
43 T: std::ops::Sub<Output = T>, | |
44 T: std::ops::Add<Output = T>, | |
45 T: Copy, | |
46 T: Default, | |
47 { | |
48 pub fn new(start_values: [T; $n], start_frame: u16, end_values: [T; $n], end_frame: u16, formula: Formula) -> $name<T> { | |
49 $name { | |
50 start_values, | |
51 end_values, | |
52 start_frame, | |
53 end_frame, | |
54 formula, | |
55 } | |
56 } | |
57 | |
58 // XXX: Make it return [T; $n] instead, we don’t want to only do f32 here. | |
59 pub fn values(&self, frame: u16) -> [f32; $n] { | |
60 if frame + 1 >= self.end_frame { | |
61 // XXX: skip the last interpolation step. | |
62 // This bug is replicated from the original game. | |
63 //self.start_frame = self.end_frame; | |
64 //self.end_values | |
65 let mut values: [f32; $n] = [Default::default(); $n]; | |
66 for (i, value) in self.end_values.iter().enumerate() { | |
67 values[i] = f32::from(*value); | |
68 } | |
69 values | |
70 } else { | |
71 let mut coeff = (frame - self.start_frame) as f32 / (self.end_frame - self.start_frame) as f32; | |
72 coeff = self.formula.apply(coeff); | |
73 let mut values: [f32; $n] = [Default::default(); $n]; | |
74 for (i, (start, end)) in self.start_values.iter().zip(&self.end_values).enumerate() { | |
75 values[i] = f32::from(*start + T::from(coeff * f32::from(*end - *start))); | |
76 } | |
77 values | |
78 } | |
79 } | |
80 } | |
81 }; | |
82 } | |
83 | |
84 generate_interpolator!(Interpolator1, 1); | |
85 generate_interpolator!(Interpolator2, 2); | |
86 generate_interpolator!(Interpolator3, 3); | |
14 | 87 |
15 /// Base visual element. | 88 /// Base visual element. |
16 #[derive(Debug, Clone, Default)] | 89 #[derive(Debug, Clone, Default)] |
17 pub struct Sprite { | 90 pub struct Sprite { |
18 blendfunc: u32, | 91 blendfunc: u32, |
29 automatic_orientation: bool, | 102 automatic_orientation: bool, |
30 allow_dest_offset: bool, | 103 allow_dest_offset: bool, |
31 mirrored: bool, | 104 mirrored: bool, |
32 corner_relative_placement: bool, | 105 corner_relative_placement: bool, |
33 | 106 |
34 scale_interpolator: Option<Interpolator>, | 107 scale_interpolator: Option<Interpolator2<f32>>, |
35 fade_interpolator: Option<Interpolator>, | 108 fade_interpolator: Option<Interpolator1<f32>>, // XXX: should be u8! |
36 offset_interpolator: Option<Interpolator>, | 109 offset_interpolator: Option<Interpolator3<f32>>, |
37 rotation_interpolator: Option<Interpolator>, | 110 rotation_interpolator: Option<Interpolator3<f32>>, |
38 color_interpolator: Option<Interpolator>, | 111 color_interpolator: Option<Interpolator3<f32>>, // XXX: should be u8! |
39 | 112 |
40 anm: Option<Anm0>, | 113 anm: Option<Anm0>, |
41 | 114 |
42 dest_offset: [f32; 3], | 115 dest_offset: [f32; 3], |
43 texcoords: [f32; 4], | 116 texcoords: [f32; 4], |
71 if sax != 0. || say != 0. || saz != 0. { | 144 if sax != 0. || say != 0. || saz != 0. { |
72 let [ax, ay, az] = self.rotations_3d; | 145 let [ax, ay, az] = self.rotations_3d; |
73 self.rotations_3d = [ax + sax, ay + say, az + saz]; | 146 self.rotations_3d = [ax + sax, ay + say, az + saz]; |
74 self.changed = true; | 147 self.changed = true; |
75 } else if let Some(ref interpolator) = self.rotation_interpolator { | 148 } else if let Some(ref interpolator) = self.rotation_interpolator { |
76 unimplemented!(); | 149 self.rotations_3d = interpolator.values(self.frame); |
77 self.changed = true; | 150 self.changed = true; |
78 } | 151 } |
79 | 152 |
80 let [rsx, rsy] = self.scale_speed; | 153 let [rsx, rsy] = self.scale_speed; |
81 if rsx != 0. || rsy != 0. { | 154 if rsx != 0. || rsy != 0. { |
83 self.rescale = [rx + rsx, ry + rsy]; | 156 self.rescale = [rx + rsx, ry + rsy]; |
84 self.changed = true; | 157 self.changed = true; |
85 } | 158 } |
86 | 159 |
87 if let Some(ref interpolator) = self.fade_interpolator { | 160 if let Some(ref interpolator) = self.fade_interpolator { |
88 unimplemented!(); | 161 self.color[3] = interpolator.values(self.frame)[0] as u8; |
89 self.changed = true; | 162 self.changed = true; |
90 } | 163 } |
91 | 164 |
92 if let Some(ref interpolator) = self.scale_interpolator { | 165 if let Some(ref interpolator) = self.scale_interpolator { |
93 unimplemented!(); | 166 self.rescale = interpolator.values(self.frame); |
94 self.changed = true; | 167 self.changed = true; |
95 } | 168 } |
96 | 169 |
97 if let Some(ref interpolator) = self.offset_interpolator { | 170 if let Some(ref interpolator) = self.offset_interpolator { |
98 unimplemented!(); | 171 self.dest_offset = interpolator.values(self.frame); |
99 self.changed = true; | 172 self.changed = true; |
100 } | 173 } |
101 | 174 |
102 if let Some(ref interpolator) = self.color_interpolator { | 175 if let Some(ref interpolator) = self.color_interpolator { |
103 unimplemented!(); | 176 let color = interpolator.values(self.frame); |
177 // TODO: this can probably be made to look nicer. | |
178 self.color[0] = color[0] as u8; | |
179 self.color[1] = color[1] as u8; | |
180 self.color[2] = color[2] as u8; | |
104 self.changed = true; | 181 self.changed = true; |
105 } | 182 } |
106 } | 183 } |
107 } | 184 } |
108 | 185 |
240 } | 317 } |
241 Instruction::SetScaleSpeed(ssx, ssy) => { | 318 Instruction::SetScaleSpeed(ssx, ssy) => { |
242 sprite.scale_speed = [ssx, ssy]; | 319 sprite.scale_speed = [ssx, ssy]; |
243 } | 320 } |
244 Instruction::Fade(new_alpha, duration) => { | 321 Instruction::Fade(new_alpha, duration) => { |
245 // XXX: implement fade(). | 322 sprite.fade_interpolator = Some(Interpolator1::new([sprite.color[3] as f32], sprite.frame, [new_alpha as f32], sprite.frame + duration as u16, Formula::Linear)); |
246 //sprite.fade(duration, new_alpha) | |
247 } | 323 } |
248 Instruction::SetBlendmodeAlphablend() => { | 324 Instruction::SetBlendmodeAlphablend() => { |
249 sprite.blendfunc = 1; | 325 sprite.blendfunc = 1; |
250 } | 326 } |
251 Instruction::SetBlendmodeAdd() => { | 327 Instruction::SetBlendmodeAdd() => { |
253 } | 329 } |
254 Instruction::KeepStill() => { | 330 Instruction::KeepStill() => { |
255 self.running = false; | 331 self.running = false; |
256 } | 332 } |
257 Instruction::LoadRandomSprite(min_index, amplitude) => { | 333 Instruction::LoadRandomSprite(min_index, amplitude) => { |
258 //self.load_sprite(min_index + randrange(amp)) | 334 let sprite_index = min_index; // XXX: + randrange(amplitude); |
335 | |
336 // TODO: refactor that with Instruction::LoadSprite. | |
337 sprite.anm = Some(self.anm.clone()); | |
338 let texcoords = &self.anm.sprites[(sprite_index + self.sprite_index_offset) as usize]; | |
339 sprite.texcoords = [texcoords.x, texcoords.y, texcoords.width, texcoords.height]; | |
259 } | 340 } |
260 Instruction::Move(x, y, z) => { | 341 Instruction::Move(x, y, z) => { |
261 sprite.dest_offset = [x, y, z]; | 342 sprite.dest_offset = [x, y, z]; |
262 } | 343 } |
263 Instruction::MoveToLinear(x, y, z, duration) => { | 344 Instruction::MoveToLinear(x, y, z, duration) => { |
264 // XXX: implement move_in(). | 345 sprite.offset_interpolator = Some(Interpolator3::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration as u16, Formula::Linear)); |
265 //sprite.move_in(duration, x, y, z); | |
266 } | 346 } |
267 Instruction::MoveToDecel(x, y, z, duration) => { | 347 Instruction::MoveToDecel(x, y, z, duration) => { |
268 // XXX: implement move_in(). | 348 sprite.offset_interpolator = Some(Interpolator3::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration as u16, Formula::InvertPower2)); |
269 //sprite.move_in(duration, x, y, z, 2*x - x**2); | |
270 } | 349 } |
271 Instruction::MoveToAccel(x, y, z, duration) => { | 350 Instruction::MoveToAccel(x, y, z, duration) => { |
272 // XXX: implement move_in(). | 351 sprite.offset_interpolator = Some(Interpolator3::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration as u16, Formula::Power2)); |
273 //sprite.move_in(duration, x, y, z, x**2); | |
274 } | 352 } |
275 Instruction::Wait() => { | 353 Instruction::Wait() => { |
276 self.waiting = true; | 354 self.waiting = true; |
277 } | 355 } |
278 // There is nothing to do here. | 356 // There is nothing to do here. |
279 Instruction::InterruptLabel(label) => (), | 357 Instruction::InterruptLabel(_label) => (), |
280 Instruction::SetCornerRelativePlacement() => { | 358 Instruction::SetCornerRelativePlacement() => { |
281 sprite.corner_relative_placement = true; | 359 sprite.corner_relative_placement = true; |
282 } | 360 } |
283 Instruction::WaitEx() => { | 361 Instruction::WaitEx() => { |
284 sprite.visible = false; | 362 sprite.visible = false; |
300 } | 378 } |
301 Instruction::SetVisible(visible) => { | 379 Instruction::SetVisible(visible) => { |
302 sprite.visible = (visible & 1) != 0; | 380 sprite.visible = (visible & 1) != 0; |
303 } | 381 } |
304 Instruction::ScaleIn(sx, sy, duration) => { | 382 Instruction::ScaleIn(sx, sy, duration) => { |
305 // TODO: implement scale_in(). | 383 sprite.scale_interpolator = Some(Interpolator2::new(sprite.rescale, sprite.frame, [sx, sy], sprite.frame + duration as u16, Formula::Linear)); |
306 //sprite.scale_in(duration, sx, sy) | 384 } |
307 } | 385 Instruction::Todo(_todo) => { |
308 Instruction::Todo(todo) => { | |
309 // TODO. | 386 // TODO. |
310 } | 387 } |
311 } | 388 } |
312 } | 389 } |
313 } | 390 } |