Coverage Report

Created: 2026-01-25 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/OpenGEX/OpenGEXImporter.cpp
Line
Count
Source
1
/*
2
Open Asset Import Library (assimp)
3
----------------------------------------------------------------------
4
5
Copyright (c) 2006-2026, 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
#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
42
43
#include "OpenGEXImporter.h"
44
#include "PostProcessing/MakeVerboseFormat.h"
45
46
#include <assimp/DefaultIOSystem.h>
47
#include <assimp/StringComparison.h>
48
#include <assimp/StringUtils.h>
49
#include <assimp/DefaultLogger.hpp>
50
#include <assimp/ai_assert.h>
51
#include <assimp/importerdesc.h>
52
#include <assimp/scene.h>
53
#include <openddlparser/OpenDDLParser.h>
54
55
static constexpr aiImporterDesc desc = {
56
    "Open Game Engine Exchange",
57
    "",
58
    "",
59
    "",
60
    aiImporterFlags_SupportTextFlavour,
61
    0,
62
    0,
63
    0,
64
    0,
65
    "ogex"
66
};
67
68
namespace Grammar {
69
    static constexpr char MetricType[] = "Metric";
70
    static constexpr char Metric_DistanceType[] = "distance";
71
    static constexpr char Metric_AngleType[] = "angle";
72
    static constexpr char Metric_TimeType[] = "time";
73
    static constexpr char Metric_UpType[] = "up";
74
    static constexpr char NameType[] = "Name";
75
    static constexpr char ObjectRefType[] = "ObjectRef";
76
    static constexpr char MaterialRefType[] = "MaterialRef";
77
    static constexpr char MetricKeyType[] = "key";
78
    static constexpr char GeometryNodeType[] = "GeometryNode";
79
    static constexpr char CameraNodeType[] = "CameraNode";
80
    static constexpr char LightNodeType[] = "LightNode";
81
    static constexpr char GeometryObjectType[] = "GeometryObject";
82
    static constexpr char CameraObjectType[] = "CameraObject";
83
    static constexpr char LightObjectType[] = "LightObject";
84
    static constexpr char TransformType[] = "Transform";
85
    static constexpr char MeshType[] = "Mesh";
86
    static constexpr char VertexArrayType[] = "VertexArray";
87
    static constexpr char IndexArrayType[] = "IndexArray";
88
    static constexpr char MaterialType[] = "Material";
89
    static constexpr char ColorType[] = "Color";
90
    static constexpr char ParamType[] = "Param";
91
    static constexpr char TextureType[] = "Texture";
92
    static constexpr char AttenType[] = "Atten";
93
94
    static constexpr char DiffuseColorToken[] = "diffuse";
95
    static constexpr char SpecularColorToken[] = "specular";
96
    static constexpr char EmissionColorToken[] = "emission";
97
98
    static constexpr char DiffuseTextureToken[] = "diffuse";
99
    static constexpr char DiffuseSpecularTextureToken[] = "specular";
100
    static constexpr char SpecularPowerTextureToken[] = "specular_power";
101
    static constexpr char EmissionTextureToken[] = "emission";
102
    static constexpr char OpacyTextureToken[] = "opacity";
103
    static constexpr char TransparencyTextureToken[] = "transparency";
104
    static constexpr char NormalTextureToken[] = "normal";
105
106
    enum TokenType {
107
        NoneType = -1,
108
        MetricToken,
109
        NameToken,
110
        ObjectRefToken,
111
        MaterialRefToken,
112
        MetricKeyToken,
113
        GeometryNodeToken,
114
        CameraNodeToken,
115
        LightNodeToken,
116
        GeometryObjectToken,
117
        CameraObjectToken,
118
        LightObjectToken,
119
        TransformToken,
120
        MeshToken,
121
        VertexArrayToken,
122
        IndexArrayToken,
123
        MaterialToken,
124
        ColorToken,
125
        ParamToken,
126
        TextureToken,
127
        AttenToken
128
    };
129
130
    static const std::string ValidMetricToken[4] = {
131
        Metric_DistanceType,
132
        Metric_AngleType,
133
        Metric_TimeType,
134
        Metric_UpType
135
    };
136
137
4
    static int isValidMetricType(const char *token) {
138
4
        if (nullptr == token) {
139
0
            return false;
140
0
        }
141
142
4
        int idx = -1;
143
10
        for (size_t i = 0; i < 4; i++) {
144
10
            if (ValidMetricToken[i] == token) {
145
4
                idx = (int)i;
146
4
                break;
147
4
            }
148
10
        }
149
150
4
        return idx;
151
4
    }
152
153
57
    static TokenType matchTokenType(const char *tokenType) {
154
57
        const size_t len = std::strlen(tokenType);
155
57
        if (0 == strncmp(MetricType, tokenType, len)) {
156
5
            return MetricToken;
157
52
        } else if (0 == strncmp(NameType, tokenType, len)) {
158
5
            return NameToken;
159
47
        } else if (0 == strncmp(ObjectRefType, tokenType, len)) {
160
5
            return ObjectRefToken;
161
42
        } else if (0 == strncmp(MaterialRefType, tokenType, len)) {
162
4
            return MaterialRefToken;
163
38
        } else if (0 == strncmp(MetricKeyType, tokenType, len)) {
164
0
            return MetricKeyToken;
165
38
        } else if (0 == strncmp(GeometryNodeType, tokenType, len)) {
166
2
            return GeometryNodeToken;
167
36
        } else if (0 == strncmp(CameraNodeType, tokenType, len)) {
168
3
            return CameraNodeToken;
169
33
        } else if (0 == strncmp(LightNodeType, tokenType, len)) {
170
3
            return LightNodeToken;
171
30
        } else if (0 == strncmp(GeometryObjectType, tokenType, len)) {
172
2
            return GeometryObjectToken;
173
28
        } else if (0 == strncmp(CameraObjectType, tokenType, len)) {
174
3
            return CameraObjectToken;
175
25
        } else if (0 == strncmp(LightObjectType, tokenType, len)) {
176
3
            return LightObjectToken;
177
22
        } else if (0 == strncmp(TransformType, tokenType, len)) {
178
5
            return TransformToken;
179
17
        } else if (0 == strncmp(MeshType, tokenType, len)) {
180
2
            return MeshToken;
181
15
        } else if (0 == strncmp(VertexArrayType, tokenType, len)) {
182
4
            return VertexArrayToken;
183
11
        } else if (0 == strncmp(IndexArrayType, tokenType, len)) {
184
2
            return IndexArrayToken;
185
9
        } else if (0 == strncmp(MaterialType, tokenType, len)) {
186
0
            return MaterialToken;
187
9
        } else if (0 == strncmp(ColorType, tokenType, len)) {
188
0
            return ColorToken;
189
9
        } else if (0 == strncmp(ParamType, tokenType, len)) {
190
9
            return ParamToken;
191
9
        } else if (0 == strncmp(TextureType, tokenType, len)) {
192
0
            return TextureToken;
193
0
        } else if (0 == strncmp(AttenType, tokenType, len)) {
194
0
            return AttenToken;
195
0
        }
196
197
0
        return NoneType;
198
57
    }
199
} // Namespace Grammar
200
201
namespace Assimp {
202
namespace OpenGEX {
203
204
USE_ODDLPARSER_NS
205
206
//------------------------------------------------------------------------------------------------
207
6
static void propId2StdString(Property *prop, std::string &name, std::string &key) {
208
6
    name = key = std::string();
209
6
    if (nullptr == prop) {
210
0
        return;
211
0
    }
212
213
6
    if (nullptr != prop->m_key) {
214
#ifdef ASSIMP_USE_HUNTER
215
        name = prop->m_key->m_text.m_buffer;
216
#else
217
6
        name = prop->m_key->m_buffer;
218
6
#endif
219
6
        if (Value::ValueType::ddl_string == prop->m_value->m_type) {
220
6
            key = prop->m_value->getString();
221
6
        }
222
6
    }
223
6
}
224
225
//------------------------------------------------------------------------------------------------
226
10
static void logDDLParserMessage (LogSeverity severity, const std::string &rawmsg) {
227
10
    std::string msg = ai_str_toprintable(rawmsg);
228
10
    switch (severity) {
229
0
    case ddl_debug_msg: ASSIMP_LOG_DEBUG(msg);         break;
230
0
    case ddl_info_msg:  ASSIMP_LOG_INFO(msg);          break;
231
0
    case ddl_warn_msg:  ASSIMP_LOG_WARN(msg);          break;
232
10
    case ddl_error_msg: ASSIMP_LOG_ERROR(msg);         break;
233
0
    default:            ASSIMP_LOG_VERBOSE_DEBUG(msg); break;
234
10
    }
235
10
}
236
237
//------------------------------------------------------------------------------------------------
238
OpenGEXImporter::VertexContainer::VertexContainer() :
239
26.2k
        m_numColors(0), m_colors(nullptr), m_numUVComps(), m_textureCoords() {
240
    // empty
241
26.2k
}
242
243
//------------------------------------------------------------------------------------------------
244
26.2k
OpenGEXImporter::VertexContainer::~VertexContainer() {
245
26.2k
    delete[] m_colors;
246
247
209k
    for (auto &texcoords : m_textureCoords) {
248
209k
        delete[] texcoords;
249
209k
    }
250
26.2k
}
251
252
//------------------------------------------------------------------------------------------------
253
OpenGEXImporter::RefInfo::RefInfo(aiNode *node, Type type, std::vector<std::string> &names) :
254
4
        m_node(node),
255
4
        m_type(type),
256
4
        m_Names(names) {
257
    // empty
258
4
}
259
260
//------------------------------------------------------------------------------------------------
261
OpenGEXImporter::OpenGEXImporter() :
262
26.2k
        m_root(nullptr),
263
26.2k
        m_nodeChildMap(),
264
26.2k
        m_mesh2refMap(),
265
26.2k
        m_material2refMap(),
266
26.2k
        m_ctx(nullptr),
267
26.2k
        m_metrics(),
268
26.2k
        m_currentNode(nullptr),
269
26.2k
        m_currentVertices(),
270
26.2k
        m_currentMesh(nullptr),
271
26.2k
        m_currentMaterial(nullptr),
272
26.2k
        m_currentLight(nullptr),
273
26.2k
        m_currentCamera(nullptr),
274
26.2k
        m_tokenType(Grammar::NoneType),
275
26.2k
        m_materialCache(),
276
26.2k
        m_cameraCache(),
277
26.2k
        m_lightCache(),
278
26.2k
        m_nodeStack(),
279
26.2k
        m_unresolvedRefStack() {
280
    // empty
281
26.2k
}
282
283
//------------------------------------------------------------------------------------------------
284
110
bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
285
110
    static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
286
110
    return SearchFileHeaderForToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens));
287
110
}
288
289
//------------------------------------------------------------------------------------------------
290
14
void OpenGEXImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
291
    // open source file
292
14
    std::unique_ptr<IOStream> file(pIOHandler->Open(filename, "rb"));
293
14
    if (!file) {
294
0
        throw DeadlyImportError("Failed to open file ", filename);
295
0
    }
296
297
14
    std::vector<char> buffer;
298
14
    TextFileToBuffer(file.get(), buffer);
299
300
14
    OpenDDLParser myParser;
301
14
    myParser.setLogCallback(&logDDLParserMessage);
302
14
    myParser.setBuffer(&buffer[0], buffer.size());
303
14
    bool success(myParser.parse());
304
14
    if (success) {
305
1
        m_ctx = myParser.getContext();
306
1
        pScene->mRootNode = new aiNode;
307
1
        pScene->mRootNode->mName.Set(filename);
308
1
        handleNodes(m_ctx->m_root, pScene);
309
1
    }
310
311
14
    copyMeshes(pScene);
312
14
    copyCameras(pScene);
313
    // TODO: lights only partially implemented and breaking model import
314
//    copyLights(pScene);
315
14
    copyMaterials(pScene);
316
14
    resolveReferences();
317
14
    createNodeTree(pScene);
318
14
}
319
320
//------------------------------------------------------------------------------------------------
321
26.2k
const aiImporterDesc *OpenGEXImporter::GetInfo() const {
322
26.2k
    return &desc;
323
26.2k
}
324
325
//------------------------------------------------------------------------------------------------
326
14
void OpenGEXImporter::SetupProperties(const Importer *pImp) {
327
14
    if (nullptr == pImp) {
328
0
        return;
329
0
    }
330
14
}
331
332
//------------------------------------------------------------------------------------------------
333
13
void OpenGEXImporter::handleNodes(DDLNode *node, aiScene *pScene) {
334
13
    if (nullptr == node) {
335
0
        return;
336
0
    }
337
338
13
    DDLNode::DllNodeList children = node->getChildNodeList();
339
70
    for (DDLNode::DllNodeList::iterator it = children.begin(); it != children.end(); ++it) {
340
57
        Grammar::TokenType tokenType(Grammar::matchTokenType((*it)->getType().c_str()));
341
57
        switch (tokenType) {
342
5
        case Grammar::MetricToken:
343
5
            handleMetricNode(*it, pScene);
344
5
            break;
345
346
5
        case Grammar::NameToken:
347
5
            handleNameNode(*it, pScene);
348
5
            break;
349
350
5
        case Grammar::ObjectRefToken:
351
5
            handleObjectRefNode(*it, pScene);
352
5
            break;
353
354
4
        case Grammar::MaterialRefToken:
355
4
            handleMaterialRefNode(*it, pScene);
356
4
            break;
357
358
0
        case Grammar::MetricKeyToken:
359
0
            break;
360
361
2
        case Grammar::GeometryNodeToken:
362
2
            handleGeometryNode(*it, pScene);
363
2
            break;
364
365
3
        case Grammar::CameraNodeToken:
366
3
            handleCameraNode(*it, pScene);
367
3
            break;
368
369
3
        case Grammar::LightNodeToken:
370
            // TODO: lights only partially implemented and breaking model import
371
//            handleLightNode(*it, pScene);
372
3
            break;
373
374
2
        case Grammar::GeometryObjectToken:
375
2
            handleGeometryObject(*it, pScene);
376
2
            break;
377
378
3
        case Grammar::CameraObjectToken:
379
3
            handleCameraObject(*it, pScene);
380
3
            break;
381
382
3
        case Grammar::LightObjectToken:
383
            // TODO: lights only partially implemented and breaking model import
384
//            handleLightObject(*it, pScene);
385
3
            break;
386
387
5
        case Grammar::TransformToken:
388
5
            handleTransformNode(*it, pScene);
389
5
            break;
390
391
2
        case Grammar::MeshToken:
392
2
            handleMeshNode(*it, pScene);
393
2
            break;
394
395
4
        case Grammar::VertexArrayToken:
396
4
            handleVertexArrayNode(*it, pScene);
397
4
            break;
398
399
2
        case Grammar::IndexArrayToken:
400
2
            handleIndexArrayNode(*it, pScene);
401
2
            break;
402
403
0
        case Grammar::MaterialToken:
404
0
            handleMaterialNode(*it, pScene);
405
0
            break;
406
407
0
        case Grammar::ColorToken:
408
0
            handleColorNode(*it, pScene);
409
0
            break;
410
411
9
        case Grammar::ParamToken:
412
9
            handleParamNode(*it, pScene);
413
9
            break;
414
415
0
        case Grammar::TextureToken:
416
0
            handleTextureNode(*it, pScene);
417
0
            break;
418
419
0
        default:
420
0
            break;
421
57
        }
422
57
    }
423
13
}
424
425
//------------------------------------------------------------------------------------------------
426
5
void OpenGEXImporter::handleMetricNode(DDLNode *node, aiScene * /*pScene*/) {
427
5
    if (nullptr == node || nullptr == m_ctx) {
428
0
        return;
429
0
    }
430
431
5
    if (m_ctx->m_root != node->getParent()) {
432
0
        return;
433
0
    }
434
435
5
    Property *prop(node->getProperties());
436
9
    while (nullptr != prop) {
437
4
        if (nullptr != prop->m_key) {
438
4
            if (Value::ValueType::ddl_string == prop->m_value->m_type) {
439
4
                std::string valName((char *)prop->m_value->m_data);
440
4
                int type(Grammar::isValidMetricType(valName.c_str()));
441
4
                if (Grammar::NoneType != type) {
442
4
                    Value *val(node->getValue());
443
4
                    if (nullptr != val) {
444
4
                        if (Value::ValueType::ddl_float == val->m_type) {
445
3
                            m_metrics[type].m_floatValue = val->getFloat();
446
3
                        } else if (Value::ValueType::ddl_int32 == val->m_type) {
447
0
                            m_metrics[type].m_intValue = val->getInt32();
448
1
                        } else if (Value::ValueType::ddl_string == val->m_type) {
449
1
                            m_metrics[type].m_stringValue = std::string(val->getString());
450
1
                        } else {
451
0
                            throw DeadlyImportError("OpenGEX: invalid data type for Metric node.");
452
0
                        }
453
4
                    }
454
4
                }
455
4
            }
456
4
        }
457
4
        prop = prop->m_next;
458
4
    }
459
5
}
460
461
//------------------------------------------------------------------------------------------------
462
5
void OpenGEXImporter::handleNameNode(DDLNode *node, aiScene * /*pScene*/) {
463
5
    if (nullptr == m_currentNode) {
464
0
        throw DeadlyImportError("No current node for name.");
465
0
    }
466
467
5
    Value *val(node->getValue());
468
5
    if (nullptr != val) {
469
5
        if (Value::ValueType::ddl_string != val->m_type) {
470
0
            throw DeadlyImportError("OpenGEX: invalid data type for value in node name.");
471
0
        }
472
473
5
        const std::string name(val->getString());
474
5
        if (m_tokenType == Grammar::GeometryNodeToken ||
475
                // TODO: lights only partially implemented and breaking model import
476
//                m_tokenType == Grammar::LightNodeToken ||
477
5
                m_tokenType == Grammar::CameraNodeToken) {
478
5
            m_currentNode->mName.Set(name.c_str());
479
5
        } else if (m_tokenType == Grammar::MaterialToken) {
480
0
            aiString aiName;
481
0
            aiName.Set(name);
482
0
            m_currentMaterial->AddProperty(&aiName, AI_MATKEY_NAME);
483
0
            m_material2refMap[name] = m_materialCache.size() - 1;
484
0
        }
485
5
    }
486
5
}
487
488
//------------------------------------------------------------------------------------------------
489
9
static void getRefNames(DDLNode *node, std::vector<std::string> &names) {
490
9
    ai_assert(nullptr != node);
491
492
9
    Reference *ref = node->getReferences();
493
9
    if (nullptr != ref) {
494
14
        for (size_t i = 0; i < ref->m_numRefs; i++) {
495
7
            Name *currentName(ref->m_referencedName[i]);
496
7
            if (nullptr != currentName && nullptr != currentName->m_id) {
497
#ifdef ASSIMP_USE_HUNTER
498
                const std::string name(currentName->m_id->m_text.m_buffer);
499
#else
500
7
                const std::string name(currentName->m_id->m_buffer);
501
7
#endif
502
7
                if (!name.empty()) {
503
7
                    names.push_back(name);
504
7
                }
505
7
            }
506
7
        }
507
7
    }
508
9
}
509
510
//------------------------------------------------------------------------------------------------
511
5
void OpenGEXImporter::handleObjectRefNode(DDLNode *node, aiScene * /*pScene*/) {
512
5
    if (nullptr == m_currentNode) {
513
0
        throw DeadlyImportError("No parent node for name.");
514
0
    }
515
516
5
    std::vector<std::string> objRefNames;
517
5
    getRefNames(node, objRefNames);
518
519
    // when we are dealing with a geometry node prepare the mesh cache
520
5
    if (m_tokenType == Grammar::GeometryNodeToken) {
521
2
        m_currentNode->mNumMeshes = static_cast<unsigned int>(objRefNames.size());
522
2
        m_currentNode->mMeshes = new unsigned int[objRefNames.size()];
523
2
        if (!objRefNames.empty()) {
524
2
            m_unresolvedRefStack.push_back(std::unique_ptr<RefInfo>(new RefInfo(m_currentNode, RefInfo::MeshRef, objRefNames)));
525
2
        }
526
3
    } else if (m_tokenType == Grammar::LightNodeToken) {
527
        // TODO!
528
3
    } else if (m_tokenType == Grammar::CameraNodeToken) {
529
        // TODO!
530
3
    }
531
5
}
532
533
//------------------------------------------------------------------------------------------------
534
4
void OpenGEXImporter::handleMaterialRefNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
535
4
    if (nullptr == m_currentNode) {
536
0
        throw DeadlyImportError("No parent node for name.");
537
0
    }
538
539
4
    std::vector<std::string> matRefNames;
540
4
    getRefNames(node, matRefNames);
541
4
    if (!matRefNames.empty()) {
542
2
        m_unresolvedRefStack.push_back(std::unique_ptr<RefInfo>(new RefInfo(m_currentNode, RefInfo::MaterialRef, matRefNames)));
543
2
    }
544
4
}
545
546
//------------------------------------------------------------------------------------------------
547
2
void OpenGEXImporter::handleGeometryNode(DDLNode *node, aiScene *pScene) {
548
2
    aiNode *newNode = new aiNode;
549
2
    pushNode(newNode, pScene);
550
2
    m_tokenType = Grammar::GeometryNodeToken;
551
2
    m_currentNode = newNode;
552
2
    handleNodes(node, pScene);
553
554
2
    popNode();
555
2
}
556
557
//------------------------------------------------------------------------------------------------
558
3
void OpenGEXImporter::handleCameraNode(DDLNode *node, aiScene *pScene) {
559
3
    aiCamera *camera(new aiCamera);
560
3
    m_cameraCache.push_back(camera);
561
3
    m_currentCamera = camera;
562
563
3
    aiNode *newNode = new aiNode;
564
3
    pushNode(newNode, pScene);
565
3
    m_tokenType = Grammar::CameraNodeToken;
566
3
    m_currentNode = newNode;
567
568
3
    handleNodes(node, pScene);
569
570
3
    popNode();
571
572
3
    m_currentCamera->mName.Set(newNode->mName.C_Str());
573
3
}
574
575
//------------------------------------------------------------------------------------------------
576
0
void OpenGEXImporter::handleLightNode(ODDLParser::DDLNode *node, aiScene *pScene) {
577
0
    aiLight *light(new aiLight);
578
0
    m_lightCache.push_back(light);
579
0
    m_currentLight = light;
580
581
0
    aiNode *newNode = new aiNode;
582
0
    m_tokenType = Grammar::LightNodeToken;
583
0
    m_currentNode = newNode;
584
0
    pushNode(newNode, pScene);
585
586
0
    handleNodes(node, pScene);
587
588
0
    popNode();
589
590
0
    m_currentLight->mName.Set(newNode->mName.C_Str());
591
0
}
592
593
//------------------------------------------------------------------------------------------------
594
2
void OpenGEXImporter::handleGeometryObject(DDLNode *node, aiScene *pScene) {
595
    // parameters will be parsed normally in the tree, so just go for it
596
2
    handleNodes(node, pScene);
597
2
}
598
599
//------------------------------------------------------------------------------------------------
600
3
void OpenGEXImporter::handleCameraObject(ODDLParser::DDLNode *node, aiScene *pScene) {
601
    // parameters will be parsed normally in the tree, so just go for it
602
603
3
    handleNodes(node, pScene);
604
3
}
605
606
//------------------------------------------------------------------------------------------------
607
0
void OpenGEXImporter::handleLightObject(ODDLParser::DDLNode *node, aiScene *pScene) {
608
0
    aiLight *light(new aiLight);
609
0
    m_lightCache.push_back(light);
610
0
    std::string objName = node->getName();
611
0
    if (!objName.empty()) {
612
0
        light->mName.Set(objName);
613
0
    }
614
0
    m_currentLight = light;
615
616
0
    Property *prop(node->findPropertyByName("type"));
617
0
    if (nullptr != prop) {
618
0
        if (nullptr != prop->m_value) {
619
0
            std::string typeStr(prop->m_value->getString());
620
0
            if ("point" == typeStr) {
621
0
                m_currentLight->mType = aiLightSource_POINT;
622
0
            } else if ("spot" == typeStr) {
623
0
                m_currentLight->mType = aiLightSource_SPOT;
624
0
            } else if ("infinite" == typeStr) {
625
0
                m_currentLight->mType = aiLightSource_DIRECTIONAL;
626
0
            }
627
0
        }
628
0
    }
629
630
    // parameters will be parsed normally in the tree, so just go for it
631
0
    handleNodes(node, pScene);
632
0
}
633
634
//------------------------------------------------------------------------------------------------
635
5
static void setMatrix(aiNode *node, DataArrayList *transformData) {
636
5
    ai_assert(nullptr != node);
637
5
    ai_assert(nullptr != transformData);
638
639
5
    float m[16];
640
5
    size_t i(1);
641
5
    Value *next(transformData->m_dataList->m_next);
642
5
    m[0] = transformData->m_dataList->getFloat();
643
80
    while (next != nullptr) {
644
75
        m[i] = next->getFloat();
645
75
        next = next->m_next;
646
75
        i++;
647
75
    }
648
649
5
    ai_assert(i == 16);
650
651
5
    node->mTransformation.a1 = m[0];
652
5
    node->mTransformation.a2 = m[4];
653
5
    node->mTransformation.a3 = m[8];
654
5
    node->mTransformation.a4 = m[12];
655
656
5
    node->mTransformation.b1 = m[1];
657
5
    node->mTransformation.b2 = m[5];
658
5
    node->mTransformation.b3 = m[9];
659
5
    node->mTransformation.b4 = m[13];
660
661
5
    node->mTransformation.c1 = m[2];
662
5
    node->mTransformation.c2 = m[6];
663
5
    node->mTransformation.c3 = m[10];
664
5
    node->mTransformation.c4 = m[14];
665
666
5
    node->mTransformation.d1 = m[3];
667
5
    node->mTransformation.d2 = m[7];
668
5
    node->mTransformation.d3 = m[11];
669
5
    node->mTransformation.d4 = m[15];
670
5
}
671
672
//------------------------------------------------------------------------------------------------
673
5
void OpenGEXImporter::handleTransformNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
674
5
    if (nullptr == m_currentNode) {
675
0
        throw DeadlyImportError("No parent node for name.");
676
0
    }
677
678
5
    DataArrayList *transformData(node->getDataArrayList());
679
5
    if (nullptr != transformData) {
680
5
        if (transformData->m_numItems != 16) {
681
0
            throw DeadlyImportError("Invalid number of data for transform matrix.");
682
0
        }
683
5
        setMatrix(m_currentNode, transformData);
684
5
    }
685
5
}
686
687
//------------------------------------------------------------------------------------------------
688
2
void OpenGEXImporter::handleMeshNode(ODDLParser::DDLNode *node, aiScene *pScene) {
689
2
    m_currentMesh = new aiMesh;
690
2
    const size_t meshidx(m_meshCache.size());
691
    // ownership is transferred but a reference remains in m_currentMesh
692
2
    m_meshCache.emplace_back(m_currentMesh);
693
694
2
    Property *prop = node->getProperties();
695
2
    if (nullptr != prop) {
696
2
        std::string propName, propKey;
697
2
        propId2StdString(prop, propName, propKey);
698
2
        if ("primitive" == propName) {
699
2
            if ("points" == propKey) {
700
0
                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
701
2
            } else if ("lines" == propKey) {
702
0
                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
703
2
            } else if ("triangles" == propKey) {
704
2
                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
705
2
            } else if ("quads" == propKey) {
706
0
                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
707
0
            } else {
708
0
                ASSIMP_LOG_WARN(propKey, " is not supported primitive type.");
709
0
            }
710
2
        }
711
2
    }
712
713
2
    handleNodes(node, pScene);
714
715
2
    DDLNode *parent(node->getParent());
716
2
    if (nullptr != parent) {
717
2
        const std::string &name = parent->getName();
718
2
        m_mesh2refMap[name] = meshidx;
719
2
    }
720
2
}
721
722
//------------------------------------------------------------------------------------------------
723
enum MeshAttribute {
724
    None,
725
    Position,
726
    Color,
727
    Normal,
728
    TexCoord
729
};
730
731
constexpr auto PosToken = "position";
732
constexpr auto ColToken = "color";
733
constexpr auto NormalToken = "normal";
734
constexpr auto TexCoordToken = "texcoord";
735
736
//------------------------------------------------------------------------------------------------
737
4
static MeshAttribute getAttributeByName(const char *attribName) {
738
4
    ai_assert(nullptr != attribName);
739
740
4
    if (0 == strcmp(PosToken, attribName)) {
741
2
        return Position;
742
2
    } else if (0 == strcmp(ColToken, attribName)) {
743
0
        return Color;
744
2
    } else if (0 == strcmp(NormalToken, attribName)) {
745
2
        return Normal;
746
2
    } else if (0 == strcmp(TexCoordToken, attribName)) {
747
0
        return TexCoord;
748
0
    }
749
750
0
    return None;
751
4
}
752
753
//------------------------------------------------------------------------------------------------
754
6.74k
static void fillVector3(aiVector3D *vec3, Value *vals) {
755
6.74k
    ai_assert(nullptr != vec3);
756
6.74k
    ai_assert(nullptr != vals);
757
758
6.74k
    float x(0.0f), y(0.0f), z(0.0f);
759
6.74k
    Value *next(vals);
760
6.74k
    x = next->getFloat();
761
6.74k
    next = next->m_next;
762
6.74k
    y = next->getFloat();
763
6.74k
    next = next->m_next;
764
6.74k
    if (nullptr != next) {
765
6.74k
        z = next->getFloat();
766
6.74k
    }
767
768
6.74k
    vec3->Set(x, y, z);
769
6.74k
}
770
771
//------------------------------------------------------------------------------------------------
772
0
static void fillColor4(aiColor4D *col4, Value *vals) {
773
0
    ai_assert(nullptr != col4);
774
0
    ai_assert(nullptr != vals);
775
776
0
    Value *next(vals);
777
0
    col4->r = next->getFloat();
778
0
    next = next->m_next;
779
0
    if (!next) {
780
0
        throw DeadlyImportError("OpenGEX: Not enough values to fill 4-element color, only 1");
781
0
    }
782
783
0
    col4->g = next->getFloat();
784
0
    next = next->m_next;
785
0
    if (!next) {
786
0
        throw DeadlyImportError("OpenGEX: Not enough values to fill 4-element color, only 2");
787
0
    }
788
789
0
    col4->b = next->getFloat();
790
0
    next = next->m_next;
791
0
    if (!next) {
792
0
        col4->a = 1.0f;
793
0
    } else {
794
0
        col4->a = next->getFloat();
795
0
    }
796
0
}
797
798
//------------------------------------------------------------------------------------------------
799
6
static size_t countDataArrayListItems(DataArrayList *vaList) {
800
6
    size_t numItems(0);
801
6
    if (nullptr == vaList) {
802
0
        return numItems;
803
0
    }
804
805
6
    DataArrayList *next(vaList);
806
13.4k
    while (nullptr != next) {
807
13.4k
        if (nullptr != vaList->m_dataList) {
808
13.4k
            numItems++;
809
13.4k
        }
810
13.4k
        next = next->m_next;
811
13.4k
    }
812
813
6
    return numItems;
814
6
}
815
816
//------------------------------------------------------------------------------------------------
817
4
static void copyVectorArray(size_t numItems, DataArrayList *vaList, aiVector3D *vectorArray) {
818
6.74k
    for (size_t i = 0; i < numItems; i++) {
819
6.74k
        Value *next(vaList->m_dataList);
820
6.74k
        fillVector3(&vectorArray[i], next);
821
6.74k
        vaList = vaList->m_next;
822
6.74k
    }
823
4
}
824
825
//------------------------------------------------------------------------------------------------
826
0
static void copyColor4DArray(size_t numItems, DataArrayList *vaList, aiColor4D *colArray) {
827
0
    for (size_t i = 0; i < numItems; i++) {
828
0
        Value *next(vaList->m_dataList);
829
0
        fillColor4(&colArray[i], next);
830
0
    }
831
0
}
832
833
//------------------------------------------------------------------------------------------------
834
4
void OpenGEXImporter::handleVertexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
835
4
    if (nullptr == node) {
836
0
        throw DeadlyImportError("No parent node for name.");
837
0
    }
838
839
4
    Property *prop = node->getProperties();
840
4
    if (nullptr != prop) {
841
4
        std::string propName, propKey;
842
4
        propId2StdString(prop, propName, propKey);
843
4
        MeshAttribute attribType(getAttributeByName(propKey.c_str()));
844
4
        if (None == attribType) {
845
0
            return;
846
0
        }
847
848
4
        DataArrayList *vaList = node->getDataArrayList();
849
4
        if (nullptr == vaList) {
850
0
            return;
851
0
        }
852
853
4
        const size_t numItems(countDataArrayListItems(vaList));
854
855
4
        if (Position == attribType) {
856
2
            m_currentVertices.m_vertices.resize(numItems);
857
2
            copyVectorArray(numItems, vaList, m_currentVertices.m_vertices.data());
858
2
        } else if (Color == attribType) {
859
0
            m_currentVertices.m_numColors = numItems;
860
0
            m_currentVertices.m_colors = new aiColor4D[numItems];
861
0
            copyColor4DArray(numItems, vaList, m_currentVertices.m_colors);
862
2
        } else if (Normal == attribType) {
863
2
            m_currentVertices.m_normals.resize(numItems);
864
2
            copyVectorArray(numItems, vaList, m_currentVertices.m_normals.data());
865
2
        } else if (TexCoord == attribType) {
866
0
            m_currentVertices.m_numUVComps[0] = numItems;
867
0
            m_currentVertices.m_textureCoords[0] = new aiVector3D[numItems];
868
0
            copyVectorArray(numItems, vaList, m_currentVertices.m_textureCoords[0]);
869
0
        }
870
4
    }
871
4
}
872
873
//------------------------------------------------------------------------------------------------
874
2
void OpenGEXImporter::handleIndexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
875
2
    if (nullptr == node) {
876
0
        throw DeadlyImportError("No parent node for name.");
877
0
    }
878
879
2
    if (nullptr == m_currentMesh) {
880
0
        throw DeadlyImportError("No current mesh for index data found.");
881
0
    }
882
883
2
    DataArrayList *vaList = node->getDataArrayList();
884
2
    if (nullptr == vaList) {
885
0
        return;
886
0
    }
887
888
2
    const size_t numItems(countDataArrayListItems(vaList));
889
2
    m_currentMesh->mNumFaces = static_cast<unsigned int>(numItems);
890
2
    m_currentMesh->mFaces = new aiFace[numItems];
891
2
    m_currentMesh->mNumVertices = static_cast<unsigned int>(numItems * 3);
892
2
    m_currentMesh->mVertices = new aiVector3D[m_currentMesh->mNumVertices];
893
2
    bool hasColors(false);
894
2
    if (m_currentVertices.m_numColors > 0) {
895
0
        m_currentMesh->mColors[0] = new aiColor4D[m_currentVertices.m_numColors];
896
0
        hasColors = true;
897
0
    }
898
2
    bool hasNormalCoords(false);
899
2
    if (!m_currentVertices.m_normals.empty()) {
900
2
        m_currentMesh->mNormals = new aiVector3D[m_currentMesh->mNumVertices];
901
2
        hasNormalCoords = true;
902
2
    }
903
2
    bool hasTexCoords(false);
904
2
    if (m_currentVertices.m_numUVComps[0] > 0) {
905
0
        m_currentMesh->mTextureCoords[0] = new aiVector3D[m_currentMesh->mNumVertices];
906
0
        hasTexCoords = true;
907
0
    }
908
909
2
    unsigned int index(0);
910
6.72k
    for (size_t i = 0; i < m_currentMesh->mNumFaces; i++) {
911
6.72k
        aiFace &current(m_currentMesh->mFaces[i]);
912
6.72k
        current.mNumIndices = 3;
913
6.72k
        current.mIndices = new unsigned int[current.mNumIndices];
914
6.72k
        Value *next(vaList->m_dataList);
915
26.8k
        for (size_t indices = 0; indices < current.mNumIndices; indices++) {
916
20.1k
            int idx = -1;
917
20.1k
            if (next->m_type == Value::ValueType::ddl_unsigned_int16) {
918
0
                idx = next->getUnsignedInt16();
919
20.1k
            } else if (next->m_type == Value::ValueType::ddl_unsigned_int32) {
920
20.1k
                idx = next->getUnsignedInt32();
921
20.1k
            }
922
            
923
20.1k
            ai_assert(static_cast<size_t>(idx) <= m_currentVertices.m_vertices.size());
924
20.1k
            ai_assert(index < m_currentMesh->mNumVertices);
925
20.1k
            aiVector3D &pos = (m_currentVertices.m_vertices[idx]);
926
20.1k
            m_currentMesh->mVertices[index].Set(pos.x, pos.y, pos.z);
927
20.1k
            if (hasColors) {
928
0
                aiColor4D &col = m_currentVertices.m_colors[idx];
929
0
                m_currentMesh->mColors[0][index] = col;
930
0
            }
931
20.1k
            if (hasNormalCoords) {
932
20.1k
                aiVector3D &normal = (m_currentVertices.m_normals[idx]);
933
20.1k
                m_currentMesh->mNormals[index].Set(normal.x, normal.y, normal.z);
934
20.1k
            }
935
20.1k
            if (hasTexCoords) {
936
0
                aiVector3D &tex = (m_currentVertices.m_textureCoords[0][idx]);
937
0
                m_currentMesh->mTextureCoords[0][index].Set(tex.x, tex.y, tex.z);
938
0
            }
939
20.1k
            current.mIndices[indices] = index;
940
20.1k
            index++;
941
942
20.1k
            next = next->m_next;
943
20.1k
        }
944
6.72k
        vaList = vaList->m_next;
945
6.72k
    }
946
2
}
947
948
//------------------------------------------------------------------------------------------------
949
0
static void getColorRGB3(aiColor3D *pColor, DataArrayList *colList) {
950
0
    if (nullptr == pColor || nullptr == colList) {
951
0
        return;
952
0
    }
953
954
0
    ai_assert(3 == colList->m_numItems);
955
0
    Value *val(colList->m_dataList);
956
0
    pColor->r = val->getFloat();
957
0
    val = val->getNext();
958
0
    pColor->g = val->getFloat();
959
0
    val = val->getNext();
960
0
    pColor->b = val->getFloat();
961
0
}
962
963
//------------------------------------------------------------------------------------------------
964
0
static void getColorRGB4(aiColor4D *pColor, DataArrayList *colList) {
965
0
    if (nullptr == pColor || nullptr == colList) {
966
0
        return;
967
0
    }
968
969
0
    ai_assert(4 == colList->m_numItems);
970
0
    Value *val(colList->m_dataList);
971
0
    pColor->r = val->getFloat();
972
0
    val = val->getNext();
973
0
    pColor->g = val->getFloat();
974
0
    val = val->getNext();
975
0
    pColor->b = val->getFloat();
976
0
    val = val->getNext();
977
0
    pColor->a = val->getFloat();
978
0
}
979
980
//------------------------------------------------------------------------------------------------
981
enum ColorType {
982
    NoneColor = 0,
983
    DiffuseColor,
984
    SpecularColor,
985
    EmissionColor,
986
    LightColor
987
};
988
989
//------------------------------------------------------------------------------------------------
990
0
static ColorType getColorType(Text *id) {
991
0
    if (nullptr == id) {
992
0
        return NoneColor;
993
0
    }
994
995
0
    if (*id == Grammar::DiffuseColorToken) {
996
0
        return DiffuseColor;
997
0
    } else if (*id == Grammar::SpecularColorToken) {
998
0
        return SpecularColor;
999
0
    } else if (*id == Grammar::EmissionColorToken) {
1000
0
        return EmissionColor;
1001
0
    } else if (*id == "light") {
1002
0
        return LightColor;
1003
0
    }
1004
1005
0
    return NoneColor;
1006
0
}
1007
1008
//------------------------------------------------------------------------------------------------
1009
0
void OpenGEXImporter::handleMaterialNode(ODDLParser::DDLNode *node, aiScene *pScene) {
1010
0
    m_currentMaterial = new aiMaterial;
1011
0
    m_materialCache.push_back(m_currentMaterial);
1012
0
    m_tokenType = Grammar::MaterialToken;
1013
0
    handleNodes(node, pScene);
1014
0
}
1015
1016
//------------------------------------------------------------------------------------------------
1017
0
void OpenGEXImporter::handleColorNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
1018
0
    if (nullptr == node) {
1019
0
        return;
1020
0
    }
1021
1022
0
    Property *prop = node->findPropertyByName("attrib");
1023
0
    if (nullptr != prop) {
1024
0
        if (nullptr != prop->m_value) {
1025
0
            DataArrayList *colList(node->getDataArrayList());
1026
0
            if (nullptr == colList) {
1027
0
                return;
1028
0
            }
1029
0
            aiColor3D col;
1030
0
            if (3 == colList->m_numItems) {
1031
0
                aiColor3D col3;
1032
0
                getColorRGB3(&col3, colList);
1033
0
                col = col3;
1034
0
            } else {
1035
0
                aiColor4D col4;
1036
0
                getColorRGB4(&col4, colList);
1037
0
                col.r = col4.r;
1038
0
                col.g = col4.g;
1039
0
                col.b = col4.b;
1040
0
            }
1041
#ifdef ASSIMP_USE_HUNTER
1042
            const ColorType colType(getColorType(&prop->m_key->m_text));
1043
#else
1044
0
            const ColorType colType(getColorType(prop->m_key));
1045
0
#endif
1046
0
            if (DiffuseColor == colType) {
1047
0
                m_currentMaterial->AddProperty(&col, 1, AI_MATKEY_COLOR_DIFFUSE);
1048
0
            } else if (SpecularColor == colType) {
1049
0
                m_currentMaterial->AddProperty(&col, 1, AI_MATKEY_COLOR_SPECULAR);
1050
0
            } else if (EmissionColor == colType) {
1051
0
                m_currentMaterial->AddProperty(&col, 1, AI_MATKEY_COLOR_EMISSIVE);
1052
0
            } else if (LightColor == colType) {
1053
0
                m_currentLight->mColorDiffuse = col;
1054
0
            }
1055
0
        }
1056
0
    }
1057
0
}
1058
1059
//------------------------------------------------------------------------------------------------
1060
0
void OpenGEXImporter::handleTextureNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
1061
0
    if (nullptr == node) {
1062
0
        return;
1063
0
    }
1064
1065
0
    Property *prop = node->findPropertyByName("attrib");
1066
0
    if (nullptr != prop) {
1067
0
        if (nullptr != prop->m_value) {
1068
0
            Value *val(node->getValue());
1069
0
            if (nullptr != val) {
1070
0
                aiString tex;
1071
0
                tex.Set(val->getString());
1072
0
                if (prop->m_value->getString() == Grammar::DiffuseTextureToken) {
1073
0
                    m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
1074
0
                } else if (prop->m_value->getString() == Grammar::DiffuseSpecularTextureToken) {
1075
0
                    m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_SPECULAR(0));
1076
0
                } else if (prop->m_value->getString() == Grammar::SpecularPowerTextureToken) {
1077
0
                    m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_SPECULAR(0));
1078
0
                } else if (prop->m_value->getString() == Grammar::EmissionTextureToken) {
1079
0
                    m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_EMISSIVE(0));
1080
0
                } else if (prop->m_value->getString() == Grammar::OpacyTextureToken) {
1081
0
                    m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_OPACITY(0));
1082
0
                } else if (prop->m_value->getString() == Grammar::TransparencyTextureToken) {
1083
                    // ToDo!
1084
                    // m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
1085
0
                } else if (prop->m_value->getString() == Grammar::NormalTextureToken) {
1086
0
                    m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_NORMALS(0));
1087
0
                } else {
1088
0
                    ai_assert(false);
1089
0
                }
1090
0
            }
1091
0
        }
1092
0
    }
1093
0
}
1094
1095
//------------------------------------------------------------------------------------------------
1096
9
void OpenGEXImporter::handleParamNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
1097
9
    if (nullptr == node) {
1098
0
        return;
1099
0
    }
1100
1101
9
    Property *prop = node->findPropertyByName("attrib");
1102
9
    if (nullptr == prop) {
1103
0
        return;
1104
0
    }
1105
1106
9
    if (nullptr != prop->m_value) {
1107
9
        Value *val(node->getValue());
1108
9
        if (nullptr == val) {
1109
0
            return;
1110
0
        }
1111
9
        const float floatVal(val->getFloat());
1112
9
        if (0 == ASSIMP_strincmp("fov", prop->m_value->getString(), 3)) {
1113
3
            m_currentCamera->mHorizontalFOV = floatVal;
1114
6
        } else if (0 == ASSIMP_strincmp("near", prop->m_value->getString(), 4)) {
1115
3
            m_currentCamera->mClipPlaneNear = floatVal;
1116
3
        } else if (0 == ASSIMP_strincmp("far", prop->m_value->getString(), 3)) {
1117
3
            m_currentCamera->mClipPlaneFar = floatVal;
1118
3
        }
1119
9
    }
1120
9
}
1121
1122
//------------------------------------------------------------------------------------------------
1123
0
void OpenGEXImporter::handleAttenNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
1124
0
    if (nullptr == node) {
1125
0
        return;
1126
0
    }
1127
1128
0
    Property *prop = node->findPropertyByName("curve");
1129
0
    if (nullptr != prop) {
1130
0
        if (nullptr != prop->m_value) {
1131
0
            Value *val(node->getValue());
1132
0
            const float floatVal(val->getFloat());
1133
0
            if (0 == strncmp("scale", prop->m_value->getString(), strlen("scale"))) {
1134
0
                m_currentLight->mAttenuationQuadratic = floatVal;
1135
0
            }
1136
0
        }
1137
0
    }
1138
0
}
1139
1140
//------------------------------------------------------------------------------------------------
1141
14
void OpenGEXImporter::copyMeshes(aiScene *pScene) {
1142
14
    ai_assert(nullptr != pScene);
1143
1144
14
    if (m_meshCache.empty()) {
1145
13
        return;
1146
13
    }
1147
1148
1
    pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size());
1149
1
    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
1150
3
    for (unsigned int i = 0; i < pScene->mNumMeshes; i++) {
1151
2
        pScene->mMeshes[i] = m_meshCache[i].release();
1152
2
    }
1153
1
}
1154
1155
//------------------------------------------------------------------------------------------------
1156
14
void OpenGEXImporter::copyCameras(aiScene *pScene) {
1157
14
    ai_assert(nullptr != pScene);
1158
1159
14
    if (m_cameraCache.empty()) {
1160
13
        return;
1161
13
    }
1162
1163
1
    pScene->mNumCameras = static_cast<unsigned int>(m_cameraCache.size());
1164
1
    pScene->mCameras = new aiCamera *[pScene->mNumCameras];
1165
1
    std::copy(m_cameraCache.begin(), m_cameraCache.end(), pScene->mCameras);
1166
1
}
1167
1168
//------------------------------------------------------------------------------------------------
1169
0
void OpenGEXImporter::copyLights(aiScene *pScene) {
1170
0
    ai_assert(nullptr != pScene);
1171
1172
0
    if (m_lightCache.empty()) {
1173
0
        return;
1174
0
    }
1175
1176
0
    pScene->mNumLights = static_cast<unsigned int>(m_lightCache.size());
1177
0
    pScene->mLights = new aiLight *[pScene->mNumLights];
1178
0
    std::copy(m_lightCache.begin(), m_lightCache.end(), pScene->mLights);
1179
0
}
1180
1181
//------------------------------------------------------------------------------------------------
1182
14
void OpenGEXImporter::copyMaterials(aiScene *pScene) {
1183
14
    ai_assert(nullptr != pScene);
1184
1185
14
    if (m_materialCache.empty()) {
1186
14
        return;
1187
14
    }
1188
1189
0
    pScene->mNumMaterials = static_cast<unsigned int>(m_materialCache.size());
1190
0
    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
1191
0
    std::copy(m_materialCache.begin(), m_materialCache.end(), pScene->mMaterials);
1192
0
}
1193
1194
//------------------------------------------------------------------------------------------------
1195
14
void OpenGEXImporter::resolveReferences() {
1196
14
    if (m_unresolvedRefStack.empty()) {
1197
13
        return;
1198
13
    }
1199
1200
1
    RefInfo *currentRefInfo(nullptr);
1201
5
    for (auto it = m_unresolvedRefStack.begin(); it != m_unresolvedRefStack.end(); ++it) {
1202
4
        currentRefInfo = it->get();
1203
4
        if (nullptr != currentRefInfo) {
1204
4
            aiNode *node(currentRefInfo->m_node);
1205
4
            if (RefInfo::MeshRef == currentRefInfo->m_type) {
1206
4
                for (size_t i = 0; i < currentRefInfo->m_Names.size(); ++i) {
1207
2
                    const std::string &name(currentRefInfo->m_Names[i]);
1208
2
                    ReferenceMap::const_iterator curIt(m_mesh2refMap.find(name));
1209
2
                    if (m_mesh2refMap.end() != curIt) {
1210
2
                        unsigned int meshIdx = static_cast<unsigned int>(m_mesh2refMap[name]);
1211
2
                        node->mMeshes[i] = meshIdx;
1212
2
                    }
1213
2
                }
1214
2
            } else if (RefInfo::MaterialRef == currentRefInfo->m_type) {
1215
4
                for (size_t i = 0; i < currentRefInfo->m_Names.size(); ++i) {
1216
2
                    const std::string name(currentRefInfo->m_Names[i]);
1217
2
                    ReferenceMap::const_iterator curIt(m_material2refMap.find(name));
1218
2
                    if (m_material2refMap.end() != curIt) {
1219
0
                        if (nullptr != m_currentMesh) {
1220
0
                            unsigned int matIdx = static_cast<unsigned int>(m_material2refMap[name]);
1221
0
                            if (m_currentMesh->mMaterialIndex != 0) {
1222
0
                                ASSIMP_LOG_WARN("Override of material reference in current mesh by material reference.");
1223
0
                            }
1224
0
                            m_currentMesh->mMaterialIndex = matIdx;
1225
0
                        } else {
1226
0
                            ASSIMP_LOG_WARN("Cannot resolve material reference, because no current mesh is there.");
1227
0
                        }
1228
0
                    }
1229
2
                }
1230
2
            } else {
1231
0
                throw DeadlyImportError("Unknown reference info to resolve.");
1232
0
            }
1233
4
        }
1234
4
    }
1235
1
}
1236
1237
//------------------------------------------------------------------------------------------------
1238
14
void OpenGEXImporter::createNodeTree(aiScene *pScene) {
1239
14
    if (nullptr == m_root) {
1240
13
        return;
1241
13
    }
1242
1243
1
    if (m_root->m_children.empty()) {
1244
0
        return;
1245
0
    }
1246
1247
1
    pScene->mRootNode->mNumChildren = static_cast<unsigned int>(m_root->m_children.size());
1248
1
    pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
1249
1
    std::copy(m_root->m_children.begin(), m_root->m_children.end(), pScene->mRootNode->mChildren);
1250
1
}
1251
1252
//------------------------------------------------------------------------------------------------
1253
5
void OpenGEXImporter::pushNode(aiNode *node, aiScene *pScene) {
1254
5
    ai_assert(nullptr != pScene);
1255
1256
5
    if (nullptr == node) {
1257
0
        return;
1258
0
    }
1259
1260
5
    ChildInfo *info(nullptr);
1261
5
    if (m_nodeStack.empty()) {
1262
5
        node->mParent = pScene->mRootNode;
1263
5
        NodeChildMap::iterator it(m_nodeChildMap.find(node->mParent));
1264
5
        if (m_nodeChildMap.end() == it) {
1265
1
            info = new ChildInfo;
1266
1
            m_root = info;
1267
1
            m_nodeChildMap[node->mParent] = std::unique_ptr<ChildInfo>(info);
1268
4
        } else {
1269
4
            info = it->second.get();
1270
4
        }
1271
5
        info->m_children.push_back(node);
1272
5
    } else {
1273
0
        aiNode *parent(m_nodeStack.back());
1274
0
        ai_assert(nullptr != parent);
1275
0
        node->mParent = parent;
1276
0
        NodeChildMap::iterator it(m_nodeChildMap.find(node->mParent));
1277
0
        if (m_nodeChildMap.end() == it) {
1278
0
            info = new ChildInfo;
1279
0
            m_nodeChildMap[node->mParent] = std::unique_ptr<ChildInfo>(info);
1280
0
        } else {
1281
0
            info = it->second.get();
1282
0
        }
1283
0
        info->m_children.push_back(node);
1284
0
    }
1285
5
    m_nodeStack.push_back(node);
1286
5
}
1287
1288
//------------------------------------------------------------------------------------------------
1289
5
aiNode *OpenGEXImporter::popNode() {
1290
5
    if (m_nodeStack.empty()) {
1291
0
        return nullptr;
1292
0
    }
1293
1294
5
    aiNode *node(top());
1295
5
    m_nodeStack.pop_back();
1296
1297
5
    return node;
1298
5
}
1299
1300
//------------------------------------------------------------------------------------------------
1301
5
aiNode *OpenGEXImporter::top() const {
1302
5
    if (m_nodeStack.empty()) {
1303
0
        return nullptr;
1304
0
    }
1305
1306
5
    return m_nodeStack.back();
1307
5
}
1308
1309
//------------------------------------------------------------------------------------------------
1310
0
void OpenGEXImporter::clearNodeStack() {
1311
0
    m_nodeStack.clear();
1312
0
}
1313
1314
//------------------------------------------------------------------------------------------------
1315
1316
} // Namespace OpenGEX
1317
} // Namespace Assimp
1318
1319
#endif // ASSIMP_BUILD_NO_OPENGEX_IMPORTER