ms3d/
lib.rs

1//! This crate provides utilities working with ms3d models. The main entry
2//! point for this crate is the [`Model::from_reader`](struct.Model.html#method.from_reader)
3//! function which parses a model file.
4
5#[macro_use]
6extern crate bitflags;
7#[macro_use]
8extern crate failure;
9extern crate memchr;
10
11mod de;
12mod model;
13mod read;
14
15pub use model::*;
16pub use failure::Error;
17
18use read::{BufReadExact, IoReader, SliceReader};
19
20use memchr::memchr;
21
22use std::io;
23use std::{mem, ptr, str, u8};
24use std::path::PathBuf;
25
26pub type Result<T> = std::result::Result<T, Error>;
27
28struct Reader<R: BufReadExact> {
29    rdr: R,
30}
31
32impl<R: io::Read> Reader<IoReader<R>> {
33    fn from_io_reader(rdr: R) -> Self {
34        Reader { rdr: IoReader::new(rdr) }
35    }
36}
37
38impl<'a> Reader<SliceReader<'a>> {
39    fn from_slice(slice: &'a [u8]) -> Self {
40        Reader { rdr: SliceReader::new(slice) }
41    }
42}
43
44impl<R: BufReadExact> Reader<R> {
45    fn read_model(&mut self) -> Result<Model> {
46        let header = self.read_header()?;
47        let vertices = self.read_vertices()?;
48        let triangles = self.read_triangles()?;
49        let groups = self.read_groups()?;
50        let materials = self.read_materials()?;
51        let key_frame_data = self.read_key_frame_data()?;
52        let joints = self.read_joints()?;
53        let comments = self.read_comments()?;
54        let vertex_ex_info = self.read_vertex_ex_info(vertices.len())?;
55        let joint_ex_info = self.read_joint_ex_info(joints.len())?;
56        let model_ex_info = self.read_model_ex_info()?;
57
58        Ok(Model {
59            header,
60            vertices,
61            triangles,
62            groups,
63            materials,
64            key_frame_data,
65            joints,
66            comments,
67            vertex_ex_info,
68            joint_ex_info,
69            model_ex_info,
70        })
71    }
72
73    fn read_header(&mut self) -> Result<Header> {
74        let de::Header { id, version } = unsafe { self.read_type()? };
75        ensure!(id == "MS3D000000".as_bytes(), "invalid header");
76        ensure!(version == 4, "unsupported version {}", version);
77        Ok(Header { version })
78    }
79
80    fn read_vertices(&mut self) -> Result<Vec<Vertex>> {
81        let len = self.read_u16()? as usize;
82        self.read_vec(len, Self::read_vertex)
83    }
84
85    fn read_vertex(&mut self) -> Result<Vertex> {
86        let de::Vertex {
87            flags,
88            vertex,
89            bone_id,
90            reference_count,
91        } = unsafe { self.read_type()? };
92        let flags = convert_flags(flags, Vertex::ALLOWED_FLAGS)?;
93        Ok(Vertex {
94            flags,
95            vertex,
96            bone_id,
97            reference_count,
98        })
99    }
100
101    fn read_triangles(&mut self) -> Result<Vec<Triangle>> {
102        let len = self.read_u16()? as usize;
103        self.read_vec(len, Self::read_triangle)
104    }
105
106    fn read_triangle(&mut self) -> Result<Triangle> {
107        let de::Triangle {
108            flags,
109            vertex_indices,
110            vertex_normals,
111            s,
112            t,
113            smoothing_group,
114            group_index,
115        } = unsafe { self.read_type()? };
116        let flags = convert_flags(flags as u8, Triangle::ALLOWED_FLAGS)?;
117        Ok(Triangle {
118            flags,
119            vertex_indices,
120            vertex_normals,
121            s,
122            t,
123            smoothing_group,
124            group_index,
125        })
126    }
127
128    fn read_groups(&mut self) -> Result<Vec<Group>> {
129        let len = self.read_u16()? as usize;
130        self.read_vec(len, Self::read_group)
131    }
132
133    fn read_group(&mut self) -> Result<Group> {
134        let de::GroupPrefix {
135            flags,
136            name,
137            num_triangles,
138        } = unsafe { self.read_type()? };
139
140        let flags = convert_flags(flags, Group::ALLOWED_FLAGS)?;
141        let name = convert_string(&name)?;
142        let triangle_indices = self.read_vec(num_triangles as usize, Self::read_u16)?;
143
144        let de::GroupSuffix { material_index } = unsafe { self.read_type()? };
145
146        Ok(Group {
147            flags,
148            name,
149            triangle_indices,
150            material_index,
151        })
152    }
153
154    fn read_materials(&mut self) -> Result<Vec<Material>> {
155        let len = self.read_u16()? as usize;
156        self.read_vec(len, Self::read_material)
157    }
158
159    fn read_material(&mut self) -> Result<Material> {
160        let de::Material {
161            name,
162            ambient,
163            diffuse,
164            specular,
165            emissive,
166            shininess,
167            transparency,
168            mode,
169            texture,
170            alphamap,
171        } = unsafe { self.read_type()? };
172
173        let name = convert_string(&name)?;
174        let texture = convert_path(&texture)?;
175        let alphamap = convert_path(&alphamap)?;
176
177        Ok(Material {
178            name,
179            ambient,
180            diffuse,
181            specular,
182            emissive,
183            shininess,
184            transparency,
185            mode,
186            texture,
187            alphamap,
188        })
189    }
190
191    fn read_key_frame_data(&mut self) -> Result<KeyFrameData> {
192        let de::KeyFrameData {
193            animation_fps,
194            current_time,
195            total_frames,
196        } = unsafe { self.read_type()? };
197        Ok(KeyFrameData {
198            animation_fps,
199            current_time,
200            total_frames,
201        })
202    }
203
204    fn read_joints(&mut self) -> Result<Vec<Joint>> {
205        let len = self.read_u16()? as usize;
206        self.read_vec(len, Self::read_joint)
207    }
208
209    fn read_joint(&mut self) -> Result<Joint> {
210        let de::JointPrefix {
211            flags,
212            name,
213            parent_name,
214            rotation,
215            position,
216            num_key_frames_rot,
217            num_key_frames_trans,
218        } = unsafe { self.read_type()? };
219
220        let flags = convert_flags(flags, Joint::ALLOWED_FLAGS)?;
221        let name = convert_string(&name)?;
222        let parent_name = convert_string(&parent_name)?;
223
224        let key_frames_rot = self.read_vec(num_key_frames_rot as usize, Self::read_key_frame_rot)?;
225        let key_frames_trans =
226            self.read_vec(num_key_frames_trans as usize, Self::read_key_frame_pos)?;
227
228        Ok(Joint {
229            flags,
230            name,
231            parent_name,
232            rotation,
233            position,
234            key_frames_rot,
235            key_frames_trans,
236        })
237    }
238
239    fn read_key_frame_rot(&mut self) -> Result<KeyFrameRot> {
240        let de::KeyFrameRot { time, rotation } = unsafe { self.read_type()? };
241        Ok(KeyFrameRot { time, rotation })
242    }
243
244    fn read_key_frame_pos(&mut self) -> Result<KeyFramePos> {
245        let de::KeyFramePos { time, position } = unsafe { self.read_type()? };
246        Ok(KeyFramePos { time, position })
247    }
248
249    fn read_comments(&mut self) -> Result<Comments> {
250        let sub_version = self.read_i32()?;
251        ensure!(
252            sub_version == 1,
253            "unsupported comment sub-version {}",
254            sub_version
255        );
256        let len = self.read_u32()? as usize;
257        let group_comments = self.read_vec(len, Self::read_comment)?;
258        let len = self.read_i32()? as usize;
259        let material_comments = self.read_vec(len, Self::read_comment)?;
260        let len = self.read_i32()? as usize;
261        let joint_comments = self.read_vec(len, Self::read_comment)?;
262        let len = self.read_i32()? as usize;
263        let model_comment = match len {
264            0 => None,
265            1 => Some(self.read_comment()?),
266            _ => bail!("invalid number of model comments"),
267        };
268
269        Ok(Comments {
270            sub_version,
271            group_comments,
272            material_comments,
273            joint_comments,
274            model_comment,
275        })
276    }
277
278    fn read_comment(&mut self) -> Result<Comment> {
279        let de::CommentPrefix {
280            index,
281            comment_length,
282        } = unsafe { self.read_type()? };
283        let comment = self.read_string(comment_length as usize)?;
284        Ok(Comment { index, comment })
285    }
286
287    fn read_vertex_ex_info(&mut self, len: usize) -> Result<VertexExInfo> {
288        use VertexExInfo::*;
289
290        let sub_version = self.read_i32()?;
291        match sub_version {
292            1 => Ok(SubVersion1(self.read_vec(len, Self::read_vertex_ex_1)?)),
293            2 => Ok(SubVersion2(self.read_vec(len, Self::read_vertex_ex_2)?)),
294            3 => Ok(SubVersion3(self.read_vec(len, Self::read_vertex_ex_3)?)),
295            v => bail!("unsupported vertex ex sub-version {}", v),
296        }
297    }
298
299    fn read_vertex_ex_1(&mut self) -> Result<VertexEx1> {
300        let de::VertexEx1 { bone_ids, weights } = unsafe { self.read_type()? };
301        Ok(VertexEx1 { bone_ids, weights })
302    }
303
304    fn read_vertex_ex_2(&mut self) -> Result<VertexEx2> {
305        let de::VertexEx2 {
306            bone_ids,
307            weights,
308            extra,
309        } = unsafe { self.read_type()? };
310        Ok(VertexEx2 {
311            bone_ids,
312            weights,
313            extra,
314        })
315    }
316
317    fn read_vertex_ex_3(&mut self) -> Result<VertexEx3> {
318        let de::VertexEx3 {
319            bone_ids,
320            weights,
321            extra,
322        } = unsafe { self.read_type()? };
323        Ok(VertexEx3 {
324            bone_ids,
325            weights,
326            extra,
327        })
328    }
329
330    fn read_joint_ex_info(&mut self, len: usize) -> Result<JointExInfo> {
331        let sub_version = self.read_i32()?;
332        ensure!(
333            sub_version == 1,
334            "unsupported joint ex sub-version {}",
335            sub_version
336        );
337        let joint_ex = self.read_vec(len, Self::read_joint_ex)?;
338        Ok(JointExInfo {
339            sub_version,
340            joint_ex,
341        })
342    }
343
344    fn read_joint_ex(&mut self) -> Result<JointEx> {
345        let de::JointEx { color } = unsafe { self.read_type()? };
346        Ok(JointEx { color })
347    }
348
349    fn read_model_ex_info(&mut self) -> Result<ModelExInfo> {
350        let sub_version = self.read_i32()?;
351        ensure!(
352            sub_version == 1,
353            "unsupported model ex sub-version {}",
354            sub_version
355        );
356        let model_ex = self.read_model_ex()?;
357        Ok(ModelExInfo {
358            sub_version,
359            model_ex,
360        })
361    }
362
363    fn read_model_ex(&mut self) -> Result<ModelEx> {
364        let de::ModelEx {
365            joint_size,
366            transparency_mode,
367            alpha_ref,
368        } = unsafe { self.read_type()? };
369        Ok(ModelEx {
370            joint_size,
371            transparency_mode,
372            alpha_ref,
373        })
374    }
375
376    fn read_string(&mut self, len: usize) -> Result<String> {
377        Ok(str::from_utf8(self.rdr.buf_read_exact(len)?)?.to_owned())
378    }
379
380    fn read_vec<T, F>(&mut self, len: usize, f: F) -> Result<Vec<T>>
381    where
382        F: Fn(&mut Self) -> Result<T>,
383    {
384        (0..len).map(|_| f(self)).collect()
385    }
386
387    fn read_u16(&mut self) -> Result<u16> {
388        unsafe { self.read_type() }
389    }
390
391    fn read_u32(&mut self) -> Result<u32> {
392        unsafe { self.read_type() }
393    }
394
395    fn read_i32(&mut self) -> Result<i32> {
396        unsafe { self.read_type() }
397    }
398
399    unsafe fn read_type<T>(&mut self) -> Result<T> {
400        Ok(ptr::read_unaligned(
401            self.rdr.buf_read_exact(mem::size_of::<T>())? as *const [u8] as *const T,
402        ))
403    }
404}
405
406fn convert_string(bytes: &[u8]) -> Result<String> {
407    let vec = if let Some(i) = memchr(0, bytes) {
408        bytes[..i].to_owned()
409    } else {
410        bytes.to_owned()
411    };
412    Ok(String::from_utf8(vec)?)
413}
414
415fn convert_path(bytes: &[u8]) -> Result<PathBuf> {
416    convert_string(bytes).map(Into::into)
417}
418
419fn convert_flags(bits: u8, allowed: Flags) -> Result<Flags> {
420    if let Some(flags) = Flags::from_bits(bits) {
421        if allowed.contains(flags) {
422            return Ok(flags);
423        }
424    }
425    Err(format_err!("invalid flags {}", bits))
426}