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 |
35 | namespace |
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. |
43 | inline 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. |
59 | inline 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 | // ======================================================================= |
77 | const 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 | // ======================================================================= |
107 | void 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 | // ======================================================================= |
155 | void 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 | // ======================================================================= |
165 | RWGltf_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 | // ======================================================================= |
185 | void 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 | // ======================================================================= |
198 | bool 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 | // ======================================================================= |
237 | void 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 | // ======================================================================= |
279 | void 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 | // ======================================================================= |
356 | void 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 | // ======================================================================= |
442 | bool 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 | // ======================================================================= |
525 | bool 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 | // ======================================================================= |
650 | bool 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 | // ======================================================================= |
676 | bool 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 | // ======================================================================= |
833 | bool 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 | // ======================================================================= |
858 | bool 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 | // ======================================================================= |
904 | bool 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 | // ======================================================================= |
1175 | bool 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 | // ======================================================================= |
1258 | bool 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 | // ======================================================================= |
1375 | bool 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 | // ======================================================================= |
1516 | bool 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 | // ======================================================================= |
1576 | bool 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 | // ======================================================================= |
1664 | void 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 | // ======================================================================= |
1759 | bool 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 | } |