Coverage Report

Created: 2025-12-05 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/LWO/LWOLoader.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 Declaration of the LWO importer class. */
43
#pragma once
44
#ifndef AI_LWOLOADER_H_INCLUDED
45
#define AI_LWOLOADER_H_INCLUDED
46
47
#include "LWOFileData.h"
48
#include <assimp/BaseImporter.h>
49
#include <assimp/material.h>
50
#include <assimp/DefaultLogger.hpp>
51
52
#include <map>
53
54
struct aiTexture;
55
struct aiNode;
56
struct aiMaterial;
57
58
namespace Assimp {
59
using namespace LWO;
60
61
// ---------------------------------------------------------------------------
62
/** Class to load LWO files.
63
 *
64
 *  @note  Methods named "xxxLWO2[xxx]" are used with the newer LWO2 format.
65
 *         Methods named "xxxLWOB[xxx]" are used with the older LWOB format.
66
 *         Methods named "xxxLWO[xxx]" are used with both formats.
67
 *         Methods named "xxx" are used to preprocess the loaded data -
68
 *         they aren't specific to one format version
69
*/
70
// ---------------------------------------------------------------------------
71
class LWOImporter : public BaseImporter {
72
public:
73
    LWOImporter();
74
    ~LWOImporter() override;
75
76
    // -------------------------------------------------------------------
77
    /** Returns whether the class can handle the format of the given file.
78
     * See BaseImporter::CanRead() for details.
79
     */
80
    bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
81
            bool checkSig) const override;
82
83
    // -------------------------------------------------------------------
84
    /** Called prior to ReadFile().
85
    * The function is a request to the importer to update its configuration
86
    * basing on the Importer's configuration property list.
87
    */
88
    void SetupProperties(const Importer *pImp) override;
89
90
protected:
91
    // -------------------------------------------------------------------
92
    // Get list of supported extensions
93
    const aiImporterDesc *GetInfo() const override;
94
95
    // -------------------------------------------------------------------
96
    /** Imports the given file into the given scene structure.
97
    * See BaseImporter::InternReadFile() for details
98
    */
99
    void InternReadFile(const std::string &pFile, aiScene *pScene,
100
            IOSystem *pIOHandler) override;
101
102
private:
103
    // -------------------------------------------------------------------
104
    /** Loads a LWO file in the older LWOB format (LW < 6)
105
     */
106
    void LoadLWOBFile();
107
108
    // -------------------------------------------------------------------
109
    /** Loads a LWO file in the newer LWO2 format (LW >= 6)
110
     */
111
    void LoadLWO2File();
112
113
    // -------------------------------------------------------------------
114
    /** Parsing functions used for all file format versions
115
    */
116
    inline void GetS0(std::string &out, unsigned int max);
117
    inline float GetF4();
118
    inline float GetF8();
119
    inline uint64_t GetU8();
120
    inline uint32_t GetU4();
121
    inline uint16_t GetU2();
122
    inline uint8_t GetU1();
123
124
    // -------------------------------------------------------------------
125
    /** Loads a surface chunk from an LWOB file
126
     *  @param size Maximum size to be read, in bytes.
127
     */
128
    void LoadLWOBSurface(unsigned int size);
129
130
    // -------------------------------------------------------------------
131
    /** Loads a surface chunk from an LWO2 file
132
     *  @param size Maximum size to be read, in bytes.
133
     */
134
    void LoadLWO2Surface(unsigned int size);
135
    void LoadLWO3Surface(unsigned int size);
136
137
    // -------------------------------------------------------------------
138
    /** Loads a texture block from a LWO2 file.
139
     *  @param size Maximum size to be read, in bytes.
140
     *  @param head Header of the SUF.BLOK header
141
     */
142
    void LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader *head,
143
            unsigned int size);
144
145
    // -------------------------------------------------------------------
146
    /** Loads a shader block from a LWO2 file.
147
     *  @param size Maximum size to be read, in bytes.
148
     *  @param head Header of the SUF.BLOK header
149
     */
150
    void LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader *head,
151
            unsigned int size);
152
153
    // -------------------------------------------------------------------
154
    /** Loads an image map from a LWO2 file
155
     *  @param size Maximum size to be read, in bytes.
156
     *  @param tex Texture object to be filled
157
     */
158
    void LoadLWO2ImageMap(unsigned int size, LWO::Texture &tex);
159
    void LoadLWO2Gradient(unsigned int size, LWO::Texture &tex);
160
    void LoadLWO2Procedural(unsigned int size, LWO::Texture &tex);
161
162
    // loads the header - used by thethree functions above
163
    void LoadLWO2TextureHeader(unsigned int size, LWO::Texture &tex);
164
165
    // -------------------------------------------------------------------
166
    /** Loads the LWO tag list from the file
167
     *  @param size Maximum size to be read, in bytes.
168
     */
169
    void LoadLWOTags(unsigned int size);
170
171
    // -------------------------------------------------------------------
172
    /** Load polygons from a POLS chunk
173
     *  @param length Size of the chunk
174
    */
175
    void LoadLWO2Polygons(unsigned int length);
176
    void LoadLWOBPolygons(unsigned int length);
177
178
    // -------------------------------------------------------------------
179
    /** Load polygon tags from a PTAG chunk
180
     *  @param length Size of the chunk
181
    */
182
    void LoadLWO2PolygonTags(unsigned int length);
183
184
    // -------------------------------------------------------------------
185
    /** Load a vertex map from a VMAP/VMAD chunk
186
     *  @param length Size of the chunk
187
     *  @param perPoly Operate on per-polygon base?
188
    */
189
    void LoadLWO2VertexMap(unsigned int length, bool perPoly);
190
191
    // -------------------------------------------------------------------
192
    /** Load polygons from a PNTS chunk
193
     *  @param length Size of the chunk
194
    */
195
    void LoadLWOPoints(unsigned int length);
196
197
    // -------------------------------------------------------------------
198
    /** Load a clip from a CLIP chunk
199
     *  @param length Size of the chunk
200
    */
201
    void LoadLWO2Clip(unsigned int length);
202
    void LoadLWO3Clip(unsigned int length);
203
204
    // -------------------------------------------------------------------
205
    /** Load an envelope from an EVL chunk
206
     *  @param length Size of the chunk
207
    */
208
    void LoadLWO2Envelope(unsigned int length);
209
    void LoadLWO3Envelope(unsigned int length);
210
211
    // -------------------------------------------------------------------
212
    /** Load an nodal blocks from surface form
213
     *  @param length Size of the chunk
214
    */
215
    void LoadNodalBlocks(unsigned int length);
216
    void LoadNodes(unsigned int length);
217
    void LoadNodeTag(unsigned int length);
218
    void LoadNodeData(unsigned int length);
219
220
    // -------------------------------------------------------------------
221
    /** Count vertices and faces in a LWOB/LWO2 file
222
    */
223
    void CountVertsAndFacesLWO2(unsigned int &verts,
224
            unsigned int &faces,
225
            uint16_t *&cursor,
226
            const uint16_t *const end,
227
            unsigned int max = UINT_MAX);
228
229
    void CountVertsAndFacesLWOB(unsigned int &verts,
230
            unsigned int &faces,
231
            LE_NCONST uint16_t *&cursor,
232
            const uint16_t *const end,
233
            unsigned int max = UINT_MAX);
234
235
    // -------------------------------------------------------------------
236
    /** Read vertices and faces in a LWOB/LWO2 file
237
    */
238
    void CopyFaceIndicesLWO2(LWO::FaceList::iterator &it,
239
            uint16_t *&cursor,
240
            const uint16_t *const end);
241
242
    // -------------------------------------------------------------------
243
    void CopyFaceIndicesLWOB(LWO::FaceList::iterator &it,
244
            LE_NCONST uint16_t *&cursor,
245
            const uint16_t *const end,
246
            unsigned int max = UINT_MAX);
247
248
    // -------------------------------------------------------------------
249
    /** Resolve the tag and surface lists that have been loaded.
250
    *   Generates the mMapping table.
251
    */
252
    void ResolveTags();
253
254
    // -------------------------------------------------------------------
255
    /** Resolve the clip list that has been loaded.
256
    *   Replaces clip references with real clips.
257
    */
258
    void ResolveClips();
259
260
    // -------------------------------------------------------------------
261
    /** Add a texture list to an output material description.
262
     *
263
     *  @param pcMat Output material
264
     *  @param in Input texture list
265
     *  @param type Type identifier of the texture list
266
    */
267
    bool HandleTextures(aiMaterial *pcMat, const TextureList &in,
268
            aiTextureType type);
269
270
    // -------------------------------------------------------------------
271
    /** Adjust a texture path
272
    */
273
    void AdjustTexturePath(std::string &out);
274
275
    // -------------------------------------------------------------------
276
    /** Convert a LWO surface description to an ASSIMP material
277
    */
278
    void ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat);
279
280
    // -------------------------------------------------------------------
281
    /** Get a list of all UV/VC channels required by a specific surface.
282
     *
283
     *  @param surf Working surface
284
     *  @param layer Working layer
285
     *  @param out Output list. The members are indices into the
286
     *    UV/VC channel lists of the layer
287
    */
288
    void FindUVChannels(/*const*/ LWO::Surface &surf,
289
            LWO::SortedRep &sorted,
290
            /*const*/ LWO::Layer &layer,
291
            unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]);
292
293
    // -------------------------------------------------------------------
294
    char FindUVChannels(LWO::TextureList &list,
295
            LWO::Layer &layer, LWO::UVChannel &uv, unsigned int next);
296
297
    // -------------------------------------------------------------------
298
    void FindVCChannels(const LWO::Surface &surf,
299
            LWO::SortedRep &sorted,
300
            const LWO::Layer &layer,
301
            unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]);
302
303
    // -------------------------------------------------------------------
304
    /** Generate the final node graph
305
     *  Unused nodes are deleted.
306
     *  @param apcNodes Flat list of nodes
307
    */
308
    void GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes);
309
310
    // -------------------------------------------------------------------
311
    /** Add children to a node
312
     *  @param node Node to become a father
313
     *  @param parent Index of the node
314
     *  @param apcNodes Flat list of nodes - used nodes are set to nullptr.
315
    */
316
    void AddChildren(aiNode *node, uint16_t parent,
317
            std::vector<aiNode *> &apcNodes);
318
319
    // -------------------------------------------------------------------
320
    /** Read a variable sized integer
321
     *  @param inout Input and output buffer
322
    */
323
    int ReadVSizedIntLWO2(uint8_t *&inout);
324
325
    // -------------------------------------------------------------------
326
    /** Assign a value from a VMAP to a vertex and all vertices
327
     *  attached to it.
328
     *  @param base VMAP destination data
329
     *  @param numRead Number of float's to be read
330
     *  @param idx Absolute index of the first vertex
331
     *  @param data Value of the VMAP to be assigned - read numRead
332
     *    floats from this array.
333
    */
334
    void DoRecursiveVMAPAssignment(VMapEntry *base, unsigned int numRead,
335
            unsigned int idx, float *data);
336
337
    // -------------------------------------------------------------------
338
    /** Compute normal vectors for a mesh
339
     *  @param mesh Input mesh
340
     *  @param smoothingGroups Smoothing-groups-per-face array
341
     *  @param surface Surface for the mesh
342
    */
343
    void ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &smoothingGroups,
344
            const LWO::Surface &surface);
345
346
    // -------------------------------------------------------------------
347
    /** Setup a new texture after the corresponding chunk was
348
     *  encountered in the file.
349
     *  @param list Texture list
350
     *  @param size Maximum number of bytes to be read
351
     *  @return Pointer to new texture
352
    */
353
    LWO::Texture *SetupNewTextureLWOB(LWO::TextureList &list,
354
            unsigned int size);
355
356
protected:
357
    /** true if the file is a LWO2 file*/
358
    bool mIsLWO2;
359
360
    /** true if the file is a LXOB file*/
361
    bool mIsLXOB;
362
363
    bool mIsLWO3;
364
365
    /** Temporary list of layers from the file */
366
    LayerList *mLayers;
367
368
    /** Pointer to the current layer */
369
    LWO::Layer *mCurLayer;
370
371
    /** Temporary tag list from the file */
372
    TagList *mTags;
373
374
    /** Mapping table to convert from tag to surface indices.
375
        UINT_MAX indicates that a no corresponding surface is available */
376
    TagMappingTable *mMapping;
377
378
    /** Temporary surface list from the file */
379
    SurfaceList *mSurfaces;
380
381
    /** Temporary clip list from the file */
382
    ClipList mClips;
383
384
    /** Temporary envelope list from the file */
385
    EnvelopeList mEnvelopes;
386
387
    /** file buffer */
388
    uint8_t *mFileBuffer;
389
390
    /** Size of the file, in bytes */
391
    unsigned int fileSize;
392
393
    /** Output scene */
394
    aiScene *mScene;
395
396
    /** Configuration option: speed flag set? */
397
    bool configSpeedFlag;
398
399
    /** Configuration option: index of layer to be loaded */
400
    unsigned int configLayerIndex;
401
402
    /** Configuration option: name of layer to be loaded */
403
    std::string configLayerName;
404
405
    /** True if we have a named layer */
406
    bool hasNamedLayer;
407
};
408
409
// ------------------------------------------------------------------------------------------------
410
0
inline float LWOImporter::GetF4() {
411
0
    float f;
412
0
    ::memcpy(&f, mFileBuffer, 4);
413
0
    mFileBuffer += 4;
414
0
    AI_LSWAP4(f);
415
0
    return f;
416
0
}
417
418
0
inline float LWOImporter::GetF8() {
419
0
    double f;
420
0
    ::memcpy(&f, mFileBuffer, 8);
421
0
    mFileBuffer += 8;
422
0
    AI_LSWAP8(f);
423
0
    return (float)f;
424
0
}
425
426
0
inline uint64_t LWOImporter::GetU8() {
427
0
    uint64_t f;
428
0
    ::memcpy(&f, mFileBuffer, 8);
429
0
    mFileBuffer += 8;
430
0
    AI_LSWAP8(f);
431
0
    return f;
432
0
}
433
434
// ------------------------------------------------------------------------------------------------
435
0
inline uint32_t LWOImporter::GetU4() {
436
0
    uint32_t f;
437
0
    ::memcpy(&f, mFileBuffer, 4);
438
0
    mFileBuffer += 4;
439
0
    AI_LSWAP4(f);
440
0
    return f;
441
0
}
442
443
// ------------------------------------------------------------------------------------------------
444
0
inline uint16_t LWOImporter::GetU2() {
445
0
    uint16_t f;
446
0
    ::memcpy(&f, mFileBuffer, 2);
447
0
    mFileBuffer += 2;
448
0
    AI_LSWAP2(f);
449
0
    return f;
450
0
}
451
452
// ------------------------------------------------------------------------------------------------
453
0
inline uint8_t LWOImporter::GetU1() {
454
0
    return *mFileBuffer++;
455
0
}
456
457
// ------------------------------------------------------------------------------------------------
458
0
inline int LWOImporter::ReadVSizedIntLWO2(uint8_t *&inout) {
459
0
    int i;
460
0
    int c = *inout;
461
0
    inout++;
462
0
    if (c != 0xFF) {
463
0
        i = c << 8;
464
0
        c = *inout;
465
0
        inout++;
466
0
        i |= c;
467
0
    } else {
468
0
        c = *inout;
469
0
        inout++;
470
0
        i = c << 16;
471
0
        c = *inout;
472
0
        inout++;
473
0
        i |= c << 8;
474
0
        c = *inout;
475
0
        inout++;
476
0
        i |= c;
477
0
    }
478
0
    return i;
479
0
}
480
481
// ------------------------------------------------------------------------------------------------
482
0
inline void LWOImporter::GetS0(std::string &out, unsigned int max) {
483
0
    unsigned int iCursor = 0;
484
0
    const char *sz = (const char *)mFileBuffer;
485
0
    while (*mFileBuffer) {
486
0
        if (++iCursor > max) {
487
0
            ASSIMP_LOG_WARN("LWO: Invalid file, string is is too long");
488
0
            break;
489
0
        }
490
0
        ++mFileBuffer;
491
0
    }
492
0
    size_t len = (size_t)((const char *)mFileBuffer - sz);
493
0
    out = std::string(sz, len);
494
0
    mFileBuffer += (len & 0x1 ? 1 : 2);
495
0
}
496
497
} // end of namespace Assimp
498
499
#endif // AI_LWOIMPORTER_H_INCLUDED