comparison src/th06/anm0.rs @ 639:a8e0219162b6

Implement AnmRunner.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Thu, 04 Jul 2019 15:21:46 +0200
parents a806f28e94fc
children 01849ffd0180
comparison
equal deleted inserted replaced
638:a806f28e94fc 639:a8e0219162b6
1 //! ANM0 animation format support. 1 //! ANM0 animation format support.
2 2
3 use nom::{ 3 use nom::{
4 IResult, 4 IResult,
5 bytes::complete::{tag, take_while_m_n}, 5 bytes::complete::{tag, take_while_m_n},
6 number::complete::{le_u8, le_u16, le_u32, le_f32}, 6 number::complete::{le_u8, le_u16, le_u32, le_i32, le_f32},
7 }; 7 };
8 use std::collections::HashMap; 8 use std::collections::HashMap;
9 9
10 /// Coordinates of a sprite into the image. 10 /// Coordinates of a sprite into the image.
11 #[derive(Debug, Clone)] 11 #[derive(Debug, Clone)]
12 pub struct Sprite { 12 pub struct Sprite {
13 index: u32, 13 /// Index inside the anm0.
14 x: f32, 14 pub index: u32,
15 y: f32, 15
16 width: f32, 16 /// X coordinate in the sprite sheet.
17 height: f32, 17 pub x: f32,
18
19 /// Y coordinate in the sprite sheet.
20 pub y: f32,
21
22 /// Width of the sprite.
23 pub width: f32,
24
25 /// Height of the sprite.
26 pub height: f32,
18 } 27 }
19 28
20 /// A single instruction, part of a `Script`. 29 /// A single instruction, part of a `Script`.
21 #[derive(Debug, Clone)] 30 #[derive(Debug, Clone)]
22 struct Instruction { 31 pub struct Call {
23 time: u16, 32 /// Time at which this instruction will be called.
24 opcode: u8, 33 pub time: u16,
25 args: Vec<Arg>, 34
35 /// The instruction to call.
36 pub instr: Instruction,
26 } 37 }
27 38
28 /// Script driving an animation. 39 /// Script driving an animation.
29 #[derive(Debug, Clone)] 40 #[derive(Debug, Clone)]
30 pub struct Script { 41 pub struct Script {
31 instructions: Vec<Instruction>, 42 /// List of instructions in this script.
32 interrupts: HashMap<u32, u8> 43 pub instructions: Vec<Call>,
44
45 /// List of interrupts in this script.
46 pub interrupts: HashMap<i32, u8>
33 } 47 }
34 48
35 /// Main struct of the ANM0 animation format. 49 /// Main struct of the ANM0 animation format.
36 #[derive(Debug, Clone)] 50 #[derive(Debug, Clone)]
37 pub struct Anm0 { 51 pub struct Anm0 {
87 width, 101 width,
88 height, 102 height,
89 })) 103 }))
90 } 104 }
91 105
92 #[derive(Debug, Clone, Copy)]
93 enum Arg {
94 U8(u8),
95 U32(u32),
96 F32(f32),
97 Ptr(u8),
98 }
99
100 fn parse_u8_arg(i: &[u8]) -> IResult<&[u8], Arg> {
101 let (i, value) = le_u8(i)?;
102 Ok((i, Arg::U8(value)))
103 }
104
105 fn parse_u32_arg(i: &[u8]) -> IResult<&[u8], Arg> {
106 let (i, value) = le_u32(i)?;
107 Ok((i, Arg::U32(value)))
108 }
109
110 fn parse_f32_arg(i: &[u8]) -> IResult<&[u8], Arg> {
111 let (i, value) = le_f32(i)?;
112 Ok((i, Arg::F32(value)))
113 }
114
115 macro_rules! declare_anm_instructions { 106 macro_rules! declare_anm_instructions {
116 ($($opcode:tt => fn $name:ident($($arg:ident: $arg_type:ty),*)),*,) => { 107 ($($opcode:tt => fn $name:ident($($arg:ident: $arg_type:ident),*)),*,) => {
117 fn parse_instruction_args(input: &[u8], opcode: u8) -> IResult<&[u8], Vec<Arg>> { 108 /// Available instructions in an `Anm0`.
118 let mut args = vec![]; 109 #[allow(missing_docs)]
110 #[derive(Debug, Clone, Copy)]
111 pub enum Instruction {
112 $(
113 $name($($arg_type),*)
114 ),*
115 }
116
117 fn parse_instruction_args(input: &[u8], opcode: u8) -> IResult<&[u8], Instruction> {
119 let mut i = &input[..]; 118 let mut i = &input[..];
120 match opcode { 119 let instr = match opcode {
121 $( 120 $(
122 $opcode => { 121 $opcode => {
123 $( 122 $(
124 let (i2, data) = match stringify!($arg_type) { 123 let (i2, $arg) = concat_idents!(le_, $arg_type)(i)?;
125 "u8" => parse_u8_arg(i),
126 "u32" => parse_u32_arg(i),
127 "f32" => parse_f32_arg(i),
128 "x8" => parse_u8_arg(i),
129 _ => unreachable!(),
130 }?;
131 i = i2; 124 i = i2;
132 if stringify!($arg_type) != "x8" {
133 args.push(data);
134 }
135 )* 125 )*
126 Instruction::$name($($arg),*)
136 } 127 }
137 )* 128 )*
138 _ => unreachable!() 129 _ => unreachable!()
139 } 130 };
140 Ok((i, args)) 131 Ok((i, instr))
141 } 132 }
142 }; 133 };
143 } 134 }
144 135
145 declare_anm_instructions!{ 136 declare_anm_instructions!{
146 0 => fn delete(), 137 0 => fn Delete(),
147 1 => fn set_sprite(sprite_number: u32), 138 1 => fn LoadSprite(sprite_number: u32),
148 2 => fn set_scale(sx: f32, sy: f32), 139 2 => fn SetScale(sx: f32, sy: f32),
149 3 => fn set_alpha(alpha: u32), 140 3 => fn SetAlpha(alpha: u32),
150 4 => fn set_color(red: u8, green: u8, blue: u8, XXX: x8), 141 4 => fn SetColor(red: u8, green: u8, blue: u8/*, XXX: x8*/),
151 5 => fn jump(instruction: u32), 142 5 => fn Jump(instruction: u32),
152 7 => fn toggle_mirrored(), 143 7 => fn ToggleMirrored(),
153 9 => fn set_3d_rotations(x: f32, y: f32, z: f32), 144 9 => fn SetRotations3d(x: f32, y: f32, z: f32),
154 10 => fn set_3d_rotations_speed(x: f32, y: f32, z: f32), 145 10 => fn SetRotationsSpeed3d(x: f32, y: f32, z: f32),
155 11 => fn set_scale_speed(sx: f32, sy: f32), 146 11 => fn SetScaleSpeed(sx: f32, sy: f32),
156 12 => fn fade(alpha: u32, duration: u32), 147 12 => fn Fade(alpha: u32, duration: u32),
157 13 => fn set_blendmode_add(), 148 13 => fn SetBlendmodeAdd(),
158 14 => fn set_blendmode_alphablend(), 149 14 => fn SetBlendmodeAlphablend(),
159 15 => fn keep_still(), 150 15 => fn KeepStill(),
160 16 => fn set_random_sprite(min_index: u32, amplitude: u32), 151 16 => fn LoadRandomSprite(min_index: u32, amplitude: u32),
161 17 => fn set_3d_translation(x: f32, y: f32, z: f32), 152 17 => fn Move(x: f32, y: f32, z: f32),
162 18 => fn move_to_linear(x: f32, y: f32, z: f32, duration: u32), 153 18 => fn MoveToLinear(x: f32, y: f32, z: f32, duration: u32),
163 19 => fn move_to_decel(x: f32, y: f32, z: f32, duration: u32), 154 19 => fn MoveToDecel(x: f32, y: f32, z: f32, duration: u32),
164 20 => fn move_to_accel(x: f32, y: f32, z: f32, duration: u32), 155 20 => fn MoveToAccel(x: f32, y: f32, z: f32, duration: u32),
165 21 => fn wait(), 156 21 => fn Wait(),
166 22 => fn interrupt_label(label: u32), 157 22 => fn InterruptLabel(label: i32),
167 23 => fn set_corner_relative_placement(), 158 23 => fn SetCornerRelativePlacement(),
168 24 => fn wait_ex(), 159 24 => fn WaitEx(),
169 25 => fn set_allow_offset(allow: u32), // TODO: better name 160 25 => fn SetAllowOffset(allow: u32), // TODO: better name
170 26 => fn set_automatic_orientation(automatic: u32), 161 26 => fn SetAutomaticOrientation(automatic: u32),
171 27 => fn shift_texture_x(dx: f32), 162 27 => fn ShiftTextureX(dx: f32),
172 28 => fn shift_texture_y(dy: f32), 163 28 => fn ShiftTextureY(dy: f32),
173 29 => fn set_visible(visible: u32), 164 29 => fn SetVisible(visible: u32),
174 30 => fn scale_in(sx: f32, sy: f32, duration: u32), 165 30 => fn ScaleIn(sx: f32, sy: f32, duration: u32),
175 31 => fn TODO(TODO: u32), 166 31 => fn Todo(todo: u32),
176 } 167 }
177 168
178 fn parse_anm0(input: &[u8]) -> IResult<&[u8], Vec<Anm0>> { 169 fn parse_anm0(input: &[u8]) -> IResult<&[u8], Vec<Anm0>> {
179 let mut list = vec![]; 170 let mut list = vec![];
180 let start_offset = 0; 171 let start_offset = 0;
241 instruction_offsets.push(tell - (start_offset + offset)); 232 instruction_offsets.push(tell - (start_offset + offset));
242 let (i2, time) = le_u16(i)?; 233 let (i2, time) = le_u16(i)?;
243 let (i2, opcode) = le_u8(i2)?; 234 let (i2, opcode) = le_u8(i2)?;
244 // TODO: maybe check against the size of parsed data? 235 // TODO: maybe check against the size of parsed data?
245 let (i2, _size) = le_u8(i2)?; 236 let (i2, _size) = le_u8(i2)?;
246 let (i2, args) = parse_instruction_args(i2, opcode)?; 237 let (i2, instr) = parse_instruction_args(i2, opcode)?;
247 instructions.push(Instruction { time, opcode, args }); 238 instructions.push(Call { time, instr });
248 i = i2; 239 i = i2;
249 if opcode == 0 { 240 if opcode == 0 {
250 break; 241 break;
251 } 242 }
252 } 243 }
253 let mut interrupts = HashMap::new(); 244 let mut interrupts = HashMap::new();
254 let mut j = 0; 245 let mut j = 0;
255 for Instruction { time: _, opcode, args } in &mut instructions { 246 for Call { time: _, instr } in &mut instructions {
256 match opcode { 247 match instr {
257 5 => { 248 Instruction::Jump(ref mut offset) => {
258 let offset = match args[0] { 249 let result = instruction_offsets.binary_search(&(*offset as usize));
259 Arg::U32(offset) => offset as usize, 250 match result {
260 _ => panic!("Wrong argument type for jump!"), 251 Ok(ptr) => *offset = ptr as u32,
261 };
262 let result = instruction_offsets.binary_search(&offset);
263 let ptr = match result {
264 Ok(ptr) => ptr as u8,
265 // TODO: make that a recoverable error instead. 252 // TODO: make that a recoverable error instead.
266 Err(ptr) => panic!("Instruction offset not found for pointer: {}", ptr), 253 Err(ptr) => panic!("Instruction offset not found for pointer: {}", ptr),
267 }; 254 }
268 args[0] = Arg::Ptr(ptr);
269 } 255 }
270 22 => { 256 Instruction::InterruptLabel(interrupt) => {
271 // TODO: maybe also remove this instruction, as the label is already 257 interrupts.insert(*interrupt, j + 1);
272 // present.
273 if let Arg::U32(interrupt) = args[0] {
274 interrupts.insert(interrupt, j + 1);
275 } else {
276 panic!("Wrong argument type for interrupt!");
277 }
278 } 258 }
279 _ => () 259 _ => ()
280 } 260 }
281 j += 1; 261 j += 1;
282 } 262 }