comparison interpreters/src/th06/anm0.rs @ 757:21b186be2590

Split the Rust version into multiple crates.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 05 Jan 2021 02:16:32 +0100
parents src/th06/anm0_vm.rs@3687205fe620
children
comparison
equal deleted inserted replaced
756:4d91790cf8ab 757:21b186be2590
1 //! Animation runner.
2
3 use touhou_formats::th06::anm0::{
4 Script,
5 Anm0,
6 Call,
7 Instruction,
8 };
9 use crate::th06::interpolator::{Interpolator1, Interpolator2, Interpolator3, Formula};
10 use touhou_utils::math::Mat4;
11 use touhou_utils::prng::Prng;
12 use std::cell::RefCell;
13 use std::rc::{Rc, Weak};
14
15 /// TODO
16 #[repr(C)]
17 #[derive(Debug)]
18 pub struct Vertex {
19 /// XXX
20 pub pos: [i16; 3],
21 /// XXX
22 pub layer: u16,
23 /// XXX
24 pub uv: [f32; 2],
25 /// XXX
26 pub color: [u8; 4],
27 }
28
29 /// Base visual element.
30 #[derive(Debug, Clone, Default)]
31 pub struct Sprite {
32 blendfunc: u32,
33 frame: u32,
34
35 width_override: f32,
36 height_override: f32,
37 angle: f32,
38
39 removed: bool,
40 changed: bool,
41 visible: bool,
42 force_rotation: bool,
43 automatic_orientation: bool,
44 allow_dest_offset: bool,
45 mirrored: bool,
46 corner_relative_placement: bool,
47
48 scale_interpolator: Option<Interpolator2<f32>>,
49 fade_interpolator: Option<Interpolator1<f32>>, // XXX: should be u8!
50 offset_interpolator: Option<Interpolator3<f32>>,
51 rotation_interpolator: Option<Interpolator3<f32>>,
52 color_interpolator: Option<Interpolator3<f32>>, // XXX: should be u8!
53
54 anm: Option<Anm0>,
55
56 dest_offset: [f32; 3],
57 texcoords: [f32; 4],
58 texoffsets: [f32; 2],
59 rescale: [f32; 2],
60 scale_speed: [f32; 2],
61 rotations_3d: [f32; 3],
62 rotations_speed_3d: [f32; 3],
63 color: [u8; 4],
64 layer: u16,
65 }
66
67 impl Sprite {
68 /// Create a new sprite.
69 pub fn new() -> Sprite {
70 Sprite {
71 changed: true,
72 visible: true,
73 rescale: [1., 1.],
74 color: [255, 255, 255, 255],
75 ..Default::default()
76 }
77 }
78
79 /// Create a new sprite overriding its size.
80 pub fn with_size(width_override: f32, height_override: f32) -> Sprite {
81 Sprite {
82 width_override,
83 height_override,
84 changed: true,
85 visible: true,
86 rescale: [1., 1.],
87 color: [255, 255, 255, 255],
88 ..Default::default()
89 }
90 }
91
92 /// TODO
93 pub fn fill_vertices(&self, vertices: &mut [Vertex; 4], x: f32, y: f32, z: f32) {
94 let mut mat = Mat4::new([[-0.5, 0.5, 0.5, -0.5],
95 [-0.5, -0.5, 0.5, 0.5],
96 [0., 0., 0., 0.],
97 [1., 1., 1., 1.]]);
98
99 let [tx, ty, tw, th] = self.texcoords;
100 let [sx, sy] = self.rescale;
101 let width = if self.width_override > 0. { self.width_override } else { tw * sx };
102 let height = if self.height_override > 0. { self.height_override } else { th * sy };
103
104 mat.scale2d(width, height);
105 if self.mirrored {
106 mat.flip();
107 }
108
109 let [rx, ry, mut rz] = self.rotations_3d;
110 if self.automatic_orientation {
111 rz += std::f32::consts::PI / 2. - self.angle;
112 } else if self.force_rotation {
113 rz += self.angle;
114 }
115
116 if rx != 0. {
117 mat.rotate_x(-rx);
118 }
119 if ry != 0. {
120 mat.rotate_y(ry);
121 }
122 if rz != 0. {
123 mat.rotate_z(-rz);
124 }
125
126 if self.allow_dest_offset {
127 mat.translate(self.dest_offset);
128 }
129 if self.corner_relative_placement {
130 mat.translate_2d(width / 2., height / 2.);
131 }
132
133 mat.translate([x, y, z]);
134
135 let mat = mat.borrow_inner();
136 vertices[0].pos[0] = mat[0][0] as i16;
137 vertices[0].pos[1] = mat[1][0] as i16;
138 vertices[0].pos[2] = mat[2][0] as i16;
139 vertices[1].pos[0] = mat[0][1] as i16;
140 vertices[1].pos[1] = mat[1][1] as i16;
141 vertices[1].pos[2] = mat[2][1] as i16;
142 vertices[2].pos[0] = mat[0][2] as i16;
143 vertices[2].pos[1] = mat[1][2] as i16;
144 vertices[2].pos[2] = mat[2][2] as i16;
145 vertices[3].pos[0] = mat[0][3] as i16;
146 vertices[3].pos[1] = mat[1][3] as i16;
147 vertices[3].pos[2] = mat[2][3] as i16;
148
149 // XXX: don’t clone here.
150 let (x_1, y_1) = self.anm.clone().unwrap().inv_size();
151 let [tox, toy] = self.texoffsets;
152 let left = tx * x_1 + tox;
153 let right = (tx + tw) * x_1 + tox;
154 let bottom = ty * y_1 + toy;
155 let top = (ty + th) * y_1 + toy;
156
157 vertices[0].uv[0] = left;
158 vertices[0].uv[1] = bottom;
159 vertices[1].uv[0] = right;
160 vertices[1].uv[1] = bottom;
161 vertices[2].uv[0] = right;
162 vertices[2].uv[1] = top;
163 vertices[3].uv[0] = left;
164 vertices[3].uv[1] = top;
165
166 vertices[0].color = self.color;
167 vertices[1].color = self.color;
168 vertices[2].color = self.color;
169 vertices[3].color = self.color;
170
171 vertices[0].layer = self.layer;
172 vertices[1].layer = self.layer;
173 vertices[2].layer = self.layer;
174 vertices[3].layer = self.layer;
175 }
176
177 /// Update sprite values from the interpolators.
178 pub fn update(&mut self) {
179 self.frame += 1;
180 self.corner_relative_placement = true;
181
182 let [sax, say, saz] = self.rotations_speed_3d;
183 if sax != 0. || say != 0. || saz != 0. {
184 let [ax, ay, az] = self.rotations_3d;
185 self.rotations_3d = [ax + sax, ay + say, az + saz];
186 self.changed = true;
187 } else if let Some(ref interpolator) = self.rotation_interpolator {
188 self.rotations_3d = interpolator.values(self.frame);
189 self.changed = true;
190 }
191
192 let [rsx, rsy] = self.scale_speed;
193 if rsx != 0. || rsy != 0. {
194 let [rx, ry] = self.rescale;
195 self.rescale = [rx + rsx, ry + rsy];
196 self.changed = true;
197 }
198
199 if let Some(ref interpolator) = self.fade_interpolator {
200 self.color[3] = interpolator.values(self.frame)[0] as u8;
201 self.changed = true;
202 }
203
204 if let Some(ref interpolator) = self.scale_interpolator {
205 self.rescale = interpolator.values(self.frame);
206 self.changed = true;
207 }
208
209 if let Some(ref interpolator) = self.offset_interpolator {
210 self.dest_offset = interpolator.values(self.frame);
211 self.changed = true;
212 }
213
214 if let Some(ref interpolator) = self.color_interpolator {
215 let color = interpolator.values(self.frame);
216 // TODO: this can probably be made to look nicer.
217 self.color[0] = color[0] as u8;
218 self.color[1] = color[1] as u8;
219 self.color[2] = color[2] as u8;
220 self.changed = true;
221 }
222 }
223 }
224
225 struct Anms {
226 inner: Rc<RefCell<[Anm0]>>,
227 }
228
229 impl Anms {
230 fn new(anms: Rc<RefCell<[Anm0]>>) -> Anms {
231 Anms {
232 inner: anms,
233 }
234 }
235
236 fn load_sprite(&self, sprite: &mut Sprite, id: u8) {
237 let anms = self.inner.borrow();
238 let mut anm = None;
239 let mut texcoords = None;
240 let mut layer = 0;
241 'anm: for anm0 in anms.iter() {
242 for sp in anm0.sprites.iter() {
243 if sp.index == id as u32 {
244 texcoords = Some(sp);
245 anm = Some(anm0.clone());
246 break 'anm;
247 }
248 }
249 layer += 1;
250 }
251 sprite.anm = anm;
252 sprite.layer = layer;
253 if let Some(texcoords) = texcoords {
254 sprite.texcoords = [texcoords.x, texcoords.y, texcoords.width, texcoords.height];
255 }
256 }
257
258 fn get_script(&self, id: u8) -> Script {
259 let anms = self.inner.borrow();
260 for anm0 in anms.iter() {
261 if anm0.scripts.contains_key(&id) {
262 return anm0.scripts[&id].clone();
263 }
264 }
265 unreachable!();
266 }
267 }
268
269 /// Interpreter for `Anm0` instructions to update a `Sprite`.
270 pub struct AnmRunner {
271 anms: Anms,
272 sprite: Rc<RefCell<Sprite>>,
273 prng: Weak<RefCell<Prng>>,
274 running: bool,
275 sprite_index_offset: u32,
276 script: Script,
277 instruction_pointer: usize,
278 frame: u16,
279 waiting: bool,
280 variables: ([i32; 4], [f32; 4], [i32; 4]),
281 timeout: Option<u32>,
282 }
283
284 impl AnmRunner {
285 /// Create a new `AnmRunner`.
286 pub fn new(anms: Rc<RefCell<[Anm0]>>, script_id: u8, sprite: Rc<RefCell<Sprite>>, prng: Weak<RefCell<Prng>>, sprite_index_offset: u32) -> AnmRunner {
287 let anms = Anms::new(anms);
288 let script = anms.get_script(script_id);
289 let mut runner = AnmRunner {
290 anms,
291 sprite: sprite,
292 prng,
293 running: true,
294 waiting: false,
295
296 script,
297 frame: 0,
298 timeout: None,
299 instruction_pointer: 0,
300 variables: ([0, 0, 0, 0 ],
301 [0., 0., 0., 0.],
302 [0, 0, 0, 0 ]),
303
304 sprite_index_offset: sprite_index_offset,
305 };
306 runner.run_frame();
307 runner.sprite_index_offset = 0;
308 runner
309 }
310
311 /// Get a Rc from the inner Sprite.
312 pub fn get_sprite(&self) -> Rc<RefCell<Sprite>> {
313 self.sprite.clone()
314 }
315
316 /// Trigger an interrupt.
317 pub fn interrupt(&mut self, interrupt: i32) -> bool {
318 let mut new_ip = self.script.interrupts.get(&interrupt);
319 if new_ip.is_none() {
320 new_ip = self.script.interrupts.get(&-1);
321 }
322 let new_ip = if let Some(new_ip) = new_ip {
323 *new_ip as usize
324 } else {
325 return false;
326 };
327 self.instruction_pointer = new_ip;
328 let Call { time: frame, instr: _ } = &self.script.instructions[self.instruction_pointer];
329 self.frame = *frame;
330 self.waiting = false;
331 self.sprite.borrow_mut().visible = true;
332 true
333 }
334
335 /// Advance the Anm of a single frame.
336 pub fn run_frame(&mut self) -> bool {
337 if !self.running {
338 return false;
339 }
340
341 while self.running && !self.waiting {
342 let Call { time: frame, instr } = self.script.instructions[self.instruction_pointer];
343 let frame = frame.clone();
344
345 if frame > self.frame {
346 break;
347 } else {
348 self.instruction_pointer += 1;
349 }
350
351 if frame == self.frame {
352 self.run_instruction(instr);
353 self.sprite.borrow_mut().changed = true;
354 }
355 }
356
357 if !self.waiting {
358 self.frame += 1;
359 } else if let Some(timeout) = self.timeout {
360 if timeout == self.sprite.borrow().frame { // TODO: check if it’s happening at the correct frame.
361 self.waiting = false;
362 }
363 }
364
365 self.sprite.borrow_mut().update();
366
367 self.running
368 }
369
370 fn run_instruction(&mut self, instruction: Instruction) {
371 let mut sprite = self.sprite.borrow_mut();
372 match instruction {
373 Instruction::Delete() => {
374 sprite.removed = true;
375 self.running = false;
376 }
377 Instruction::LoadSprite(sprite_index) => {
378 self.anms.load_sprite(&mut sprite, (sprite_index + self.sprite_index_offset) as u8);
379 }
380 Instruction::SetScale(sx, sy) => {
381 sprite.rescale = [sx, sy];
382 }
383 Instruction::SetAlpha(alpha) => {
384 // TODO: check this modulo.
385 sprite.color[3] = (alpha % 256) as u8;
386 }
387 Instruction::SetColor(b, g, r) => {
388 if sprite.fade_interpolator.is_none() {
389 sprite.color[0] = r;
390 sprite.color[1] = g;
391 sprite.color[2] = b;
392 }
393 }
394 Instruction::Jump(pointer) => {
395 // TODO: is that really how it works?
396 self.instruction_pointer = pointer as usize;
397 self.frame = self.script.instructions[pointer as usize].time;
398 }
399 Instruction::ToggleMirrored() => {
400 sprite.mirrored = !sprite.mirrored;
401 }
402 Instruction::SetRotations3d(rx, ry, rz) => {
403 sprite.rotations_3d = [rx, ry, rz];
404 }
405 Instruction::SetRotationsSpeed3d(srx, sry, srz) => {
406 sprite.rotations_speed_3d = [srx, sry, srz];
407 }
408 Instruction::SetScaleSpeed(ssx, ssy) => {
409 sprite.scale_speed = [ssx, ssy];
410 }
411 Instruction::Fade(new_alpha, duration) => {
412 sprite.fade_interpolator = Some(Interpolator1::new([sprite.color[3] as f32], sprite.frame, [new_alpha as f32], sprite.frame + duration, Formula::Linear));
413 }
414 Instruction::SetBlendmodeAlphablend() => {
415 sprite.blendfunc = 1;
416 }
417 Instruction::SetBlendmodeAdd() => {
418 sprite.blendfunc = 0;
419 }
420 Instruction::KeepStill() => {
421 self.running = false;
422 }
423 Instruction::LoadRandomSprite(min_index, mut amplitude) => {
424 if amplitude > 0 {
425 let prng = self.prng.upgrade().unwrap();
426 let rand = prng.borrow_mut().get_u16();
427 amplitude = (rand as u32) % amplitude;
428 }
429 let sprite_index = min_index + amplitude;
430 self.anms.load_sprite(&mut sprite, (sprite_index + self.sprite_index_offset) as u8);
431 }
432 Instruction::Move(x, y, z) => {
433 sprite.dest_offset = [x, y, z];
434 }
435 Instruction::MoveToLinear(x, y, z, duration) => {
436 sprite.offset_interpolator = Some(Interpolator3::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration, Formula::Linear));
437 }
438 Instruction::MoveToDecel(x, y, z, duration) => {
439 sprite.offset_interpolator = Some(Interpolator3::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration, Formula::InvertPower2));
440 }
441 Instruction::MoveToAccel(x, y, z, duration) => {
442 sprite.offset_interpolator = Some(Interpolator3::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration, Formula::Power2));
443 }
444 Instruction::Wait() => {
445 self.waiting = true;
446 }
447 // There is nothing to do here.
448 Instruction::InterruptLabel(_label) => (),
449 Instruction::SetCornerRelativePlacement() => {
450 sprite.corner_relative_placement = true;
451 }
452 Instruction::WaitEx() => {
453 sprite.visible = false;
454 self.waiting = true;
455 }
456 Instruction::SetAllowOffset(value) => {
457 sprite.allow_dest_offset = value == 1
458 }
459 Instruction::SetAutomaticOrientation(value) => {
460 sprite.automatic_orientation = value == 1
461 }
462 Instruction::ShiftTextureX(dx) => {
463 let [tox, toy] = sprite.texoffsets;
464 sprite.texoffsets = [tox + dx, toy];
465 }
466 Instruction::ShiftTextureY(dy) => {
467 let [tox, toy] = sprite.texoffsets;
468 sprite.texoffsets = [tox, toy + dy];
469 }
470 Instruction::SetVisible(visible) => {
471 sprite.visible = (visible & 1) != 0;
472 }
473 Instruction::ScaleIn(sx, sy, duration) => {
474 sprite.scale_interpolator = Some(Interpolator2::new(sprite.rescale, sprite.frame, [sx, sy], sprite.frame + duration, Formula::Linear));
475 }
476 Instruction::Todo(_todo) => {
477 // TODO.
478 }
479 }
480 }
481 }
482
483 #[cfg(test)]
484 mod tests {
485 use super::*;
486 use std::io::{self, Read};
487 use std::fs::File;
488
489 #[test]
490 fn anm_runner() {
491 let file = File::open("EoSD/CM/player01.anm").unwrap();
492 let mut file = io::BufReader::new(file);
493 let mut buf = vec![];
494 file.read_to_end(&mut buf).unwrap();
495 let (_, mut anms) = Anm0::from_slice(&buf).unwrap();
496 let anm0 = anms.pop().unwrap();
497 assert_eq!(anm0.size, (256, 256));
498 assert_eq!(anm0.format, 5);
499 let sprite = Rc::new(RefCell::new(Sprite::new()));
500 let prng = Rc::new(RefCell::new(Prng::new(0)));
501 let mut anm_runner = AnmRunner::new(&anm0, 1, sprite.clone(), Rc::downgrade(&prng), 0);
502 for _ in 0..50 {
503 anm_runner.run_frame();
504 }
505 }
506 }