1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4 
5 Copyright (c) 2006-2017, assimp team
6 
7 All rights reserved.
8 
9 Redistribution and use of this software in source and binary forms,
10 with or without modification, are permitted provided that the
11 following conditions are met:
12 
13 * Redistributions of source code must retain the above
14   copyright notice, this list of conditions and the
15   following disclaimer.
16 
17 * Redistributions in binary form must reproduce the above
18   copyright notice, this list of conditions and the
19   following disclaimer in the documentation and/or other
20   materials provided with the distribution.
21 
22 * Neither the name of the assimp team, nor the names of its
23   contributors may be used to endorse or promote products
24   derived from this software without specific prior
25   written permission of the assimp team.
26 
27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 
39 ----------------------------------------------------------------------
40 */
41 
42 
43 /** @file  MD5Parser.h
44  *  @brief Definition of the .MD5 parser class.
45  *  http://www.modwiki.net/wiki/MD5_(file_format)
46  */
47 #ifndef AI_MD5PARSER_H_INCLUDED
48 #define AI_MD5PARSER_H_INCLUDED
49 
50 #include <assimp/types.h>
51 #include "ParsingUtils.h"
52 #include <vector>
53 #include <stdint.h>
54 
55 struct aiFace;
56 
57 namespace Assimp    {
58 namespace MD5           {
59 
60 // ---------------------------------------------------------------------------
61 /** Represents a single element in a MD5 file
62  *
63  *  Elements are always contained in sections.
64 */
65 struct Element
66 {
67     //! Points to the starting point of the element
68     //! Whitespace at the beginning and at the end have been removed,
69     //! Elements are terminated with \0
70     char* szStart;
71 
72     //! Original line number (can be used in error messages
73     //! if a parsing error occurs)
74     unsigned int iLineNumber;
75 };
76 
77 typedef std::vector< Element > ElementList;
78 
79 // ---------------------------------------------------------------------------
80 /** Represents a section of a MD5 file (such as the mesh or the joints section)
81  *
82  *  A section is always enclosed in { and } brackets.
83 */
84 struct Section
85 {
86     //! Original line number (can be used in error messages
87     //! if a parsing error occurs)
88     unsigned int iLineNumber;
89 
90     //! List of all elements which have been parsed in this section.
91     ElementList mElements;
92 
93     //! Name of the section
94     std::string mName;
95 
96     //! For global elements: the value of the element as string
97     //! Iif !length() the section is not a global element
98     std::string mGlobalValue;
99 };
100 
101 typedef std::vector< Section> SectionList;
102 
103 // ---------------------------------------------------------------------------
104 /** Basic information about a joint
105 */
106 struct BaseJointDescription
107 {
108     //! Name of the bone
109     aiString mName;
110 
111     //! Parent index of the bone
112     int mParentIndex;
113 };
114 
115 // ---------------------------------------------------------------------------
116 /** Represents a bone (joint) descriptor in a MD5Mesh file
117 */
118 struct BoneDesc : BaseJointDescription
119 {
120     //! Absolute position of the bone
121     aiVector3D mPositionXYZ;
122 
123     //! Absolute rotation of the bone
124     aiVector3D mRotationQuat;
125     aiQuaternion mRotationQuatConverted;
126 
127     //! Absolute transformation of the bone
128     //! (temporary)
129     aiMatrix4x4 mTransform;
130 
131     //! Inverse transformation of the bone
132     //! (temporary)
133     aiMatrix4x4 mInvTransform;
134 
135     //! Internal
136     unsigned int mMap;
137 };
138 
139 typedef std::vector< BoneDesc > BoneList;
140 
141 // ---------------------------------------------------------------------------
142 /** Represents a bone (joint) descriptor in a MD5Anim file
143 */
144 struct AnimBoneDesc : BaseJointDescription
145 {
146     //! Flags (AI_MD5_ANIMATION_FLAG_xxx)
147     unsigned int iFlags;
148 
149     //! Index of the first key that corresponds to this anim bone
150     unsigned int iFirstKeyIndex;
151 };
152 
153 typedef std::vector< AnimBoneDesc > AnimBoneList;
154 
155 
156 // ---------------------------------------------------------------------------
157 /** Represents a base frame descriptor in a MD5Anim file
158 */
159 struct BaseFrameDesc
160 {
161     aiVector3D vPositionXYZ;
162     aiVector3D vRotationQuat;
163 };
164 
165 typedef std::vector< BaseFrameDesc > BaseFrameList;
166 
167 // ---------------------------------------------------------------------------
168 /** Represents a camera animation frame in a MDCamera file
169 */
170 struct CameraAnimFrameDesc : BaseFrameDesc
171 {
172     float fFOV;
173 };
174 
175 typedef std::vector< CameraAnimFrameDesc > CameraFrameList;
176 
177 // ---------------------------------------------------------------------------
178 /** Represents a frame descriptor in a MD5Anim file
179 */
180 struct FrameDesc
181 {
182     //! Index of the frame
183     unsigned int iIndex;
184 
185     //! Animation keyframes - a large blob of data at first
186     std::vector< float > mValues;
187 };
188 
189 typedef std::vector< FrameDesc > FrameList;
190 
191 // ---------------------------------------------------------------------------
192 /** Represents a vertex  descriptor in a MD5 file
193 */
194 struct VertexDesc
195 {
VertexDescVertexDesc196     VertexDesc()
197         : mFirstWeight  (0)
198         , mNumWeights   (0)
199     {}
200 
201     //! UV cordinate of the vertex
202     aiVector2D mUV;
203 
204     //! Index of the first weight of the vertex in
205     //! the vertex weight list
206     unsigned int mFirstWeight;
207 
208     //! Number of weights assigned to this vertex
209     unsigned int mNumWeights;
210 };
211 
212 typedef std::vector< VertexDesc > VertexList;
213 
214 // ---------------------------------------------------------------------------
215 /** Represents a vertex weight descriptor in a MD5 file
216 */
217 struct WeightDesc
218 {
219     //! Index of the bone to which this weight refers
220     unsigned int mBone;
221 
222     //! The weight value
223     float mWeight;
224 
225     //! The offset position of this weight
226     // ! (in the coordinate system defined by the parent bone)
227     aiVector3D vOffsetPosition;
228 };
229 
230 typedef std::vector< WeightDesc > WeightList;
231 typedef std::vector< aiFace > FaceList;
232 
233 // ---------------------------------------------------------------------------
234 /** Represents a mesh in a MD5 file
235 */
236 struct MeshDesc
237 {
238     //! Weights of the mesh
239     WeightList mWeights;
240 
241     //! Vertices of the mesh
242     VertexList mVertices;
243 
244     //! Faces of the mesh
245     FaceList mFaces;
246 
247     //! Name of the shader (=texture) to be assigned to the mesh
248     aiString mShader;
249 };
250 
251 typedef std::vector< MeshDesc > MeshList;
252 
253 // ---------------------------------------------------------------------------
254 // Convert a quaternion to its usual representation
ConvertQuaternion(const aiVector3D & in,aiQuaternion & out)255 inline void ConvertQuaternion (const aiVector3D& in, aiQuaternion& out) {
256 
257     out.x = in.x;
258     out.y = in.y;
259     out.z = in.z;
260 
261     const float t = 1.0f - (in.x*in.x) - (in.y*in.y) - (in.z*in.z);
262 
263     if (t < 0.0f)
264         out.w = 0.0f;
265     else out.w = std::sqrt (t);
266 
267     // Assimp convention.
268     out.w *= -1.f;
269 }
270 
271 // ---------------------------------------------------------------------------
272 /** Parses the data sections of a MD5 mesh file
273 */
274 class MD5MeshParser
275 {
276 public:
277 
278     // -------------------------------------------------------------------
279     /** Constructs a new MD5MeshParser instance from an existing
280      *  preparsed list of file sections.
281      *
282      *  @param mSections List of file sections (output of MD5Parser)
283      */
284     explicit MD5MeshParser(SectionList& mSections);
285 
286     //! List of all meshes
287     MeshList mMeshes;
288 
289     //! List of all joints
290     BoneList mJoints;
291 };
292 
293 // remove this flag if you need to the bounding box data
294 #define AI_MD5_PARSE_NO_BOUNDS
295 
296 // ---------------------------------------------------------------------------
297 /** Parses the data sections of a MD5 animation file
298 */
299 class MD5AnimParser
300 {
301 public:
302 
303     // -------------------------------------------------------------------
304     /** Constructs a new MD5AnimParser instance from an existing
305      *  preparsed list of file sections.
306      *
307      *  @param mSections List of file sections (output of MD5Parser)
308      */
309     explicit MD5AnimParser(SectionList& mSections);
310 
311 
312     //! Output frame rate
313     float fFrameRate;
314 
315     //! List of animation bones
316     AnimBoneList mAnimatedBones;
317 
318     //! List of base frames
319     BaseFrameList mBaseFrames;
320 
321     //! List of animation frames
322     FrameList mFrames;
323 
324     //! Number of animated components
325     unsigned int mNumAnimatedComponents;
326 };
327 
328 // ---------------------------------------------------------------------------
329 /** Parses the data sections of a MD5 camera animation file
330 */
331 class MD5CameraParser
332 {
333 public:
334 
335     // -------------------------------------------------------------------
336     /** Constructs a new MD5CameraParser instance from an existing
337      *  preparsed list of file sections.
338      *
339      *  @param mSections List of file sections (output of MD5Parser)
340      */
341     explicit MD5CameraParser(SectionList& mSections);
342 
343 
344     //! Output frame rate
345     float fFrameRate;
346 
347     //! List of cuts
348     std::vector<unsigned int> cuts;
349 
350     //! Frames
351     CameraFrameList frames;
352 };
353 
354 // ---------------------------------------------------------------------------
355 /** Parses the block structure of MD5MESH and MD5ANIM files (but does no
356  *  further processing)
357 */
358 class MD5Parser
359 {
360 public:
361 
362     // -------------------------------------------------------------------
363     /** Constructs a new MD5Parser instance from an existing buffer.
364      *
365      *  @param buffer File buffer
366      *  @param fileSize Length of the file in bytes (excluding a terminal 0)
367      */
368     MD5Parser(char* buffer, unsigned int fileSize);
369 
370 
371     // -------------------------------------------------------------------
372     /** Report a specific error message and throw an exception
373      *  @param error Error message to be reported
374      *  @param line Index of the line where the error occurred
375      */
376     AI_WONT_RETURN static void ReportError (const char* error, unsigned int line) AI_WONT_RETURN_SUFFIX;
377 
378     // -------------------------------------------------------------------
379     /** Report a specific warning
380      *  @param warn Warn message to be reported
381      *  @param line Index of the line where the error occurred
382      */
383     static void ReportWarning (const char* warn, unsigned int line);
384 
385 
ReportError(const char * error)386     void ReportError (const char* error) {
387         return ReportError(error, lineNumber);
388     }
389 
ReportWarning(const char * warn)390     void ReportWarning (const char* warn) {
391         return ReportWarning(warn, lineNumber);
392     }
393 
394 public:
395 
396     //! List of all sections which have been read
397     SectionList mSections;
398 
399 private:
400 
401     // -------------------------------------------------------------------
402     /** Parses a file section. The current file pointer must be outside
403      *  of a section.
404      *  @param out Receives the section data
405      *  @return true if the end of the file has been reached
406      *  @throws ImportErrorException if an error occurs
407      */
408     bool ParseSection(Section& out);
409 
410     // -------------------------------------------------------------------
411     /** Parses the file header
412      *  @throws ImportErrorException if an error occurs
413      */
414     void ParseHeader();
415 
416 
417     // override these functions to make sure the line counter gets incremented
418     // -------------------------------------------------------------------
SkipLine(const char * in,const char ** out)419     bool SkipLine( const char* in, const char** out)
420     {
421         ++lineNumber;
422         return Assimp::SkipLine(in,out);
423     }
424     // -------------------------------------------------------------------
SkipLine()425     bool SkipLine( )
426     {
427         return SkipLine(buffer,(const char**)&buffer);
428     }
429     // -------------------------------------------------------------------
SkipSpacesAndLineEnd(const char * in,const char ** out)430     bool SkipSpacesAndLineEnd( const char* in, const char** out)
431     {
432         bool bHad = false;
433         bool running = true;
434         while (running) {
435             if( *in == '\r' || *in == '\n') {
436                  // we open files in binary mode, so there could be \r\n sequences ...
437                 if (!bHad)  {
438                     bHad = true;
439                     ++lineNumber;
440                 }
441             }
442             else if (*in == '\t' || *in == ' ')bHad = false;
443             else break;
444             in++;
445         }
446         *out = in;
447         return *in != '\0';
448     }
449     // -------------------------------------------------------------------
SkipSpacesAndLineEnd()450     bool SkipSpacesAndLineEnd( )
451     {
452         return SkipSpacesAndLineEnd(buffer,(const char**)&buffer);
453     }
454     // -------------------------------------------------------------------
SkipSpaces()455     bool SkipSpaces( )
456     {
457         return Assimp::SkipSpaces((const char**)&buffer);
458     }
459 
460     char* buffer;
461     unsigned int fileSize;
462     unsigned int lineNumber;
463 };
464 }}
465 
466 #endif // AI_MD5PARSER_H_INCLUDED
467