Coverage Report

Created: 2025-11-11 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/SMD/SMDLoader.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
42
/** @file  SMDLoader.h
43
 *  @brief Definition of the Valve SMD file format
44
 */
45
46
#pragma once
47
#ifndef AI_SMDLOADER_H_INCLUDED
48
#define AI_SMDLOADER_H_INCLUDED
49
50
#include <assimp/BaseImporter.h>
51
#include <assimp/ParsingUtils.h>
52
#include <assimp/types.h>
53
#include <assimp/texture.h>
54
#include <assimp/anim.h>
55
#include <assimp/material.h>
56
57
#include <vector>
58
59
struct aiNode;
60
61
namespace Assimp {
62
namespace SMD {
63
64
// ---------------------------------------------------------------------------
65
/** Data structure for a vertex in a SMD file
66
*/
67
struct Vertex {
68
1.06k
    Vertex() AI_NO_EXCEPT : iParentNode(UINT_MAX) {
69
        // empty
70
1.06k
    }
71
72
    //! Vertex position, normal and texture coordinate
73
    aiVector3D pos,nor,uv;
74
75
    //! Vertex parent node
76
    unsigned int iParentNode;
77
78
    //! Links to bones: pair.first is the bone index,
79
    //! pair.second is the vertex weight.
80
    //! WARN: The remaining weight (to reach 1.0f) is assigned
81
    //! to the parent node/bone
82
    std::vector<std::pair<unsigned int, float> > aiBoneLinks;
83
};
84
85
// ---------------------------------------------------------------------------
86
/** Data structure for a face in a SMD file
87
*/
88
struct Face {
89
    Face() AI_NO_EXCEPT :
90
356
            iTexture(0x0) {
91
        // empty
92
356
    }
93
94
    //! Texture index for the face
95
    unsigned int iTexture;
96
97
    //! The three vertices of the face
98
    Vertex avVertices[3];
99
};
100
101
// ---------------------------------------------------------------------------
102
/** Data structure for a bone in a SMD file
103
*/
104
struct Bone {
105
    //! Default constructor
106
7.18k
    Bone() AI_NO_EXCEPT : iParent(UINT_MAX), bIsUsed(false) {
107
        // empty
108
7.18k
    }
109
110
    //! Name of the bone
111
    std::string mName;
112
113
    //! Parent of the bone
114
    uint32_t iParent;
115
116
    //! Animation of the bone
117
    struct Animation {
118
        //! Public default constructor
119
7.18k
        Animation() AI_NO_EXCEPT : iFirstTimeKey() {
120
7.18k
            asKeys.reserve(20);
121
7.18k
        }
122
123
        //! Data structure for a matrix key
124
        struct MatrixKey {
125
            //! Matrix at this time
126
            aiMatrix4x4 matrix;
127
128
            //! Absolute transformation matrix
129
            aiMatrix4x4 matrixAbsolute;
130
131
            //! Position
132
            aiVector3D vPos;
133
134
            //! Rotation (euler angles)
135
            aiVector3D vRot;
136
137
            //! Current time. may be negative, this
138
            //! will be fixed later
139
            double dTime;
140
        };
141
142
        //! Index of the key with the smallest time value
143
        uint32_t iFirstTimeKey;
144
145
        //! Array of matrix keys
146
        std::vector<MatrixKey> asKeys;
147
148
    } sAnim;
149
150
    //! Offset matrix of the bone
151
    aiMatrix4x4 mOffsetMatrix;
152
153
    //! true if the bone is referenced by at least one mesh
154
    bool bIsUsed;
155
};
156
157
} //! namespace SMD
158
159
// ---------------------------------------------------------------------------
160
/** Used to load Half-life 1 and 2 SMD models
161
*/
162
class ASSIMP_API SMDImporter : public BaseImporter {
163
public:
164
    SMDImporter();
165
891
    ~SMDImporter() override = default;
166
167
    // -------------------------------------------------------------------
168
    /** Returns whether the class can handle the format of the given file.
169
     * See BaseImporter::CanRead() for details.
170
     */
171
    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
172
        bool checkSig) const override;
173
174
    // -------------------------------------------------------------------
175
    /** Called prior to ReadFile().
176
     * The function is a request to the importer to update its configuration
177
     * basing on the Importer's configuration property list.
178
     */
179
    void SetupProperties(const Importer* pImp) override;
180
181
protected:
182
    // -------------------------------------------------------------------
183
    /** Return importer meta information.
184
     * See #BaseImporter::GetInfo for the details
185
     */
186
    const aiImporterDesc* GetInfo () const override;
187
188
    // -------------------------------------------------------------------
189
    /** Imports the given file into the given scene structure.
190
    * See BaseImporter::InternReadFile() for details
191
    */
192
    void InternReadFile( const std::string& pFile, aiScene* pScene,
193
        IOSystem* pIOHandler) override;
194
195
    // -------------------------------------------------------------------
196
    /** Parse the SMD file and create the output scene
197
    */
198
    void ParseFile();
199
    void ReadSmd(const std::string &pFile, IOSystem* pIOHandler);
200
201
    // -------------------------------------------------------------------
202
    /** Parse the triangles section of the SMD file
203
     * \param szCurrent Current position in the file. Points to the first
204
     * data line of the section.
205
     * \param szCurrentOut Receives a pointer to the heading line of
206
     * the next section (or to EOF)
207
    */
208
    void ParseTrianglesSection(const char* szCurrent,
209
            const char **szCurrentOut, const char *end);
210
211
    // -------------------------------------------------------------------
212
    /** Parse the vertex animation section in VTA files
213
     * \param szCurrent Current position in the file. Points to the first
214
     * data line of the section.
215
     * \param szCurrentOut Receives a pointer to the heading line of
216
     * the next section (or to EOF)
217
    */
218
    void ParseVASection(const char* szCurrent,
219
            const char **szCurrentOu, const char *end);
220
221
    // -------------------------------------------------------------------
222
    /** Parse the nodes section of the SMD file
223
     * \param szCurrent Current position in the file. Points to the first
224
     * data line of the section.
225
     * \param szCurrentOut Receives a pointer to the heading line of
226
     * the next section (or to EOF)
227
    */
228
    void ParseNodesSection(const char* szCurrent,
229
            const char **szCurrentOut, const char *end);
230
231
    // -------------------------------------------------------------------
232
    /** Parse the skeleton section of the SMD file
233
     * \param szCurrent Current position in the file. Points to the first
234
     * data line of the section.
235
     * \param szCurrentOut Receives a pointer to the heading line of
236
     * the next section (or to EOF)
237
    */
238
    void ParseSkeletonSection(const char* szCurrent,
239
            const char **szCurrentOut, const char *end);
240
241
    // -------------------------------------------------------------------
242
    /** Parse a single triangle in the SMD file
243
     * \param szCurrent Current position in the file. Points to the first
244
     * data line of the section.
245
     * \param szCurrentOut Receives the output cursor position
246
    */
247
    void ParseTriangle(const char* szCurrent,
248
            const char **szCurrentOut, const char *end);
249
250
    // -------------------------------------------------------------------
251
    /** Parse a single vertex in the SMD file
252
     * \param szCurrent Current position in the file. Points to the first
253
     * data line of the section.
254
     * \param szCurrentOut Receives the output cursor position
255
     * \param vertex Vertex to be filled
256
    */
257
    void ParseVertex(const char* szCurrent,
258
            const char **szCurrentOut, const char *end, SMD::Vertex &vertex,
259
        bool bVASection = false);
260
261
    // -------------------------------------------------------------------
262
    /** Get  the index of a texture. If the texture was not yet known
263
     *  it will be added to the internal texture list.
264
     * \param filename Name of the texture
265
     * \return Value texture index
266
     */
267
    unsigned int GetTextureIndex(const std::string& filename);
268
269
    // -------------------------------------------------------------------
270
    /** Parse a line in the skeleton section
271
     */
272
    void ParseSkeletonElement(const char* szCurrent,
273
            const char **szCurrentOut, const char *end, int iTime);
274
275
    // -------------------------------------------------------------------
276
    /** Parse a line in the nodes section
277
     */
278
    void ParseNodeInfo(const char* szCurrent,
279
            const char **szCurrentOut, const char *end);
280
281
    // -------------------------------------------------------------------
282
    /** Parse a floating-point value
283
     */
284
    bool ParseFloat(const char* szCurrent,
285
            const char **szCurrentOut, const char *end, float &out);
286
287
    // -------------------------------------------------------------------
288
    /** Parse an unsigned integer. There may be no sign!
289
     */
290
    bool ParseUnsignedInt(const char* szCurrent,
291
            const char **szCurrentOut, const char *end, unsigned int &out);
292
293
    // -------------------------------------------------------------------
294
    /** Parse a signed integer. Signs (+,-) are handled.
295
     */
296
    bool ParseSignedInt(const char* szCurrent,
297
            const char **szCurrentOut, const char *end, int &out);
298
299
    // -------------------------------------------------------------------
300
    /** Fix invalid time values in the file
301
     */
302
    void FixTimeValues();
303
304
    // -------------------------------------------------------------------
305
    /** Add all children of a bone as sub-nodes to a node
306
     * \param pcNode Parent node
307
     * \param iParent Parent bone index
308
     */
309
    void AddBoneChildren(aiNode* pcNode, uint32_t iParent);
310
311
    // -------------------------------------------------------------------
312
    /** Build output meshes/materials/nodes/animations
313
     */
314
    void CreateOutputMeshes();
315
    void CreateOutputNodes();
316
    void CreateOutputAnimations(const std::string &pFile, IOSystem* pIOHandler);
317
    void CreateOutputAnimation(int index, const std::string &name);
318
    void GetAnimationFileList(const std::string &pFile, IOSystem* pIOHandler, std::vector<std::tuple<std::string, std::string>>& outList);
319
    void CreateOutputMaterials();
320
321
322
    // -------------------------------------------------------------------
323
    /** Print a log message together with the current line number
324
     */
325
    void LogErrorNoThrow(const char* msg);
326
    void LogWarning(const char* msg);
327
328
329
    // -------------------------------------------------------------------
330
2.37M
    inline bool SkipLine( const char* in, const char** out, const char *end) {
331
2.37M
        Assimp::SkipLine(in, out, end);
332
2.37M
        ++iLineNumber;
333
2.37M
        return true;
334
2.37M
    }
335
    // -------------------------------------------------------------------
336
2.38M
    inline bool SkipSpacesAndLineEnd(const char *in, const char **out, const char *end) {
337
2.38M
        ++iLineNumber;
338
2.38M
        return Assimp::SkipSpacesAndLineEnd(in, out, end);
339
2.38M
    }
340
341
private:
342
343
    /** Configuration option: frame to be loaded */
344
    unsigned int configFrameID;
345
346
    /** Buffer to hold the loaded file */
347
    std::vector<char> mBuffer;
348
    char *mEnd;
349
350
    /** Output scene to be filled
351
    */
352
    aiScene* pScene;
353
354
    /** Size of the input file in bytes
355
     */
356
    unsigned int iFileSize;
357
358
    /** Array of textures found in the file
359
     */
360
    std::vector<std::string> aszTextures;
361
362
    /** Array of triangles found in the file
363
     */
364
    std::vector<SMD::Face> asTriangles;
365
366
    /** Array of bones found in the file
367
     */
368
    std::vector<SMD::Bone> asBones;
369
370
    /** Smallest frame index found in the skeleton
371
     */
372
    int iSmallestFrame;
373
374
    /** Length of the whole animation, in frames
375
     */
376
    double dLengthOfAnim;
377
378
    /** Do we have texture coordinates?
379
     */
380
    bool bHasUVs;
381
382
    /** Current line number
383
     */
384
    unsigned int iLineNumber;
385
386
    bool bLoadAnimationList = true;
387
    bool noSkeletonMesh = false;
388
};
389
390
} // end of namespace Assimp
391
392
#endif // AI_SMDIMPORTER_H_INC