Coverage Report

Created: 2025-08-26 06:41

/src/assimp/code/AssetLib/OpenGEX/OpenGEXImporter.cpp
Line
Count
Source (jump to first uncovered line)
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
#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
0
    static int isValidMetricType(const char *token) {
138
0
        if (nullptr == token) {
139
0
            return false;
140
0
        }
141
142
0
        int idx = -1;
143
0
        for (size_t i = 0; i < 4; i++) {
144
0
            if (ValidMetricToken[i] == token) {
145
0
                idx = (int)i;
146
0
                break;
147
0
            }
148
0
        }
149
150
0
        return idx;
151
0
    }
152
153
0
    static TokenType matchTokenType(const char *tokenType) {
154
0
        const size_t len = std::strlen(tokenType);
155
0
        if (0 == strncmp(MetricType, tokenType, len)) {
156
0
            return MetricToken;
157
0
        } else if (0 == strncmp(NameType, tokenType, len)) {
158
0
            return NameToken;
159
0
        } else if (0 == strncmp(ObjectRefType, tokenType, len)) {
160
0
            return ObjectRefToken;
161
0
        } else if (0 == strncmp(MaterialRefType, tokenType, len)) {
162
0
            return MaterialRefToken;
163
0
        } else if (0 == strncmp(MetricKeyType, tokenType, len)) {
164
0
            return MetricKeyToken;
165
0
        } else if (0 == strncmp(GeometryNodeType, tokenType, len)) {
166
0
            return GeometryNodeToken;
167
0
        } else if (0 == strncmp(CameraNodeType, tokenType, len)) {
168
0
            return CameraNodeToken;
169
0
        } else if (0 == strncmp(LightNodeType, tokenType, len)) {
170
0
            return LightNodeToken;
171
0
        } else if (0 == strncmp(GeometryObjectType, tokenType, len)) {
172
0
            return GeometryObjectToken;
173
0
        } else if (0 == strncmp(CameraObjectType, tokenType, len)) {
174
0
            return CameraObjectToken;
175
0
        } else if (0 == strncmp(LightObjectType, tokenType, len)) {
176
0
            return LightObjectToken;
177
0
        } else if (0 == strncmp(TransformType, tokenType, len)) {
178
0
            return TransformToken;
179
0
        } else if (0 == strncmp(MeshType, tokenType, len)) {
180
0
            return MeshToken;
181
0
        } else if (0 == strncmp(VertexArrayType, tokenType, len)) {
182
0
            return VertexArrayToken;
183
0
        } else if (0 == strncmp(IndexArrayType, tokenType, len)) {
184
0
            return IndexArrayToken;
185
0
        } else if (0 == strncmp(MaterialType, tokenType, len)) {
186
0
            return MaterialToken;
187
0
        } else if (0 == strncmp(ColorType, tokenType, len)) {
188
0
            return ColorToken;
189
0
        } else if (0 == strncmp(ParamType, tokenType, len)) {
190
0
            return ParamToken;
191
0
        } 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
0
    }
199
} // Namespace Grammar
200
201
namespace Assimp {
202
namespace OpenGEX {
203
204
USE_ODDLPARSER_NS
205
206
//------------------------------------------------------------------------------------------------
207
0
static void propId2StdString(Property *prop, std::string &name, std::string &key) {
208
0
    name = key = std::string();
209
0
    if (nullptr == prop) {
210
0
        return;
211
0
    }
212
213
0
    if (nullptr != prop->m_key) {
214
#ifdef ASSIMP_USE_HUNTER
215
        name = prop->m_key->m_text.m_buffer;
216
#else
217
0
        name = prop->m_key->m_buffer;
218
0
#endif
219
0
        if (Value::ValueType::ddl_string == prop->m_value->m_type) {
220
0
            key = prop->m_value->getString();
221
0
        }
222
0
    }
223
0
}
224
225
//------------------------------------------------------------------------------------------------
226
5
static void logDDLParserMessage (LogSeverity severity, const std::string &rawmsg) {
227
5
    std::string msg = ai_str_toprintable(rawmsg);
228
5
    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
5
    case ddl_error_msg: ASSIMP_LOG_ERROR(msg);         break;
233
0
    default:            ASSIMP_LOG_VERBOSE_DEBUG(msg); break;
234
5
    }
235
5
}
236
237
//------------------------------------------------------------------------------------------------
238
OpenGEXImporter::VertexContainer::VertexContainer() :
239
220
        m_numColors(0), m_colors(nullptr), m_numUVComps(), m_textureCoords() {
240
    // empty
241
220
}
242
243
//------------------------------------------------------------------------------------------------
244
220
OpenGEXImporter::VertexContainer::~VertexContainer() {
245
220
    delete[] m_colors;
246
247
1.76k
    for (auto &texcoords : m_textureCoords) {
248
1.76k
        delete[] texcoords;
249
1.76k
    }
250
220
}
251
252
//------------------------------------------------------------------------------------------------
253
OpenGEXImporter::RefInfo::RefInfo(aiNode *node, Type type, std::vector<std::string> &names) :
254
0
        m_node(node),
255
0
        m_type(type),
256
0
        m_Names(names) {
257
    // empty
258
0
}
259
260
//------------------------------------------------------------------------------------------------
261
OpenGEXImporter::OpenGEXImporter() :
262
220
        m_root(nullptr),
263
220
        m_nodeChildMap(),
264
220
        m_mesh2refMap(),
265
220
        m_material2refMap(),
266
220
        m_ctx(nullptr),
267
220
        m_metrics(),
268
220
        m_currentNode(nullptr),
269
220
        m_currentVertices(),
270
220
        m_currentMesh(nullptr),
271
220
        m_currentMaterial(nullptr),
272
220
        m_currentLight(nullptr),
273
220
        m_currentCamera(nullptr),
274
220
        m_tokenType(Grammar::NoneType),
275
220
        m_materialCache(),
276
220
        m_cameraCache(),
277
220
        m_lightCache(),
278
220
        m_nodeStack(),
279
220
        m_unresolvedRefStack() {
280
    // empty
281
220
}
282
283
//------------------------------------------------------------------------------------------------
284
60
bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
285
60
    static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
286
60
    return SearchFileHeaderForToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens));
287
60
}
288
289
//------------------------------------------------------------------------------------------------
290
8
void OpenGEXImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
291
    // open source file
292
8
    std::unique_ptr<IOStream> file(pIOHandler->Open(filename, "rb"));
293
8
    if (!file) {
294
0
        throw DeadlyImportError("Failed to open file ", filename);
295
0
    }
296
297
8
    std::vector<char> buffer;
298
8
    TextFileToBuffer(file.get(), buffer);
299
300
8
    OpenDDLParser myParser;
301
8
    myParser.setLogCallback(&logDDLParserMessage);
302
8
    myParser.setBuffer(&buffer[0], buffer.size());
303
8
    bool success(myParser.parse());
304
8
    if (success) {
305
0
        m_ctx = myParser.getContext();
306
0
        pScene->mRootNode = new aiNode;
307
0
        pScene->mRootNode->mName.Set(filename);
308
0
        handleNodes(m_ctx->m_root, pScene);
309
0
    }
310
311
8
    copyMeshes(pScene);
312
8
    copyCameras(pScene);
313
    // TODO: lights only partially implemented and breaking model import
314
//    copyLights(pScene);
315
8
    copyMaterials(pScene);
316
8
    resolveReferences();
317
8
    createNodeTree(pScene);
318
8
}
319
320
//------------------------------------------------------------------------------------------------
321
218
const aiImporterDesc *OpenGEXImporter::GetInfo() const {
322
218
    return &desc;
323
218
}
324
325
//------------------------------------------------------------------------------------------------
326
8
void OpenGEXImporter::SetupProperties(const Importer *pImp) {
327
8
    if (nullptr == pImp) {
328
0
        return;
329
0
    }
330
8
}
331
332
//------------------------------------------------------------------------------------------------
333
0
void OpenGEXImporter::handleNodes(DDLNode *node, aiScene *pScene) {
334
0
    if (nullptr == node) {
335
0
        return;
336
0
    }
337
338
0
    DDLNode::DllNodeList children = node->getChildNodeList();
339
0
    for (DDLNode::DllNodeList::iterator it = children.begin(); it != children.end(); ++it) {
340
0
        Grammar::TokenType tokenType(Grammar::matchTokenType((*it)->getType().c_str()));
341
0
        switch (tokenType) {
342
0
        case Grammar::MetricToken:
343
0
            handleMetricNode(*it, pScene);
344
0
            break;
345
346
0
        case Grammar::NameToken:
347
0
            handleNameNode(*it, pScene);
348
0
            break;
349
350
0
        case Grammar::ObjectRefToken:
351
0
            handleObjectRefNode(*it, pScene);
352
0
            break;
353
354
0
        case Grammar::MaterialRefToken:
355
0
            handleMaterialRefNode(*it, pScene);
356
0
            break;
357
358
0
        case Grammar::MetricKeyToken:
359
0
            break;
360
361
0
        case Grammar::GeometryNodeToken:
362
0
            handleGeometryNode(*it, pScene);
363
0
            break;
364
365
0
        case Grammar::CameraNodeToken:
366
0
            handleCameraNode(*it, pScene);
367
0
            break;
368
369
0
        case Grammar::LightNodeToken:
370
            // TODO: lights only partially implemented and breaking model import
371
//            handleLightNode(*it, pScene);
372
0
            break;
373
374
0
        case Grammar::GeometryObjectToken:
375
0
            handleGeometryObject(*it, pScene);
376
0
            break;
377
378
0
        case Grammar::CameraObjectToken:
379
0
            handleCameraObject(*it, pScene);
380
0
            break;
381
382
0
        case Grammar::LightObjectToken:
383
            // TODO: lights only partially implemented and breaking model import
384
//            handleLightObject(*it, pScene);
385
0
            break;
386
387
0
        case Grammar::TransformToken:
388
0
            handleTransformNode(*it, pScene);
389
0
            break;
390
391
0
        case Grammar::MeshToken:
392
0
            handleMeshNode(*it, pScene);
393
0
            break;
394
395
0
        case Grammar::VertexArrayToken:
396
0
            handleVertexArrayNode(*it, pScene);
397
0
            break;
398
399
0
        case Grammar::IndexArrayToken:
400
0
            handleIndexArrayNode(*it, pScene);
401
0
            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
0
        case Grammar::ParamToken:
412
0
            handleParamNode(*it, pScene);
413
0
            break;
414
415
0
        case Grammar::TextureToken:
416
0
            handleTextureNode(*it, pScene);
417
0
            break;
418
419
0
        default:
420
0
            break;
421
0
        }
422
0
    }
423
0
}
424
425
//------------------------------------------------------------------------------------------------
426
0
void OpenGEXImporter::handleMetricNode(DDLNode *node, aiScene * /*pScene*/) {
427
0
    if (nullptr == node || nullptr == m_ctx) {
428
0
        return;
429
0
    }
430
431
0
    if (m_ctx->m_root != node->getParent()) {
432
0
        return;
433
0
    }
434
435
0
    Property *prop(node->getProperties());
436
0
    while (nullptr != prop) {
437
0
        if (nullptr != prop->m_key) {
438
0
            if (Value::ValueType::ddl_string == prop->m_value->m_type) {
439
0
                std::string valName((char *)prop->m_value->m_data);
440
0
                int type(Grammar::isValidMetricType(valName.c_str()));
441
0
                if (Grammar::NoneType != type) {
442
0
                    Value *val(node->getValue());
443
0
                    if (nullptr != val) {
444
0
                        if (Value::ValueType::ddl_float == val->m_type) {
445
0
                            m_metrics[type].m_floatValue = val->getFloat();
446
0
                        } else if (Value::ValueType::ddl_int32 == val->m_type) {
447
0
                            m_metrics[type].m_intValue = val->getInt32();
448
0
                        } else if (Value::ValueType::ddl_string == val->m_type) {
449
0
                            m_metrics[type].m_stringValue = std::string(val->getString());
450
0
                        } else {
451
0
                            throw DeadlyImportError("OpenGEX: invalid data type for Metric node.");
452
0
                        }
453
0
                    }
454
0
                }
455
0
            }
456
0
        }
457
0
        prop = prop->m_next;
458
0
    }
459
0
}
460
461
//------------------------------------------------------------------------------------------------
462
0
void OpenGEXImporter::handleNameNode(DDLNode *node, aiScene * /*pScene*/) {
463
0
    if (nullptr == m_currentNode) {
464
0
        throw DeadlyImportError("No current node for name.");
465
0
    }
466
467
0
    Value *val(node->getValue());
468
0
    if (nullptr != val) {
469
0
        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
0
        const std::string name(val->getString());
474
0
        if (m_tokenType == Grammar::GeometryNodeToken ||
475
                // TODO: lights only partially implemented and breaking model import
476
//                m_tokenType == Grammar::LightNodeToken ||
477
0
                m_tokenType == Grammar::CameraNodeToken) {
478
0
            m_currentNode->mName.Set(name.c_str());
479
0
        } 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
0
    }
486
0
}
487
488
//------------------------------------------------------------------------------------------------
489
0
static void getRefNames(DDLNode *node, std::vector<std::string> &names) {
490
0
    ai_assert(nullptr != node);
491
492
0
    Reference *ref = node->getReferences();
493
0
    if (nullptr != ref) {
494
0
        for (size_t i = 0; i < ref->m_numRefs; i++) {
495
0
            Name *currentName(ref->m_referencedName[i]);
496
0
            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
0
                const std::string name(currentName->m_id->m_buffer);
501
0
#endif
502
0
                if (!name.empty()) {
503
0
                    names.push_back(name);
504
0
                }
505
0
            }
506
0
        }
507
0
    }
508
0
}
509
510
//------------------------------------------------------------------------------------------------
511
0
void OpenGEXImporter::handleObjectRefNode(DDLNode *node, aiScene * /*pScene*/) {
512
0
    if (nullptr == m_currentNode) {
513
0
        throw DeadlyImportError("No parent node for name.");
514
0
    }
515
516
0
    std::vector<std::string> objRefNames;
517
0
    getRefNames(node, objRefNames);
518
519
    // when we are dealing with a geometry node prepare the mesh cache
520
0
    if (m_tokenType == Grammar::GeometryNodeToken) {
521
0
        m_currentNode->mNumMeshes = static_cast<unsigned int>(objRefNames.size());
522
0
        m_currentNode->mMeshes = new unsigned int[objRefNames.size()];
523
0
        if (!objRefNames.empty()) {
524
0
            m_unresolvedRefStack.push_back(std::unique_ptr<RefInfo>(new RefInfo(m_currentNode, RefInfo::MeshRef, objRefNames)));
525
0
        }
526
0
    } else if (m_tokenType == Grammar::LightNodeToken) {
527
        // TODO!
528
0
    } else if (m_tokenType == Grammar::CameraNodeToken) {
529
        // TODO!
530
0
    }
531
0
}
532
533
//------------------------------------------------------------------------------------------------
534
0
void OpenGEXImporter::handleMaterialRefNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
535
0
    if (nullptr == m_currentNode) {
536
0
        throw DeadlyImportError("No parent node for name.");
537
0
    }
538
539
0
    std::vector<std::string> matRefNames;
540
0
    getRefNames(node, matRefNames);
541
0
    if (!matRefNames.empty()) {
542
0
        m_unresolvedRefStack.push_back(std::unique_ptr<RefInfo>(new RefInfo(m_currentNode, RefInfo::MaterialRef, matRefNames)));
543
0
    }
544
0
}
545
546
//------------------------------------------------------------------------------------------------
547
0
void OpenGEXImporter::handleGeometryNode(DDLNode *node, aiScene *pScene) {
548
0
    aiNode *newNode = new aiNode;
549
0
    pushNode(newNode, pScene);
550
0
    m_tokenType = Grammar::GeometryNodeToken;
551
0
    m_currentNode = newNode;
552
0
    handleNodes(node, pScene);
553
554
0
    popNode();
555
0
}
556
557
//------------------------------------------------------------------------------------------------
558
0
void OpenGEXImporter::handleCameraNode(DDLNode *node, aiScene *pScene) {
559
0
    aiCamera *camera(new aiCamera);
560
0
    m_cameraCache.push_back(camera);
561
0
    m_currentCamera = camera;
562
563
0
    aiNode *newNode = new aiNode;
564
0
    pushNode(newNode, pScene);
565
0
    m_tokenType = Grammar::CameraNodeToken;
566
0
    m_currentNode = newNode;
567
568
0
    handleNodes(node, pScene);
569
570
0
    popNode();
571
572
0
    m_currentCamera->mName.Set(newNode->mName.C_Str());
573
0
}
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
0
void OpenGEXImporter::handleGeometryObject(DDLNode *node, aiScene *pScene) {
595
    // parameters will be parsed normally in the tree, so just go for it
596
0
    handleNodes(node, pScene);
597
0
}
598
599
//------------------------------------------------------------------------------------------------
600
0
void OpenGEXImporter::handleCameraObject(ODDLParser::DDLNode *node, aiScene *pScene) {
601
    // parameters will be parsed normally in the tree, so just go for it
602
603
0
    handleNodes(node, pScene);
604
0
}
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
0
static void setMatrix(aiNode *node, DataArrayList *transformData) {
636
0
    ai_assert(nullptr != node);
637
0
    ai_assert(nullptr != transformData);
638
639
0
    float m[16];
640
0
    size_t i(1);
641
0
    Value *next(transformData->m_dataList->m_next);
642
0
    m[0] = transformData->m_dataList->getFloat();
643
0
    while (next != nullptr) {
644
0
        m[i] = next->getFloat();
645
0
        next = next->m_next;
646
0
        i++;
647
0
    }
648
649
0
    ai_assert(i == 16);
650
651
0
    node->mTransformation.a1 = m[0];
652
0
    node->mTransformation.a2 = m[4];
653
0
    node->mTransformation.a3 = m[8];
654
0
    node->mTransformation.a4 = m[12];
655
656
0
    node->mTransformation.b1 = m[1];
657
0
    node->mTransformation.b2 = m[5];
658
0
    node->mTransformation.b3 = m[9];
659
0
    node->mTransformation.b4 = m[13];
660
661
0
    node->mTransformation.c1 = m[2];
662
0
    node->mTransformation.c2 = m[6];
663
0
    node->mTransformation.c3 = m[10];
664
0
    node->mTransformation.c4 = m[14];
665
666
0
    node->mTransformation.d1 = m[3];
667
0
    node->mTransformation.d2 = m[7];
668
0
    node->mTransformation.d3 = m[11];
669
0
    node->mTransformation.d4 = m[15];
670
0
}
671
672
//------------------------------------------------------------------------------------------------
673
0
void OpenGEXImporter::handleTransformNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
674
0
    if (nullptr == m_currentNode) {
675
0
        throw DeadlyImportError("No parent node for name.");
676
0
    }
677
678
0
    DataArrayList *transformData(node->getDataArrayList());
679
0
    if (nullptr != transformData) {
680
0
        if (transformData->m_numItems != 16) {
681
0
            throw DeadlyImportError("Invalid number of data for transform matrix.");
682
0
        }
683
0
        setMatrix(m_currentNode, transformData);
684
0
    }
685
0
}
686
687
//------------------------------------------------------------------------------------------------
688
0
void OpenGEXImporter::handleMeshNode(ODDLParser::DDLNode *node, aiScene *pScene) {
689
0
    m_currentMesh = new aiMesh;
690
0
    const size_t meshidx(m_meshCache.size());
691
    // ownership is transferred but a reference remains in m_currentMesh
692
0
    m_meshCache.emplace_back(m_currentMesh);
693
694
0
    Property *prop = node->getProperties();
695
0
    if (nullptr != prop) {
696
0
        std::string propName, propKey;
697
0
        propId2StdString(prop, propName, propKey);
698
0
        if ("primitive" == propName) {
699
0
            if ("points" == propKey) {
700
0
                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
701
0
            } else if ("lines" == propKey) {
702
0
                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
703
0
            } else if ("triangles" == propKey) {
704
0
                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
705
0
            } 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
0
        }
711
0
    }
712
713
0
    handleNodes(node, pScene);
714
715
0
    DDLNode *parent(node->getParent());
716
0
    if (nullptr != parent) {
717
0
        const std::string &name = parent->getName();
718
0
        m_mesh2refMap[name] = meshidx;
719
0
    }
720
0
}
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
0
static MeshAttribute getAttributeByName(const char *attribName) {
738
0
    ai_assert(nullptr != attribName);
739
740
0
    if (0 == strcmp(PosToken, attribName)) {
741
0
        return Position;
742
0
    } else if (0 == strcmp(ColToken, attribName)) {
743
0
        return Color;
744
0
    } else if (0 == strcmp(NormalToken, attribName)) {
745
0
        return Normal;
746
0
    } else if (0 == strcmp(TexCoordToken, attribName)) {
747
0
        return TexCoord;
748
0
    }
749
750
0
    return None;
751
0
}
752
753
//------------------------------------------------------------------------------------------------
754
0
static void fillVector3(aiVector3D *vec3, Value *vals) {
755
0
    ai_assert(nullptr != vec3);
756
0
    ai_assert(nullptr != vals);
757
758
0
    float x(0.0f), y(0.0f), z(0.0f);
759
0
    Value *next(vals);
760
0
    x = next->getFloat();
761
0
    next = next->m_next;
762
0
    y = next->getFloat();
763
0
    next = next->m_next;
764
0
    if (nullptr != next) {
765
0
        z = next->getFloat();
766
0
    }
767
768
0
    vec3->Set(x, y, z);
769
0
}
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
0
static size_t countDataArrayListItems(DataArrayList *vaList) {
800
0
    size_t numItems(0);
801
0
    if (nullptr == vaList) {
802
0
        return numItems;
803
0
    }
804
805
0
    DataArrayList *next(vaList);
806
0
    while (nullptr != next) {
807
0
        if (nullptr != vaList->m_dataList) {
808
0
            numItems++;
809
0
        }
810
0
        next = next->m_next;
811
0
    }
812
813
0
    return numItems;
814
0
}
815
816
//------------------------------------------------------------------------------------------------
817
0
static void copyVectorArray(size_t numItems, DataArrayList *vaList, aiVector3D *vectorArray) {
818
0
    for (size_t i = 0; i < numItems; i++) {
819
0
        Value *next(vaList->m_dataList);
820
0
        fillVector3(&vectorArray[i], next);
821
0
        vaList = vaList->m_next;
822
0
    }
823
0
}
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
0
void OpenGEXImporter::handleVertexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
835
0
    if (nullptr == node) {
836
0
        throw DeadlyImportError("No parent node for name.");
837
0
    }
838
839
0
    Property *prop = node->getProperties();
840
0
    if (nullptr != prop) {
841
0
        std::string propName, propKey;
842
0
        propId2StdString(prop, propName, propKey);
843
0
        MeshAttribute attribType(getAttributeByName(propKey.c_str()));
844
0
        if (None == attribType) {
845
0
            return;
846
0
        }
847
848
0
        DataArrayList *vaList = node->getDataArrayList();
849
0
        if (nullptr == vaList) {
850
0
            return;
851
0
        }
852
853
0
        const size_t numItems(countDataArrayListItems(vaList));
854
855
0
        if (Position == attribType) {
856
0
            m_currentVertices.m_vertices.resize(numItems);
857
0
            copyVectorArray(numItems, vaList, m_currentVertices.m_vertices.data());
858
0
        } 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
0
        } else if (Normal == attribType) {
863
0
            m_currentVertices.m_normals.resize(numItems);
864
0
            copyVectorArray(numItems, vaList, m_currentVertices.m_normals.data());
865
0
        } 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
0
    }
871
0
}
872
873
//------------------------------------------------------------------------------------------------
874
0
void OpenGEXImporter::handleIndexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
875
0
    if (nullptr == node) {
876
0
        throw DeadlyImportError("No parent node for name.");
877
0
    }
878
879
0
    if (nullptr == m_currentMesh) {
880
0
        throw DeadlyImportError("No current mesh for index data found.");
881
0
    }
882
883
0
    DataArrayList *vaList = node->getDataArrayList();
884
0
    if (nullptr == vaList) {
885
0
        return;
886
0
    }
887
888
0
    const size_t numItems(countDataArrayListItems(vaList));
889
0
    m_currentMesh->mNumFaces = static_cast<unsigned int>(numItems);
890
0
    m_currentMesh->mFaces = new aiFace[numItems];
891
0
    m_currentMesh->mNumVertices = static_cast<unsigned int>(numItems * 3);
892
0
    m_currentMesh->mVertices = new aiVector3D[m_currentMesh->mNumVertices];
893
0
    bool hasColors(false);
894
0
    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
0
    bool hasNormalCoords(false);
899
0
    if (!m_currentVertices.m_normals.empty()) {
900
0
        m_currentMesh->mNormals = new aiVector3D[m_currentMesh->mNumVertices];
901
0
        hasNormalCoords = true;
902
0
    }
903
0
    bool hasTexCoords(false);
904
0
    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
0
    unsigned int index(0);
910
0
    for (size_t i = 0; i < m_currentMesh->mNumFaces; i++) {
911
0
        aiFace &current(m_currentMesh->mFaces[i]);
912
0
        current.mNumIndices = 3;
913
0
        current.mIndices = new unsigned int[current.mNumIndices];
914
0
        Value *next(vaList->m_dataList);
915
0
        for (size_t indices = 0; indices < current.mNumIndices; indices++) {
916
0
            int idx = -1;
917
0
            if (next->m_type == Value::ValueType::ddl_unsigned_int16) {
918
0
                idx = next->getUnsignedInt16();
919
0
            } else if (next->m_type == Value::ValueType::ddl_unsigned_int32) {
920
0
                idx = next->getUnsignedInt32();
921
0
            }
922
            
923
0
            ai_assert(static_cast<size_t>(idx) <= m_currentVertices.m_vertices.size());
924
0
            ai_assert(index < m_currentMesh->mNumVertices);
925
0
            aiVector3D &pos = (m_currentVertices.m_vertices[idx]);
926
0
            m_currentMesh->mVertices[index].Set(pos.x, pos.y, pos.z);
927
0
            if (hasColors) {
928
0
                aiColor4D &col = m_currentVertices.m_colors[idx];
929
0
                m_currentMesh->mColors[0][index] = col;
930
0
            }
931
0
            if (hasNormalCoords) {
932
0
                aiVector3D &normal = (m_currentVertices.m_normals[idx]);
933
0
                m_currentMesh->mNormals[index].Set(normal.x, normal.y, normal.z);
934
0
            }
935
0
            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
0
            current.mIndices[indices] = index;
940
0
            index++;
941
942
0
            next = next->m_next;
943
0
        }
944
0
        vaList = vaList->m_next;
945
0
    }
946
0
}
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
0
void OpenGEXImporter::handleParamNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
1097
0
    if (nullptr == node) {
1098
0
        return;
1099
0
    }
1100
1101
0
    Property *prop = node->findPropertyByName("attrib");
1102
0
    if (nullptr == prop) {
1103
0
        return;
1104
0
    }
1105
1106
0
    if (nullptr != prop->m_value) {
1107
0
        Value *val(node->getValue());
1108
0
        if (nullptr == val) {
1109
0
            return;
1110
0
        }
1111
0
        const float floatVal(val->getFloat());
1112
0
        if (0 == ASSIMP_strincmp("fov", prop->m_value->getString(), 3)) {
1113
0
            m_currentCamera->mHorizontalFOV = floatVal;
1114
0
        } else if (0 == ASSIMP_strincmp("near", prop->m_value->getString(), 4)) {
1115
0
            m_currentCamera->mClipPlaneNear = floatVal;
1116
0
        } else if (0 == ASSIMP_strincmp("far", prop->m_value->getString(), 3)) {
1117
0
            m_currentCamera->mClipPlaneFar = floatVal;
1118
0
        }
1119
0
    }
1120
0
}
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
8
void OpenGEXImporter::copyMeshes(aiScene *pScene) {
1142
8
    ai_assert(nullptr != pScene);
1143
1144
8
    if (m_meshCache.empty()) {
1145
8
        return;
1146
8
    }
1147
1148
0
    pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size());
1149
0
    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
1150
0
    for (unsigned int i = 0; i < pScene->mNumMeshes; i++) {
1151
0
        pScene->mMeshes[i] = m_meshCache[i].release();
1152
0
    }
1153
0
}
1154
1155
//------------------------------------------------------------------------------------------------
1156
8
void OpenGEXImporter::copyCameras(aiScene *pScene) {
1157
8
    ai_assert(nullptr != pScene);
1158
1159
8
    if (m_cameraCache.empty()) {
1160
8
        return;
1161
8
    }
1162
1163
0
    pScene->mNumCameras = static_cast<unsigned int>(m_cameraCache.size());
1164
0
    pScene->mCameras = new aiCamera *[pScene->mNumCameras];
1165
0
    std::copy(m_cameraCache.begin(), m_cameraCache.end(), pScene->mCameras);
1166
0
}
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
8
void OpenGEXImporter::copyMaterials(aiScene *pScene) {
1183
8
    ai_assert(nullptr != pScene);
1184
1185
8
    if (m_materialCache.empty()) {
1186
8
        return;
1187
8
    }
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
8
void OpenGEXImporter::resolveReferences() {
1196
8
    if (m_unresolvedRefStack.empty()) {
1197
8
        return;
1198
8
    }
1199
1200
0
    RefInfo *currentRefInfo(nullptr);
1201
0
    for (auto it = m_unresolvedRefStack.begin(); it != m_unresolvedRefStack.end(); ++it) {
1202
0
        currentRefInfo = it->get();
1203
0
        if (nullptr != currentRefInfo) {
1204
0
            aiNode *node(currentRefInfo->m_node);
1205
0
            if (RefInfo::MeshRef == currentRefInfo->m_type) {
1206
0
                for (size_t i = 0; i < currentRefInfo->m_Names.size(); ++i) {
1207
0
                    const std::string &name(currentRefInfo->m_Names[i]);
1208
0
                    ReferenceMap::const_iterator curIt(m_mesh2refMap.find(name));
1209
0
                    if (m_mesh2refMap.end() != curIt) {
1210
0
                        unsigned int meshIdx = static_cast<unsigned int>(m_mesh2refMap[name]);
1211
0
                        node->mMeshes[i] = meshIdx;
1212
0
                    }
1213
0
                }
1214
0
            } else if (RefInfo::MaterialRef == currentRefInfo->m_type) {
1215
0
                for (size_t i = 0; i < currentRefInfo->m_Names.size(); ++i) {
1216
0
                    const std::string name(currentRefInfo->m_Names[i]);
1217
0
                    ReferenceMap::const_iterator curIt(m_material2refMap.find(name));
1218
0
                    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
0
                }
1230
0
            } else {
1231
0
                throw DeadlyImportError("Unknown reference info to resolve.");
1232
0
            }
1233
0
        }
1234
0
    }
1235
0
}
1236
1237
//------------------------------------------------------------------------------------------------
1238
8
void OpenGEXImporter::createNodeTree(aiScene *pScene) {
1239
8
    if (nullptr == m_root) {
1240
8
        return;
1241
8
    }
1242
1243
0
    if (m_root->m_children.empty()) {
1244
0
        return;
1245
0
    }
1246
1247
0
    pScene->mRootNode->mNumChildren = static_cast<unsigned int>(m_root->m_children.size());
1248
0
    pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
1249
0
    std::copy(m_root->m_children.begin(), m_root->m_children.end(), pScene->mRootNode->mChildren);
1250
0
}
1251
1252
//------------------------------------------------------------------------------------------------
1253
0
void OpenGEXImporter::pushNode(aiNode *node, aiScene *pScene) {
1254
0
    ai_assert(nullptr != pScene);
1255
1256
0
    if (nullptr == node) {
1257
0
        return;
1258
0
    }
1259
1260
0
    ChildInfo *info(nullptr);
1261
0
    if (m_nodeStack.empty()) {
1262
0
        node->mParent = pScene->mRootNode;
1263
0
        NodeChildMap::iterator it(m_nodeChildMap.find(node->mParent));
1264
0
        if (m_nodeChildMap.end() == it) {
1265
0
            info = new ChildInfo;
1266
0
            m_root = info;
1267
0
            m_nodeChildMap[node->mParent] = std::unique_ptr<ChildInfo>(info);
1268
0
        } else {
1269
0
            info = it->second.get();
1270
0
        }
1271
0
        info->m_children.push_back(node);
1272
0
    } 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
0
    m_nodeStack.push_back(node);
1286
0
}
1287
1288
//------------------------------------------------------------------------------------------------
1289
0
aiNode *OpenGEXImporter::popNode() {
1290
0
    if (m_nodeStack.empty()) {
1291
0
        return nullptr;
1292
0
    }
1293
1294
0
    aiNode *node(top());
1295
0
    m_nodeStack.pop_back();
1296
1297
0
    return node;
1298
0
}
1299
1300
//------------------------------------------------------------------------------------------------
1301
0
aiNode *OpenGEXImporter::top() const {
1302
0
    if (m_nodeStack.empty()) {
1303
0
        return nullptr;
1304
0
    }
1305
1306
0
    return m_nodeStack.back();
1307
0
}
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