0031258: Mesh - OCCT 7.4.0 VIS get wrong render data
[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");
0858125f 545 // TODO ADOBE_materials_thin_transparency extension can be used to read IOR (Index of Refraction for transparent materials)
0a419c51 546 if (aMetalRoughVal == NULL)
547 {
548 return false;
549 }
550
551 theMat = new RWGltf_MaterialMetallicRoughness();
552 const RWGltf_JsonValue* aBaseColorFactorVal = findObjectMember (*aMetalRoughVal, "baseColorFactor");
553 const RWGltf_JsonValue* aBaseColorTexVal = findObjectMember (*aMetalRoughVal, "baseColorTexture");
554 const RWGltf_JsonValue* aMetallicFactorVal = findObjectMember (*aMetalRoughVal, "metallicFactor");
555 const RWGltf_JsonValue* aRoughnessFactorVal = findObjectMember (*aMetalRoughVal, "roughnessFactor");
556 const RWGltf_JsonValue* aMetalRoughTexVal = findObjectMember (*aMetalRoughVal, "metallicRoughnessTexture");
557
a4815d55 558 if (aDoubleSidedVal != NULL
559 && aDoubleSidedVal->IsBool())
560 {
561 theMat->IsDoubleSided = aDoubleSidedVal->GetBool();
562 }
563 if (anAlphaCutoffVal != NULL
564 && anAlphaCutoffVal->IsNumber())
565 {
566 theMat->AlphaCutOff = (float )anAlphaCutoffVal->GetDouble();
567 }
568 if (anAlphaModeVal != NULL
569 && anAlphaModeVal->IsString())
570 {
571 theMat->AlphaMode = RWGltf_GltfParseAlphaMode (anAlphaModeVal->GetString());
572 }
573
0a419c51 574 if (aBaseColorTexVal != NULL
575 && aBaseColorTexVal->IsObject())
576 {
577 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*aBaseColorTexVal, "index"))
578 {
579 gltfParseTexture (theMat->BaseColorTexture, aTexIndexVal);
580 }
581 }
582
583 Graphic3d_Vec4d aBaseColorFactor;
584 if (gltfReadVec4 (aBaseColorFactor, aBaseColorFactorVal)
585 && validateColor4 (aBaseColorFactor))
586 {
587 theMat->BaseColor = Quantity_ColorRGBA (Graphic3d_Vec4 (aBaseColorFactor));
588 }
589
590 Graphic3d_Vec3d anEmissiveFactor;
591 if (gltfReadVec3 (anEmissiveFactor, anEmissFactorVal)
592 && validateColor3 (anEmissiveFactor))
593 {
594 theMat->EmissiveFactor = Graphic3d_Vec3 (anEmissiveFactor);
595 }
596
597 if (aMetalRoughTexVal != NULL
598 && aMetalRoughTexVal->IsObject())
599 {
600 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*aMetalRoughTexVal, "index"))
601 {
602 gltfParseTexture (theMat->MetallicRoughnessTexture, aTexIndexVal);
603 }
604 }
605
606 if (aMetallicFactorVal != NULL
607 && aMetallicFactorVal->IsNumber())
608 {
609 theMat->Metallic = (float )aMetallicFactorVal->GetDouble();
610 }
611
612 if (aRoughnessFactorVal != NULL
613 && aRoughnessFactorVal->IsNumber())
614 {
615 theMat->Roughness = (float )aRoughnessFactorVal->GetDouble();
616 }
617
618 if (aNormTexVal != NULL
619 && aNormTexVal->IsObject())
620 {
621 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*aNormTexVal, "index"))
622 {
623 gltfParseTexture (theMat->NormalTexture, aTexIndexVal);
624 }
625 }
626
627 if (anEmissTexVal != NULL
628 && anEmissTexVal->IsObject())
629 {
630 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*anEmissTexVal, "index"))
631 {
632 gltfParseTexture (theMat->EmissiveTexture, aTexIndexVal);
633 }
634 }
635
636 if (anOcclusionTexVal != NULL
637 && anOcclusionTexVal->IsObject())
638 {
639 if (const RWGltf_JsonValue* aTexIndexVal = findObjectMember (*anOcclusionTexVal, "index"))
640 {
641 gltfParseTexture (theMat->OcclusionTexture, aTexIndexVal);
642 }
643 }
644 return true;
645}
646
647// =======================================================================
648// function : gltfParseCommonMaterial
649// purpose :
650// =======================================================================
651bool RWGltf_GltfJsonParser::gltfParseCommonMaterial (Handle(RWGltf_MaterialCommon)& theMat,
652 const RWGltf_JsonValue& theMatNode)
653{
654 const RWGltf_JsonValue* anExtVal = findObjectMember (theMatNode, "extensions");
655 if (anExtVal == NULL)
656 {
657 return false;
658 }
659
660 const RWGltf_JsonValue* aMatCommon = findObjectMember (*anExtVal, THE_KHR_materials_common);
661 if (aMatCommon == NULL)
662 {
663 return false;
664 }
665
666 if (!gltfParseStdMaterial (theMat, *aMatCommon))
667 {
668 return false;
669 }
670 return true;
671}
672
673// =======================================================================
674// function : gltfParseTexture
675// purpose :
676// =======================================================================
677bool RWGltf_GltfJsonParser::gltfParseTexture (Handle(Image_Texture)& theTexture,
678 const RWGltf_JsonValue* theTextureId)
679{
680 if (theTextureId == NULL
681 || myGltfRoots[RWGltf_GltfRootElement_Textures].IsNull()
682 || myGltfRoots[RWGltf_GltfRootElement_Images].IsNull())
683 {
684 return false;
685 }
686
687 const TCollection_AsciiString aTextureId = getKeyString (*theTextureId);
688 const RWGltf_JsonValue* aTexNode = myGltfRoots[RWGltf_GltfRootElement_Textures].FindChild (*theTextureId);
689 if (aTexNode == NULL)
690 {
691 reportGltfWarning ("Texture node '" + aTextureId + "' is not found.");
692 return false;
693 }
694
695 const RWGltf_JsonValue* aSrcVal = findObjectMember (*aTexNode, "source");
696 const RWGltf_JsonValue* aTargVal = findObjectMember (*aTexNode, "target");
697 if (aSrcVal == NULL)
698 {
699 reportGltfWarning ("Invalid texture node '" + aTextureId + "' without a 'source' property.");
700 return false;
701 }
702 if (aTargVal != NULL
703 && aTargVal->IsNumber()
704 && aTargVal->GetInt() != 3553) // GL_TEXTURE_2D
705 {
706 return false;
707 }
708
709 const RWGltf_JsonValue* anImgNode = myGltfRoots[RWGltf_GltfRootElement_Images].FindChild (*aSrcVal);
710 if (anImgNode == NULL)
711 {
712 reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to non-existing image '" + getKeyString (*aSrcVal) + "'.");
713 return false;
714 }
715
716 if (myIsBinary)
717 {
718 const RWGltf_JsonValue* aBinVal = NULL;
719 const RWGltf_JsonValue* aBufferViewName = findObjectMember (*anImgNode, "bufferView");
720 if (aBufferViewName != NULL)
721 {
722 aBinVal = anImgNode;
723 }
724 else if (myIsGltf1)
725 {
726 const RWGltf_JsonValue* anExtVal = findObjectMember (*anImgNode, "extensions");
727 if (anExtVal != NULL)
728 {
729 aBinVal = findObjectMember (*anExtVal, THE_KHR_binary_glTF);
730 if (aBinVal != NULL)
731 {
732 aBufferViewName = findObjectMember (*aBinVal, "bufferView");
733 }
734 }
735 }
736
737 if (aBinVal != NULL)
738 {
739 //const RWGltf_JsonValue* aMimeTypeVal = findObjectMember (*aBinVal, "mimeType");
740 //const RWGltf_JsonValue* aWidthVal = findObjectMember (*aBinVal, "width");
741 //const RWGltf_JsonValue* aHeightVal = findObjectMember (*aBinVal, "height");
742 if (aBufferViewName == NULL)
743 {
744 reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid data source.");
745 return false;
746 }
747
748 const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
749 if (aBufferView == NULL
750 || !aBufferView->IsObject())
751 {
752 reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid buffer view '" + getKeyString (*aBufferViewName) + "'.");
753 return false;
754 }
755
756 const RWGltf_JsonValue* aBufferName = findObjectMember (*aBufferView, "buffer");
757 const RWGltf_JsonValue* aByteLength = findObjectMember (*aBufferView, "byteLength");
758 const RWGltf_JsonValue* aByteOffset = findObjectMember (*aBufferView, "byteOffset");
759 if (aBufferName != NULL
760 && aBufferName->IsString()
761 && !IsEqual (aBufferName->GetString(), "binary_glTF"))
762 {
763 reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' does not define binary_glTF buffer.");
764 return false;
765 }
766
767 RWGltf_GltfBufferView aBuffView;
768 aBuffView.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
769 ? (int64_t )aByteOffset->GetDouble()
770 : 0;
771 aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
772 ? (int64_t )aByteLength->GetDouble()
773 : 0;
774 if (aBuffView.ByteLength < 0)
775 {
776 reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' defines invalid byteLength.");
777 return false;
778 }
779 else if (aBuffView.ByteOffset < 0)
780 {
781 reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' defines invalid byteOffset.");
782 return false;
783 }
784
785
786 const int64_t anOffset = myBinBodyOffset + aBuffView.ByteOffset;
787 theTexture = new Image_Texture (myFilePath, anOffset, aBuffView.ByteLength);
788 return true;
789 }
790 }
791
792 const RWGltf_JsonValue* anUriVal = findObjectMember (*anImgNode, "uri");
793 if (anUriVal == NULL
794 || !anUriVal->IsString())
795 {
796 return false;
797 }
798
799 const char* anUriData = anUriVal->GetString();
800 if (::strncmp (anUriData, "data:", 5) == 0) // data:image/png;base64
801 {
802 // uncompressing base64 here is inefficient, because the same image can be shared by several nodes
803 const char* aDataStart = anUriData + 5;
804 for (const char* aDataIter = aDataStart; *aDataIter != '\0'; ++aDataIter)
805 {
806 if (::memcmp (aDataIter, ";base64,", 8) == 0)
807 {
808 const char* aBase64End = anUriData + anUriVal->GetStringLength();
809 const char* aBase64Data = aDataIter + 8;
810 const size_t aBase64Len = size_t(aBase64End - aBase64Data);
811 //const TCollection_AsciiString aMime (aDataStart, aDataIter - aDataStart);
812 Handle(NCollection_Buffer) aData = FSD_Base64Decoder::Decode ((const Standard_Byte* )aBase64Data, aBase64Len);
813 theTexture = new Image_Texture (aData, myFilePath + "@" + getKeyString (*aSrcVal));
814 return true;
815 }
816 }
817 Message::DefaultMessenger()->Send ("glTF reader - embedded image has been skipped", Message_Warning);
818 return false;
819 }
820
821 TCollection_AsciiString anImageFile = myFolder + anUriVal->GetString();
822 theTexture = new Image_Texture (anImageFile);
823 if (myExternalFiles != NULL)
824 {
825 myExternalFiles->Add (anImageFile);
826 }
827 return true;
828}
829
830// =======================================================================
831// function : gltfParseScene
832// purpose :
833// =======================================================================
834bool RWGltf_GltfJsonParser::gltfParseScene (const Handle(Message_ProgressIndicator)& theProgress)
835{
836 // search default scene
837 const RWGltf_JsonValue* aDefScene = myGltfRoots[RWGltf_GltfRootElement_Scenes].FindChild (*myGltfRoots[RWGltf_GltfRootElement_Scene].Root());
838 if (aDefScene == NULL)
839 {
840 reportGltfError ("Default scene is not found.");
841 return false;
842 }
843
844 const RWGltf_JsonValue* aSceneNodes = findObjectMember (*aDefScene, "nodes");
845 if (aSceneNodes == NULL
846 || !aSceneNodes->IsArray())
847 {
848 reportGltfError ("Empty scene '" + getKeyString (*myGltfRoots[RWGltf_GltfRootElement_Scene].Root()) + "'.");
849 return false;
850 }
851
852 return gltfParseSceneNodes (*myRootShapes, *aSceneNodes, theProgress);
853}
854
855// =======================================================================
856// function : gltfParseSceneNodes
857// purpose :
858// =======================================================================
859bool RWGltf_GltfJsonParser::gltfParseSceneNodes (TopTools_SequenceOfShape& theShapeSeq,
860 const RWGltf_JsonValue& theSceneNodes,
861 const Handle(Message_ProgressIndicator)& theProgress)
862{
863 if (!theSceneNodes.IsArray())
864 {
865 reportGltfError ("Scene nodes is not array.");
866 return false;
867 }
868
869 Message_ProgressSentry aPSentry (theProgress, "Reading scene nodes", 0, theSceneNodes.Size(), 1);
870 for (rapidjson::Value::ConstValueIterator aSceneNodeIter = theSceneNodes.Begin();
871 aSceneNodeIter != theSceneNodes.End() && aPSentry.More(); ++aSceneNodeIter, aPSentry.Next())
872 {
873 const RWGltf_JsonValue* aSceneNode = myGltfRoots[RWGltf_GltfRootElement_Nodes].FindChild (*aSceneNodeIter);
874 if (aSceneNode == NULL)
875 {
876 reportGltfWarning ("Scene refers to non-existing node '" + getKeyString (*aSceneNodeIter) + "'.");
877 return true;
878 }
879
880 TopoDS_Shape aNodeShape;
881 if (!gltfParseSceneNode (aNodeShape, getKeyString (*aSceneNodeIter), *aSceneNode, theProgress))
882 {
883 return false;
884 }
885
886 if (aNodeShape.IsNull())
887 {
888 continue;
889 }
890 else if (myToSkipEmptyNodes
891 && !TopExp_Explorer (aNodeShape, TopAbs_FACE).More())
892 {
893 continue;
894 }
895
896 theShapeSeq.Append (aNodeShape);
897 }
898 return true;
899}
900
901// =======================================================================
902// function : gltfParseSceneNode
903// purpose :
904// =======================================================================
905bool RWGltf_GltfJsonParser::gltfParseSceneNode (TopoDS_Shape& theNodeShape,
906 const TCollection_AsciiString& theSceneNodeId,
907 const RWGltf_JsonValue& theSceneNode,
908 const Handle(Message_ProgressIndicator)& theProgress)
909{
910 const RWGltf_JsonValue* aName = findObjectMember (theSceneNode, "name");
911 //const RWGltf_JsonValue* aJointName = findObjectMember (theSceneNode, "jointName");
912 const RWGltf_JsonValue* aChildren = findObjectMember (theSceneNode, "children");
913 const RWGltf_JsonValue* aMeshes_1 = findObjectMember (theSceneNode, "meshes");
914 const RWGltf_JsonValue* aMesh_2 = findObjectMember (theSceneNode, "mesh");
915 //const RWGltf_JsonValue* aCamera = findObjectMember (theSceneNode, "camera");
916 const RWGltf_JsonValue* aTrsfMatVal = findObjectMember (theSceneNode, "matrix");
917 const RWGltf_JsonValue* aTrsfRotVal = findObjectMember (theSceneNode, "rotation");
918 const RWGltf_JsonValue* aTrsfScaleVal = findObjectMember (theSceneNode, "scale");
919 const RWGltf_JsonValue* aTrsfTransVal = findObjectMember (theSceneNode, "translation");
920 if (findNodeShape (theNodeShape, theSceneNodeId))
921 {
922 return true;
923 }
924
925 TopLoc_Location aNodeLoc;
926 const bool hasTrs = aTrsfRotVal != NULL
927 || aTrsfScaleVal != NULL
928 || aTrsfTransVal != NULL;
929 if (aTrsfMatVal != NULL)
930 {
931 if (hasTrs)
932 {
933 reportGltfError ("Scene node '" + theSceneNodeId + "' defines ambiguous transformation.");
934 return false;
935 }
936 else if (!aTrsfMatVal->IsArray()
937 || aTrsfMatVal->Size() != 16)
938 {
939 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid transformation matrix array.");
940 return false;
941 }
942
943 Graphic3d_Mat4d aMat4;
944 for (int aColIter = 0; aColIter < 4; ++aColIter)
945 {
946 for (int aRowIter = 0; aRowIter < 4; ++aRowIter)
947 {
948 const RWGltf_JsonValue& aGenVal = (*aTrsfMatVal)[aColIter * 4 + aRowIter];
949 if (!aGenVal.IsNumber())
950 {
951 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid transformation matrix.");
952 return false;
953 }
954 aMat4.SetValue (aRowIter, aColIter, aGenVal.GetDouble());
955 }
956 }
957
958 if (!aMat4.IsIdentity())
959 {
960 gp_Trsf aTrsf;
961 aTrsf.SetValues (aMat4.GetValue (0, 0), aMat4.GetValue (0, 1), aMat4.GetValue (0, 2), aMat4.GetValue (0, 3),
962 aMat4.GetValue (1, 0), aMat4.GetValue (1, 1), aMat4.GetValue (1, 2), aMat4.GetValue (1, 3),
963 aMat4.GetValue (2, 0), aMat4.GetValue (2, 1), aMat4.GetValue (2, 2), aMat4.GetValue (2, 3));
964 myCSTrsf.TransformTransformation (aTrsf);
965 if (aTrsf.Form() != gp_Identity)
966 {
967 aNodeLoc = TopLoc_Location (aTrsf);
968 }
969 }
970 }
971 else if (hasTrs)
972 {
973 gp_Trsf aTrsf;
974 if (aTrsfRotVal != NULL)
975 {
976 if (!aTrsfRotVal->IsArray()
977 || aTrsfRotVal->Size() != 4)
978 {
979 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid rotation quaternion.");
980 return false;
981 }
982
983 Graphic3d_Vec4d aRotVec4;
984 for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
985 {
986 const RWGltf_JsonValue& aGenVal = (*aTrsfRotVal)[aCompIter];
987 if (!aGenVal.IsNumber())
988 {
989 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid rotation.");
990 return false;
991 }
992 aRotVec4[aCompIter] = aGenVal.GetDouble();
993 }
994 const gp_Quaternion aQuaternion (aRotVec4.x(), aRotVec4.y(), aRotVec4.z(), aRotVec4.w());
995 if (Abs (aQuaternion.X()) > gp::Resolution()
996 || Abs (aQuaternion.Y()) > gp::Resolution()
997 || Abs (aQuaternion.Z()) > gp::Resolution()
998 || Abs (aQuaternion.W() - 1.0) > gp::Resolution())
999 {
1000 aTrsf.SetRotation (aQuaternion);
1001 }
1002 }
1003
1004 if (aTrsfTransVal != NULL)
1005 {
1006 if (!aTrsfTransVal->IsArray()
1007 || aTrsfTransVal->Size() != 3)
1008 {
1009 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid translation vector.");
1010 return false;
1011 }
1012
1013 gp_XYZ aTransVec;
1014 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
1015 {
1016 const RWGltf_JsonValue& aGenVal = (*aTrsfTransVal)[aCompIter];
1017 if (!aGenVal.IsNumber())
1018 {
1019 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid translation.");
1020 return false;
1021 }
1022 aTransVec.SetCoord (aCompIter + 1, aGenVal.GetDouble());
1023 }
1024 aTrsf.SetTranslationPart (aTransVec);
1025 }
1026
1027 if (aTrsfScaleVal != NULL)
1028 {
1029 Graphic3d_Vec3d aScaleVec;
1030 if (!aTrsfScaleVal->IsArray()
1031 || aTrsfScaleVal->Size() != 3)
1032 {
1033 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid scale vector.");
1034 return false;
1035 }
1036 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
1037 {
1038 const RWGltf_JsonValue& aGenVal = (*aTrsfScaleVal)[aCompIter];
1039 if (!aGenVal.IsNumber())
1040 {
1041 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid scale.");
1042 return false;
1043 }
1044 aScaleVec[aCompIter] = aGenVal.GetDouble();
1045 if (Abs (aScaleVec[aCompIter]) <= gp::Resolution())
1046 {
1047 reportGltfError ("Scene node '" + theSceneNodeId + "' defines invalid scale.");
1048 return false;
1049 }
1050 }
1051
1052 if (Abs (aScaleVec.x() - aScaleVec.y()) > Precision::Confusion()
1053 || Abs (aScaleVec.y() - aScaleVec.z()) > Precision::Confusion()
1054 || Abs (aScaleVec.x() - aScaleVec.z()) > Precision::Confusion())
1055 {
1056 Graphic3d_Mat4d aScaleMat;
1057 aScaleMat.SetDiagonal (aScaleVec);
1058
1059 Graphic3d_Mat4d aMat4;
1060 aTrsf.GetMat4 (aMat4);
1061
1062 aMat4 = aMat4 * aScaleMat;
1063 aTrsf = gp_Trsf();
1064 aTrsf.SetValues (aMat4.GetValue (0, 0), aMat4.GetValue (0, 1), aMat4.GetValue (0, 2), aMat4.GetValue (0, 3),
1065 aMat4.GetValue (1, 0), aMat4.GetValue (1, 1), aMat4.GetValue (1, 2), aMat4.GetValue (1, 3),
1066 aMat4.GetValue (2, 0), aMat4.GetValue (2, 1), aMat4.GetValue (2, 2), aMat4.GetValue (2, 3));
1067
1068 Message::DefaultMessenger()->Send (TCollection_AsciiString ("glTF reader, scene node '")
1069 + theSceneNodeId + "' defines unsupported scaling "
1070 + aScaleVec.x() + " " + aScaleVec.y() + " " + aScaleVec.z(), Message_Warning);
1071 }
1072 else if (Abs (aScaleVec.x() - 1.0) > Precision::Confusion())
1073 {
1074 aTrsf.SetScaleFactor (aScaleVec.x());
1075 }
1076 }
1077
1078 myCSTrsf.TransformTransformation (aTrsf);
1079 if (aTrsf.Form() != gp_Identity)
1080 {
1081 aNodeLoc = TopLoc_Location (aTrsf);
1082 }
1083 }
1084
1085 BRep_Builder aBuilder;
1086 TopoDS_Compound aNodeShape;
1087 aBuilder.MakeCompound (aNodeShape);
1088 TopTools_SequenceOfShape aChildShapes;
1089 int aNbSubShapes = 0;
1090 if (aChildren != NULL
1091 && !gltfParseSceneNodes (aChildShapes, *aChildren, theProgress))
1092 {
1093 theNodeShape = aNodeShape;
1094 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1095 return false;
1096 }
1097 for (TopTools_SequenceOfShape::Iterator aChildShapeIter (aChildShapes); aChildShapeIter.More(); aChildShapeIter.Next())
1098 {
1099 aBuilder.Add (aNodeShape, aChildShapeIter.Value());
1100 ++aNbSubShapes;
1101 }
1102
1103 if (aMeshes_1 != NULL
1104 && aMeshes_1->IsArray())
1105 {
1106 // glTF 1.0
1107 Message_ProgressSentry aPSentry (theProgress, "Reading scene meshes", 0, aMeshes_1->Size(), 1);
1108 for (rapidjson::Value::ConstValueIterator aMeshIter = aMeshes_1->Begin();
1109 aMeshIter != aMeshes_1->End() && aPSentry.More(); ++aMeshIter, aPSentry.Next())
1110 {
1111 const RWGltf_JsonValue* aMesh = myGltfRoots[RWGltf_GltfRootElement_Meshes].FindChild (*aMeshIter);
1112 if (aMesh == NULL)
1113 {
1114 theNodeShape = aNodeShape;
1115 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1116 reportGltfError ("Scene node '" + theSceneNodeId + "' refers to non-existing mesh.");
1117 return false;
1118 }
1119
1120 TopoDS_Shape aMeshShape;
1121 if (!gltfParseMesh (aMeshShape, getKeyString (*aMeshIter), *aMesh, theProgress))
1122 {
1123 theNodeShape = aNodeShape;
1124 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1125 return false;
1126 }
1127 if (!aMeshShape.IsNull())
1128 {
1129 aBuilder.Add (aNodeShape, aMeshShape);
1130 ++aNbSubShapes;
1131 }
1132 }
1133 }
1134 if (aMesh_2 != NULL)
1135 {
1136 // glTF 2.0
1137 const RWGltf_JsonValue* aMesh = myGltfRoots[RWGltf_GltfRootElement_Meshes].FindChild (*aMesh_2);
1138 if (aMesh == NULL)
1139 {
1140 theNodeShape = aNodeShape;
1141 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1142 reportGltfError ("Scene node '" + theSceneNodeId + "' refers to non-existing mesh.");
1143 return false;
1144 }
1145
1146 TopoDS_Shape aMeshShape;
1147 if (!gltfParseMesh (aMeshShape, getKeyString (*aMesh_2), *aMesh, theProgress))
1148 {
1149 theNodeShape = aNodeShape;
1150 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1151 return false;
1152 }
1153 if (!aMeshShape.IsNull())
1154 {
1155 aBuilder.Add (aNodeShape, aMeshShape);
1156 ++aNbSubShapes;
1157 }
1158 }
1159
1160 if (aNbSubShapes == 1)
1161 {
1162 theNodeShape = TopoDS_Iterator (aNodeShape).Value();
1163 }
1164 else
1165 {
1166 theNodeShape = aNodeShape;
1167 }
1168 bindNodeShape (theNodeShape, aNodeLoc, theSceneNodeId, aName);
1169 return true;
1170}
1171
1172// =======================================================================
1173// function : gltfParseMesh
1174// purpose :
1175// =======================================================================
1176bool RWGltf_GltfJsonParser::gltfParseMesh (TopoDS_Shape& theMeshShape,
1177 const TCollection_AsciiString& theMeshId,
1178 const RWGltf_JsonValue& theMesh,
1179 const Handle(Message_ProgressIndicator)& theProgress)
1180{
1181 const RWGltf_JsonValue* aName = findObjectMember (theMesh, "name");
1182 const RWGltf_JsonValue* aPrims = findObjectMember (theMesh, "primitives");
1183 if (!aPrims->IsArray())
1184 {
1185 reportGltfError ("Primitive array attributes within Mesh '" + theMeshId + "' is not an array.");
1186 return false;
1187 }
1188
1189 if (findMeshShape (theMeshShape, theMeshId))
1190 {
1191 return true;
1192 }
1193
1194 BRep_Builder aBuilder;
1195 TopoDS_Compound aMeshShape;
1196 int aNbFaces = 0;
1197 for (rapidjson::Value::ConstValueIterator aPrimArrIter = aPrims->Begin();
1198 aPrimArrIter != aPrims->End(); ++aPrimArrIter)
1199 {
1200 TCollection_AsciiString aUserName;
1201 if (aName != NULL
1202 && aName->IsString())
1203 {
1204 aUserName = aName->GetString();
1205 }
1206
1207 Handle(RWGltf_GltfLatePrimitiveArray) aMeshData = new RWGltf_GltfLatePrimitiveArray (theMeshId, aUserName);
1208 if (!gltfParsePrimArray (aMeshData, theMeshId, *aPrimArrIter, theProgress))
1209 {
1210 return false;
1211 }
1212
1213 if (!aMeshData->Data().IsEmpty())
1214 {
1215 if (aMeshShape.IsNull())
1216 {
1217 aBuilder.MakeCompound (aMeshShape);
1218 }
1219
1220 TopoDS_Face aFace;
1221 aBuilder.MakeFace (aFace, aMeshData);
1222 aBuilder.Add (aMeshShape, aFace);
1223 if (myAttribMap != NULL
1224 && aMeshData->HasStyle())
1225 {
1226 RWMesh_NodeAttributes aShapeAttribs;
1227 aShapeAttribs.RawName = aUserName;
a4815d55 1228
1229 // assign material and not color
1230 //aShapeAttribs.Style.SetColorSurf (aMeshData->BaseColor());
1231
1232 Handle(XCAFDoc_VisMaterial) aMat;
1233 myMaterials.Find (!aMeshData->MaterialPbr().IsNull() ? aMeshData->MaterialPbr()->Id : aMeshData->MaterialCommon()->Id, aMat);
1234 aShapeAttribs.Style.SetMaterial (aMat);
1235
0a419c51 1236 myAttribMap->Bind (aFace, aShapeAttribs);
1237 }
1238 myFaceList.Append (aFace);
1239 ++aNbFaces;
1240 }
1241 }
1242
1243 if (aNbFaces == 1)
1244 {
1245 theMeshShape = TopoDS_Iterator (aMeshShape).Value();
1246 }
1247 else
1248 {
1249 theMeshShape = aMeshShape;
1250 }
1251 bindMeshShape (theMeshShape, theMeshId, aName);
1252 return true;
1253}
1254
1255// =======================================================================
1256// function : gltfParsePrimArray
1257// purpose :
1258// =======================================================================
1259bool RWGltf_GltfJsonParser::gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1260 const TCollection_AsciiString& theMeshId,
1261 const RWGltf_JsonValue& thePrimArray,
1262 const Handle(Message_ProgressIndicator)& /*theProgress*/)
1263{
1264 const RWGltf_JsonValue* anAttribs = findObjectMember (thePrimArray, "attributes");
1265 const RWGltf_JsonValue* anIndices = findObjectMember (thePrimArray, "indices");
1266 const RWGltf_JsonValue* aMaterial = findObjectMember (thePrimArray, "material");
1267 const RWGltf_JsonValue* aModeVal = findObjectMember (thePrimArray, "mode");
1268 RWGltf_GltfPrimitiveMode aMode = RWGltf_GltfPrimitiveMode_Triangles;
1269 if (anAttribs == NULL
1270 || !anAttribs->IsObject())
1271 {
1272 reportGltfError ("Primitive array within Mesh '" + theMeshId + "' defines no attributes.");
1273 return false;
1274 }
1275 else if (aModeVal != NULL)
1276 {
1277 aMode = RWGltf_GltfPrimitiveMode_UNKNOWN;
1278 if (aModeVal->IsInt())
1279 {
1280 aMode = (RWGltf_GltfPrimitiveMode )aModeVal->GetInt();
1281 }
1282 if (aMode < RWGltf_GltfPrimitiveMode_Points
1283 || aMode > RWGltf_GltfPrimitiveMode_TriangleFan)
1284 {
1285 reportGltfError ("Primitive array within Mesh '" + theMeshId + "' has unknown mode.");
1286 return false;
1287 }
1288 }
1289 if (aMode != RWGltf_GltfPrimitiveMode_Triangles)
1290 {
1291 Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Primitive array within Mesh '"
1292 + theMeshId + "' skipped due to unsupported mode.", Message_Warning);
1293 return true;
1294 }
1295 theMeshData->SetPrimitiveMode (aMode);
1296
1297 // assign material
1298 if (aMaterial != NULL)
1299 {
1300 Handle(RWGltf_MaterialMetallicRoughness) aMatPbr;
1301 if (myMaterialsPbr.Find (getKeyString (*aMaterial), aMatPbr))
1302 {
1303 theMeshData->SetMaterialPbr (aMatPbr);
1304 }
1305
1306 Handle(RWGltf_MaterialCommon) aMatCommon;
1307 if (myMaterialsCommon.Find (getKeyString (*aMaterial), aMatCommon))
1308 {
1309 theMeshData->SetMaterialCommon (aMatCommon);
1310 }
1311 }
1312
1313 bool hasPositions = false;
1314 for (rapidjson::Value::ConstMemberIterator anAttribIter = anAttribs->MemberBegin();
1315 anAttribIter != anAttribs->MemberEnd(); ++anAttribIter)
1316 {
1317 const TCollection_AsciiString anAttribId = getKeyString (anAttribIter->value);
1318 if (anAttribId.IsEmpty())
1319 {
1320 reportGltfError ("Primitive array attribute accessor key within Mesh '" + theMeshId + "' is not a string.");
1321 return false;
1322 }
1323
1324 RWGltf_GltfArrayType aType = RWGltf_GltfParseAttribType (anAttribIter->name.GetString());
1325 if (aType == RWGltf_GltfArrayType_UNKNOWN)
1326 {
1327 // just ignore unknown attributes
1328 continue;
1329 }
1330
1331 const RWGltf_JsonValue* anAccessor = myGltfRoots[RWGltf_GltfRootElement_Accessors].FindChild (anAttribIter->value);
1332 if (anAccessor == NULL
1333 || !anAccessor->IsObject())
1334 {
1335 reportGltfError ("Primitive array attribute accessor key '" + anAttribId + "' points to non-existing object.");
1336 return false;
1337 }
1338 else if (!gltfParseAccessor (theMeshData, anAttribId, *anAccessor, aType))
1339 {
1340 return false;
1341 }
1342 else if (aType == RWGltf_GltfArrayType_Position)
1343 {
1344 hasPositions = true;
1345 }
1346 }
1347 if (!hasPositions)
1348 {
1349 reportGltfError ("Primitive array within Mesh '" + theMeshId + "' does not define vertex positions.");
1350 return false;
1351 }
1352
1353 if (anIndices != NULL)
1354 {
1355 const TCollection_AsciiString anIndicesId = getKeyString (*anIndices);
1356 const RWGltf_JsonValue* anAccessor = myGltfRoots[RWGltf_GltfRootElement_Accessors].FindChild (*anIndices);
1357 if (anAccessor == NULL
1358 || !anAccessor->IsObject())
1359 {
1360 reportGltfError ("Primitive array indices accessor key '" + anIndicesId + "' points to non-existing object.");
1361 return false;
1362 }
1363 else if (!gltfParseAccessor (theMeshData, anIndicesId, *anAccessor, RWGltf_GltfArrayType_Indices))
1364 {
1365 return false;
1366 }
1367 }
1368
1369 return true;
1370}
1371
1372// =======================================================================
1373// function : gltfParseAccessor
1374// purpose :
1375// =======================================================================
1376bool RWGltf_GltfJsonParser::gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1377 const TCollection_AsciiString& theName,
1378 const RWGltf_JsonValue& theAccessor,
1379 const RWGltf_GltfArrayType theType)
1380{
1381 RWGltf_GltfAccessor aStruct;
1382 const RWGltf_JsonValue* aTypeStr = findObjectMember (theAccessor, "type");
1383 const RWGltf_JsonValue* aBufferViewName = findObjectMember (theAccessor, "bufferView");
1384 const RWGltf_JsonValue* aByteOffset = findObjectMember (theAccessor, "byteOffset");
1385 const RWGltf_JsonValue* aByteStride = findObjectMember (theAccessor, "byteStride");
1386 const RWGltf_JsonValue* aCompType = findObjectMember (theAccessor, "componentType");
1387 const RWGltf_JsonValue* aCount = findObjectMember (theAccessor, "count");
1388 if (aTypeStr == NULL
1389 || !aTypeStr->IsString())
1390 {
1391 reportGltfError ("Accessor '" + theName + "' does not define type.");
1392 return false;
1393 }
1394 aStruct.Type = RWGltf_GltfParseAccessorType (aTypeStr->GetString());
1395 if (aStruct.Type == RWGltf_GltfAccessorLayout_UNKNOWN)
1396 {
1397 reportGltfError ("Accessor '" + theName + "' has invalid type.");
1398 return false;
1399 }
1400
1401 if (aBufferViewName == NULL)
1402 {
1403 reportGltfError ("Accessor '" + theName + "' does not define bufferView.");
1404 return false;
1405 }
1406 if (aCompType == NULL
1407 || !aCompType->IsInt())
1408 {
1409 reportGltfError ("Accessor '" + theName + "' does not define componentType.");
1410 return false;
1411 }
1412 aStruct.ComponentType = (RWGltf_GltfAccessorCompType )aCompType->GetInt();
1413 if (aStruct.ComponentType != RWGltf_GltfAccessorCompType_Int8
1414 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_UInt8
1415 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_Int16
1416 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_UInt16
1417 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_UInt32
1418 && aStruct.ComponentType != RWGltf_GltfAccessorCompType_Float32)
1419 {
1420 reportGltfError ("Accessor '" + theName + "' defines invalid componentType value.");
1421 return false;
1422 }
1423
1424 if (aCount == NULL
1425 || !aCount->IsNumber())
1426 {
1427 reportGltfError ("Accessor '" + theName + "' does not define count.");
1428 return false;
1429 }
1430
1431 aStruct.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
1432 ? (int64_t )aByteOffset->GetDouble()
1433 : 0;
1434 aStruct.ByteStride = aByteStride != NULL && aByteStride->IsInt()
1435 ? aByteStride->GetInt()
1436 : 0;
1437 aStruct.Count = (int64_t )aCount->GetDouble();
1438
1439 if (aStruct.ByteOffset < 0)
1440 {
1441 reportGltfError ("Accessor '" + theName + "' defines invalid byteOffset.");
1442 return false;
1443 }
1444 else if (aStruct.ByteStride < 0
1445 || aStruct.ByteStride > 255)
1446 {
1447 reportGltfError ("Accessor '" + theName + "' defines invalid byteStride.");
1448 return false;
1449 }
1450 else if (aStruct.Count < 1)
1451 {
1452 reportGltfError ("Accessor '" + theName + "' defines invalid count.");
1453 return false;
1454 }
1455
1456 // Read Min/Max values for POSITION type. It is used for bounding boxes
1457 if (theType == RWGltf_GltfArrayType_Position)
1458 {
1459 const RWGltf_JsonValue* aMin = findObjectMember (theAccessor, "min");
1460 const RWGltf_JsonValue* aMax = findObjectMember (theAccessor, "max");
1461 if (aMin != NULL && aMax != NULL)
1462 {
1463 // Note: Min/Max values can be not defined in glTF file.
1464 // In this case it is not used only.
1465 if (!aMin->IsArray() || !aMax->IsArray() ||
1466 aMin->Size() != 3 || aMax->Size() != 3)
1467 {
1468 reportGltfWarning ("Accessor '" + theName + "' defines invalid min/max values.");
1469 }
1470 else
1471 {
1472 bool isValidMinMax = true;
1473 gp_Pnt aMinPnt, aMaxPnt;
1474 for (int anIter = 0; anIter < 3; ++anIter)
1475 {
1476 const RWGltf_JsonValue& aMinVal = (*aMin)[anIter];
1477 const RWGltf_JsonValue& aMaxVal = (*aMax)[anIter];
1478 if (!aMinVal.IsNumber() || !aMaxVal.IsNumber())
1479 {
1480 reportGltfWarning ("Accessor '" + theName + "' defines invalid min/max value.");
1481 isValidMinMax = false;
1482 break;
1483 }
1484 aMinPnt.SetCoord (anIter + 1, aMinVal.GetDouble());
1485 aMinPnt.SetCoord (anIter + 1, aMaxVal.GetDouble());
1486 }
1487 if (isValidMinMax)
1488 {
1489 myCSTrsf.TransformPosition (aMinPnt.ChangeCoord());
1490 myCSTrsf.TransformPosition (aMaxPnt.ChangeCoord());
1491
1492 Bnd_Box aBox;
1493 aBox.Add (aMinPnt);
1494 aBox.Add (aMaxPnt);
1495
1496 theMeshData->SetBoundingBox (aBox);
1497 }
1498 }
1499 }
1500 }
1501
1502 const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
1503 if (aBufferView == NULL
1504 || !aBufferView->IsObject())
1505 {
1506 reportGltfError ("Accessor '" + theName + "' refers to non-existing bufferView.");
1507 return false;
1508 }
1509
1510 return gltfParseBufferView (theMeshData, getKeyString (*aBufferViewName), *aBufferView, aStruct, theType);
1511}
1512
1513// =======================================================================
1514// function : gltfParseBufferView
1515// purpose :
1516// =======================================================================
1517bool RWGltf_GltfJsonParser::gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1518 const TCollection_AsciiString& theName,
1519 const RWGltf_JsonValue& theBufferView,
1520 const RWGltf_GltfAccessor& theAccessor,
1521 const RWGltf_GltfArrayType theType)
1522{
1523 RWGltf_GltfBufferView aBuffView;
1524 const RWGltf_JsonValue* aBufferName = findObjectMember (theBufferView, "buffer");
1525 const RWGltf_JsonValue* aByteLength = findObjectMember (theBufferView, "byteLength");
1526 const RWGltf_JsonValue* aByteOffset = findObjectMember (theBufferView, "byteOffset");
1527 const RWGltf_JsonValue* aTarget = findObjectMember (theBufferView, "target");
1528 if (aBufferName == NULL)
1529 {
1530 reportGltfError ("BufferView '" + theName + "' does not define buffer.");
1531 return false;
1532 }
1533
1534 aBuffView.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
1535 ? (int64_t )aByteOffset->GetDouble()
1536 : 0;
1537 aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
1538 ? (int64_t )aByteLength->GetDouble()
1539 : 0;
1540 if (aTarget != NULL && aTarget->IsInt())
1541 {
1542 aBuffView.Target = (RWGltf_GltfBufferViewTarget )aTarget->GetInt();
1543 if (aBuffView.Target != RWGltf_GltfBufferViewTarget_ARRAY_BUFFER
1544 && aBuffView.Target != RWGltf_GltfBufferViewTarget_ELEMENT_ARRAY_BUFFER)
1545 {
1546 reportGltfError ("BufferView '" + theName + "' defines invalid target.");
1547 return false;
1548 }
1549 }
1550
1551 if (aBuffView.ByteLength < 0)
1552 {
1553 reportGltfError ("BufferView '" + theName + "' defines invalid byteLength.");
1554 return false;
1555 }
1556 else if (aBuffView.ByteOffset < 0)
1557 {
1558 reportGltfError ("BufferView '" + theName + "' defines invalid byteOffset.");
1559 return false;
1560 }
1561
1562 const RWGltf_JsonValue* aBuffer = myGltfRoots[RWGltf_GltfRootElement_Buffers].FindChild (*aBufferName);
1563 if (aBuffer == NULL
1564 || !aBuffer->IsObject())
1565 {
1566 reportGltfError ("BufferView '" + theName + "' refers to non-existing buffer.");
1567 return false;
1568 }
1569
1570 return gltfParseBuffer (theMeshData, getKeyString (*aBufferName), *aBuffer, theAccessor, aBuffView, theType);
1571}
1572
1573// =======================================================================
1574// function : gltfParseBuffer
1575// purpose :
1576// =======================================================================
1577bool RWGltf_GltfJsonParser::gltfParseBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
1578 const TCollection_AsciiString& theName,
1579 const RWGltf_JsonValue& theBuffer,
1580 const RWGltf_GltfAccessor& theAccessor,
1581 const RWGltf_GltfBufferView& theView,
1582 const RWGltf_GltfArrayType theType)
1583{
1584 //const RWGltf_JsonValue* aType = findObjectMember (theBuffer, "type");
1585 //const RWGltf_JsonValue* aByteLength = findObjectMember (theBuffer, "byteLength");
1586 const RWGltf_JsonValue* anUriVal = findObjectMember (theBuffer, "uri");
1587
1588 int64_t anOffset = theView.ByteOffset + theAccessor.ByteOffset;
1589 bool isBinary = false;
1590 if (myIsBinary)
1591 {
1592 isBinary = IsEqual ("binary_glTF", theName) // glTF 1.0
1593 || anUriVal == NULL; // glTF 2.0
1594 }
1595 if (isBinary)
1596 {
1597 anOffset += myBinBodyOffset;
1598
1599 RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
1600 aData.Accessor = theAccessor;
1601 aData.StreamOffset = anOffset;
1602 aData.StreamUri = myFilePath;
1603 return true;
1604 }
1605
1606 if (anUriVal == NULL
1607 || !anUriVal->IsString())
1608 {
1609 reportGltfError ("Buffer '" + theName + "' does not define uri.");
1610 return false;
1611 }
1612
1613 const char* anUriData = anUriVal->GetString();
1614 if (::strncmp (anUriData, "data:application/octet-stream;base64,", 37) == 0)
1615 {
1616 RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
1617 aData.Accessor = theAccessor;
1618 aData.StreamOffset = anOffset;
1619 if (!myDecodedBuffers.Find (theName, aData.StreamData))
1620 {
1621 // it is better decoding in multiple threads
1622 aData.StreamData = FSD_Base64Decoder::Decode ((const Standard_Byte* )anUriData + 37, anUriVal->GetStringLength() - 37);
1623 myDecodedBuffers.Bind (theName, aData.StreamData);
1624 }
1625 return true;
1626 }
1627 else
1628 {
1629 TCollection_AsciiString anUri = anUriData;
1630 if (anUri.IsEmpty())
1631 {
1632 reportGltfError ("Buffer '" + theName + "' does not define uri.");
1633 return false;
1634 }
1635
1636 TCollection_AsciiString aPath = myFolder + anUri;
1637 bool isFileExist = false;
1638 if (!myProbedFiles.Find (aPath, isFileExist))
1639 {
1640 isFileExist = OSD_File (aPath).Exists();
1641 myProbedFiles.Bind (aPath, isFileExist);
1642 }
1643 if (!isFileExist)
1644 {
1645 reportGltfError ("Buffer '" + theName + "' refers to non-existing file '" + anUri + "'.");
1646 return false;
1647 }
1648
1649 RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
1650 aData.Accessor = theAccessor;
1651 aData.StreamOffset = anOffset;
1652 aData.StreamUri = myFolder + anUri;
1653 if (myExternalFiles != NULL)
1654 {
1655 myExternalFiles->Add (aData.StreamUri);
1656 }
1657 return true;
1658 }
1659}
1660
1661// =======================================================================
1662// function : bindNamedShape
1663// purpose :
1664// =======================================================================
1665void RWGltf_GltfJsonParser::bindNamedShape (TopoDS_Shape& theShape,
1666 ShapeMapGroup theGroup,
1667 const TopLoc_Location& theLoc,
1668 const TCollection_AsciiString& theId,
1669 const RWGltf_JsonValue* theUserName)
1670{
1671 if (theShape.IsNull())
1672 {
1673 return;
1674 }
1675
1676 if (!theLoc.IsIdentity())
1677 {
1678 theShape.Location (theLoc);
1679 }
1680
1681 TCollection_AsciiString aUserName;
1682 if (theUserName != NULL
1683 && theUserName->IsString())
1684 {
1685 aUserName = theUserName->GetString();
1686 }
1687 else if (myIsGltf1)
1688 {
1689 aUserName = theId;
1690 }
1691
1692 myShapeMap[theGroup].Bind (theId, theShape);
1693 if (myAttribMap != NULL)
1694 {
1695 RWMesh_NodeAttributes aShapeAttribs;
1696 aShapeAttribs.Name = aUserName;
1697 aShapeAttribs.RawName = theId;
1698 if (theShape.ShapeType() == TopAbs_FACE)
1699 {
1700 TopLoc_Location aDummy;
1701 if (Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (TopoDS::Face (theShape), aDummy)))
1702 {
1703 if (aLateData->HasStyle())
1704 {
a4815d55 1705 // assign material and not color
1706 //aShapeAttribs.Style.SetColorSurf (aLateData->BaseColor());
1707
1708 Handle(XCAFDoc_VisMaterial) aMat;
1709 myMaterials.Find (!aLateData->MaterialPbr().IsNull() ? aLateData->MaterialPbr()->Id : aLateData->MaterialCommon()->Id, aMat);
1710 aShapeAttribs.Style.SetMaterial (aMat);
0a419c51 1711 }
803bdcdf 1712 if (aShapeAttribs.Name.IsEmpty()
1713 && myUseMeshNameAsFallback)
1714 {
1715 // fallback using Mesh name
1716 aShapeAttribs.Name = aLateData->Name();
1717 }
1718 }
1719 }
1720 else if (aShapeAttribs.Name.IsEmpty()
1721 && myUseMeshNameAsFallback)
1722 {
1723 // fallback using Mesh name
1724 TopLoc_Location aDummy;
1725 TCollection_AsciiString aMeshName;
1726 for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
1727 {
1728 if (Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (TopoDS::Face (aFaceIter.Value()), aDummy)))
1729 {
1730 if (aLateData->Name().IsEmpty())
1731 {
1732 aMeshName.Clear();
1733 break;
1734 }
1735 else if (aMeshName.IsEmpty())
1736 {
1737 aMeshName = aLateData->Name();
1738 }
1739 else if (!aMeshName.IsEqual (aLateData->Name()))
1740 {
1741 aMeshName.Clear();
1742 break;
1743 }
1744 }
1745 }
1746 if (!aMeshName.IsEmpty())
1747 {
1748 aShapeAttribs.Name = aMeshName;
0a419c51 1749 }
1750 }
1751 myAttribMap->Bind (theShape, aShapeAttribs);
1752 }
1753}
1754#endif
1755
1756// =======================================================================
1757// function : Parse
1758// purpose :
1759// =======================================================================
1760bool RWGltf_GltfJsonParser::Parse (const Handle(Message_ProgressIndicator)& theProgress)
1761{
1762 Message_ProgressSentry aPSentry (theProgress, "Reading Gltf", 0, 2, 1);
1763#ifdef HAVE_RAPIDJSON
1764 {
1765 if (!gltfParseRoots())
1766 {
1767 return false;
1768 }
1769
1770 gltfParseAsset();
1771 gltfParseMaterials();
1772 if (!gltfParseScene (theProgress))
1773 {
1774 return false;
1775 }
1776 }
1777 aPSentry.Next();
1778 if (!aPSentry.More())
1779 {
1780 return false;
1781 }
1782 return true;
1783#else
01b2f506 1784 Message::DefaultMessenger()->Send ("Error: glTF reader is unavailable - OCCT has been built without RapidJSON support [HAVE_RAPIDJSON undefined].", Message_Fail);
0a419c51 1785 return false;
1786#endif
1787}