0029902: Data Exchange, XCAF - provide extended Material definition for visualization...
[occt.git] / src / RWGltf / RWGltf_GltfJsonParser.cxx
CommitLineData
0a419c51 1// Author: Kirill Gavrilov
2// Copyright (c) 2016-2019 OPEN CASCADE SAS
3//
4// This file is part of Open CASCADE Technology software library.
5//
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.
11//
12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
14
15#include "RWGltf_GltfJsonParser.pxx"
16
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>
29#include <TopoDS.hxx>
30#include <TopoDS_Iterator.hxx>
31
32#include <fstream>
33
34#ifdef HAVE_RAPIDJSON
35namespace
36{
37 //! Material extension.
38 const char THE_KHR_materials_common[] = "KHR_materials_common";
39 const char THE_KHR_binary_glTF[] = "KHR_binary_glTF";
40}
41
42//! Find member of the object in a safe way.
43inline const RWGltf_JsonValue* findObjectMember (const RWGltf_JsonValue& theObject,
44 const RWGltf_JsonValue& theName)
45{
46 if (!theObject.IsObject()
47 || !theName.IsString())
48 {
49 return NULL;
50 }
51
52 rapidjson::Document::ConstMemberIterator anIter = theObject.FindMember (theName);
53 return anIter != theObject.MemberEnd()
54 ? &anIter->value
55 : NULL;
56}
57
58//! Find member of the object in a safe way.
59inline const RWGltf_JsonValue* findObjectMember (const RWGltf_JsonValue& theObject,
60 const char* theName)
61{
62 if (!theObject.IsObject())
63 {
64 return NULL;
65 }
66
67 rapidjson::Document::ConstMemberIterator anIter = theObject.FindMember (theName);
68 return anIter != theObject.MemberEnd()
69 ? &anIter->value
70 : NULL;
71}
72
73// =======================================================================
74// function : RWGltf_GltfJsonParser::FormatParseError
75// purpose :
76// =======================================================================
77const char* RWGltf_GltfJsonParser::FormatParseError (rapidjson::ParseErrorCode theCode)
78{
79 switch (theCode)
80 {
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";
99 }
100 return "UNKOWN syntax error";
101}
102
103// =======================================================================
104// function : GltfElementMap::Init
105// purpose :
106// =======================================================================
107void RWGltf_GltfJsonParser::GltfElementMap::Init (const TCollection_AsciiString& theRootName,
108 const RWGltf_JsonValue* theRoot)
109{
110 myRoot = theRoot;
111 myChildren.Clear();
112 if (theRoot == NULL)
113 {
114 return;
115 }
116
117 if (theRoot->IsObject())
118 {
119 // glTF 1.0
120 for (ConstMemberIterator aChildIter = theRoot->MemberBegin(); aChildIter != theRoot->MemberEnd(); ++aChildIter)
121 {
122 if (!aChildIter->name.IsString())
123 {
124 continue;
125 }
126
127 const TCollection_AsciiString aKey (aChildIter->name.GetString());
128 if (!myChildren.Bind (aKey, &aChildIter->value))
129 {
130 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Invalid glTF syntax - key '")
131 + aKey + "' is already defined in '" + theRootName + "'.", Message_Warning);
132 }
133 }
134 }
135 else if (theRoot->IsArray())
136 {
137 // glTF 2.0
138 int aChildIndex = 0;
139 for (rapidjson::Value::ConstValueIterator aChildIter = theRoot->Begin(); aChildIter != theRoot->End(); ++aChildIter, ++aChildIndex)
140 {
141 myChildren.Bind (TCollection_AsciiString (aChildIndex), aChildIter);
142 }
143 }
144}
145#endif
146
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);
150
151// =======================================================================
152// function : reportGltfSyntaxProblem
153// purpose :
154// =======================================================================
155void RWGltf_GltfJsonParser::reportGltfSyntaxProblem (const TCollection_AsciiString& theMsg,
156 Message_Gravity theGravity)
157{
158 Message::DefaultMessenger()->Send (myErrorPrefix + theMsg, theGravity);
159}
160
161// =======================================================================
162// function : RWGltf_GltfJsonParser
163// purpose :
164// =======================================================================
165RWGltf_GltfJsonParser::RWGltf_GltfJsonParser (TopTools_SequenceOfShape& theRootShapes)
166: myRootShapes(&theRootShapes),
167 myAttribMap (NULL),
168 myExternalFiles (NULL),
169 myBinBodyOffset (0),
170 myBinBodyLen (0),
171 myIsBinary (false),
172 myIsGltf1 (false),
173 myToSkipEmptyNodes (true),
803bdcdf 174 myUseMeshNameAsFallback (true),
0a419c51 175 myToProbeHeader (false)
176{
177 myCSTrsf.SetInputLengthUnit (1.0); // meters
178 myCSTrsf.SetInputCoordinateSystem (RWMesh_CoordinateSystem_glTF);
179}
180
181// =======================================================================
182// function : SetFilePath
183// purpose :
184// =======================================================================
185void RWGltf_GltfJsonParser::SetFilePath (const TCollection_AsciiString& theFilePath)
186{
187 myFilePath = theFilePath;
188 // determine file location to load associated files
189 TCollection_AsciiString aFileName;
190 OSD_Path::FolderAndFileFromPath (theFilePath, myFolder, aFileName);
191}
192
193#ifdef HAVE_RAPIDJSON
194// =======================================================================
195// function : gltfParseRoots
196// purpose :
197// =======================================================================
198bool RWGltf_GltfJsonParser::gltfParseRoots()
199{
200 // find glTF root elements for smooth navigation
201 RWGltf_JsonValue aNames[RWGltf_GltfRootElement_NB];
202 for (int aRootNameIter = 0; aRootNameIter < RWGltf_GltfRootElement_NB; ++aRootNameIter)
203 {
204 aNames[aRootNameIter] = rapidjson::StringRef (RWGltf_GltfRootElementName ((RWGltf_GltfRootElement )aRootNameIter));
205 }
206
207 for (ConstMemberIterator aRootIter = MemberBegin();
208 aRootIter != MemberEnd(); ++aRootIter)
209 {
210 for (int aRootNameIter = 0; aRootNameIter < RWGltf_GltfRootElement_NB; ++aRootNameIter)
211 {
212 if (myGltfRoots[aRootNameIter].IsNull()
213 && aNames[aRootNameIter] == aRootIter->name)
214 {
215 // we will not modify JSON document, thus it is OK to keep the pointers
216 myGltfRoots[aRootNameIter].Init (RWGltf_GltfRootElementName ((RWGltf_GltfRootElement )aRootNameIter), &aRootIter->value);
217 break;
218 }
219 }
220 }
221
222 for (int aRootNameIter = 0; aRootNameIter < RWGltf_GltfRootElement_NB_MANDATORY; ++aRootNameIter)
223 {
224 if (myGltfRoots[aRootNameIter].IsNull())
225 {
226 reportGltfError ("Member '" + RWGltf_GltfRootElementName ((RWGltf_GltfRootElement )aRootNameIter) + "' is not found.");
227 return false;
228 }
229 }
230 return true;
231}
232
233// =======================================================================
234// function : gltfParseAsset
235// purpose :
236// =======================================================================
237void RWGltf_GltfJsonParser::gltfParseAsset()
238{
239 const RWGltf_JsonValue* anAsset = myGltfRoots[RWGltf_GltfRootElement_Asset].Root();
240 if (anAsset == NULL)
241 {
242 return;
243 }
244
245 if (const RWGltf_JsonValue* aVersion = findObjectMember (*anAsset, "version"))
246 {
247 if (aVersion->IsString())
248 {
249 TCollection_AsciiString aVerStr (aVersion->GetString());
250 myIsGltf1 = aVerStr.StartsWith ("1.");
251 }
252 }
253
82c59511 254 if (myMetadata == NULL)
255 {
256 return;
257 }
258
0a419c51 259 if (const RWGltf_JsonValue* aGenerator = findObjectMember (*anAsset, "generator"))
260 {
261 if (aGenerator->IsString())
262 {
82c59511 263 myMetadata->Add ("generator", aGenerator->GetString());
0a419c51 264 }
265 }
266 if (const RWGltf_JsonValue* aCopyRight = findObjectMember (*anAsset, "copyright"))
267 {
268 if (aCopyRight->IsString())
269 {
82c59511 270 myMetadata->Add ("copyright", aCopyRight->GetString());
0a419c51 271 }
272 }
273}
274
275// =======================================================================
276// function : gltfParseMaterials
277// purpose :
278// =======================================================================
279void RWGltf_GltfJsonParser::gltfParseMaterials()
280{
281 const RWGltf_JsonValue* aMatList = myGltfRoots[RWGltf_GltfRootElement_Materials].Root();
282 if (aMatList == NULL)
283 {
284 return;
285 }
286 else if (aMatList->IsObject())
287 {
288 // glTF 1.0
289 for (ConstMemberIterator aMatIter = aMatList->MemberBegin();
290 aMatIter != aMatList->MemberEnd(); ++aMatIter)
291 {
292 Handle(RWGltf_MaterialCommon) aMat;
293 const RWGltf_JsonValue& aMatNode = aMatIter->value;
294 const RWGltf_JsonValue& aMatId = aMatIter->name;
295 const RWGltf_JsonValue* aNameVal = findObjectMember (aMatNode, "name");
296 if (!gltfParseCommonMaterial (aMat, aMatNode))
297 {
298 if (!gltfParseStdMaterial (aMat, aMatNode))
299 {
300 continue;
301 }
302 }
303
304 if (aNameVal != NULL
305 && aNameVal->IsString())
306 {
307 aMat->Name = aNameVal->GetString();
308 }
309 aMat->Id = aMatId.GetString();
310 myMaterialsCommon.Bind (aMat->Id, aMat);
a4815d55 311 gltfBindMaterial (Handle(RWGltf_MaterialMetallicRoughness)(), aMat);
0a419c51 312 }
313 }
314 else if (aMatList->IsArray())
315 {
316 // glTF 2.0
317 int aMatIndex = 0;
318 for (rapidjson::Value::ConstValueIterator aMatIter = aMatList->Begin(); aMatIter != aMatList->End(); ++aMatIter, ++aMatIndex)
319 {
320 Handle(RWGltf_MaterialMetallicRoughness) aMatPbr;
321 const RWGltf_JsonValue& aMatNode = *aMatIter;
322 const RWGltf_JsonValue* aNameVal = findObjectMember (aMatNode, "name");
323 if (gltfParsePbrMaterial (aMatPbr, aMatNode))
324 {
325 if (aNameVal != NULL
326 && aNameVal->IsString())
327 {
328 aMatPbr->Name = aNameVal->GetString();
329 }
330 aMatPbr->Id = TCollection_AsciiString ("mat_") + aMatIndex;
331 myMaterialsPbr.Bind (TCollection_AsciiString (aMatIndex), aMatPbr);
332 }
333
334 Handle(RWGltf_MaterialCommon) aMatCommon;
335 if (gltfParseCommonMaterial(aMatCommon, aMatNode)
336 || gltfParseStdMaterial (aMatCommon, aMatNode))
337 {
338 if (aNameVal != NULL
339 && aNameVal->IsString())
340 {
341 aMatCommon->Name = aNameVal->GetString();
342 }
343 aMatCommon->Id = TCollection_AsciiString ("mat_") + aMatIndex;
344 myMaterialsCommon.Bind (TCollection_AsciiString (aMatIndex), aMatCommon);
345 }
a4815d55 346
347 gltfBindMaterial (aMatPbr, aMatCommon);
0a419c51 348 }
349 }
350}
351
a4815d55 352// =======================================================================
353// function : gltfBindMaterial
354// purpose :
355// =======================================================================
356void RWGltf_GltfJsonParser::gltfBindMaterial (const Handle(RWGltf_MaterialMetallicRoughness)& theMatPbr,
357 const Handle(RWGltf_MaterialCommon)& theMatCommon)
358{
359 if (theMatPbr.IsNull()
360 && theMatCommon.IsNull())
361 {
362 return;
363 }
364
365 Handle(XCAFDoc_VisMaterial) aMat = new XCAFDoc_VisMaterial();
366 if (!theMatCommon.IsNull())
367 {
368 XCAFDoc_VisMaterialCommon aMatXde;
369 aMatXde.IsDefined = true;
370 aMatXde.AmbientColor = theMatCommon->AmbientColor;
371 aMatXde.DiffuseColor = theMatCommon->DiffuseColor;
372 aMatXde.SpecularColor = theMatCommon->SpecularColor;
373 aMatXde.EmissiveColor = theMatCommon->EmissiveColor;
374 aMatXde.Shininess = theMatCommon->Shininess;
375 aMatXde.Transparency = theMatCommon->Transparency;
376 aMatXde.DiffuseTexture = theMatCommon->DiffuseTexture;
377 if (aMatXde.DiffuseTexture.IsNull()
378 && !theMatCommon->AmbientTexture.IsNull())
379 {
380 aMatXde.DiffuseTexture = theMatCommon->AmbientTexture;
381 }
382 aMat->SetCommonMaterial (aMatXde);
383 if (!theMatCommon->Name.IsEmpty())
384 {
385 aMat->SetRawName (new TCollection_HAsciiString (theMatCommon->Name));
386 }
387 }
388 if (!theMatPbr.IsNull())
389 {
390 XCAFDoc_VisMaterialPBR aMatXde;
391 aMatXde.IsDefined = true;
392 aMatXde.MetallicRoughnessTexture = theMatPbr->MetallicRoughnessTexture;
393 aMatXde.BaseColorTexture = theMatPbr->BaseColorTexture;
394 aMatXde.EmissiveTexture = theMatPbr->EmissiveTexture;
395 aMatXde.OcclusionTexture = theMatPbr->OcclusionTexture;
396 aMatXde.NormalTexture = theMatPbr->NormalTexture;
397 aMatXde.BaseColor = theMatPbr->BaseColor;
398 aMatXde.EmissiveFactor = theMatPbr->EmissiveFactor;
399 aMatXde.Metallic = theMatPbr->Metallic;
400 aMatXde.Roughness = theMatPbr->Roughness;
401 aMat->SetPbrMaterial (aMatXde);
402
403 Graphic3d_AlphaMode anAlphaMode = Graphic3d_AlphaMode_BlendAuto;
404 switch (theMatPbr->AlphaMode)
405 {
406 case RWGltf_GltfAlphaMode_Opaque:
407 {
408 anAlphaMode = Graphic3d_AlphaMode_Opaque;
409 if (aMatXde.BaseColor.Alpha() < 1.0f)
410 {
411 Message::DefaultMessenger()->Send ("glTF reader - material with non-zero Transparency specifies Opaque AlphaMode", Message_Warning);
412 }
413 break;
414 }
415 case RWGltf_GltfAlphaMode_Mask:
416 {
417 anAlphaMode = Graphic3d_AlphaMode_Mask;
418 break;
419 }
420 case RWGltf_GltfAlphaMode_Blend:
421 {
422 anAlphaMode = Graphic3d_AlphaMode_Blend;
423 break;
424 }
425 }
426 aMat->SetAlphaMode (anAlphaMode, theMatPbr->AlphaCutOff);
427 aMat->SetDoubleSided (theMatPbr->IsDoubleSided);
428
429 if (!theMatPbr->Name.IsEmpty())
430 {
431 aMat->SetRawName (new TCollection_HAsciiString (theMatPbr->Name));
432 }
433 }
434
435 myMaterials.Bind (!theMatPbr.IsNull() ? theMatPbr->Id : theMatCommon->Id, aMat);
436}
437
0a419c51 438// =======================================================================
439// function : gltfParseStdMaterial
440// purpose :
441// =======================================================================
442bool RWGltf_GltfJsonParser::gltfParseStdMaterial (Handle(RWGltf_MaterialCommon)& theMat,
443 const RWGltf_JsonValue& theMatNode)
444{
445 //const RWGltf_JsonValue* aTechVal = findObjectMember (theMatNode, "technique");
446 const RWGltf_JsonValue* aValues = findObjectMember (theMatNode, "values");
447 if (aValues == NULL)
448 {
449 return false;
450 }
451
452 const RWGltf_JsonValue* anAmbVal = findObjectMember (*aValues, "ambient");
453 const RWGltf_JsonValue* aDiffVal = findObjectMember (*aValues, "diffuse");
454 const RWGltf_JsonValue* anEmiVal = findObjectMember (*aValues, "emission");
455 const RWGltf_JsonValue* aSpecVal = findObjectMember (*aValues, "specular");
456 const RWGltf_JsonValue* aShinVal = findObjectMember (*aValues, "shininess");
457 if (anAmbVal == NULL
458 && aDiffVal == NULL
459 && anEmiVal == NULL
460 && aSpecVal == NULL
461 && aShinVal == NULL)
462 {
463 return false;
464 }
465
466 theMat = new RWGltf_MaterialCommon();
467
468 Graphic3d_Vec4d anAmb, aDiff, anEmi, aSpec;
469 if (anAmbVal != NULL
470 && anAmbVal->IsString())
471 {
472 gltfParseTexture (theMat->AmbientTexture, anAmbVal);
473 }
474 else if (gltfReadVec4 (anAmb, anAmbVal)
475 && validateColor4 (anAmb))
476 {
ba00aab7 477 theMat->AmbientColor = Quantity_Color (anAmb.r(), anAmb.g(), anAmb.b(), Quantity_TOC_sRGB);
0a419c51 478 }
479
480 if (aDiffVal != NULL
481 && aDiffVal->IsString())
482 {
483 gltfParseTexture (theMat->DiffuseTexture, aDiffVal);
484 }
485 else if (gltfReadVec4 (aDiff, aDiffVal)
486 && validateColor4 (aDiff))
487 {
ba00aab7 488 theMat->DiffuseColor = Quantity_Color (aDiff.r(), aDiff.g(), aDiff.b(), Quantity_TOC_sRGB);
0a419c51 489 theMat->Transparency = float(1.0 - aDiff.a());
490 }
491
492 if (gltfReadVec4 (anEmi, anEmiVal)
493 && validateColor4 (anEmi))
494 {
ba00aab7 495 theMat->EmissiveColor = Quantity_Color (anEmi.r(), anEmi.g(), anEmi.b(), Quantity_TOC_sRGB);
0a419c51 496 }
497
498 if (aSpecVal != NULL
499 && aSpecVal->IsString())
500 {
501 gltfParseTexture (theMat->SpecularTexture, aSpecVal);
502 }
503 if (gltfReadVec4 (aSpec, aSpecVal)
504 && validateColor4 (aSpec))
505 {
ba00aab7 506 theMat->SpecularColor = Quantity_Color (aSpec.r(), aSpec.g(), aSpec.b(), Quantity_TOC_sRGB);
0a419c51 507 }
508
509 if (aShinVal != NULL
510 && aShinVal->IsNumber())
511 {
512 const double aSpecular = aShinVal->GetDouble();
513 if (aSpecular >= 0)
514 {
515 theMat->Shininess = (float )Min (aSpecular / 1000.0, 1.0);
516 }
517 }
518 return true;
519}
520
521// =======================================================================
522// function : gltfParsePbrMaterial
523// purpose :
524// =======================================================================
525bool RWGltf_GltfJsonParser::gltfParsePbrMaterial (Handle(RWGltf_MaterialMetallicRoughness)& theMat,
526 const RWGltf_JsonValue& theMatNode)
527{
528 /*if (const RWGltf_JsonValue* anExtVal = findObjectMember (theMatNode, "extensions"))
529 {
530 if (const RWGltf_JsonValue* anExtDefVal = findObjectMember (*anExtVal, "KHR_materials_pbrSpecularGlossiness"))
531 {
532 const RWGltf_JsonValue* aDiffTexVal = findObjectMember (*anExtDefVal, "diffuseTexture");
533 const RWGltf_JsonValue* aSpecTexVal = findObjectMember (*anExtDefVal, "specularGlossinessTexture");
534 }
535 }*/
536
537 const RWGltf_JsonValue* aMetalRoughVal = findObjectMember (theMatNode, "pbrMetallicRoughness");
538 const RWGltf_JsonValue* aNormTexVal = findObjectMember (theMatNode, "normalTexture");
539 const RWGltf_JsonValue* anEmissFactorVal = findObjectMember (theMatNode, "emissiveFactor");
540 const RWGltf_JsonValue* anEmissTexVal = findObjectMember (theMatNode, "emissiveTexture");
541 const RWGltf_JsonValue* anOcclusionTexVal = findObjectMember (theMatNode, "occlusionTexture");
a4815d55 542 const RWGltf_JsonValue* aDoubleSidedVal = findObjectMember (theMatNode, "doubleSided");
543 const RWGltf_JsonValue* anAlphaModeVal = findObjectMember (theMatNode, "alphaMode");
544 const RWGltf_JsonValue* anAlphaCutoffVal = findObjectMember (theMatNode, "alphaCutoff");
0a419c51 545 if (aMetalRoughVal == NULL)
546 {
547 return false;
548 }
549
550 theMat = new RWGltf_MaterialMetallicRoughness();
551 const RWGltf_JsonValue* aBaseColorFactorVal = findObjectMember (*aMetalRoughVal, "baseColorFactor");
552 const RWGltf_JsonValue* aBaseColorTexVal = findObjectMember (*aMetalRoughVal, "baseColorTexture");
553 const RWGltf_JsonValue* aMetallicFactorVal = findObjectMember (*aMetalRoughVal, "metallicFactor");
554 const RWGltf_JsonValue* aRoughnessFactorVal = findObjectMember (*aMetalRoughVal, "roughnessFactor");
555 const RWGltf_JsonValue* aMetalRoughTexVal = findObjectMember (*aMetalRoughVal, "metallicRoughnessTexture");
556
a4815d55 557 if (aDoubleSidedVal != NULL
558 && aDoubleSidedVal->IsBool())
559 {
560 theMat->IsDoubleSided = aDoubleSidedVal->GetBool();
561 }
562 if (anAlphaCutoffVal != NULL
563 && anAlphaCutoffVal->IsNumber())
564 {
565 theMat->AlphaCutOff = (float )anAlphaCutoffVal->GetDouble();
566 }
567 if (anAlphaModeVal != NULL
568 && anAlphaModeVal->IsString())
569 {
570 theMat->AlphaMode = RWGltf_GltfParseAlphaMode (anAlphaModeVal->GetString());
571 }
572
0a419c51 573 if (aBaseColorTexVal != NULL
574 && aBaseColorTexVal->IsObject())
575 {
576 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*aBaseColorTexVal, "index"))
577 {
578 gltfParseTexture (theMat->BaseColorTexture, aTexIndexVal);
579 }
580 }
581
582 Graphic3d_Vec4d aBaseColorFactor;
583 if (gltfReadVec4 (aBaseColorFactor, aBaseColorFactorVal)
584 && validateColor4 (aBaseColorFactor))
585 {
586 theMat->BaseColor = Quantity_ColorRGBA (Graphic3d_Vec4 (aBaseColorFactor));
587 }
588
589 Graphic3d_Vec3d anEmissiveFactor;
590 if (gltfReadVec3 (anEmissiveFactor, anEmissFactorVal)
591 && validateColor3 (anEmissiveFactor))
592 {
593 theMat->EmissiveFactor = Graphic3d_Vec3 (anEmissiveFactor);
594 }
595
596 if (aMetalRoughTexVal != NULL
597 && aMetalRoughTexVal->IsObject())
598 {
599 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*aMetalRoughTexVal, "index"))
600 {
601 gltfParseTexture (theMat->MetallicRoughnessTexture, aTexIndexVal);
602 }
603 }
604
605 if (aMetallicFactorVal != NULL
606 && aMetallicFactorVal->IsNumber())
607 {
608 theMat->Metallic = (float )aMetallicFactorVal->GetDouble();
609 }
610
611 if (aRoughnessFactorVal != NULL
612 && aRoughnessFactorVal->IsNumber())
613 {
614 theMat->Roughness = (float )aRoughnessFactorVal->GetDouble();
615 }
616
617 if (aNormTexVal != NULL
618 && aNormTexVal->IsObject())
619 {
620 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*aNormTexVal, "index"))
621 {
622 gltfParseTexture (theMat->NormalTexture, aTexIndexVal);
623 }
624 }
625
626 if (anEmissTexVal != NULL
627 && anEmissTexVal->IsObject())
628 {
629 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*anEmissTexVal, "index"))
630 {
631 gltfParseTexture (theMat->EmissiveTexture, aTexIndexVal);
632 }
633 }
634
635 if (anOcclusionTexVal != NULL
636 && anOcclusionTexVal->IsObject())
637 {
638 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*anOcclusionTexVal, "index"))
639 {
640 gltfParseTexture (theMat->OcclusionTexture, aTexIndexVal);
641 }
642 }
643 return true;
644}
645
646// =======================================================================
647// function : gltfParseCommonMaterial
648// purpose :
649// =======================================================================
650bool RWGltf_GltfJsonParser::gltfParseCommonMaterial (Handle(RWGltf_MaterialCommon)& theMat,
651 const RWGltf_JsonValue& theMatNode)
652{
653 const RWGltf_JsonValue* anExtVal = findObjectMember (theMatNode, "extensions");
654 if (anExtVal == NULL)
655 {
656 return false;
657 }
658
659 const RWGltf_JsonValue* aMatCommon = findObjectMember (*anExtVal, THE_KHR_materials_common);
660 if (aMatCommon == NULL)
661 {
662 return false;
663 }
664
665 if (!gltfParseStdMaterial (theMat, *aMatCommon))
666 {
667 return false;
668 }
669 return true;
670}
671
672// =======================================================================
673// function : gltfParseTexture
674// purpose :
675// =======================================================================
676bool RWGltf_GltfJsonParser::gltfParseTexture (Handle(Image_Texture)& theTexture,
677 const RWGltf_JsonValue* theTextureId)
678{
679 if (theTextureId == NULL
680 || myGltfRoots[RWGltf_GltfRootElement_Textures].IsNull()
681 || myGltfRoots[RWGltf_GltfRootElement_Images].IsNull())
682 {
683 return false;
684 }
685
686 const TCollection_AsciiString aTextureId = getKeyString (*theTextureId);
687 const RWGltf_JsonValue* aTexNode = myGltfRoots[RWGltf_GltfRootElement_Textures].FindChild (*theTextureId);
688 if (aTexNode == NULL)
689 {
690 reportGltfWarning ("Texture node '" + aTextureId + "' is not found.");
691 return false;
692 }
693
694 const RWGltf_JsonValue* aSrcVal = findObjectMember (*aTexNode, "source");
695 const RWGltf_JsonValue* aTargVal = findObjectMember (*aTexNode, "target");
696 if (aSrcVal == NULL)
697 {
698 reportGltfWarning ("Invalid texture node '" + aTextureId + "' without a 'source' property.");
699 return false;
700 }
701 if (aTargVal != NULL
702 && aTargVal->IsNumber()
703 && aTargVal->GetInt() != 3553) // GL_TEXTURE_2D
704 {
705 return false;
706 }
707
708 const RWGltf_JsonValue* anImgNode = myGltfRoots[RWGltf_GltfRootElement_Images].FindChild (*aSrcVal);
709 if (anImgNode == NULL)
710 {
711 reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to non-existing image '" + getKeyString (*aSrcVal) + "'.");
712 return false;
713 }
714
715 if (myIsBinary)
716 {
717 const RWGltf_JsonValue* aBinVal = NULL;
718 const RWGltf_JsonValue* aBufferViewName = findObjectMember (*anImgNode, "bufferView");
719 if (aBufferViewName != NULL)
720 {
721 aBinVal = anImgNode;
722 }
723 else if (myIsGltf1)
724 {
725 const RWGltf_JsonValue* anExtVal = findObjectMember (*anImgNode, "extensions");
726 if (anExtVal != NULL)
727 {
728 aBinVal = findObjectMember (*anExtVal, THE_KHR_binary_glTF);
729 if (aBinVal != NULL)
730 {
731 aBufferViewName = findObjectMember (*aBinVal, "bufferView");
732 }
733 }
734 }
735
736 if (aBinVal != NULL)
737 {
738 //const RWGltf_JsonValue* aMimeTypeVal = findObjectMember (*aBinVal, "mimeType");
739 //const RWGltf_JsonValue* aWidthVal = findObjectMember (*aBinVal, "width");
740 //const RWGltf_JsonValue* aHeightVal = findObjectMember (*aBinVal, "height");
741 if (aBufferViewName == NULL)
742 {
743 reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid data source.");
744 return false;
745 }
746
747 const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
748 if (aBufferView == NULL
749 || !aBufferView->IsObject())
750 {
751 reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid buffer view '" + getKeyString (*aBufferViewName) + "'.");
752 return false;
753 }
754
755 const RWGltf_JsonValue* aBufferName = findObjectMember (*aBufferView, "buffer");
756 const RWGltf_JsonValue* aByteLength = findObjectMember (*aBufferView, "byteLength");
757 const RWGltf_JsonValue* aByteOffset = findObjectMember (*aBufferView, "byteOffset");
758 if (aBufferName != NULL
759 && aBufferName->IsString()
760 && !IsEqual (aBufferName->GetString(), "binary_glTF"))
761 {
762 reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' does not define binary_glTF buffer.");
763 return false;
764 }
765
766 RWGltf_GltfBufferView aBuffView;
767 aBuffView.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
768 ? (int64_t )aByteOffset->GetDouble()
769 : 0;
770 aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
771 ? (int64_t )aByteLength->GetDouble()
772 : 0;
773 if (aBuffView.ByteLength < 0)
774 {
775 reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' defines invalid byteLength.");
776 return false;
777 }
778 else if (aBuffView.ByteOffset < 0)
779 {
780 reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' defines invalid byteOffset.");
781 return false;
782 }
783
784
785 const int64_t anOffset = myBinBodyOffset + aBuffView.ByteOffset;
786 theTexture = new Image_Texture (myFilePath, anOffset, aBuffView.ByteLength);
787 return true;
788 }
789 }
790
791 const RWGltf_JsonValue* anUriVal = findObjectMember (*anImgNode, "uri");
792 if (anUriVal == NULL
793 || !anUriVal->IsString())
794 {
795 return false;
796 }
797
798 const char* anUriData = anUriVal->GetString();
799 if (::strncmp (anUriData, "data:", 5) == 0) // data:image/png;base64
800 {
801 // uncompressing base64 here is inefficient, because the same image can be shared by several nodes
802 const char* aDataStart = anUriData + 5;
803 for (const char* aDataIter = aDataStart; *aDataIter != '\0'; ++aDataIter)
804 {
805 if (::memcmp (aDataIter, ";base64,", 8) == 0)
806 {
807 const char* aBase64End = anUriData + anUriVal->GetStringLength();
808 const char* aBase64Data = aDataIter + 8;
809 const size_t aBase64Len = size_t(aBase64End - aBase64Data);
810 //const TCollection_AsciiString aMime (aDataStart, aDataIter - aDataStart);
811 Handle(NCollection_Buffer) aData = FSD_Base64Decoder::Decode ((const Standard_Byte* )aBase64Data, aBase64Len);
812 theTexture = new Image_Texture (aData, myFilePath + "@" + getKeyString (*aSrcVal));
813 return true;
814 }
815 }
816 Message::DefaultMessenger()->Send ("glTF reader - embedded image has been skipped", Message_Warning);
817 return false;
818 }
819
820 TCollection_AsciiString anImageFile = myFolder + anUriVal->GetString();
821 theTexture = new Image_Texture (anImageFile);
822 if (myExternalFiles != NULL)
823 {
824 myExternalFiles->Add (anImageFile);
825 }
826 return true;
827}
828
829// =======================================================================
830// function : gltfParseScene
831// purpose :
832// =======================================================================
833bool RWGltf_GltfJsonParser::gltfParseScene (const Handle(Message_ProgressIndicator)& theProgress)
834{
835 // search default scene
836 const RWGltf_JsonValue* aDefScene = myGltfRoots[RWGltf_GltfRootElement_Scenes].FindChild (*myGltfRoots[RWGltf_GltfRootElement_Scene].Root());
837 if (aDefScene == NULL)
838 {
839 reportGltfError ("Default scene is not found.");
840 return false;
841 }
842
843 const RWGltf_JsonValue* aSceneNodes = findObjectMember (*aDefScene, "nodes");
844 if (aSceneNodes == NULL
845 || !aSceneNodes->IsArray())
846 {
847 reportGltfError ("Empty scene '" + getKeyString (*myGltfRoots[RWGltf_GltfRootElement_Scene].Root()) + "'.");
848 return false;
849 }
850
851 return gltfParseSceneNodes (*myRootShapes, *aSceneNodes, theProgress);
852}
853
854// =======================================================================
855// function : gltfParseSceneNodes
856// purpose :
857// =======================================================================
858bool RWGltf_GltfJsonParser::gltfParseSceneNodes (TopTools_SequenceOfShape& theShapeSeq,
859 const RWGltf_JsonValue& theSceneNodes,
860 const Handle(Message_ProgressIndicator)& theProgress)
861{
862 if (!theSceneNodes.IsArray())
863 {
864 reportGltfError ("Scene nodes is not array.");
865 return false;
866 }
867
868 Message_ProgressSentry aPSentry (theProgress, "Reading scene nodes", 0, theSceneNodes.Size(), 1);
869 for (rapidjson::Value::ConstValueIterator aSceneNodeIter = theSceneNodes.Begin();
870 aSceneNodeIter != theSceneNodes.End() && aPSentry.More(); ++aSceneNodeIter, aPSentry.Next())
871 {
872 const RWGltf_JsonValue* aSceneNode = myGltfRoots[RWGltf_GltfRootElement_Nodes].FindChild (*aSceneNodeIter);
873 if (aSceneNode == NULL)
874 {
875 reportGltfWarning ("Scene refers to non-existing node '" + getKeyString (*aSceneNodeIter) + "'.");
876 return true;
877 }
878
879 TopoDS_Shape aNodeShape;
880 if (!gltfParseSceneNode (aNodeShape, getKeyString (*aSceneNodeIter), *aSceneNode, theProgress))
881 {
882 return false;
883 }
884
885 if (aNodeShape.IsNull())
886 {
887 continue;
888 }
889 else if (myToSkipEmptyNodes
890 && !TopExp_Explorer (aNodeShape, TopAbs_FACE).More())
891 {
892 continue;
893 }
894
895 theShapeSeq.Append (aNodeShape);
896 }
897 return true;
898}
899
900// =======================================================================
901// function : gltfParseSceneNode
902// purpose :
903// =======================================================================
904bool RWGltf_GltfJsonParser::gltfParseSceneNode (TopoDS_Shape& theNodeShape,
905 const TCollection_AsciiString& theSceneNodeId,
906 const RWGltf_JsonValue& theSceneNode,
907 const Handle(Message_ProgressIndicator)& theProgress)
908{
909 const RWGltf_JsonValue* aName = findObjectMember (theSceneNode, "name");
910 //const RWGltf_JsonValue* aJointName = findObjectMember (theSceneNode, "jointName");
911 const RWGltf_JsonValue* aChildren = findObjectMember (theSceneNode, "children");
912 const RWGltf_JsonValue* aMeshes_1 = findObjectMember (theSceneNode, "meshes");
913 const RWGltf_JsonValue* aMesh_2 = findObjectMember (theSceneNode, "mesh");
914 //const RWGltf_JsonValue* aCamera = findObjectMember (theSceneNode, "camera");
915 const RWGltf_JsonValue* aTrsfMatVal = findObjectMember (theSceneNode, "matrix");
916 const RWGltf_JsonValue* aTrsfRotVal = findObjectMember (theSceneNode, "rotation");
917 const RWGltf_JsonValue* aTrsfScaleVal = findObjectMember (theSceneNode, "scale");
918 const RWGltf_JsonValue* aTrsfTransVal = findObjectMember (theSceneNode, "translation");
919 if (findNodeShape (theNodeShape, theSceneNodeId))
920 {
921 return true;
922 }
923
924 TopLoc_Location aNodeLoc;
925 const bool hasTrs = aTrsfRotVal != NULL
926 || aTrsfScaleVal != NULL
927 || aTrsfTransVal != NULL;
928 if (aTrsfMatVal != NULL)
929 {
930 if (hasTrs)
931 {
932 reportGltfError ("Scene node '" + theSceneNodeId + "' defines ambiguous transformation.");
933 return false;
934 }
935 else if (!aTrsfMatVal->IsArray()
936 || aTrsfMatVal->Size() != 16)
937 {
938 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid transformation matrix array.");
939 return false;
940 }
941
942 Graphic3d_Mat4d aMat4;
943 for (int aColIter = 0; aColIter < 4; ++aColIter)
944 {
945 for (int aRowIter = 0; aRowIter < 4; ++aRowIter)
946 {
947 const RWGltf_JsonValue& aGenVal = (*aTrsfMatVal)[aColIter * 4 + aRowIter];
948 if (!aGenVal.IsNumber())
949 {
950 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid transformation matrix.");
951 return false;
952 }
953 aMat4.SetValue (aRowIter, aColIter, aGenVal.GetDouble());
954 }
955 }
956
957 if (!aMat4.IsIdentity())
958 {
959 gp_Trsf aTrsf;
960 aTrsf.SetValues (aMat4.GetValue (0, 0), aMat4.GetValue (0, 1), aMat4.GetValue (0, 2), aMat4.GetValue (0, 3),
961 aMat4.GetValue (1, 0), aMat4.GetValue (1, 1), aMat4.GetValue (1, 2), aMat4.GetValue (1, 3),
962 aMat4.GetValue (2, 0), aMat4.GetValue (2, 1), aMat4.GetValue (2, 2), aMat4.GetValue (2, 3));
963 myCSTrsf.TransformTransformation (aTrsf);
964 if (aTrsf.Form() != gp_Identity)
965 {
966 aNodeLoc = TopLoc_Location (aTrsf);
967 }
968 }
969 }
970 else if (hasTrs)
971 {
972 gp_Trsf aTrsf;
973 if (aTrsfRotVal != NULL)
974 {
975 if (!aTrsfRotVal->IsArray()
976 || aTrsfRotVal->Size() != 4)
977 {
978 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid rotation quaternion.");
979 return false;
980 }
981
982 Graphic3d_Vec4d aRotVec4;
983 for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
984 {
985 const RWGltf_JsonValue& aGenVal = (*aTrsfRotVal)[aCompIter];
986 if (!aGenVal.IsNumber())
987 {
988 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid rotation.");
989 return false;
990 }
991 aRotVec4[aCompIter] = aGenVal.GetDouble();
992 }
993 const gp_Quaternion aQuaternion (aRotVec4.x(), aRotVec4.y(), aRotVec4.z(), aRotVec4.w());
994 if (Abs (aQuaternion.X()) > gp::Resolution()
995 || Abs (aQuaternion.Y()) > gp::Resolution()
996 || Abs (aQuaternion.Z()) > gp::Resolution()
997 || Abs (aQuaternion.W() - 1.0) > gp::Resolution())
998 {
999 aTrsf.SetRotation (aQuaternion);
1000 }
1001 }
1002
1003 if (aTrsfTransVal != NULL)
1004 {
1005 if (!aTrsfTransVal->IsArray()
1006 || aTrsfTransVal->Size() != 3)
1007 {
1008 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid translation vector.");
1009 return false;
1010 }
1011
1012 gp_XYZ aTransVec;
1013 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
1014 {
1015 const RWGltf_JsonValue& aGenVal = (*aTrsfTransVal)[aCompIter];
1016 if (!aGenVal.IsNumber())
1017 {
1018 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid translation.");
1019 return false;
1020 }
1021 aTransVec.SetCoord (aCompIter + 1, aGenVal.GetDouble());
1022 }
1023 aTrsf.SetTranslationPart (aTransVec);
1024 }
1025
1026 if (aTrsfScaleVal != NULL)
1027 {
1028 Graphic3d_Vec3d aScaleVec;
1029 if (!aTrsfScaleVal->IsArray()
1030 || aTrsfScaleVal->Size() != 3)
1031 {
1032 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid scale vector.");
1033 return false;
1034 }
1035 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
1036 {
1037 const RWGltf_JsonValue& aGenVal = (*aTrsfScaleVal)[aCompIter];
1038 if (!aGenVal.IsNumber())
1039 {
1040 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid scale.");
1041 return false;
1042 }
1043 aScaleVec[aCompIter] = aGenVal.GetDouble();
1044 if (Abs (aScaleVec[aCompIter]) <= gp::Resolution())
1045 {
1046 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid scale.");
1047 return false;
1048 }
1049 }
1050
1051 if (Abs (aScaleVec.x() - aScaleVec.y()) > Precision::Confusion()
1052 || Abs (aScaleVec.y() - aScaleVec.z()) > Precision::Confusion()
1053 || Abs (aScaleVec.x() - aScaleVec.z()) > Precision::Confusion())
1054 {
1055 Graphic3d_Mat4d aScaleMat;
1056 aScaleMat.SetDiagonal (aScaleVec);
1057
1058 Graphic3d_Mat4d aMat4;
1059 aTrsf.GetMat4 (aMat4);
1060
1061 aMat4 = aMat4 * aScaleMat;
1062 aTrsf = gp_Trsf();
1063 aTrsf.SetValues (aMat4.GetValue (0, 0), aMat4.GetValue (0, 1), aMat4.GetValue (0, 2), aMat4.GetValue (0, 3),
1064 aMat4.GetValue (1, 0), aMat4.GetValue (1, 1), aMat4.GetValue (1, 2), aMat4.GetValue (1, 3),
1065 aMat4.GetValue (2, 0), aMat4.GetValue (2, 1), aMat4.GetValue (2, 2), aMat4.GetValue (2, 3));
1066
1067 Message::DefaultMessenger()->Send (TCollection_AsciiString ("glTF reader, scene node '")
1068 + theSceneNodeId + "' defines unsupported scaling "
1069 + aScaleVec.x() + " " + aScaleVec.y() + " " + aScaleVec.z(), Message_Warning);
1070 }
1071 else if (Abs (aScaleVec.x() - 1.0) > Precision::Confusion())
1072 {
1073 aTrsf.SetScaleFactor (aScaleVec.x());
1074 }
1075 }
1076
1077 myCSTrsf.TransformTransformation (aTrsf);
1078 if (aTrsf.Form() != gp_Identity)
1079 {
1080 aNodeLoc = TopLoc_Location (aTrsf);
1081 }
1082 }
1083
1084 BRep_Builder aBuilder;
1085 TopoDS_Compound aNodeShape;
1086 aBuilder.MakeCompound (aNodeShape);
1087 TopTools_SequenceOfShape aChildShapes;
1088 int aNbSubShapes = 0;
1089 if (aChildren != NULL
1090 && !gltfParseSceneNodes (aChildShapes, *aChildren, theProgress))
1091 {
1092 theNodeShape = aNodeShape;
1093 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1094 return false;
1095 }
1096 for (TopTools_SequenceOfShape::Iterator aChildShapeIter (aChildShapes); aChildShapeIter.More(); aChildShapeIter.Next())
1097 {
1098 aBuilder.Add (aNodeShape, aChildShapeIter.Value());
1099 ++aNbSubShapes;
1100 }
1101
1102 if (aMeshes_1 != NULL
1103 && aMeshes_1->IsArray())
1104 {
1105 // glTF 1.0
1106 Message_ProgressSentry aPSentry (theProgress, "Reading scene meshes", 0, aMeshes_1->Size(), 1);
1107 for (rapidjson::Value::ConstValueIterator aMeshIter = aMeshes_1->Begin();
1108 aMeshIter != aMeshes_1->End() && aPSentry.More(); ++aMeshIter, aPSentry.Next())
1109 {
1110 const RWGltf_JsonValue* aMesh = myGltfRoots[RWGltf_GltfRootElement_Meshes].FindChild (*aMeshIter);
1111 if (aMesh == NULL)
1112 {
1113 theNodeShape = aNodeShape;
1114 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1115 reportGltfError ("Scene node '" + theSceneNodeId + "' refers to non-existing mesh.");
1116 return false;
1117 }
1118
1119 TopoDS_Shape aMeshShape;
1120 if (!gltfParseMesh (aMeshShape, getKeyString (*aMeshIter), *aMesh, theProgress))
1121 {
1122 theNodeShape = aNodeShape;
1123 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1124 return false;
1125 }
1126 if (!aMeshShape.IsNull())
1127 {
1128 aBuilder.Add (aNodeShape, aMeshShape);
1129 ++aNbSubShapes;
1130 }
1131 }
1132 }
1133 if (aMesh_2 != NULL)
1134 {
1135 // glTF 2.0
1136 const RWGltf_JsonValue* aMesh = myGltfRoots[RWGltf_GltfRootElement_Meshes].FindChild (*aMesh_2);
1137 if (aMesh == NULL)
1138 {
1139 theNodeShape = aNodeShape;
1140 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1141 reportGltfError ("Scene node '" + theSceneNodeId + "' refers to non-existing mesh.");
1142 return false;
1143 }
1144
1145 TopoDS_Shape aMeshShape;
1146 if (!gltfParseMesh (aMeshShape, getKeyString (*aMesh_2), *aMesh, theProgress))
1147 {
1148 theNodeShape = aNodeShape;
1149 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1150 return false;
1151 }
1152 if (!aMeshShape.IsNull())
1153 {
1154 aBuilder.Add (aNodeShape, aMeshShape);
1155 ++aNbSubShapes;
1156 }
1157 }
1158
1159 if (aNbSubShapes == 1)
1160 {
1161 theNodeShape = TopoDS_Iterator (aNodeShape).Value();
1162 }
1163 else
1164 {
1165 theNodeShape = aNodeShape;
1166 }
1167 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1168 return true;
1169}
1170
1171// =======================================================================
1172// function : gltfParseMesh
1173// purpose :
1174// =======================================================================
1175bool RWGltf_GltfJsonParser::gltfParseMesh (TopoDS_Shape& theMeshShape,
1176 const TCollection_AsciiString& theMeshId,
1177 const RWGltf_JsonValue& theMesh,
1178 const Handle(Message_ProgressIndicator)& theProgress)
1179{
1180 const RWGltf_JsonValue* aName = findObjectMember (theMesh, "name");
1181 const RWGltf_JsonValue* aPrims = findObjectMember (theMesh, "primitives");
1182 if (!aPrims->IsArray())
1183 {
1184 reportGltfError ("Primitive array attributes within Mesh '" + theMeshId + "' is not an array.");
1185 return false;
1186 }
1187
1188 if (findMeshShape (theMeshShape, theMeshId))
1189 {
1190 return true;
1191 }
1192
1193 BRep_Builder aBuilder;
1194 TopoDS_Compound aMeshShape;
1195 int aNbFaces = 0;
1196 for (rapidjson::Value::ConstValueIterator aPrimArrIter = aPrims->Begin();
1197 aPrimArrIter != aPrims->End(); ++aPrimArrIter)
1198 {
1199 TCollection_AsciiString aUserName;
1200 if (aName != NULL
1201 && aName->IsString())
1202 {
1203 aUserName = aName->GetString();
1204 }
1205
1206 Handle(RWGltf_GltfLatePrimitiveArray) aMeshData = new RWGltf_GltfLatePrimitiveArray (theMeshId, aUserName);
1207 if (!gltfParsePrimArray (aMeshData, theMeshId, *aPrimArrIter, theProgress))
1208 {
1209 return false;
1210 }
1211
1212 if (!aMeshData->Data().IsEmpty())
1213 {
1214 if (aMeshShape.IsNull())
1215 {
1216 aBuilder.MakeCompound (aMeshShape);
1217 }
1218
1219 TopoDS_Face aFace;
1220 aBuilder.MakeFace (aFace, aMeshData);
1221 aBuilder.Add (aMeshShape, aFace);
1222 if (myAttribMap != NULL
1223 && aMeshData->HasStyle())
1224 {
1225 RWMesh_NodeAttributes aShapeAttribs;
1226 aShapeAttribs.RawName = aUserName;
a4815d55 1227
1228 // assign material and not color
1229 //aShapeAttribs.Style.SetColorSurf (aMeshData->BaseColor());
1230
1231 Handle(XCAFDoc_VisMaterial) aMat;
1232 myMaterials.Find (!aMeshData->MaterialPbr().IsNull() ? aMeshData->MaterialPbr()->Id : aMeshData->MaterialCommon()->Id, aMat);
1233 aShapeAttribs.Style.SetMaterial (aMat);
1234
0a419c51 1235 myAttribMap->Bind (aFace, aShapeAttribs);
1236 }
1237 myFaceList.Append (aFace);
1238 ++aNbFaces;
1239 }
1240 }
1241
1242 if (aNbFaces == 1)
1243 {
1244 theMeshShape = TopoDS_Iterator (aMeshShape).Value();
1245 }
1246 else
1247 {
1248 theMeshShape = aMeshShape;
1249 }
1250 bindMeshShape (theMeshShape, theMeshId, aName);
1251 return true;
1252}
1253
1254// =======================================================================
1255// function : gltfParsePrimArray
1256// purpose :
1257// =======================================================================
1258bool RWGltf_GltfJsonParser::gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1259 const TCollection_AsciiString& theMeshId,
1260 const RWGltf_JsonValue& thePrimArray,
1261 const Handle(Message_ProgressIndicator)& /*theProgress*/)
1262{
1263 const RWGltf_JsonValue* anAttribs = findObjectMember (thePrimArray, "attributes");
1264 const RWGltf_JsonValue* anIndices = findObjectMember (thePrimArray, "indices");
1265 const RWGltf_JsonValue* aMaterial = findObjectMember (thePrimArray, "material");
1266 const RWGltf_JsonValue* aModeVal = findObjectMember (thePrimArray, "mode");
1267 RWGltf_GltfPrimitiveMode aMode = RWGltf_GltfPrimitiveMode_Triangles;
1268 if (anAttribs == NULL
1269 || !anAttribs->IsObject())
1270 {
1271 reportGltfError ("Primitive array within Mesh '" + theMeshId + "' defines no attributes.");
1272 return false;
1273 }
1274 else if (aModeVal != NULL)
1275 {
1276 aMode = RWGltf_GltfPrimitiveMode_UNKNOWN;
1277 if (aModeVal->IsInt())
1278 {
1279 aMode = (RWGltf_GltfPrimitiveMode )aModeVal->GetInt();
1280 }
1281 if (aMode < RWGltf_GltfPrimitiveMode_Points
1282 || aMode > RWGltf_GltfPrimitiveMode_TriangleFan)
1283 {
1284 reportGltfError ("Primitive array within Mesh '" + theMeshId + "' has unknown mode.");
1285 return false;
1286 }
1287 }
1288 if (aMode != RWGltf_GltfPrimitiveMode_Triangles)
1289 {
1290 Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Primitive array within Mesh '"
1291 + theMeshId + "' skipped due to unsupported mode.", Message_Warning);
1292 return true;
1293 }
1294 theMeshData->SetPrimitiveMode (aMode);
1295
1296 // assign material
1297 if (aMaterial != NULL)
1298 {
1299 Handle(RWGltf_MaterialMetallicRoughness) aMatPbr;
1300 if (myMaterialsPbr.Find (getKeyString (*aMaterial), aMatPbr))
1301 {
1302 theMeshData->SetMaterialPbr (aMatPbr);
1303 }
1304
1305 Handle(RWGltf_MaterialCommon) aMatCommon;
1306 if (myMaterialsCommon.Find (getKeyString (*aMaterial), aMatCommon))
1307 {
1308 theMeshData->SetMaterialCommon (aMatCommon);
1309 }
1310 }
1311
1312 bool hasPositions = false;
1313 for (rapidjson::Value::ConstMemberIterator anAttribIter = anAttribs->MemberBegin();
1314 anAttribIter != anAttribs->MemberEnd(); ++anAttribIter)
1315 {
1316 const TCollection_AsciiString anAttribId = getKeyString (anAttribIter->value);
1317 if (anAttribId.IsEmpty())
1318 {
1319 reportGltfError ("Primitive array attribute accessor key within Mesh '" + theMeshId + "' is not a string.");
1320 return false;
1321 }
1322
1323 RWGltf_GltfArrayType aType = RWGltf_GltfParseAttribType (anAttribIter->name.GetString());
1324 if (aType == RWGltf_GltfArrayType_UNKNOWN)
1325 {
1326 // just ignore unknown attributes
1327 continue;
1328 }
1329
1330 const RWGltf_JsonValue* anAccessor = myGltfRoots[RWGltf_GltfRootElement_Accessors].FindChild (anAttribIter->value);
1331 if (anAccessor == NULL
1332 || !anAccessor->IsObject())
1333 {
1334 reportGltfError ("Primitive array attribute accessor key '" + anAttribId + "' points to non-existing object.");
1335 return false;
1336 }
1337 else if (!gltfParseAccessor (theMeshData, anAttribId, *anAccessor, aType))
1338 {
1339 return false;
1340 }
1341 else if (aType == RWGltf_GltfArrayType_Position)
1342 {
1343 hasPositions = true;
1344 }
1345 }
1346 if (!hasPositions)
1347 {
1348 reportGltfError ("Primitive array within Mesh '" + theMeshId + "' does not define vertex positions.");
1349 return false;
1350 }
1351
1352 if (anIndices != NULL)
1353 {
1354 const TCollection_AsciiString anIndicesId = getKeyString (*anIndices);
1355 const RWGltf_JsonValue* anAccessor = myGltfRoots[RWGltf_GltfRootElement_Accessors].FindChild (*anIndices);
1356 if (anAccessor == NULL
1357 || !anAccessor->IsObject())
1358 {
1359 reportGltfError ("Primitive array indices accessor key '" + anIndicesId + "' points to non-existing object.");
1360 return false;
1361 }
1362 else if (!gltfParseAccessor (theMeshData, anIndicesId, *anAccessor, RWGltf_GltfArrayType_Indices))
1363 {
1364 return false;
1365 }
1366 }
1367
1368 return true;
1369}
1370
1371// =======================================================================
1372// function : gltfParseAccessor
1373// purpose :
1374// =======================================================================
1375bool RWGltf_GltfJsonParser::gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1376 const TCollection_AsciiString& theName,
1377 const RWGltf_JsonValue& theAccessor,
1378 const RWGltf_GltfArrayType theType)
1379{
1380 RWGltf_GltfAccessor aStruct;
1381 const RWGltf_JsonValue* aTypeStr = findObjectMember (theAccessor, "type");
1382 const RWGltf_JsonValue* aBufferViewName = findObjectMember (theAccessor, "bufferView");
1383 const RWGltf_JsonValue* aByteOffset = findObjectMember (theAccessor, "byteOffset");
1384 const RWGltf_JsonValue* aByteStride = findObjectMember (theAccessor, "byteStride");
1385 const RWGltf_JsonValue* aCompType = findObjectMember (theAccessor, "componentType");
1386 const RWGltf_JsonValue* aCount = findObjectMember (theAccessor, "count");
1387 if (aTypeStr == NULL
1388 || !aTypeStr->IsString())
1389 {
1390 reportGltfError ("Accessor '" + theName + "' does not define type.");
1391 return false;
1392 }
1393 aStruct.Type = RWGltf_GltfParseAccessorType (aTypeStr->GetString());
1394 if (aStruct.Type == RWGltf_GltfAccessorLayout_UNKNOWN)
1395 {
1396 reportGltfError ("Accessor '" + theName + "' has invalid type.");
1397 return false;
1398 }
1399
1400 if (aBufferViewName == NULL)
1401 {
1402 reportGltfError ("Accessor '" + theName + "' does not define bufferView.");
1403 return false;
1404 }
1405 if (aCompType == NULL
1406 || !aCompType->IsInt())
1407 {
1408 reportGltfError ("Accessor '" + theName + "' does not define componentType.");
1409 return false;
1410 }
1411 aStruct.ComponentType = (RWGltf_GltfAccessorCompType )aCompType->GetInt();
1412 if (aStruct.ComponentType != RWGltf_GltfAccessorCompType_Int8
1413 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_UInt8
1414 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_Int16
1415 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_UInt16
1416 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_UInt32
1417 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_Float32)
1418 {
1419 reportGltfError ("Accessor '" + theName + "' defines invalid componentType value.");
1420 return false;
1421 }
1422
1423 if (aCount == NULL
1424 || !aCount->IsNumber())
1425 {
1426 reportGltfError ("Accessor '" + theName + "' does not define count.");
1427 return false;
1428 }
1429
1430 aStruct.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
1431 ? (int64_t )aByteOffset->GetDouble()
1432 : 0;
1433 aStruct.ByteStride = aByteStride != NULL && aByteStride->IsInt()
1434 ? aByteStride->GetInt()
1435 : 0;
1436 aStruct.Count = (int64_t )aCount->GetDouble();
1437
1438 if (aStruct.ByteOffset < 0)
1439 {
1440 reportGltfError ("Accessor '" + theName + "' defines invalid byteOffset.");
1441 return false;
1442 }
1443 else if (aStruct.ByteStride < 0
1444 || aStruct.ByteStride > 255)
1445 {
1446 reportGltfError ("Accessor '" + theName + "' defines invalid byteStride.");
1447 return false;
1448 }
1449 else if (aStruct.Count < 1)
1450 {
1451 reportGltfError ("Accessor '" + theName + "' defines invalid count.");
1452 return false;
1453 }
1454
1455 // Read Min/Max values for POSITION type. It is used for bounding boxes
1456 if (theType == RWGltf_GltfArrayType_Position)
1457 {
1458 const RWGltf_JsonValue* aMin = findObjectMember (theAccessor, "min");
1459 const RWGltf_JsonValue* aMax = findObjectMember (theAccessor, "max");
1460 if (aMin != NULL && aMax != NULL)
1461 {
1462 // Note: Min/Max values can be not defined in glTF file.
1463 // In this case it is not used only.
1464 if (!aMin->IsArray() || !aMax->IsArray() ||
1465 aMin->Size() != 3 || aMax->Size() != 3)
1466 {
1467 reportGltfWarning ("Accessor '" + theName + "' defines invalid min/max values.");
1468 }
1469 else
1470 {
1471 bool isValidMinMax = true;
1472 gp_Pnt aMinPnt, aMaxPnt;
1473 for (int anIter = 0; anIter < 3; ++anIter)
1474 {
1475 const RWGltf_JsonValue& aMinVal = (*aMin)[anIter];
1476 const RWGltf_JsonValue& aMaxVal = (*aMax)[anIter];
1477 if (!aMinVal.IsNumber() || !aMaxVal.IsNumber())
1478 {
1479 reportGltfWarning ("Accessor '" + theName + "' defines invalid min/max value.");
1480 isValidMinMax = false;
1481 break;
1482 }
1483 aMinPnt.SetCoord (anIter + 1, aMinVal.GetDouble());
1484 aMinPnt.SetCoord (anIter + 1, aMaxVal.GetDouble());
1485 }
1486 if (isValidMinMax)
1487 {
1488 myCSTrsf.TransformPosition (aMinPnt.ChangeCoord());
1489 myCSTrsf.TransformPosition (aMaxPnt.ChangeCoord());
1490
1491 Bnd_Box aBox;
1492 aBox.Add (aMinPnt);
1493 aBox.Add (aMaxPnt);
1494
1495 theMeshData->SetBoundingBox (aBox);
1496 }
1497 }
1498 }
1499 }
1500
1501 const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
1502 if (aBufferView == NULL
1503 || !aBufferView->IsObject())
1504 {
1505 reportGltfError ("Accessor '" + theName + "' refers to non-existing bufferView.");
1506 return false;
1507 }
1508
1509 return gltfParseBufferView (theMeshData, getKeyString (*aBufferViewName), *aBufferView, aStruct, theType);
1510}
1511
1512// =======================================================================
1513// function : gltfParseBufferView
1514// purpose :
1515// =======================================================================
1516bool RWGltf_GltfJsonParser::gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1517 const TCollection_AsciiString& theName,
1518 const RWGltf_JsonValue& theBufferView,
1519 const RWGltf_GltfAccessor& theAccessor,
1520 const RWGltf_GltfArrayType theType)
1521{
1522 RWGltf_GltfBufferView aBuffView;
1523 const RWGltf_JsonValue* aBufferName = findObjectMember (theBufferView, "buffer");
1524 const RWGltf_JsonValue* aByteLength = findObjectMember (theBufferView, "byteLength");
1525 const RWGltf_JsonValue* aByteOffset = findObjectMember (theBufferView, "byteOffset");
1526 const RWGltf_JsonValue* aTarget = findObjectMember (theBufferView, "target");
1527 if (aBufferName == NULL)
1528 {
1529 reportGltfError ("BufferView '" + theName + "' does not define buffer.");
1530 return false;
1531 }
1532
1533 aBuffView.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
1534 ? (int64_t )aByteOffset->GetDouble()
1535 : 0;
1536 aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
1537 ? (int64_t )aByteLength->GetDouble()
1538 : 0;
1539 if (aTarget != NULL && aTarget->IsInt())
1540 {
1541 aBuffView.Target = (RWGltf_GltfBufferViewTarget )aTarget->GetInt();
1542 if (aBuffView.Target != RWGltf_GltfBufferViewTarget_ARRAY_BUFFER
1543 && aBuffView.Target != RWGltf_GltfBufferViewTarget_ELEMENT_ARRAY_BUFFER)
1544 {
1545 reportGltfError ("BufferView '" + theName + "' defines invalid target.");
1546 return false;
1547 }
1548 }
1549
1550 if (aBuffView.ByteLength < 0)
1551 {
1552 reportGltfError ("BufferView '" + theName + "' defines invalid byteLength.");
1553 return false;
1554 }
1555 else if (aBuffView.ByteOffset < 0)
1556 {
1557 reportGltfError ("BufferView '" + theName + "' defines invalid byteOffset.");
1558 return false;
1559 }
1560
1561 const RWGltf_JsonValue* aBuffer = myGltfRoots[RWGltf_GltfRootElement_Buffers].FindChild (*aBufferName);
1562 if (aBuffer == NULL
1563 || !aBuffer->IsObject())
1564 {
1565 reportGltfError ("BufferView '" + theName + "' refers to non-existing buffer.");
1566 return false;
1567 }
1568
1569 return gltfParseBuffer (theMeshData, getKeyString (*aBufferName), *aBuffer, theAccessor, aBuffView, theType);
1570}
1571
1572// =======================================================================
1573// function : gltfParseBuffer
1574// purpose :
1575// =======================================================================
1576bool RWGltf_GltfJsonParser::gltfParseBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1577 const TCollection_AsciiString& theName,
1578 const RWGltf_JsonValue& theBuffer,
1579 const RWGltf_GltfAccessor& theAccessor,
1580 const RWGltf_GltfBufferView& theView,
1581 const RWGltf_GltfArrayType theType)
1582{
1583 //const RWGltf_JsonValue* aType = findObjectMember (theBuffer, "type");
1584 //const RWGltf_JsonValue* aByteLength = findObjectMember (theBuffer, "byteLength");
1585 const RWGltf_JsonValue* anUriVal = findObjectMember (theBuffer, "uri");
1586
1587 int64_t anOffset = theView.ByteOffset + theAccessor.ByteOffset;
1588 bool isBinary = false;
1589 if (myIsBinary)
1590 {
1591 isBinary = IsEqual ("binary_glTF", theName) // glTF 1.0
1592 || anUriVal == NULL; // glTF 2.0
1593 }
1594 if (isBinary)
1595 {
1596 anOffset += myBinBodyOffset;
1597
1598 RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
1599 aData.Accessor = theAccessor;
1600 aData.StreamOffset = anOffset;
1601 aData.StreamUri = myFilePath;
1602 return true;
1603 }
1604
1605 if (anUriVal == NULL
1606 || !anUriVal->IsString())
1607 {
1608 reportGltfError ("Buffer '" + theName + "' does not define uri.");
1609 return false;
1610 }
1611
1612 const char* anUriData = anUriVal->GetString();
1613 if (::strncmp (anUriData, "data:application/octet-stream;base64,", 37) == 0)
1614 {
1615 RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
1616 aData.Accessor = theAccessor;
1617 aData.StreamOffset = anOffset;
1618 if (!myDecodedBuffers.Find (theName, aData.StreamData))
1619 {
1620 // it is better decoding in multiple threads
1621 aData.StreamData = FSD_Base64Decoder::Decode ((const Standard_Byte* )anUriData + 37, anUriVal->GetStringLength() - 37);
1622 myDecodedBuffers.Bind (theName, aData.StreamData);
1623 }
1624 return true;
1625 }
1626 else
1627 {
1628 TCollection_AsciiString anUri = anUriData;
1629 if (anUri.IsEmpty())
1630 {
1631 reportGltfError ("Buffer '" + theName + "' does not define uri.");
1632 return false;
1633 }
1634
1635 TCollection_AsciiString aPath = myFolder + anUri;
1636 bool isFileExist = false;
1637 if (!myProbedFiles.Find (aPath, isFileExist))
1638 {
1639 isFileExist = OSD_File (aPath).Exists();
1640 myProbedFiles.Bind (aPath, isFileExist);
1641 }
1642 if (!isFileExist)
1643 {
1644 reportGltfError ("Buffer '" + theName + "' refers to non-existing file '" + anUri + "'.");
1645 return false;
1646 }
1647
1648 RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
1649 aData.Accessor = theAccessor;
1650 aData.StreamOffset = anOffset;
1651 aData.StreamUri = myFolder + anUri;
1652 if (myExternalFiles != NULL)
1653 {
1654 myExternalFiles->Add (aData.StreamUri);
1655 }
1656 return true;
1657 }
1658}
1659
1660// =======================================================================
1661// function : bindNamedShape
1662// purpose :
1663// =======================================================================
1664void RWGltf_GltfJsonParser::bindNamedShape (TopoDS_Shape& theShape,
1665 ShapeMapGroup theGroup,
1666 const TopLoc_Location& theLoc,
1667 const TCollection_AsciiString& theId,
1668 const RWGltf_JsonValue* theUserName)
1669{
1670 if (theShape.IsNull())
1671 {
1672 return;
1673 }
1674
1675 if (!theLoc.IsIdentity())
1676 {
1677 theShape.Location (theLoc);
1678 }
1679
1680 TCollection_AsciiString aUserName;
1681 if (theUserName != NULL
1682 && theUserName->IsString())
1683 {
1684 aUserName = theUserName->GetString();
1685 }
1686 else if (myIsGltf1)
1687 {
1688 aUserName = theId;
1689 }
1690
1691 myShapeMap[theGroup].Bind (theId, theShape);
1692 if (myAttribMap != NULL)
1693 {
1694 RWMesh_NodeAttributes aShapeAttribs;
1695 aShapeAttribs.Name = aUserName;
1696 aShapeAttribs.RawName = theId;
1697 if (theShape.ShapeType() == TopAbs_FACE)
1698 {
1699 TopLoc_Location aDummy;
1700 if (Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (TopoDS::Face (theShape), aDummy)))
1701 {
1702 if (aLateData->HasStyle())
1703 {
a4815d55 1704 // assign material and not color
1705 //aShapeAttribs.Style.SetColorSurf (aLateData->BaseColor());
1706
1707 Handle(XCAFDoc_VisMaterial) aMat;
1708 myMaterials.Find (!aLateData->MaterialPbr().IsNull() ? aLateData->MaterialPbr()->Id : aLateData->MaterialCommon()->Id, aMat);
1709 aShapeAttribs.Style.SetMaterial (aMat);
0a419c51 1710 }
803bdcdf 1711 if (aShapeAttribs.Name.IsEmpty()
1712 && myUseMeshNameAsFallback)
1713 {
1714 // fallback using Mesh name
1715 aShapeAttribs.Name = aLateData->Name();
1716 }
1717 }
1718 }
1719 else if (aShapeAttribs.Name.IsEmpty()
1720 && myUseMeshNameAsFallback)
1721 {
1722 // fallback using Mesh name
1723 TopLoc_Location aDummy;
1724 TCollection_AsciiString aMeshName;
1725 for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
1726 {
1727 if (Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (TopoDS::Face (aFaceIter.Value()), aDummy)))
1728 {
1729 if (aLateData->Name().IsEmpty())
1730 {
1731 aMeshName.Clear();
1732 break;
1733 }
1734 else if (aMeshName.IsEmpty())
1735 {
1736 aMeshName = aLateData->Name();
1737 }
1738 else if (!aMeshName.IsEqual (aLateData->Name()))
1739 {
1740 aMeshName.Clear();
1741 break;
1742 }
1743 }
1744 }
1745 if (!aMeshName.IsEmpty())
1746 {
1747 aShapeAttribs.Name = aMeshName;
0a419c51 1748 }
1749 }
1750 myAttribMap->Bind (theShape, aShapeAttribs);
1751 }
1752}
1753#endif
1754
1755// =======================================================================
1756// function : Parse
1757// purpose :
1758// =======================================================================
1759bool RWGltf_GltfJsonParser::Parse (const Handle(Message_ProgressIndicator)& theProgress)
1760{
1761 Message_ProgressSentry aPSentry (theProgress, "Reading Gltf", 0, 2, 1);
1762#ifdef HAVE_RAPIDJSON
1763 {
1764 if (!gltfParseRoots())
1765 {
1766 return false;
1767 }
1768
1769 gltfParseAsset();
1770 gltfParseMaterials();
1771 if (!gltfParseScene (theProgress))
1772 {
1773 return false;
1774 }
1775 }
1776 aPSentry.Next();
1777 if (!aPSentry.More())
1778 {
1779 return false;
1780 }
1781 return true;
1782#else
1783 Message::DefaultMessenger()->Send ("Error: glTF reader is unavailable - OCCT has been built without RapidJSON support.", Message_Fail);
1784 return false;
1785#endif
1786}