Mercurial > touhou
annotate src/th06/anm0.rs @ 702:718348c7608e
anm0: simplify parsing with more combinators.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Fri, 23 Aug 2019 17:22:38 +0200 |
parents | b6c351ca0a35 |
children | 84af5bedbde4 |
rev | line source |
---|---|
638 | 1 //! ANM0 animation format support. |
2 | |
3 use nom::{ | |
4 IResult, | |
5 bytes::complete::{tag, take_while_m_n}, | |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
6 number::complete::{le_u8, le_u16, le_u32, le_i32, le_f32}, |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
7 sequence::tuple, |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
8 multi::many_m_n, |
638 | 9 }; |
10 use std::collections::HashMap; | |
11 | |
12 /// Coordinates of a sprite into the image. | |
13 #[derive(Debug, Clone)] | |
14 pub struct Sprite { | |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
15 /// Index inside the anm0. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
16 pub index: u32, |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
17 |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
18 /// X coordinate in the sprite sheet. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
19 pub x: f32, |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
20 |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
21 /// Y coordinate in the sprite sheet. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
22 pub y: f32, |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
23 |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
24 /// Width of the sprite. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
25 pub width: f32, |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
26 |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
27 /// Height of the sprite. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
28 pub height: f32, |
638 | 29 } |
30 | |
31 /// A single instruction, part of a `Script`. | |
32 #[derive(Debug, Clone)] | |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
33 pub struct Call { |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
34 /// Time at which this instruction will be called. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
35 pub time: u16, |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
36 |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
37 /// The instruction to call. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
38 pub instr: Instruction, |
638 | 39 } |
40 | |
41 /// Script driving an animation. | |
42 #[derive(Debug, Clone)] | |
43 pub struct Script { | |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
44 /// List of instructions in this script. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
45 pub instructions: Vec<Call>, |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
46 |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
47 /// List of interrupts in this script. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
48 pub interrupts: HashMap<i32, u8> |
638 | 49 } |
50 | |
51 /// Main struct of the ANM0 animation format. | |
52 #[derive(Debug, Clone)] | |
53 pub struct Anm0 { | |
54 /// Resolution of the image used by this ANM. | |
55 pub size: (u32, u32), | |
56 | |
57 /// Format of this ANM. | |
58 pub format: u32, | |
59 | |
60 /// File name of the main image. | |
61 pub first_name: String, | |
62 | |
63 /// File name of an alpha channel image. | |
64 pub second_name: String, | |
65 | |
66 /// A list of sprites, coordinates into the attached image. | |
67 pub sprites: Vec<Sprite>, | |
68 | |
69 /// A map of scripts. | |
70 pub scripts: HashMap<u8, Script>, | |
71 } | |
72 | |
73 impl Anm0 { | |
74 /// Parse a slice of bytes into an `Anm0` struct. | |
701
b6c351ca0a35
anm0: return the nom IResult and the list of Anm0s.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
694
diff
changeset
|
75 pub fn from_slice(data: &[u8]) -> IResult<&[u8], Vec<Anm0>> { |
b6c351ca0a35
anm0: return the nom IResult and the list of Anm0s.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
694
diff
changeset
|
76 parse_anm0(data) |
638 | 77 } |
643
01849ffd0180
Add an anmrenderer binary.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
639
diff
changeset
|
78 |
01849ffd0180
Add an anmrenderer binary.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
639
diff
changeset
|
79 /// TODO |
01849ffd0180
Add an anmrenderer binary.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
639
diff
changeset
|
80 pub fn inv_size(&self) -> (f32, f32) { |
01849ffd0180
Add an anmrenderer binary.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
639
diff
changeset
|
81 let (x, y) = self.size; |
01849ffd0180
Add an anmrenderer binary.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
639
diff
changeset
|
82 (1. / x as f32, 1. / y as f32) |
01849ffd0180
Add an anmrenderer binary.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
639
diff
changeset
|
83 } |
638 | 84 } |
85 | |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
86 fn parse_name(i: &[u8]) -> IResult<&[u8], String> { |
638 | 87 let (_, slice) = take_while_m_n(0, 32, |c| c != 0)(i)?; |
694
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
88 let string = match String::from_utf8(slice.to_vec()) { |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
89 Ok(string) => string, |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
90 // XXX: use a more specific error instead. |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
91 Err(_) => return Err(nom::Err::Failure((i, nom::error::ErrorKind::Eof))) |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
92 }; |
638 | 93 Ok((i, string)) |
94 } | |
95 | |
96 fn parse_sprite(i: &[u8]) -> IResult<&[u8], Sprite> { | |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
97 let (i, (index, x, y, width, height)) = tuple((le_u32, le_f32, le_f32, le_f32, le_f32))(i)?; |
638 | 98 Ok((i, Sprite { |
99 index, | |
100 x, | |
101 y, | |
102 width, | |
103 height, | |
104 })) | |
105 } | |
106 | |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
107 macro_rules! declare_anm_instructions { |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
108 ($($opcode:tt => fn $name:ident($($arg:ident: $arg_type:ident),*)),*,) => { |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
109 /// Available instructions in an `Anm0`. |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
110 #[allow(missing_docs)] |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
111 #[derive(Debug, Clone, Copy)] |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
112 pub enum Instruction { |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
113 $( |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
114 $name($($arg_type),*) |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
115 ),* |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
116 } |
638 | 117 |
694
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
118 fn parse_instruction_args(mut i: &[u8], opcode: u8) -> IResult<&[u8], Instruction> { |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
119 let instr = match opcode { |
638 | 120 $( |
121 $opcode => { | |
122 $( | |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
123 let (i2, $arg) = concat_idents!(le_, $arg_type)(i)?; |
638 | 124 i = i2; |
125 )* | |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
126 Instruction::$name($($arg),*) |
638 | 127 } |
128 )* | |
694
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
129 // XXX: use a more specific error instead. |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
130 _ => return Err(nom::Err::Failure((i, nom::error::ErrorKind::Eof))) |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
131 }; |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
132 Ok((i, instr)) |
638 | 133 } |
134 }; | |
135 } | |
136 | |
137 declare_anm_instructions!{ | |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
138 0 => fn Delete(), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
139 1 => fn LoadSprite(sprite_number: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
140 2 => fn SetScale(sx: f32, sy: f32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
141 3 => fn SetAlpha(alpha: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
142 4 => fn SetColor(red: u8, green: u8, blue: u8/*, XXX: x8*/), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
143 5 => fn Jump(instruction: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
144 7 => fn ToggleMirrored(), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
145 9 => fn SetRotations3d(x: f32, y: f32, z: f32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
146 10 => fn SetRotationsSpeed3d(x: f32, y: f32, z: f32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
147 11 => fn SetScaleSpeed(sx: f32, sy: f32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
148 12 => fn Fade(alpha: u32, duration: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
149 13 => fn SetBlendmodeAdd(), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
150 14 => fn SetBlendmodeAlphablend(), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
151 15 => fn KeepStill(), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
152 16 => fn LoadRandomSprite(min_index: u32, amplitude: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
153 17 => fn Move(x: f32, y: f32, z: f32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
154 18 => fn MoveToLinear(x: f32, y: f32, z: f32, duration: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
155 19 => fn MoveToDecel(x: f32, y: f32, z: f32, duration: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
156 20 => fn MoveToAccel(x: f32, y: f32, z: f32, duration: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
157 21 => fn Wait(), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
158 22 => fn InterruptLabel(label: i32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
159 23 => fn SetCornerRelativePlacement(), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
160 24 => fn WaitEx(), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
161 25 => fn SetAllowOffset(allow: u32), // TODO: better name |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
162 26 => fn SetAutomaticOrientation(automatic: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
163 27 => fn ShiftTextureX(dx: f32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
164 28 => fn ShiftTextureY(dy: f32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
165 29 => fn SetVisible(visible: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
166 30 => fn ScaleIn(sx: f32, sy: f32, duration: u32), |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
167 31 => fn Todo(todo: u32), |
638 | 168 } |
169 | |
170 fn parse_anm0(input: &[u8]) -> IResult<&[u8], Vec<Anm0>> { | |
171 let mut list = vec![]; | |
172 let start_offset = 0; | |
173 loop { | |
174 let i = &input[start_offset..]; | |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
175 let (mut i, (num_sprites, num_scripts, _, width, height, format, _unknown1, |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
176 first_name_offset, _unused, second_name_offset, version, _unknown2, |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
177 _texture_offset, has_data, _next_offset, unknown3)) = |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
178 tuple((le_u32, le_u32, tag(b"\0\0\0\0"), le_u32, le_u32, le_u32, le_u32, le_u32, |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
179 le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32))(i)?; |
638 | 180 |
181 assert_eq!(version, 0); | |
182 assert_eq!(unknown3, 0); | |
183 assert_eq!(has_data, 0); | |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
184 let num_sprites = num_sprites as usize; |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
185 let num_scripts = num_scripts as usize; |
638 | 186 |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
187 let (i, sprite_offsets) = many_m_n(num_sprites, num_sprites, le_u32)(i)?; |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
188 let (_, script_offsets) = many_m_n(num_scripts, num_scripts, tuple((le_u32, le_u32)))(i)?; |
638 | 189 |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
190 let first_name = if first_name_offset > 0 { |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
191 if input.len() < start_offset + first_name_offset as usize { |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
192 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
193 } |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
194 let i = &input[start_offset + first_name_offset as usize..]; |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
195 let (_, name) = parse_name(i)?; |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
196 name |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
197 } else { |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
198 String::new() |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
199 }; |
638 | 200 |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
201 let second_name = if second_name_offset > 0 { |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
202 if input.len() < start_offset + second_name_offset as usize { |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
203 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
204 } |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
205 let i = &input[start_offset + second_name_offset as usize..]; |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
206 let (_, name) = parse_name(i)?; |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
207 name |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
208 } else { |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
209 String::new() |
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
210 }; |
638 | 211 |
212 let mut sprites = vec![]; | |
213 let mut i; | |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
214 for offset in sprite_offsets.into_iter().map(|x| x as usize) { |
694
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
215 if input.len() < start_offset + offset { |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
216 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
217 } |
638 | 218 i = &input[start_offset + offset..]; |
219 let (_, sprite) = parse_sprite(i)?; | |
220 sprites.push(sprite); | |
221 } | |
222 | |
223 let mut scripts = HashMap::new(); | |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
224 for (index, offset) in script_offsets.into_iter().map(|(index, offset)| (index as u8, offset as usize)) { |
694
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
225 if input.len() < start_offset + offset { |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
226 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
227 } |
638 | 228 i = &input[start_offset + offset..]; |
229 let mut instruction_offsets = vec![]; | |
230 | |
231 let mut instructions = vec![]; | |
232 loop { | |
233 let tell = input.len() - i.len(); | |
234 instruction_offsets.push(tell - (start_offset + offset)); | |
235 // TODO: maybe check against the size of parsed data? | |
702
718348c7608e
anm0: simplify parsing with more combinators.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
701
diff
changeset
|
236 let (i2, (time, opcode, _size)) = tuple((le_u16, le_u8, le_u8))(i)?; |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
237 let (i2, instr) = parse_instruction_args(i2, opcode)?; |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
238 instructions.push(Call { time, instr }); |
638 | 239 i = i2; |
240 if opcode == 0 { | |
241 break; | |
242 } | |
243 } | |
244 let mut interrupts = HashMap::new(); | |
245 let mut j = 0; | |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
246 for Call { time: _, instr } in &mut instructions { |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
247 match instr { |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
248 Instruction::Jump(ref mut offset) => { |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
249 let result = instruction_offsets.binary_search(&(*offset as usize)); |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
250 match result { |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
251 Ok(ptr) => *offset = ptr as u32, |
694
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
252 Err(ptr) => { |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
253 // XXX: use a more specific error instead. |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
254 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
255 //println!("Instruction offset not found for pointer: {}", ptr); |
3ff1af76e413
anm0: only use recoverable errors, no panics except for anm0 asserts.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
645
diff
changeset
|
256 } |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
257 } |
638 | 258 } |
639
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
259 Instruction::InterruptLabel(interrupt) => { |
a8e0219162b6
Implement AnmRunner.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
638
diff
changeset
|
260 interrupts.insert(*interrupt, j + 1); |
638 | 261 } |
262 _ => () | |
263 } | |
264 j += 1; | |
265 } | |
266 scripts.insert(index, Script { | |
267 instructions, | |
268 interrupts, | |
269 }); | |
270 } | |
271 | |
272 let anm0 = Anm0 { | |
273 size: (width, height), | |
274 format, | |
275 first_name, | |
276 second_name, | |
277 sprites, | |
278 scripts, | |
279 }; | |
280 list.push(anm0); | |
281 break; | |
282 } | |
283 Ok((b"", list)) | |
284 } | |
285 | |
286 #[cfg(test)] | |
287 mod tests { | |
288 use super::*; | |
289 use std::io::{self, Read}; | |
290 use std::fs::File; | |
291 | |
292 #[test] | |
293 fn anm0() { | |
645
7bde50132735
Don’t hardcode my home directory in tests.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
643
diff
changeset
|
294 let file = File::open("EoSD/CM/player01.anm").unwrap(); |
638 | 295 let mut file = io::BufReader::new(file); |
296 let mut buf = vec![]; | |
297 file.read_to_end(&mut buf).unwrap(); | |
701
b6c351ca0a35
anm0: return the nom IResult and the list of Anm0s.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
694
diff
changeset
|
298 let (_, mut anms) = Anm0::from_slice(&buf).unwrap(); |
b6c351ca0a35
anm0: return the nom IResult and the list of Anm0s.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
694
diff
changeset
|
299 assert_eq!(anms.len(), 1); |
b6c351ca0a35
anm0: return the nom IResult and the list of Anm0s.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
694
diff
changeset
|
300 let anm0 = anms.pop().unwrap(); |
638 | 301 assert_eq!(anm0.size, (256, 256)); |
302 assert_eq!(anm0.format, 5); | |
303 } | |
304 } |