1 // Author: Kirill Gavrilov
2 // Copyright (c) 2016-2019 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include "RWGltf_GltfJsonParser.pxx"
17 #include <BRep_Builder.hxx>
18 #include <gp_Quaternion.hxx>
19 #include <Message.hxx>
20 #include <Message_Messenger.hxx>
21 #include <Message_ProgressSentry.hxx>
22 #include <OSD_File.hxx>
23 #include <OSD_OpenFile.hxx>
24 #include <OSD_Path.hxx>
25 #include <OSD_ThreadPool.hxx>
26 #include <Precision.hxx>
27 #include <FSD_Base64Decoder.hxx>
28 #include <TopExp_Explorer.hxx>
30 #include <TopoDS_Iterator.hxx>
37 //! Material extension.
38 const char THE_KHR_materials_common[] = "KHR_materials_common";
39 const char THE_KHR_binary_glTF[] = "KHR_binary_glTF";
42 //! Find member of the object in a safe way.
43 inline const RWGltf_JsonValue* findObjectMember (const RWGltf_JsonValue& theObject,
44 const RWGltf_JsonValue& theName)
46 if (!theObject.IsObject()
47 || !theName.IsString())
52 rapidjson::Document::ConstMemberIterator anIter = theObject.FindMember (theName);
53 return anIter != theObject.MemberEnd()
58 //! Find member of the object in a safe way.
59 inline const RWGltf_JsonValue* findObjectMember (const RWGltf_JsonValue& theObject,
62 if (!theObject.IsObject())
67 rapidjson::Document::ConstMemberIterator anIter = theObject.FindMember (theName);
68 return anIter != theObject.MemberEnd()
73 // =======================================================================
74 // function : RWGltf_GltfJsonParser::FormatParseError
76 // =======================================================================
77 const char* RWGltf_GltfJsonParser::FormatParseError (rapidjson::ParseErrorCode theCode)
81 case rapidjson::kParseErrorNone: return "";
82 case rapidjson::kParseErrorDocumentEmpty: return "Empty Document";
83 case rapidjson::kParseErrorDocumentRootNotSingular: return "The document root must not follow by other values";
84 case rapidjson::kParseErrorValueInvalid: return "Invalid value";
85 case rapidjson::kParseErrorObjectMissName: return "Missing a name for object member";
86 case rapidjson::kParseErrorObjectMissColon: return "Missing a colon after a name of object member";
87 case rapidjson::kParseErrorObjectMissCommaOrCurlyBracket: return "Missing a comma or '}' after an object member";
88 case rapidjson::kParseErrorArrayMissCommaOrSquareBracket: return "Missing a comma or ']' after an array element";
89 case rapidjson::kParseErrorStringUnicodeEscapeInvalidHex: return "Incorrect hex digit after \\u escape in string";
90 case rapidjson::kParseErrorStringUnicodeSurrogateInvalid: return "The surrogate pair in string is invalid";
91 case rapidjson::kParseErrorStringEscapeInvalid: return "Invalid escape character in string";
92 case rapidjson::kParseErrorStringMissQuotationMark: return "Missing a closing quotation mark in string";
93 case rapidjson::kParseErrorStringInvalidEncoding: return "Invalid encoding in string";
94 case rapidjson::kParseErrorNumberTooBig: return "Number is too big to be stored in double";
95 case rapidjson::kParseErrorNumberMissFraction: return "Miss fraction part in number";
96 case rapidjson::kParseErrorNumberMissExponent: return "Miss exponent in number";
97 case rapidjson::kParseErrorTermination: return "Parsing was terminated";
98 case rapidjson::kParseErrorUnspecificSyntaxError: return "Unspecific syntax error";
100 return "UNKOWN syntax error";
103 // =======================================================================
104 // function : GltfElementMap::Init
106 // =======================================================================
107 void RWGltf_GltfJsonParser::GltfElementMap::Init (const TCollection_AsciiString& theRootName,
108 const RWGltf_JsonValue* theRoot)
117 if (theRoot->IsObject())
120 for (ConstMemberIterator aChildIter = theRoot->MemberBegin(); aChildIter != theRoot->MemberEnd(); ++aChildIter)
122 if (!aChildIter->name.IsString())
127 const TCollection_AsciiString aKey (aChildIter->name.GetString());
128 if (!myChildren.Bind (aKey, &aChildIter->value))
130 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Invalid glTF syntax - key '")
131 + aKey + "' is already defined in '" + theRootName + "'.", Message_Warning);
135 else if (theRoot->IsArray())
139 for (rapidjson::Value::ConstValueIterator aChildIter = theRoot->Begin(); aChildIter != theRoot->End(); ++aChildIter, ++aChildIndex)
141 myChildren.Bind (TCollection_AsciiString (aChildIndex), aChildIter);
147 // Auxiliary macros for formatting message.
148 #define reportGltfError(theMsg) reportGltfSyntaxProblem(TCollection_AsciiString() + theMsg, Message_Fail);
149 #define reportGltfWarning(theMsg) reportGltfSyntaxProblem(TCollection_AsciiString() + theMsg, Message_Warning);
151 // =======================================================================
152 // function : reportGltfSyntaxProblem
154 // =======================================================================
155 void RWGltf_GltfJsonParser::reportGltfSyntaxProblem (const TCollection_AsciiString& theMsg,
156 Message_Gravity theGravity)
158 Message::DefaultMessenger()->Send (myErrorPrefix + theMsg, theGravity);
161 // =======================================================================
162 // function : RWGltf_GltfJsonParser
164 // =======================================================================
165 RWGltf_GltfJsonParser::RWGltf_GltfJsonParser (TopTools_SequenceOfShape& theRootShapes)
166 : myRootShapes(&theRootShapes),
168 myExternalFiles (NULL),
173 myToSkipEmptyNodes (true),
174 myToProbeHeader (false)
176 myCSTrsf.SetInputLengthUnit (1.0); // meters
177 myCSTrsf.SetInputCoordinateSystem (RWMesh_CoordinateSystem_glTF);
180 // =======================================================================
181 // function : SetFilePath
183 // =======================================================================
184 void RWGltf_GltfJsonParser::SetFilePath (const TCollection_AsciiString& theFilePath)
186 myFilePath = theFilePath;
187 // determine file location to load associated files
188 TCollection_AsciiString aFileName;
189 OSD_Path::FolderAndFileFromPath (theFilePath, myFolder, aFileName);
192 #ifdef HAVE_RAPIDJSON
193 // =======================================================================
194 // function : gltfParseRoots
196 // =======================================================================
197 bool RWGltf_GltfJsonParser::gltfParseRoots()
199 // find glTF root elements for smooth navigation
200 RWGltf_JsonValue aNames[RWGltf_GltfRootElement_NB];
201 for (int aRootNameIter = 0; aRootNameIter < RWGltf_GltfRootElement_NB; ++aRootNameIter)
203 aNames[aRootNameIter] = rapidjson::StringRef (RWGltf_GltfRootElementName ((RWGltf_GltfRootElement )aRootNameIter));
206 for (ConstMemberIterator aRootIter = MemberBegin();
207 aRootIter != MemberEnd(); ++aRootIter)
209 for (int aRootNameIter = 0; aRootNameIter < RWGltf_GltfRootElement_NB; ++aRootNameIter)
211 if (myGltfRoots[aRootNameIter].IsNull()
212 && aNames[aRootNameIter] == aRootIter->name)
214 // we will not modify JSON document, thus it is OK to keep the pointers
215 myGltfRoots[aRootNameIter].Init (RWGltf_GltfRootElementName ((RWGltf_GltfRootElement )aRootNameIter), &aRootIter->value);
221 for (int aRootNameIter = 0; aRootNameIter < RWGltf_GltfRootElement_NB_MANDATORY; ++aRootNameIter)
223 if (myGltfRoots[aRootNameIter].IsNull())
225 reportGltfError ("Member '" + RWGltf_GltfRootElementName ((RWGltf_GltfRootElement )aRootNameIter) + "' is not found.");
232 // =======================================================================
233 // function : gltfParseAsset
235 // =======================================================================
236 void RWGltf_GltfJsonParser::gltfParseAsset()
238 const RWGltf_JsonValue* anAsset = myGltfRoots[RWGltf_GltfRootElement_Asset].Root();
244 if (const RWGltf_JsonValue* aVersion = findObjectMember (*anAsset, "version"))
246 if (aVersion->IsString())
248 TCollection_AsciiString aVerStr (aVersion->GetString());
249 myIsGltf1 = aVerStr.StartsWith ("1.");
253 if (const RWGltf_JsonValue* aGenerator = findObjectMember (*anAsset, "generator"))
255 if (aGenerator->IsString())
257 myMetadata.Add ("generator", aGenerator->GetString());
260 if (const RWGltf_JsonValue* aCopyRight = findObjectMember (*anAsset, "copyright"))
262 if (aCopyRight->IsString())
264 myMetadata.Add ("copyright", aCopyRight->GetString());
269 // =======================================================================
270 // function : gltfParseMaterials
272 // =======================================================================
273 void RWGltf_GltfJsonParser::gltfParseMaterials()
275 const RWGltf_JsonValue* aMatList = myGltfRoots[RWGltf_GltfRootElement_Materials].Root();
276 if (aMatList == NULL)
280 else if (aMatList->IsObject())
283 for (ConstMemberIterator aMatIter = aMatList->MemberBegin();
284 aMatIter != aMatList->MemberEnd(); ++aMatIter)
286 Handle(RWGltf_MaterialCommon) aMat;
287 const RWGltf_JsonValue& aMatNode = aMatIter->value;
288 const RWGltf_JsonValue& aMatId = aMatIter->name;
289 const RWGltf_JsonValue* aNameVal = findObjectMember (aMatNode, "name");
290 if (!gltfParseCommonMaterial (aMat, aMatNode))
292 if (!gltfParseStdMaterial (aMat, aMatNode))
299 && aNameVal->IsString())
301 aMat->Name = aNameVal->GetString();
303 aMat->Id = aMatId.GetString();
304 myMaterialsCommon.Bind (aMat->Id, aMat);
307 else if (aMatList->IsArray())
311 for (rapidjson::Value::ConstValueIterator aMatIter = aMatList->Begin(); aMatIter != aMatList->End(); ++aMatIter, ++aMatIndex)
313 Handle(RWGltf_MaterialMetallicRoughness) aMatPbr;
314 const RWGltf_JsonValue& aMatNode = *aMatIter;
315 const RWGltf_JsonValue* aNameVal = findObjectMember (aMatNode, "name");
316 if (gltfParsePbrMaterial (aMatPbr, aMatNode))
319 && aNameVal->IsString())
321 aMatPbr->Name = aNameVal->GetString();
323 aMatPbr->Id = TCollection_AsciiString ("mat_") + aMatIndex;
324 myMaterialsPbr.Bind (TCollection_AsciiString (aMatIndex), aMatPbr);
327 Handle(RWGltf_MaterialCommon) aMatCommon;
328 if (gltfParseCommonMaterial(aMatCommon, aMatNode)
329 || gltfParseStdMaterial (aMatCommon, aMatNode))
332 && aNameVal->IsString())
334 aMatCommon->Name = aNameVal->GetString();
336 aMatCommon->Id = TCollection_AsciiString ("mat_") + aMatIndex;
337 myMaterialsCommon.Bind (TCollection_AsciiString (aMatIndex), aMatCommon);
343 // =======================================================================
344 // function : gltfParseStdMaterial
346 // =======================================================================
347 bool RWGltf_GltfJsonParser::gltfParseStdMaterial (Handle(RWGltf_MaterialCommon)& theMat,
348 const RWGltf_JsonValue& theMatNode)
350 //const RWGltf_JsonValue* aTechVal = findObjectMember (theMatNode, "technique");
351 const RWGltf_JsonValue* aValues = findObjectMember (theMatNode, "values");
357 const RWGltf_JsonValue* anAmbVal = findObjectMember (*aValues, "ambient");
358 const RWGltf_JsonValue* aDiffVal = findObjectMember (*aValues, "diffuse");
359 const RWGltf_JsonValue* anEmiVal = findObjectMember (*aValues, "emission");
360 const RWGltf_JsonValue* aSpecVal = findObjectMember (*aValues, "specular");
361 const RWGltf_JsonValue* aShinVal = findObjectMember (*aValues, "shininess");
371 theMat = new RWGltf_MaterialCommon();
373 Graphic3d_Vec4d anAmb, aDiff, anEmi, aSpec;
375 && anAmbVal->IsString())
377 gltfParseTexture (theMat->AmbientTexture, anAmbVal);
379 else if (gltfReadVec4 (anAmb, anAmbVal)
380 && validateColor4 (anAmb))
382 theMat->AmbientColor = Quantity_Color (anAmb.r(), anAmb.g(), anAmb.b(), Quantity_TOC_RGB);
386 && aDiffVal->IsString())
388 gltfParseTexture (theMat->DiffuseTexture, aDiffVal);
390 else if (gltfReadVec4 (aDiff, aDiffVal)
391 && validateColor4 (aDiff))
393 theMat->DiffuseColor = Quantity_Color (aDiff.r(), aDiff.g(), aDiff.b(), Quantity_TOC_RGB);
394 theMat->Transparency = float(1.0 - aDiff.a());
397 if (gltfReadVec4 (anEmi, anEmiVal)
398 && validateColor4 (anEmi))
400 theMat->EmissiveColor = Quantity_Color (anEmi.r(), anEmi.g(), anEmi.b(), Quantity_TOC_RGB);
404 && aSpecVal->IsString())
406 gltfParseTexture (theMat->SpecularTexture, aSpecVal);
408 if (gltfReadVec4 (aSpec, aSpecVal)
409 && validateColor4 (aSpec))
411 theMat->SpecularColor = Quantity_Color (aSpec.r(), aSpec.g(), aSpec.b(), Quantity_TOC_RGB);
415 && aShinVal->IsNumber())
417 const double aSpecular = aShinVal->GetDouble();
420 theMat->Shininess = (float )Min (aSpecular / 1000.0, 1.0);
426 // =======================================================================
427 // function : gltfParsePbrMaterial
429 // =======================================================================
430 bool RWGltf_GltfJsonParser::gltfParsePbrMaterial (Handle(RWGltf_MaterialMetallicRoughness)& theMat,
431 const RWGltf_JsonValue& theMatNode)
433 /*if (const RWGltf_JsonValue* anExtVal = findObjectMember (theMatNode, "extensions"))
435 if (const RWGltf_JsonValue* anExtDefVal = findObjectMember (*anExtVal, "KHR_materials_pbrSpecularGlossiness"))
437 const RWGltf_JsonValue* aDiffTexVal = findObjectMember (*anExtDefVal, "diffuseTexture");
438 const RWGltf_JsonValue* aSpecTexVal = findObjectMember (*anExtDefVal, "specularGlossinessTexture");
442 const RWGltf_JsonValue* aMetalRoughVal = findObjectMember (theMatNode, "pbrMetallicRoughness");
443 const RWGltf_JsonValue* aNormTexVal = findObjectMember (theMatNode, "normalTexture");
444 const RWGltf_JsonValue* anEmissFactorVal = findObjectMember (theMatNode, "emissiveFactor");
445 const RWGltf_JsonValue* anEmissTexVal = findObjectMember (theMatNode, "emissiveTexture");
446 const RWGltf_JsonValue* anOcclusionTexVal = findObjectMember (theMatNode, "occlusionTexture");
447 if (aMetalRoughVal == NULL)
452 theMat = new RWGltf_MaterialMetallicRoughness();
453 const RWGltf_JsonValue* aBaseColorFactorVal = findObjectMember (*aMetalRoughVal, "baseColorFactor");
454 const RWGltf_JsonValue* aBaseColorTexVal = findObjectMember (*aMetalRoughVal, "baseColorTexture");
455 const RWGltf_JsonValue* aMetallicFactorVal = findObjectMember (*aMetalRoughVal, "metallicFactor");
456 const RWGltf_JsonValue* aRoughnessFactorVal = findObjectMember (*aMetalRoughVal, "roughnessFactor");
457 const RWGltf_JsonValue* aMetalRoughTexVal = findObjectMember (*aMetalRoughVal, "metallicRoughnessTexture");
459 if (aBaseColorTexVal != NULL
460 && aBaseColorTexVal->IsObject())
462 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*aBaseColorTexVal, "index"))
464 gltfParseTexture (theMat->BaseColorTexture, aTexIndexVal);
468 Graphic3d_Vec4d aBaseColorFactor;
469 if (gltfReadVec4 (aBaseColorFactor, aBaseColorFactorVal)
470 && validateColor4 (aBaseColorFactor))
472 theMat->BaseColor = Quantity_ColorRGBA (Graphic3d_Vec4 (aBaseColorFactor));
475 Graphic3d_Vec3d anEmissiveFactor;
476 if (gltfReadVec3 (anEmissiveFactor, anEmissFactorVal)
477 && validateColor3 (anEmissiveFactor))
479 theMat->EmissiveFactor = Graphic3d_Vec3 (anEmissiveFactor);
482 if (aMetalRoughTexVal != NULL
483 && aMetalRoughTexVal->IsObject())
485 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*aMetalRoughTexVal, "index"))
487 gltfParseTexture (theMat->MetallicRoughnessTexture, aTexIndexVal);
491 if (aMetallicFactorVal != NULL
492 && aMetallicFactorVal->IsNumber())
494 theMat->Metallic = (float )aMetallicFactorVal->GetDouble();
497 if (aRoughnessFactorVal != NULL
498 && aRoughnessFactorVal->IsNumber())
500 theMat->Roughness = (float )aRoughnessFactorVal->GetDouble();
503 if (aNormTexVal != NULL
504 && aNormTexVal->IsObject())
506 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*aNormTexVal, "index"))
508 gltfParseTexture (theMat->NormalTexture, aTexIndexVal);
512 if (anEmissTexVal != NULL
513 && anEmissTexVal->IsObject())
515 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*anEmissTexVal, "index"))
517 gltfParseTexture (theMat->EmissiveTexture, aTexIndexVal);
521 if (anOcclusionTexVal != NULL
522 && anOcclusionTexVal->IsObject())
524 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*anOcclusionTexVal, "index"))
526 gltfParseTexture (theMat->OcclusionTexture, aTexIndexVal);
532 // =======================================================================
533 // function : gltfParseCommonMaterial
535 // =======================================================================
536 bool RWGltf_GltfJsonParser::gltfParseCommonMaterial (Handle(RWGltf_MaterialCommon)& theMat,
537 const RWGltf_JsonValue& theMatNode)
539 const RWGltf_JsonValue* anExtVal = findObjectMember (theMatNode, "extensions");
540 if (anExtVal == NULL)
545 const RWGltf_JsonValue* aMatCommon = findObjectMember (*anExtVal, THE_KHR_materials_common);
546 if (aMatCommon == NULL)
551 if (!gltfParseStdMaterial (theMat, *aMatCommon))
558 // =======================================================================
559 // function : gltfParseTexture
561 // =======================================================================
562 bool RWGltf_GltfJsonParser::gltfParseTexture (Handle(Image_Texture)& theTexture,
563 const RWGltf_JsonValue* theTextureId)
565 if (theTextureId == NULL
566 || myGltfRoots[RWGltf_GltfRootElement_Textures].IsNull()
567 || myGltfRoots[RWGltf_GltfRootElement_Images].IsNull())
572 const TCollection_AsciiString aTextureId = getKeyString (*theTextureId);
573 const RWGltf_JsonValue* aTexNode = myGltfRoots[RWGltf_GltfRootElement_Textures].FindChild (*theTextureId);
574 if (aTexNode == NULL)
576 reportGltfWarning ("Texture node '" + aTextureId + "' is not found.");
580 const RWGltf_JsonValue* aSrcVal = findObjectMember (*aTexNode, "source");
581 const RWGltf_JsonValue* aTargVal = findObjectMember (*aTexNode, "target");
584 reportGltfWarning ("Invalid texture node '" + aTextureId + "' without a 'source' property.");
588 && aTargVal->IsNumber()
589 && aTargVal->GetInt() != 3553) // GL_TEXTURE_2D
594 const RWGltf_JsonValue* anImgNode = myGltfRoots[RWGltf_GltfRootElement_Images].FindChild (*aSrcVal);
595 if (anImgNode == NULL)
597 reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to non-existing image '" + getKeyString (*aSrcVal) + "'.");
603 const RWGltf_JsonValue* aBinVal = NULL;
604 const RWGltf_JsonValue* aBufferViewName = findObjectMember (*anImgNode, "bufferView");
605 if (aBufferViewName != NULL)
611 const RWGltf_JsonValue* anExtVal = findObjectMember (*anImgNode, "extensions");
612 if (anExtVal != NULL)
614 aBinVal = findObjectMember (*anExtVal, THE_KHR_binary_glTF);
617 aBufferViewName = findObjectMember (*aBinVal, "bufferView");
624 //const RWGltf_JsonValue* aMimeTypeVal = findObjectMember (*aBinVal, "mimeType");
625 //const RWGltf_JsonValue* aWidthVal = findObjectMember (*aBinVal, "width");
626 //const RWGltf_JsonValue* aHeightVal = findObjectMember (*aBinVal, "height");
627 if (aBufferViewName == NULL)
629 reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid data source.");
633 const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
634 if (aBufferView == NULL
635 || !aBufferView->IsObject())
637 reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid buffer view '" + getKeyString (*aBufferViewName) + "'.");
641 const RWGltf_JsonValue* aBufferName = findObjectMember (*aBufferView, "buffer");
642 const RWGltf_JsonValue* aByteLength = findObjectMember (*aBufferView, "byteLength");
643 const RWGltf_JsonValue* aByteOffset = findObjectMember (*aBufferView, "byteOffset");
644 if (aBufferName != NULL
645 && aBufferName->IsString()
646 && !IsEqual (aBufferName->GetString(), "binary_glTF"))
648 reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' does not define binary_glTF buffer.");
652 RWGltf_GltfBufferView aBuffView;
653 aBuffView.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
654 ? (int64_t )aByteOffset->GetDouble()
656 aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
657 ? (int64_t )aByteLength->GetDouble()
659 if (aBuffView.ByteLength < 0)
661 reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' defines invalid byteLength.");
664 else if (aBuffView.ByteOffset < 0)
666 reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' defines invalid byteOffset.");
671 const int64_t anOffset = myBinBodyOffset + aBuffView.ByteOffset;
672 theTexture = new Image_Texture (myFilePath, anOffset, aBuffView.ByteLength);
677 const RWGltf_JsonValue* anUriVal = findObjectMember (*anImgNode, "uri");
679 || !anUriVal->IsString())
684 const char* anUriData = anUriVal->GetString();
685 if (::strncmp (anUriData, "data:", 5) == 0) // data:image/png;base64
687 // uncompressing base64 here is inefficient, because the same image can be shared by several nodes
688 const char* aDataStart = anUriData + 5;
689 for (const char* aDataIter = aDataStart; *aDataIter != '\0'; ++aDataIter)
691 if (::memcmp (aDataIter, ";base64,", 8) == 0)
693 const char* aBase64End = anUriData + anUriVal->GetStringLength();
694 const char* aBase64Data = aDataIter + 8;
695 const size_t aBase64Len = size_t(aBase64End - aBase64Data);
696 //const TCollection_AsciiString aMime (aDataStart, aDataIter - aDataStart);
697 Handle(NCollection_Buffer) aData = FSD_Base64Decoder::Decode ((const Standard_Byte* )aBase64Data, aBase64Len);
698 theTexture = new Image_Texture (aData, myFilePath + "@" + getKeyString (*aSrcVal));
702 Message::DefaultMessenger()->Send ("glTF reader - embedded image has been skipped", Message_Warning);
706 TCollection_AsciiString anImageFile = myFolder + anUriVal->GetString();
707 theTexture = new Image_Texture (anImageFile);
708 if (myExternalFiles != NULL)
710 myExternalFiles->Add (anImageFile);
715 // =======================================================================
716 // function : gltfParseScene
718 // =======================================================================
719 bool RWGltf_GltfJsonParser::gltfParseScene (const Handle(Message_ProgressIndicator)& theProgress)
721 // search default scene
722 const RWGltf_JsonValue* aDefScene = myGltfRoots[RWGltf_GltfRootElement_Scenes].FindChild (*myGltfRoots[RWGltf_GltfRootElement_Scene].Root());
723 if (aDefScene == NULL)
725 reportGltfError ("Default scene is not found.");
729 const RWGltf_JsonValue* aSceneNodes = findObjectMember (*aDefScene, "nodes");
730 if (aSceneNodes == NULL
731 || !aSceneNodes->IsArray())
733 reportGltfError ("Empty scene '" + getKeyString (*myGltfRoots[RWGltf_GltfRootElement_Scene].Root()) + "'.");
737 return gltfParseSceneNodes (*myRootShapes, *aSceneNodes, theProgress);
740 // =======================================================================
741 // function : gltfParseSceneNodes
743 // =======================================================================
744 bool RWGltf_GltfJsonParser::gltfParseSceneNodes (TopTools_SequenceOfShape& theShapeSeq,
745 const RWGltf_JsonValue& theSceneNodes,
746 const Handle(Message_ProgressIndicator)& theProgress)
748 if (!theSceneNodes.IsArray())
750 reportGltfError ("Scene nodes is not array.");
754 Message_ProgressSentry aPSentry (theProgress, "Reading scene nodes", 0, theSceneNodes.Size(), 1);
755 for (rapidjson::Value::ConstValueIterator aSceneNodeIter = theSceneNodes.Begin();
756 aSceneNodeIter != theSceneNodes.End() && aPSentry.More(); ++aSceneNodeIter, aPSentry.Next())
758 const RWGltf_JsonValue* aSceneNode = myGltfRoots[RWGltf_GltfRootElement_Nodes].FindChild (*aSceneNodeIter);
759 if (aSceneNode == NULL)
761 reportGltfWarning ("Scene refers to non-existing node '" + getKeyString (*aSceneNodeIter) + "'.");
765 TopoDS_Shape aNodeShape;
766 if (!gltfParseSceneNode (aNodeShape, getKeyString (*aSceneNodeIter), *aSceneNode, theProgress))
771 if (aNodeShape.IsNull())
775 else if (myToSkipEmptyNodes
776 && !TopExp_Explorer (aNodeShape, TopAbs_FACE).More())
781 theShapeSeq.Append (aNodeShape);
786 // =======================================================================
787 // function : gltfParseSceneNode
789 // =======================================================================
790 bool RWGltf_GltfJsonParser::gltfParseSceneNode (TopoDS_Shape& theNodeShape,
791 const TCollection_AsciiString& theSceneNodeId,
792 const RWGltf_JsonValue& theSceneNode,
793 const Handle(Message_ProgressIndicator)& theProgress)
795 const RWGltf_JsonValue* aName = findObjectMember (theSceneNode, "name");
796 //const RWGltf_JsonValue* aJointName = findObjectMember (theSceneNode, "jointName");
797 const RWGltf_JsonValue* aChildren = findObjectMember (theSceneNode, "children");
798 const RWGltf_JsonValue* aMeshes_1 = findObjectMember (theSceneNode, "meshes");
799 const RWGltf_JsonValue* aMesh_2 = findObjectMember (theSceneNode, "mesh");
800 //const RWGltf_JsonValue* aCamera = findObjectMember (theSceneNode, "camera");
801 const RWGltf_JsonValue* aTrsfMatVal = findObjectMember (theSceneNode, "matrix");
802 const RWGltf_JsonValue* aTrsfRotVal = findObjectMember (theSceneNode, "rotation");
803 const RWGltf_JsonValue* aTrsfScaleVal = findObjectMember (theSceneNode, "scale");
804 const RWGltf_JsonValue* aTrsfTransVal = findObjectMember (theSceneNode, "translation");
805 if (findNodeShape (theNodeShape, theSceneNodeId))
810 TopLoc_Location aNodeLoc;
811 const bool hasTrs = aTrsfRotVal != NULL
812 || aTrsfScaleVal != NULL
813 || aTrsfTransVal != NULL;
814 if (aTrsfMatVal != NULL)
818 reportGltfError ("Scene node '" + theSceneNodeId + "' defines ambiguous transformation.");
821 else if (!aTrsfMatVal->IsArray()
822 || aTrsfMatVal->Size() != 16)
824 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid transformation matrix array.");
828 Graphic3d_Mat4d aMat4;
829 for (int aColIter = 0; aColIter < 4; ++aColIter)
831 for (int aRowIter = 0; aRowIter < 4; ++aRowIter)
833 const RWGltf_JsonValue& aGenVal = (*aTrsfMatVal)[aColIter * 4 + aRowIter];
834 if (!aGenVal.IsNumber())
836 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid transformation matrix.");
839 aMat4.SetValue (aRowIter, aColIter, aGenVal.GetDouble());
843 if (!aMat4.IsIdentity())
846 aTrsf.SetValues (aMat4.GetValue (0, 0), aMat4.GetValue (0, 1), aMat4.GetValue (0, 2), aMat4.GetValue (0, 3),
847 aMat4.GetValue (1, 0), aMat4.GetValue (1, 1), aMat4.GetValue (1, 2), aMat4.GetValue (1, 3),
848 aMat4.GetValue (2, 0), aMat4.GetValue (2, 1), aMat4.GetValue (2, 2), aMat4.GetValue (2, 3));
849 myCSTrsf.TransformTransformation (aTrsf);
850 if (aTrsf.Form() != gp_Identity)
852 aNodeLoc = TopLoc_Location (aTrsf);
859 if (aTrsfRotVal != NULL)
861 if (!aTrsfRotVal->IsArray()
862 || aTrsfRotVal->Size() != 4)
864 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid rotation quaternion.");
868 Graphic3d_Vec4d aRotVec4;
869 for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
871 const RWGltf_JsonValue& aGenVal = (*aTrsfRotVal)[aCompIter];
872 if (!aGenVal.IsNumber())
874 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid rotation.");
877 aRotVec4[aCompIter] = aGenVal.GetDouble();
879 const gp_Quaternion aQuaternion (aRotVec4.x(), aRotVec4.y(), aRotVec4.z(), aRotVec4.w());
880 if (Abs (aQuaternion.X()) > gp::Resolution()
881 || Abs (aQuaternion.Y()) > gp::Resolution()
882 || Abs (aQuaternion.Z()) > gp::Resolution()
883 || Abs (aQuaternion.W() - 1.0) > gp::Resolution())
885 aTrsf.SetRotation (aQuaternion);
889 if (aTrsfTransVal != NULL)
891 if (!aTrsfTransVal->IsArray()
892 || aTrsfTransVal->Size() != 3)
894 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid translation vector.");
899 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
901 const RWGltf_JsonValue& aGenVal = (*aTrsfTransVal)[aCompIter];
902 if (!aGenVal.IsNumber())
904 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid translation.");
907 aTransVec.SetCoord (aCompIter + 1, aGenVal.GetDouble());
909 aTrsf.SetTranslationPart (aTransVec);
912 if (aTrsfScaleVal != NULL)
914 Graphic3d_Vec3d aScaleVec;
915 if (!aTrsfScaleVal->IsArray()
916 || aTrsfScaleVal->Size() != 3)
918 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid scale vector.");
921 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
923 const RWGltf_JsonValue& aGenVal = (*aTrsfScaleVal)[aCompIter];
924 if (!aGenVal.IsNumber())
926 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid scale.");
929 aScaleVec[aCompIter] = aGenVal.GetDouble();
930 if (Abs (aScaleVec[aCompIter]) <= gp::Resolution())
932 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid scale.");
937 if (Abs (aScaleVec.x() - aScaleVec.y()) > Precision::Confusion()
938 || Abs (aScaleVec.y() - aScaleVec.z()) > Precision::Confusion()
939 || Abs (aScaleVec.x() - aScaleVec.z()) > Precision::Confusion())
941 Graphic3d_Mat4d aScaleMat;
942 aScaleMat.SetDiagonal (aScaleVec);
944 Graphic3d_Mat4d aMat4;
945 aTrsf.GetMat4 (aMat4);
947 aMat4 = aMat4 * aScaleMat;
949 aTrsf.SetValues (aMat4.GetValue (0, 0), aMat4.GetValue (0, 1), aMat4.GetValue (0, 2), aMat4.GetValue (0, 3),
950 aMat4.GetValue (1, 0), aMat4.GetValue (1, 1), aMat4.GetValue (1, 2), aMat4.GetValue (1, 3),
951 aMat4.GetValue (2, 0), aMat4.GetValue (2, 1), aMat4.GetValue (2, 2), aMat4.GetValue (2, 3));
953 Message::DefaultMessenger()->Send (TCollection_AsciiString ("glTF reader, scene node '")
954 + theSceneNodeId + "' defines unsupported scaling "
955 + aScaleVec.x() + " " + aScaleVec.y() + " " + aScaleVec.z(), Message_Warning);
957 else if (Abs (aScaleVec.x() - 1.0) > Precision::Confusion())
959 aTrsf.SetScaleFactor (aScaleVec.x());
963 myCSTrsf.TransformTransformation (aTrsf);
964 if (aTrsf.Form() != gp_Identity)
966 aNodeLoc = TopLoc_Location (aTrsf);
970 BRep_Builder aBuilder;
971 TopoDS_Compound aNodeShape;
972 aBuilder.MakeCompound (aNodeShape);
973 TopTools_SequenceOfShape aChildShapes;
974 int aNbSubShapes = 0;
975 if (aChildren != NULL
976 && !gltfParseSceneNodes (aChildShapes, *aChildren, theProgress))
978 theNodeShape = aNodeShape;
979 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
982 for (TopTools_SequenceOfShape::Iterator aChildShapeIter (aChildShapes); aChildShapeIter.More(); aChildShapeIter.Next())
984 aBuilder.Add (aNodeShape, aChildShapeIter.Value());
988 if (aMeshes_1 != NULL
989 && aMeshes_1->IsArray())
992 Message_ProgressSentry aPSentry (theProgress, "Reading scene meshes", 0, aMeshes_1->Size(), 1);
993 for (rapidjson::Value::ConstValueIterator aMeshIter = aMeshes_1->Begin();
994 aMeshIter != aMeshes_1->End() && aPSentry.More(); ++aMeshIter, aPSentry.Next())
996 const RWGltf_JsonValue* aMesh = myGltfRoots[RWGltf_GltfRootElement_Meshes].FindChild (*aMeshIter);
999 theNodeShape = aNodeShape;
1000 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1001 reportGltfError ("Scene node '" + theSceneNodeId + "' refers to non-existing mesh.");
1005 TopoDS_Shape aMeshShape;
1006 if (!gltfParseMesh (aMeshShape, getKeyString (*aMeshIter), *aMesh, theProgress))
1008 theNodeShape = aNodeShape;
1009 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1012 if (!aMeshShape.IsNull())
1014 aBuilder.Add (aNodeShape, aMeshShape);
1019 if (aMesh_2 != NULL)
1022 const RWGltf_JsonValue* aMesh = myGltfRoots[RWGltf_GltfRootElement_Meshes].FindChild (*aMesh_2);
1025 theNodeShape = aNodeShape;
1026 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1027 reportGltfError ("Scene node '" + theSceneNodeId + "' refers to non-existing mesh.");
1031 TopoDS_Shape aMeshShape;
1032 if (!gltfParseMesh (aMeshShape, getKeyString (*aMesh_2), *aMesh, theProgress))
1034 theNodeShape = aNodeShape;
1035 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1038 if (!aMeshShape.IsNull())
1040 aBuilder.Add (aNodeShape, aMeshShape);
1045 if (aNbSubShapes == 1)
1047 theNodeShape = TopoDS_Iterator (aNodeShape).Value();
1051 theNodeShape = aNodeShape;
1053 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1057 // =======================================================================
1058 // function : gltfParseMesh
1060 // =======================================================================
1061 bool RWGltf_GltfJsonParser::gltfParseMesh (TopoDS_Shape& theMeshShape,
1062 const TCollection_AsciiString& theMeshId,
1063 const RWGltf_JsonValue& theMesh,
1064 const Handle(Message_ProgressIndicator)& theProgress)
1066 const RWGltf_JsonValue* aName = findObjectMember (theMesh, "name");
1067 const RWGltf_JsonValue* aPrims = findObjectMember (theMesh, "primitives");
1068 if (!aPrims->IsArray())
1070 reportGltfError ("Primitive array attributes within Mesh '" + theMeshId + "' is not an array.");
1074 if (findMeshShape (theMeshShape, theMeshId))
1079 BRep_Builder aBuilder;
1080 TopoDS_Compound aMeshShape;
1082 for (rapidjson::Value::ConstValueIterator aPrimArrIter = aPrims->Begin();
1083 aPrimArrIter != aPrims->End(); ++aPrimArrIter)
1085 TCollection_AsciiString aUserName;
1087 && aName->IsString())
1089 aUserName = aName->GetString();
1092 Handle(RWGltf_GltfLatePrimitiveArray) aMeshData = new RWGltf_GltfLatePrimitiveArray (theMeshId, aUserName);
1093 if (!gltfParsePrimArray (aMeshData, theMeshId, *aPrimArrIter, theProgress))
1098 if (!aMeshData->Data().IsEmpty())
1100 if (aMeshShape.IsNull())
1102 aBuilder.MakeCompound (aMeshShape);
1106 aBuilder.MakeFace (aFace, aMeshData);
1107 aBuilder.Add (aMeshShape, aFace);
1108 if (myAttribMap != NULL
1109 && aMeshData->HasStyle())
1111 RWMesh_NodeAttributes aShapeAttribs;
1112 aShapeAttribs.RawName = aUserName;
1113 aShapeAttribs.Style.SetColorSurf (aMeshData->BaseColor());
1114 myAttribMap->Bind (aFace, aShapeAttribs);
1116 myFaceList.Append (aFace);
1123 theMeshShape = TopoDS_Iterator (aMeshShape).Value();
1127 theMeshShape = aMeshShape;
1129 bindMeshShape (theMeshShape, theMeshId, aName);
1133 // =======================================================================
1134 // function : gltfParsePrimArray
1136 // =======================================================================
1137 bool RWGltf_GltfJsonParser::gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1138 const TCollection_AsciiString& theMeshId,
1139 const RWGltf_JsonValue& thePrimArray,
1140 const Handle(Message_ProgressIndicator)& /*theProgress*/)
1142 const RWGltf_JsonValue* anAttribs = findObjectMember (thePrimArray, "attributes");
1143 const RWGltf_JsonValue* anIndices = findObjectMember (thePrimArray, "indices");
1144 const RWGltf_JsonValue* aMaterial = findObjectMember (thePrimArray, "material");
1145 const RWGltf_JsonValue* aModeVal = findObjectMember (thePrimArray, "mode");
1146 RWGltf_GltfPrimitiveMode aMode = RWGltf_GltfPrimitiveMode_Triangles;
1147 if (anAttribs == NULL
1148 || !anAttribs->IsObject())
1150 reportGltfError ("Primitive array within Mesh '" + theMeshId + "' defines no attributes.");
1153 else if (aModeVal != NULL)
1155 aMode = RWGltf_GltfPrimitiveMode_UNKNOWN;
1156 if (aModeVal->IsInt())
1158 aMode = (RWGltf_GltfPrimitiveMode )aModeVal->GetInt();
1160 if (aMode < RWGltf_GltfPrimitiveMode_Points
1161 || aMode > RWGltf_GltfPrimitiveMode_TriangleFan)
1163 reportGltfError ("Primitive array within Mesh '" + theMeshId + "' has unknown mode.");
1167 if (aMode != RWGltf_GltfPrimitiveMode_Triangles)
1169 Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Primitive array within Mesh '"
1170 + theMeshId + "' skipped due to unsupported mode.", Message_Warning);
1173 theMeshData->SetPrimitiveMode (aMode);
1176 if (aMaterial != NULL)
1178 Handle(RWGltf_MaterialMetallicRoughness) aMatPbr;
1179 if (myMaterialsPbr.Find (getKeyString (*aMaterial), aMatPbr))
1181 theMeshData->SetMaterialPbr (aMatPbr);
1184 Handle(RWGltf_MaterialCommon) aMatCommon;
1185 if (myMaterialsCommon.Find (getKeyString (*aMaterial), aMatCommon))
1187 theMeshData->SetMaterialCommon (aMatCommon);
1191 bool hasPositions = false;
1192 for (rapidjson::Value::ConstMemberIterator anAttribIter = anAttribs->MemberBegin();
1193 anAttribIter != anAttribs->MemberEnd(); ++anAttribIter)
1195 const TCollection_AsciiString anAttribId = getKeyString (anAttribIter->value);
1196 if (anAttribId.IsEmpty())
1198 reportGltfError ("Primitive array attribute accessor key within Mesh '" + theMeshId + "' is not a string.");
1202 RWGltf_GltfArrayType aType = RWGltf_GltfParseAttribType (anAttribIter->name.GetString());
1203 if (aType == RWGltf_GltfArrayType_UNKNOWN)
1205 // just ignore unknown attributes
1209 const RWGltf_JsonValue* anAccessor = myGltfRoots[RWGltf_GltfRootElement_Accessors].FindChild (anAttribIter->value);
1210 if (anAccessor == NULL
1211 || !anAccessor->IsObject())
1213 reportGltfError ("Primitive array attribute accessor key '" + anAttribId + "' points to non-existing object.");
1216 else if (!gltfParseAccessor (theMeshData, anAttribId, *anAccessor, aType))
1220 else if (aType == RWGltf_GltfArrayType_Position)
1222 hasPositions = true;
1227 reportGltfError ("Primitive array within Mesh '" + theMeshId + "' does not define vertex positions.");
1231 if (anIndices != NULL)
1233 const TCollection_AsciiString anIndicesId = getKeyString (*anIndices);
1234 const RWGltf_JsonValue* anAccessor = myGltfRoots[RWGltf_GltfRootElement_Accessors].FindChild (*anIndices);
1235 if (anAccessor == NULL
1236 || !anAccessor->IsObject())
1238 reportGltfError ("Primitive array indices accessor key '" + anIndicesId + "' points to non-existing object.");
1241 else if (!gltfParseAccessor (theMeshData, anIndicesId, *anAccessor, RWGltf_GltfArrayType_Indices))
1250 // =======================================================================
1251 // function : gltfParseAccessor
1253 // =======================================================================
1254 bool RWGltf_GltfJsonParser::gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1255 const TCollection_AsciiString& theName,
1256 const RWGltf_JsonValue& theAccessor,
1257 const RWGltf_GltfArrayType theType)
1259 RWGltf_GltfAccessor aStruct;
1260 const RWGltf_JsonValue* aTypeStr = findObjectMember (theAccessor, "type");
1261 const RWGltf_JsonValue* aBufferViewName = findObjectMember (theAccessor, "bufferView");
1262 const RWGltf_JsonValue* aByteOffset = findObjectMember (theAccessor, "byteOffset");
1263 const RWGltf_JsonValue* aByteStride = findObjectMember (theAccessor, "byteStride");
1264 const RWGltf_JsonValue* aCompType = findObjectMember (theAccessor, "componentType");
1265 const RWGltf_JsonValue* aCount = findObjectMember (theAccessor, "count");
1266 if (aTypeStr == NULL
1267 || !aTypeStr->IsString())
1269 reportGltfError ("Accessor '" + theName + "' does not define type.");
1272 aStruct.Type = RWGltf_GltfParseAccessorType (aTypeStr->GetString());
1273 if (aStruct.Type == RWGltf_GltfAccessorLayout_UNKNOWN)
1275 reportGltfError ("Accessor '" + theName + "' has invalid type.");
1279 if (aBufferViewName == NULL)
1281 reportGltfError ("Accessor '" + theName + "' does not define bufferView.");
1284 if (aCompType == NULL
1285 || !aCompType->IsInt())
1287 reportGltfError ("Accessor '" + theName + "' does not define componentType.");
1290 aStruct.ComponentType = (RWGltf_GltfAccessorCompType )aCompType->GetInt();
1291 if (aStruct.ComponentType != RWGltf_GltfAccessorCompType_Int8
1292 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_UInt8
1293 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_Int16
1294 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_UInt16
1295 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_UInt32
1296 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_Float32)
1298 reportGltfError ("Accessor '" + theName + "' defines invalid componentType value.");
1303 || !aCount->IsNumber())
1305 reportGltfError ("Accessor '" + theName + "' does not define count.");
1309 aStruct.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
1310 ? (int64_t )aByteOffset->GetDouble()
1312 aStruct.ByteStride = aByteStride != NULL && aByteStride->IsInt()
1313 ? aByteStride->GetInt()
1315 aStruct.Count = (int64_t )aCount->GetDouble();
1317 if (aStruct.ByteOffset < 0)
1319 reportGltfError ("Accessor '" + theName + "' defines invalid byteOffset.");
1322 else if (aStruct.ByteStride < 0
1323 || aStruct.ByteStride > 255)
1325 reportGltfError ("Accessor '" + theName + "' defines invalid byteStride.");
1328 else if (aStruct.Count < 1)
1330 reportGltfError ("Accessor '" + theName + "' defines invalid count.");
1334 // Read Min/Max values for POSITION type. It is used for bounding boxes
1335 if (theType == RWGltf_GltfArrayType_Position)
1337 const RWGltf_JsonValue* aMin = findObjectMember (theAccessor, "min");
1338 const RWGltf_JsonValue* aMax = findObjectMember (theAccessor, "max");
1339 if (aMin != NULL && aMax != NULL)
1341 // Note: Min/Max values can be not defined in glTF file.
1342 // In this case it is not used only.
1343 if (!aMin->IsArray() || !aMax->IsArray() ||
1344 aMin->Size() != 3 || aMax->Size() != 3)
1346 reportGltfWarning ("Accessor '" + theName + "' defines invalid min/max values.");
1350 bool isValidMinMax = true;
1351 gp_Pnt aMinPnt, aMaxPnt;
1352 for (int anIter = 0; anIter < 3; ++anIter)
1354 const RWGltf_JsonValue& aMinVal = (*aMin)[anIter];
1355 const RWGltf_JsonValue& aMaxVal = (*aMax)[anIter];
1356 if (!aMinVal.IsNumber() || !aMaxVal.IsNumber())
1358 reportGltfWarning ("Accessor '" + theName + "' defines invalid min/max value.");
1359 isValidMinMax = false;
1362 aMinPnt.SetCoord (anIter + 1, aMinVal.GetDouble());
1363 aMinPnt.SetCoord (anIter + 1, aMaxVal.GetDouble());
1367 myCSTrsf.TransformPosition (aMinPnt.ChangeCoord());
1368 myCSTrsf.TransformPosition (aMaxPnt.ChangeCoord());
1374 theMeshData->SetBoundingBox (aBox);
1380 const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
1381 if (aBufferView == NULL
1382 || !aBufferView->IsObject())
1384 reportGltfError ("Accessor '" + theName + "' refers to non-existing bufferView.");
1388 return gltfParseBufferView (theMeshData, getKeyString (*aBufferViewName), *aBufferView, aStruct, theType);
1391 // =======================================================================
1392 // function : gltfParseBufferView
1394 // =======================================================================
1395 bool RWGltf_GltfJsonParser::gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1396 const TCollection_AsciiString& theName,
1397 const RWGltf_JsonValue& theBufferView,
1398 const RWGltf_GltfAccessor& theAccessor,
1399 const RWGltf_GltfArrayType theType)
1401 RWGltf_GltfBufferView aBuffView;
1402 const RWGltf_JsonValue* aBufferName = findObjectMember (theBufferView, "buffer");
1403 const RWGltf_JsonValue* aByteLength = findObjectMember (theBufferView, "byteLength");
1404 const RWGltf_JsonValue* aByteOffset = findObjectMember (theBufferView, "byteOffset");
1405 const RWGltf_JsonValue* aTarget = findObjectMember (theBufferView, "target");
1406 if (aBufferName == NULL)
1408 reportGltfError ("BufferView '" + theName + "' does not define buffer.");
1412 aBuffView.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
1413 ? (int64_t )aByteOffset->GetDouble()
1415 aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
1416 ? (int64_t )aByteLength->GetDouble()
1418 if (aTarget != NULL && aTarget->IsInt())
1420 aBuffView.Target = (RWGltf_GltfBufferViewTarget )aTarget->GetInt();
1421 if (aBuffView.Target != RWGltf_GltfBufferViewTarget_ARRAY_BUFFER
1422 && aBuffView.Target != RWGltf_GltfBufferViewTarget_ELEMENT_ARRAY_BUFFER)
1424 reportGltfError ("BufferView '" + theName + "' defines invalid target.");
1429 if (aBuffView.ByteLength < 0)
1431 reportGltfError ("BufferView '" + theName + "' defines invalid byteLength.");
1434 else if (aBuffView.ByteOffset < 0)
1436 reportGltfError ("BufferView '" + theName + "' defines invalid byteOffset.");
1440 const RWGltf_JsonValue* aBuffer = myGltfRoots[RWGltf_GltfRootElement_Buffers].FindChild (*aBufferName);
1442 || !aBuffer->IsObject())
1444 reportGltfError ("BufferView '" + theName + "' refers to non-existing buffer.");
1448 return gltfParseBuffer (theMeshData, getKeyString (*aBufferName), *aBuffer, theAccessor, aBuffView, theType);
1451 // =======================================================================
1452 // function : gltfParseBuffer
1454 // =======================================================================
1455 bool RWGltf_GltfJsonParser::gltfParseBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1456 const TCollection_AsciiString& theName,
1457 const RWGltf_JsonValue& theBuffer,
1458 const RWGltf_GltfAccessor& theAccessor,
1459 const RWGltf_GltfBufferView& theView,
1460 const RWGltf_GltfArrayType theType)
1462 //const RWGltf_JsonValue* aType = findObjectMember (theBuffer, "type");
1463 //const RWGltf_JsonValue* aByteLength = findObjectMember (theBuffer, "byteLength");
1464 const RWGltf_JsonValue* anUriVal = findObjectMember (theBuffer, "uri");
1466 int64_t anOffset = theView.ByteOffset + theAccessor.ByteOffset;
1467 bool isBinary = false;
1470 isBinary = IsEqual ("binary_glTF", theName) // glTF 1.0
1471 || anUriVal == NULL; // glTF 2.0
1475 anOffset += myBinBodyOffset;
1477 RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
1478 aData.Accessor = theAccessor;
1479 aData.StreamOffset = anOffset;
1480 aData.StreamUri = myFilePath;
1484 if (anUriVal == NULL
1485 || !anUriVal->IsString())
1487 reportGltfError ("Buffer '" + theName + "' does not define uri.");
1491 const char* anUriData = anUriVal->GetString();
1492 if (::strncmp (anUriData, "data:application/octet-stream;base64,", 37) == 0)
1494 RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
1495 aData.Accessor = theAccessor;
1496 aData.StreamOffset = anOffset;
1497 if (!myDecodedBuffers.Find (theName, aData.StreamData))
1499 // it is better decoding in multiple threads
1500 aData.StreamData = FSD_Base64Decoder::Decode ((const Standard_Byte* )anUriData + 37, anUriVal->GetStringLength() - 37);
1501 myDecodedBuffers.Bind (theName, aData.StreamData);
1507 TCollection_AsciiString anUri = anUriData;
1508 if (anUri.IsEmpty())
1510 reportGltfError ("Buffer '" + theName + "' does not define uri.");
1514 TCollection_AsciiString aPath = myFolder + anUri;
1515 bool isFileExist = false;
1516 if (!myProbedFiles.Find (aPath, isFileExist))
1518 isFileExist = OSD_File (aPath).Exists();
1519 myProbedFiles.Bind (aPath, isFileExist);
1523 reportGltfError ("Buffer '" + theName + "' refers to non-existing file '" + anUri + "'.");
1527 RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
1528 aData.Accessor = theAccessor;
1529 aData.StreamOffset = anOffset;
1530 aData.StreamUri = myFolder + anUri;
1531 if (myExternalFiles != NULL)
1533 myExternalFiles->Add (aData.StreamUri);
1539 // =======================================================================
1540 // function : bindNamedShape
1542 // =======================================================================
1543 void RWGltf_GltfJsonParser::bindNamedShape (TopoDS_Shape& theShape,
1544 ShapeMapGroup theGroup,
1545 const TopLoc_Location& theLoc,
1546 const TCollection_AsciiString& theId,
1547 const RWGltf_JsonValue* theUserName)
1549 if (theShape.IsNull())
1554 if (!theLoc.IsIdentity())
1556 theShape.Location (theLoc);
1559 TCollection_AsciiString aUserName;
1560 if (theUserName != NULL
1561 && theUserName->IsString())
1563 aUserName = theUserName->GetString();
1570 myShapeMap[theGroup].Bind (theId, theShape);
1571 if (myAttribMap != NULL)
1573 RWMesh_NodeAttributes aShapeAttribs;
1574 aShapeAttribs.Name = aUserName;
1575 aShapeAttribs.RawName = theId;
1576 if (theShape.ShapeType() == TopAbs_FACE)
1578 TopLoc_Location aDummy;
1579 if (Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (TopoDS::Face (theShape), aDummy)))
1581 if (aLateData->HasStyle())
1583 aShapeAttribs.Style.SetColorSurf (aLateData->BaseColor());
1587 myAttribMap->Bind (theShape, aShapeAttribs);
1592 // =======================================================================
1595 // =======================================================================
1596 bool RWGltf_GltfJsonParser::Parse (const Handle(Message_ProgressIndicator)& theProgress)
1598 Message_ProgressSentry aPSentry (theProgress, "Reading Gltf", 0, 2, 1);
1599 #ifdef HAVE_RAPIDJSON
1601 if (!gltfParseRoots())
1607 gltfParseMaterials();
1608 if (!gltfParseScene (theProgress))
1614 if (!aPSentry.More())
1620 Message::DefaultMessenger()->Send ("Error: glTF reader is unavailable - OCCT has been built without RapidJSON support.", Message_Fail);