/src/assimp/code/AssetLib/MD5/MD5Parser.h
Line | Count | Source |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2025, 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 | | #pragma once |
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 <assimp/ParsingUtils.h> |
52 | | #include <vector> |
53 | | #include <cstdint> |
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 | | //! Points to the starting point of the element |
67 | | //! Whitespace at the beginning and at the end have been removed, |
68 | | //! Elements are terminated with \0 |
69 | | char* szStart; |
70 | | |
71 | | const char *end; |
72 | | |
73 | | //! Original line number (can be used in error messages |
74 | | //! if a parsing error occurs) |
75 | | unsigned int iLineNumber; |
76 | | }; |
77 | | |
78 | | using ElementArray = std::vector<Element>; |
79 | | |
80 | | // --------------------------------------------------------------------------- |
81 | | /** Represents a section of a MD5 file (such as the mesh or the joints section) |
82 | | * |
83 | | * A section is always enclosed in { and } brackets. |
84 | | */ |
85 | | struct Section { |
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 | | ElementArray mElements; |
92 | | |
93 | | //! Name of the section |
94 | | std::string mName; |
95 | | |
96 | | //! For global elements: the value of the element as string |
97 | | //! if !length() the section is not a global element |
98 | | std::string mGlobalValue; |
99 | | }; |
100 | | |
101 | | using SectionArray = std::vector<Section>; |
102 | | |
103 | | // --------------------------------------------------------------------------- |
104 | | /** Basic information about a joint |
105 | | */ |
106 | | struct BaseJointDescription { |
107 | | //! Name of the bone |
108 | | aiString mName; |
109 | | |
110 | | //! Parent index of the bone |
111 | | int mParentIndex; |
112 | | }; |
113 | | |
114 | | // --------------------------------------------------------------------------- |
115 | | /** Represents a bone (joint) descriptor in a MD5Mesh file |
116 | | */ |
117 | | struct BoneDesc : BaseJointDescription { |
118 | | //! Absolute position of the bone |
119 | | aiVector3D mPositionXYZ; |
120 | | |
121 | | //! Absolute rotation of the bone |
122 | | aiVector3D mRotationQuat; |
123 | | aiQuaternion mRotationQuatConverted; |
124 | | |
125 | | //! Absolute transformation of the bone |
126 | | //! (temporary) |
127 | | aiMatrix4x4 mTransform; |
128 | | |
129 | | //! Inverse transformation of the bone |
130 | | //! (temporary) |
131 | | aiMatrix4x4 mInvTransform; |
132 | | |
133 | | //! Internal |
134 | | unsigned int mMap; |
135 | | }; |
136 | | |
137 | | using BoneArray = std::vector<BoneDesc>; |
138 | | |
139 | | // --------------------------------------------------------------------------- |
140 | | /** Represents a bone (joint) descriptor in a MD5Anim file |
141 | | */ |
142 | | struct AnimBoneDesc : BaseJointDescription { |
143 | | //! Flags (AI_MD5_ANIMATION_FLAG_xxx) |
144 | | unsigned int iFlags; |
145 | | |
146 | | //! Index of the first key that corresponds to this anim bone |
147 | | unsigned int iFirstKeyIndex; |
148 | | }; |
149 | | |
150 | | using AnimBoneArray = std::vector< AnimBoneDesc >; |
151 | | |
152 | | // --------------------------------------------------------------------------- |
153 | | /** Represents a base frame descriptor in a MD5Anim file |
154 | | */ |
155 | | struct BaseFrameDesc { |
156 | | aiVector3D vPositionXYZ; |
157 | | aiVector3D vRotationQuat; |
158 | | }; |
159 | | |
160 | | using BaseFrameArray = std::vector<BaseFrameDesc>; |
161 | | |
162 | | // --------------------------------------------------------------------------- |
163 | | /** Represents a camera animation frame in a MDCamera file |
164 | | */ |
165 | | struct CameraAnimFrameDesc : BaseFrameDesc { |
166 | | float fFOV; |
167 | | }; |
168 | | |
169 | | using CameraFrameArray = std::vector<CameraAnimFrameDesc>; |
170 | | |
171 | | // --------------------------------------------------------------------------- |
172 | | /** Represents a frame descriptor in a MD5Anim file |
173 | | */ |
174 | | struct FrameDesc { |
175 | | //! Index of the frame |
176 | | unsigned int iIndex; |
177 | | |
178 | | //! Animation keyframes - a large blob of data at first |
179 | | std::vector< float > mValues; |
180 | | }; |
181 | | |
182 | | using FrameArray = std::vector<FrameDesc>; |
183 | | |
184 | | // --------------------------------------------------------------------------- |
185 | | /** Represents a vertex descriptor in a MD5 file |
186 | | */ |
187 | | struct VertexDesc { |
188 | | VertexDesc() AI_NO_EXCEPT |
189 | 4.56k | : mFirstWeight(0), mNumWeights(0) { |
190 | | // empty |
191 | 4.56k | } |
192 | | |
193 | | //! UV coordinate of the vertex |
194 | | aiVector2D mUV; |
195 | | |
196 | | //! Index of the first weight of the vertex in |
197 | | //! the vertex weight list |
198 | | unsigned int mFirstWeight; |
199 | | |
200 | | //! Number of weights assigned to this vertex |
201 | | unsigned int mNumWeights; |
202 | | }; |
203 | | |
204 | | using VertexArray = std::vector<VertexDesc>; |
205 | | |
206 | | // --------------------------------------------------------------------------- |
207 | | /** Represents a vertex weight descriptor in a MD5 file |
208 | | */ |
209 | | struct WeightDesc { |
210 | | //! Index of the bone to which this weight refers |
211 | | unsigned int mBone; |
212 | | |
213 | | //! The weight value |
214 | | float mWeight; |
215 | | |
216 | | //! The offset position of this weight |
217 | | // ! (in the coordinate system defined by the parent bone) |
218 | | aiVector3D vOffsetPosition; |
219 | | }; |
220 | | |
221 | | using WeightArray = std::vector<WeightDesc>; |
222 | | using FaceArray = std::vector<aiFace>; |
223 | | |
224 | | // --------------------------------------------------------------------------- |
225 | | /** Represents a mesh in a MD5 file |
226 | | */ |
227 | | struct MeshDesc { |
228 | | //! Weights of the mesh |
229 | | WeightArray mWeights; |
230 | | |
231 | | //! Vertices of the mesh |
232 | | VertexArray mVertices; |
233 | | |
234 | | //! Faces of the mesh |
235 | | FaceArray mFaces; |
236 | | |
237 | | //! Name of the shader (=texture) to be assigned to the mesh |
238 | | aiString mShader; |
239 | | }; |
240 | | |
241 | | using MeshArray = std::vector<MeshDesc>; |
242 | | |
243 | | // --------------------------------------------------------------------------- |
244 | | // Convert a quaternion to its usual representation |
245 | 0 | inline void ConvertQuaternion (const aiVector3D& in, aiQuaternion& out) { |
246 | |
|
247 | 0 | out.x = in.x; |
248 | 0 | out.y = in.y; |
249 | 0 | out.z = in.z; |
250 | |
|
251 | 0 | const float t = 1.0f - (in.x*in.x) - (in.y*in.y) - (in.z*in.z); |
252 | |
|
253 | 0 | if (t < 0.0f) { |
254 | 0 | out.w = 0.0f; |
255 | 0 | } else { |
256 | 0 | out.w = std::sqrt (t); |
257 | 0 | } |
258 | | |
259 | | // Assimp convention. |
260 | 0 | out.w *= -1.f; |
261 | 0 | } |
262 | | |
263 | | // --------------------------------------------------------------------------- |
264 | | /** Parses the data sections of a MD5 mesh file |
265 | | */ |
266 | | class MD5MeshParser { |
267 | | public: |
268 | | // ------------------------------------------------------------------- |
269 | | /** Constructs a new MD5MeshParser instance from an existing |
270 | | * preparsed list of file sections. |
271 | | * |
272 | | * @param mSections List of file sections (output of MD5Parser) |
273 | | */ |
274 | | explicit MD5MeshParser(SectionArray& mSections); |
275 | | |
276 | | //! List of all meshes |
277 | | MeshArray mMeshes; |
278 | | |
279 | | //! List of all joints |
280 | | BoneArray mJoints; |
281 | | }; |
282 | | |
283 | | // remove this flag if you need to the bounding box data |
284 | | #define AI_MD5_PARSE_NO_BOUNDS |
285 | | |
286 | | // --------------------------------------------------------------------------- |
287 | | /** Parses the data sections of a MD5 animation file |
288 | | */ |
289 | | class MD5AnimParser { |
290 | | public: |
291 | | // ------------------------------------------------------------------- |
292 | | /** Constructs a new MD5AnimParser instance from an existing |
293 | | * preparsed list of file sections. |
294 | | * |
295 | | * @param mSections List of file sections (output of MD5Parser) |
296 | | */ |
297 | | explicit MD5AnimParser(SectionArray& mSections); |
298 | | |
299 | | |
300 | | //! Output frame rate |
301 | | float fFrameRate; |
302 | | |
303 | | //! List of animation bones |
304 | | AnimBoneArray mAnimatedBones; |
305 | | |
306 | | //! List of base frames |
307 | | BaseFrameArray mBaseFrames; |
308 | | |
309 | | //! List of animation frames |
310 | | FrameArray mFrames; |
311 | | |
312 | | //! Number of animated components |
313 | | unsigned int mNumAnimatedComponents; |
314 | | }; |
315 | | |
316 | | // --------------------------------------------------------------------------- |
317 | | /** Parses the data sections of a MD5 camera animation file |
318 | | */ |
319 | | class MD5CameraParser { |
320 | | public: |
321 | | // ------------------------------------------------------------------- |
322 | | /** Constructs a new MD5CameraParser instance from an existing |
323 | | * preparsed list of file sections. |
324 | | * |
325 | | * @param mSections List of file sections (output of MD5Parser) |
326 | | */ |
327 | | explicit MD5CameraParser(SectionArray& mSections); |
328 | | |
329 | | //! Output frame rate |
330 | | float fFrameRate; |
331 | | |
332 | | //! List of cuts |
333 | | std::vector<unsigned int> cuts; |
334 | | |
335 | | //! Frames |
336 | | CameraFrameArray frames; |
337 | | }; |
338 | | |
339 | | // --------------------------------------------------------------------------- |
340 | | /** Parses the block structure of MD5MESH and MD5ANIM files (but does no |
341 | | * further processing) |
342 | | */ |
343 | | class MD5Parser { |
344 | | public: |
345 | | // ------------------------------------------------------------------- |
346 | | /** Constructs a new MD5Parser instance from an existing buffer. |
347 | | * |
348 | | * @param buffer File buffer |
349 | | * @param fileSize Length of the file in bytes (excluding a terminal 0) |
350 | | */ |
351 | | MD5Parser(char* buffer, unsigned int fileSize); |
352 | | |
353 | | // ------------------------------------------------------------------- |
354 | | /** Report a specific error message and throw an exception |
355 | | * @param error Error message to be reported |
356 | | * @param line Index of the line where the error occurred |
357 | | */ |
358 | | AI_WONT_RETURN static void ReportError(const char* error, unsigned int line) AI_WONT_RETURN_SUFFIX; |
359 | | |
360 | | // ------------------------------------------------------------------- |
361 | | /** Report a specific warning |
362 | | * @param warn Warn message to be reported |
363 | | * @param line Index of the line where the error occurred |
364 | | */ |
365 | | static void ReportWarning(const char* warn, unsigned int line); |
366 | | |
367 | | // ------------------------------------------------------------------- |
368 | | /** Report a specific error |
369 | | * @param error Error message to be reported |
370 | | */ |
371 | | AI_WONT_RETURN void ReportError (const char* error) AI_WONT_RETURN_SUFFIX; |
372 | | |
373 | | // ------------------------------------------------------------------- |
374 | | /** Report a specific warning |
375 | | * @param error Warn message to be reported |
376 | | */ |
377 | | void ReportWarning (const char* warn); |
378 | | |
379 | | //! List of all sections which have been read |
380 | | SectionArray mSections; |
381 | | |
382 | | private: |
383 | | bool ParseSection(Section& out); |
384 | | void ParseHeader(); |
385 | | bool SkipLine(const char* in, const char** out); |
386 | | bool SkipLine( ); |
387 | | bool SkipSpacesAndLineEnd( const char* in, const char** out); |
388 | | bool SkipSpacesAndLineEnd(); |
389 | | bool SkipSpaces(); |
390 | | |
391 | | private: |
392 | | char* buffer; |
393 | | const char* bufferEnd; |
394 | | unsigned int fileSize; |
395 | | unsigned int lineNumber; |
396 | | }; |
397 | | |
398 | | // ------------------------------------------------------------------- |
399 | 0 | inline void MD5Parser::ReportWarning (const char* warn) { |
400 | 0 | return ReportWarning(warn, lineNumber); |
401 | 0 | } |
402 | | |
403 | | // ------------------------------------------------------------------- |
404 | 0 | inline void MD5Parser::ReportError(const char* error) { |
405 | 0 | ReportError(error, lineNumber); |
406 | 0 | } |
407 | | |
408 | | // ------------------------------------------------------------------- |
409 | 44 | inline bool MD5Parser::SkipLine(const char* in, const char** out) { |
410 | 44 | ++lineNumber; |
411 | 44 | return Assimp::SkipLine(in, out, bufferEnd); |
412 | 44 | } |
413 | | |
414 | | // ------------------------------------------------------------------- |
415 | 44 | inline bool MD5Parser::SkipLine( ) { |
416 | 44 | return SkipLine(buffer,(const char**)&buffer); |
417 | 44 | } |
418 | | |
419 | | // ------------------------------------------------------------------- |
420 | 44 | inline bool MD5Parser::SkipSpacesAndLineEnd( const char* in, const char** out) { |
421 | 44 | if (in == bufferEnd) { |
422 | 0 | *out = in; |
423 | 0 | return false; |
424 | 0 | } |
425 | | |
426 | 44 | bool bHad = false, running = true; |
427 | 46 | while (running) { |
428 | 46 | if( *in == '\r' || *in == '\n') { |
429 | | // we open files in binary mode, so there could be \r\n sequences ... |
430 | 2 | if (!bHad) { |
431 | 2 | bHad = true; |
432 | 2 | ++lineNumber; |
433 | 2 | } |
434 | 44 | } else if (*in == '\t' || *in == ' ') { |
435 | 0 | bHad = false; |
436 | 44 | } else { |
437 | 44 | break; |
438 | 44 | } |
439 | 2 | ++in; |
440 | 2 | if (in == bufferEnd) { |
441 | 0 | break; |
442 | 0 | } |
443 | 2 | } |
444 | 44 | *out = in; |
445 | 44 | return *in != '\0'; |
446 | 44 | } |
447 | | |
448 | | // ------------------------------------------------------------------- |
449 | 44 | inline bool MD5Parser::SkipSpacesAndLineEnd() { |
450 | 44 | return SkipSpacesAndLineEnd(buffer,(const char**)&buffer); |
451 | 44 | } |
452 | | |
453 | | // ------------------------------------------------------------------- |
454 | 88 | inline bool MD5Parser::SkipSpaces() { |
455 | 88 | return Assimp::SkipSpaces((const char**)&buffer, bufferEnd); |
456 | 88 | } |
457 | | |
458 | | } // namespace Assimp |
459 | | } // namespace MD5 |
460 | | |
461 | | #endif // AI_MD5PARSER_H_INCLUDED |