1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14copyright notice, this list of conditions and the
15following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18copyright notice, this list of conditions and the
19following disclaimer in the documentation and/or other
20materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23contributors may be used to endorse or promote products
24derived from this software without specific prior
25written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
43
44#include "glTFImporter.h"
45#include "StringComparison.h"
46#include "StringUtils.h"
47
48#include <assimp/Importer.hpp>
49#include <assimp/scene.h>
50#include <assimp/ai_assert.h>
51#include <assimp/DefaultLogger.hpp>
52#include <assimp/importerdesc.h>
53
54#include <memory>
55
56#include "MakeVerboseFormat.h"
57
58#include "glTFAsset.h"
59// This is included here so WriteLazyDict<T>'s definition is found.
60#include "glTFAssetWriter.h"
61
62using namespace Assimp;
63using namespace glTF;
64
65
66//
67// glTFImporter
68//
69
70static const aiImporterDesc desc = {
71 "glTF Importer",
72 "",
73 "",
74 "",
75 aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour
76 | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
77 0,
78 0,
79 0,
80 0,
81 "gltf glb"
82};
83
84glTFImporter::glTFImporter()
85: BaseImporter()
86, meshOffsets()
87, embeddedTexIdxs()
88, mScene( NULL ) {
89 // empty
90}
91
92glTFImporter::~glTFImporter() {
93 // empty
94}
95
96const aiImporterDesc* glTFImporter::GetInfo() const
97{
98 return &desc;
99}
100
101bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
102{
103 const std::string &extension = GetExtension(pFile);
104
105 if (extension != "gltf" && extension != "glb")
106 return false;
107
108 if (checkSig && pIOHandler) {
109 glTF::Asset asset(pIOHandler);
110 try {
111 asset.Load(pFile, extension == "glb");
112 std::string version = asset.asset.version;
113 return !version.empty() && version[0] == '1';
114 } catch (...) {
115 return false;
116 }
117 }
118
119 return false;
120}
121
122
123
124//static void CopyValue(const glTF::vec3& v, aiColor3D& out)
125//{
126// out.r = v[0]; out.g = v[1]; out.b = v[2];
127//}
128
129static void CopyValue(const glTF::vec4& v, aiColor4D& out)
130{
131 out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3];
132}
133
134static void CopyValue(const glTF::vec4& v, aiColor3D& out)
135{
136 out.r = v[0]; out.g = v[1]; out.b = v[2];
137}
138
139static void CopyValue(const glTF::vec3& v, aiVector3D& out)
140{
141 out.x = v[0]; out.y = v[1]; out.z = v[2];
142}
143
144static void CopyValue(const glTF::vec4& v, aiQuaternion& out)
145{
146 out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3];
147}
148
149static void CopyValue(const glTF::mat4& v, aiMatrix4x4& o)
150{
151 o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3];
152 o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7];
153 o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11];
154 o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15];
155}
156
157inline void SetMaterialColorProperty(std::vector<int>& embeddedTexIdxs, Asset& /*r*/, glTF::TexProperty prop, aiMaterial* mat,
158 aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx)
159{
160 if (prop.texture) {
161 if (prop.texture->source) {
162 aiString uri(prop.texture->source->uri);
163
164 int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()];
165 if (texIdx != -1) { // embedded
166 // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
167 uri.data[0] = '*';
168 uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
169 }
170
171 mat->AddProperty(&uri, _AI_MATKEY_TEXTURE_BASE, texType, 0);
172 }
173 }
174 else {
175 aiColor4D col;
176 CopyValue(prop.color, col);
177 mat->AddProperty(&col, 1, pKey, type, idx);
178 }
179}
180
181void glTFImporter::ImportMaterials(glTF::Asset& r)
182{
183 mScene->mNumMaterials = unsigned(r.materials.Size());
184 mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials];
185
186 for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
187 aiMaterial* aimat = mScene->mMaterials[i] = new aiMaterial();
188
189 Material& mat = r.materials[i];
190
191 /*if (!mat.name.empty())*/ {
192 aiString str(mat.id /*mat.name*/);
193 aimat->AddProperty(&str, AI_MATKEY_NAME);
194 }
195
196 SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
197 SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
198 SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
199
200 if (mat.shininess > 0.f) {
201 aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS);
202 }
203 }
204
205 if (mScene->mNumMaterials == 0) {
206 mScene->mNumMaterials = 1;
207 mScene->mMaterials = new aiMaterial*[1];
208 mScene->mMaterials[0] = new aiMaterial();
209 }
210}
211
212
213static inline void SetFace(aiFace& face, int a)
214{
215 face.mNumIndices = 1;
216 face.mIndices = new unsigned int[1];
217 face.mIndices[0] = a;
218}
219
220static inline void SetFace(aiFace& face, int a, int b)
221{
222 face.mNumIndices = 2;
223 face.mIndices = new unsigned int[2];
224 face.mIndices[0] = a;
225 face.mIndices[1] = b;
226}
227
228static inline void SetFace(aiFace& face, int a, int b, int c)
229{
230 face.mNumIndices = 3;
231 face.mIndices = new unsigned int[3];
232 face.mIndices[0] = a;
233 face.mIndices[1] = b;
234 face.mIndices[2] = c;
235}
236
237#ifdef ASSIMP_BUILD_DEBUG
238static inline bool CheckValidFacesIndices(aiFace* faces, unsigned nFaces, unsigned nVerts)
239{
240 for (unsigned i = 0; i < nFaces; ++i) {
241 for (unsigned j = 0; j < faces[i].mNumIndices; ++j) {
242 unsigned idx = faces[i].mIndices[j];
243 if (idx >= nVerts)
244 return false;
245 }
246 }
247 return true;
248}
249#endif // ASSIMP_BUILD_DEBUG
250
251void glTFImporter::ImportMeshes(glTF::Asset& r)
252{
253 std::vector<aiMesh*> meshes;
254
255 unsigned int k = 0;
256
257 for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
258 Mesh& mesh = r.meshes[m];
259
260 // Check if mesh extensions is used
261 if(mesh.Extension.size() > 0)
262 {
263 for(Mesh::SExtension* cur_ext : mesh.Extension)
264 {
265#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
266 if(cur_ext->Type == Mesh::SExtension::EType::Compression_Open3DGC)
267 {
268 // Limitations for meshes when using Open3DGC-compression.
269 // It's a current limitation of sp... Specification have not this part still - about mesh compression. Why only one primitive?
270 // Because glTF is very flexibly. But in fact it ugly flexible. Every primitive can has own set of accessors and accessors can
271 // point to a-a-a-a-any part of buffer (through bufferview of course) and even to another buffer. We know that "Open3DGC-compression"
272 // is applicable only to part of buffer. As we can't guaranty continuity of the data for decoder, we will limit quantity of primitives.
273 // Yes indices, coordinates etc. still can br stored in different buffers, but with current specification it's a exporter problem.
274 // Also primitive can has only one of "POSITION", "NORMAL" and less then "AI_MAX_NUMBER_OF_TEXTURECOORDS" of "TEXCOORD". All accessor
275 // of primitive must point to one continuous region of the buffer.
276 if(mesh.primitives.size() > 2) throw DeadlyImportError("GLTF: When using Open3DGC compression then only one primitive per mesh are allowed.");
277
278 Mesh::SCompression_Open3DGC* o3dgc_ext = (Mesh::SCompression_Open3DGC*)cur_ext;
279 Ref<Buffer> buf = r.buffers.Get(o3dgc_ext->Buffer);
280
281 buf->EncodedRegion_SetCurrent(mesh.id);
282 }
283 else
284#endif
285 {
286 throw DeadlyImportError("GLTF: Can not import mesh: unknown mesh extension (code: \"" + to_string(cur_ext->Type) +
287 "\"), only Open3DGC is supported.");
288 }
289 }
290 }// if(mesh.Extension.size() > 0)
291
292 meshOffsets.push_back(k);
293 k += unsigned(mesh.primitives.size());
294
295 for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
296 Mesh::Primitive& prim = mesh.primitives[p];
297
298 aiMesh* aim = new aiMesh();
299 meshes.push_back(aim);
300
301 aim->mName = mesh.id;
302 if (mesh.primitives.size() > 1) {
303 size_t& len = aim->mName.length;
304 aim->mName.data[len] = '-';
305 len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p);
306 }
307
308 switch (prim.mode) {
309 case PrimitiveMode_POINTS:
310 aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
311 break;
312
313 case PrimitiveMode_LINES:
314 case PrimitiveMode_LINE_LOOP:
315 case PrimitiveMode_LINE_STRIP:
316 aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
317 break;
318
319 case PrimitiveMode_TRIANGLES:
320 case PrimitiveMode_TRIANGLE_STRIP:
321 case PrimitiveMode_TRIANGLE_FAN:
322 aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
323 break;
324 }
325
326 Mesh::Primitive::Attributes& attr = prim.attributes;
327
328 if (attr.position.size() > 0 && attr.position[0]) {
329 aim->mNumVertices = attr.position[0]->count;
330 attr.position[0]->ExtractData(aim->mVertices);
331 }
332
333 if (attr.normal.size() > 0 && attr.normal[0]) attr.normal[0]->ExtractData(aim->mNormals);
334
335 for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
336 attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
337 aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
338
339 aiVector3D* values = aim->mTextureCoords[tc];
340 for (unsigned int i = 0; i < aim->mNumVertices; ++i) {
341 values[i].y = 1 - values[i].y; // Flip Y coords
342 }
343 }
344
345
346 if (prim.indices) {
347 aiFace* faces = 0;
348 unsigned int nFaces = 0;
349
350 unsigned int count = prim.indices->count;
351
352 Accessor::Indexer data = prim.indices->GetIndexer();
353 ai_assert(data.IsValid());
354
355 switch (prim.mode) {
356 case PrimitiveMode_POINTS: {
357 nFaces = count;
358 faces = new aiFace[nFaces];
359 for (unsigned int i = 0; i < count; ++i) {
360 SetFace(faces[i], data.GetUInt(i));
361 }
362 break;
363 }
364
365 case PrimitiveMode_LINES: {
366 nFaces = count / 2;
367 faces = new aiFace[nFaces];
368 for (unsigned int i = 0; i < count; i += 2) {
369 SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
370 }
371 break;
372 }
373
374 case PrimitiveMode_LINE_LOOP:
375 case PrimitiveMode_LINE_STRIP: {
376 nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
377 faces = new aiFace[nFaces];
378 SetFace(faces[0], data.GetUInt(0), data.GetUInt(1));
379 for (unsigned int i = 2; i < count; ++i) {
380 SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i));
381 }
382 if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
383 SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
384 }
385 break;
386 }
387
388 case PrimitiveMode_TRIANGLES: {
389 nFaces = count / 3;
390 faces = new aiFace[nFaces];
391 for (unsigned int i = 0; i < count; i += 3) {
392 SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
393 }
394 break;
395 }
396 case PrimitiveMode_TRIANGLE_STRIP: {
397 nFaces = count - 2;
398 faces = new aiFace[nFaces];
399 SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
400 for (unsigned int i = 3; i < count; ++i) {
401 SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i));
402 }
403 break;
404 }
405 case PrimitiveMode_TRIANGLE_FAN:
406 nFaces = count - 2;
407 faces = new aiFace[nFaces];
408 SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
409 for (unsigned int i = 3; i < count; ++i) {
410 SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i));
411 }
412 break;
413 }
414
415 if (faces) {
416 aim->mFaces = faces;
417 aim->mNumFaces = nFaces;
418 ai_assert(CheckValidFacesIndices(faces, nFaces, aim->mNumVertices));
419 }
420 }
421
422
423 if (prim.material) {
424 aim->mMaterialIndex = prim.material.GetIndex();
425 }
426 }
427 }
428
429 meshOffsets.push_back(k);
430
431 CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
432}
433
434void glTFImporter::ImportCameras(glTF::Asset& r)
435{
436 if (!r.cameras.Size()) return;
437
438 mScene->mNumCameras = r.cameras.Size();
439 mScene->mCameras = new aiCamera*[r.cameras.Size()];
440
441 for (size_t i = 0; i < r.cameras.Size(); ++i) {
442 Camera& cam = r.cameras[i];
443
444 aiCamera* aicam = mScene->mCameras[i] = new aiCamera();
445
446 if (cam.type == Camera::Perspective) {
447
448 aicam->mAspect = cam.perspective.aspectRatio;
449 aicam->mHorizontalFOV = cam.perspective.yfov * aicam->mAspect;
450 aicam->mClipPlaneFar = cam.perspective.zfar;
451 aicam->mClipPlaneNear = cam.perspective.znear;
452 }
453 else {
454 // assimp does not support orthographic cameras
455 }
456 }
457}
458
459void glTFImporter::ImportLights(glTF::Asset& r)
460{
461 if (!r.lights.Size()) return;
462
463 mScene->mNumLights = r.lights.Size();
464 mScene->mLights = new aiLight*[r.lights.Size()];
465
466 for (size_t i = 0; i < r.lights.Size(); ++i) {
467 Light& l = r.lights[i];
468
469 aiLight* ail = mScene->mLights[i] = new aiLight();
470
471 switch (l.type) {
472 case Light::Type_directional:
473 ail->mType = aiLightSource_DIRECTIONAL; break;
474
475 case Light::Type_spot:
476 ail->mType = aiLightSource_SPOT; break;
477
478 case Light::Type_ambient:
479 ail->mType = aiLightSource_AMBIENT; break;
480
481 default: // Light::Type_point
482 ail->mType = aiLightSource_POINT; break;
483 }
484
485 CopyValue(l.color, ail->mColorAmbient);
486 CopyValue(l.color, ail->mColorDiffuse);
487 CopyValue(l.color, ail->mColorSpecular);
488
489 ail->mAngleOuterCone = l.falloffAngle;
490 ail->mAngleInnerCone = l.falloffExponent; // TODO fix this, it does not look right at all
491
492 ail->mAttenuationConstant = l.constantAttenuation;
493 ail->mAttenuationLinear = l.linearAttenuation;
494 ail->mAttenuationQuadratic = l.quadraticAttenuation;
495 }
496}
497
498
499aiNode* ImportNode(aiScene* pScene, glTF::Asset& r, std::vector<unsigned int>& meshOffsets, glTF::Ref<glTF::Node>& ptr)
500{
501 Node& node = *ptr;
502
503 aiNode* ainode = new aiNode(node.id);
504
505 if (!node.children.empty()) {
506 ainode->mNumChildren = unsigned(node.children.size());
507 ainode->mChildren = new aiNode*[ainode->mNumChildren];
508
509 for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
510 aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]);
511 child->mParent = ainode;
512 ainode->mChildren[i] = child;
513 }
514 }
515
516 aiMatrix4x4& matrix = ainode->mTransformation;
517 if (node.matrix.isPresent) {
518 CopyValue(node.matrix.value, matrix);
519 }
520 else {
521 if (node.translation.isPresent) {
522 aiVector3D trans;
523 CopyValue(node.translation.value, trans);
524 aiMatrix4x4 t;
525 aiMatrix4x4::Translation(trans, t);
526 matrix = t * matrix;
527 }
528
529 if (node.scale.isPresent) {
530 aiVector3D scal(1.f);
531 CopyValue(node.scale.value, scal);
532 aiMatrix4x4 s;
533 aiMatrix4x4::Scaling(scal, s);
534 matrix = s * matrix;
535 }
536
537
538 if (node.rotation.isPresent) {
539 aiQuaternion rot;
540 CopyValue(node.rotation.value, rot);
541 matrix = aiMatrix4x4(rot.GetMatrix()) * matrix;
542 }
543 }
544
545 if (!node.meshes.empty()) {
546 int count = 0;
547 for (size_t i = 0; i < node.meshes.size(); ++i) {
548 int idx = node.meshes[i].GetIndex();
549 count += meshOffsets[idx + 1] - meshOffsets[idx];
550 }
551
552 ainode->mNumMeshes = count;
553 ainode->mMeshes = new unsigned int[count];
554
555 int k = 0;
556 for (size_t i = 0; i < node.meshes.size(); ++i) {
557 int idx = node.meshes[i].GetIndex();
558 for (unsigned int j = meshOffsets[idx]; j < meshOffsets[idx + 1]; ++j, ++k) {
559 ainode->mMeshes[k] = j;
560 }
561 }
562 }
563
564 if (node.camera) {
565 pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
566 }
567
568 if (node.light) {
569 pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
570 }
571
572 return ainode;
573}
574
575void glTFImporter::ImportNodes(glTF::Asset& r)
576{
577 if (!r.scene) return;
578
579 std::vector< Ref<Node> > rootNodes = r.scene->nodes;
580
581 // The root nodes
582 unsigned int numRootNodes = unsigned(rootNodes.size());
583 if (numRootNodes == 1) { // a single root node: use it
584 mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
585 }
586 else if (numRootNodes > 1) { // more than one root node: create a fake root
587 aiNode* root = new aiNode("ROOT");
588 root->mChildren = new aiNode*[numRootNodes];
589 for (unsigned int i = 0; i < numRootNodes; ++i) {
590 aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
591 node->mParent = root;
592 root->mChildren[root->mNumChildren++] = node;
593 }
594 mScene->mRootNode = root;
595 }
596
597 //if (!mScene->mRootNode) {
598 // mScene->mRootNode = new aiNode("EMPTY");
599 //}
600}
601
602void glTFImporter::ImportEmbeddedTextures(glTF::Asset& r)
603{
604 embeddedTexIdxs.resize(r.images.Size(), -1);
605
606 int numEmbeddedTexs = 0;
607 for (size_t i = 0; i < r.images.Size(); ++i) {
608 if (r.images[i].HasData())
609 numEmbeddedTexs += 1;
610 }
611
612 if (numEmbeddedTexs == 0)
613 return;
614
615 mScene->mTextures = new aiTexture*[numEmbeddedTexs];
616
617 // Add the embedded textures
618 for (size_t i = 0; i < r.images.Size(); ++i) {
619 Image img = r.images[i];
620 if (!img.HasData()) continue;
621
622 int idx = mScene->mNumTextures++;
623 embeddedTexIdxs[i] = idx;
624
625 aiTexture* tex = mScene->mTextures[idx] = new aiTexture();
626
627 size_t length = img.GetDataLength();
628 void* data = img.StealData();
629
630 tex->mWidth = static_cast<unsigned int>(length);
631 tex->mHeight = 0;
632 tex->pcData = reinterpret_cast<aiTexel*>(data);
633
634 if (!img.mimeType.empty()) {
635 const char* ext = strchr(img.mimeType.c_str(), '/') + 1;
636 if (ext) {
637 if (strcmp(ext, "jpeg") == 0) ext = "jpg";
638
639 size_t len = strlen(ext);
640 if (len <= 3) {
641 strcpy(tex->achFormatHint, ext);
642 }
643 }
644 }
645 }
646}
647
648void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
649
650 this->mScene = pScene;
651
652 // read the asset file
653 glTF::Asset asset(pIOHandler);
654 asset.Load(pFile, GetExtension(pFile) == "glb");
655
656
657 //
658 // Copy the data out
659 //
660
661 ImportEmbeddedTextures(asset);
662 ImportMaterials(asset);
663
664 ImportMeshes(asset);
665
666 ImportCameras(asset);
667 ImportLights(asset);
668
669 ImportNodes(asset);
670
671 // TODO: it does not split the loaded vertices, should it?
672 //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
673 MakeVerboseFormatProcess process;
674 process.Execute(pScene);
675
676
677 if (pScene->mNumMeshes == 0) {
678 pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
679 }
680}
681
682#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
683
684