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