Coverage Report

Created: 2025-11-11 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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