1 // Author: Kirill Gavrilov
2 // Copyright (c) 2016-2019 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #ifndef _RWGltf_GltfJsonParser_HeaderFile
16 #define _RWGltf_GltfJsonParser_HeaderFile
18 #include <Graphic3d_Vec.hxx>
19 #include <Message_Gravity.hxx>
20 #include <Message_ProgressScope.hxx>
21 #include <NCollection_DataMap.hxx>
22 #include <NCollection_IndexedMap.hxx>
23 #include <RWGltf_GltfAccessor.hxx>
24 #include <RWGltf_GltfPrimArrayData.hxx>
25 #include <RWGltf_GltfLatePrimitiveArray.hxx>
26 #include <RWGltf_GltfBufferView.hxx>
27 #include <RWGltf_GltfRootElement.hxx>
28 #include <RWGltf_MaterialCommon.hxx>
29 #include <RWGltf_MaterialMetallicRoughness.hxx>
30 #include <RWMesh_CoordinateSystemConverter.hxx>
31 #include <RWMesh_NodeAttributes.hxx>
32 #include <TColStd_IndexedDataMapOfStringString.hxx>
33 #include <TopoDS_Face.hxx>
34 #include <TopTools_SequenceOfShape.hxx>
36 // workaround name collisions with XLib
45 //#define RAPIDJSON_ASSERT
46 #include <rapidjson/document.h>
47 #include <rapidjson/prettywriter.h>
48 #include <rapidjson/stringbuffer.h>
49 #include <rapidjson/istreamwrapper.h>
50 #include <rapidjson/ostreamwrapper.h>
52 typedef rapidjson::Document::ValueType RWGltf_JsonValue;
55 class Message_ProgressIndicator;
57 //! INTERNAL tool for parsing glTF document (JSON structure).
58 class RWGltf_GltfJsonParser
60 : public rapidjson::Document
66 //! Auxiliary method for formatting error code.
67 Standard_EXPORT static const char* FormatParseError (rapidjson::ParseErrorCode theCode);
72 //! Empty constructor.
73 Standard_EXPORT RWGltf_GltfJsonParser (TopTools_SequenceOfShape& theRootShapes);
76 Standard_EXPORT void SetFilePath (const TCollection_AsciiString& theFilePath);
78 //! Set flag for probing file without complete reading.
79 void SetProbeHeader (bool theToProbe) { myToProbeHeader = theToProbe; }
81 //! Return prefix for reporting issues.
82 const TCollection_AsciiString& ErrorPrefix() const { return myErrorPrefix; }
84 //! Set prefix for reporting issues.
85 void SetErrorPrefix (const TCollection_AsciiString& theErrPrefix) { myErrorPrefix = theErrPrefix; }
87 //! Set map for storing node attributes.
88 void SetAttributeMap (RWMesh_NodeAttributeMap& theAttribMap) { myAttribMap = &theAttribMap; }
90 //! Set list for storing external files.
91 void SetExternalFiles (NCollection_IndexedMap<TCollection_AsciiString>& theExternalFiles) { myExternalFiles = &theExternalFiles; }
94 void SetMetadata (TColStd_IndexedDataMapOfStringString& theMetadata) { myMetadata = &theMetadata; }
96 //! Return transformation from glTF to OCCT coordinate system.
97 const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCSTrsf; }
99 //! Set transformation from glTF to OCCT coordinate system.
100 void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCSTrsf = theConverter; }
102 //! Initialize binary format.
103 void SetBinaryFormat (int64_t theBinBodyOffset,
104 int64_t theBinBodyLen)
107 myBinBodyOffset = theBinBodyOffset;
108 myBinBodyLen = theBinBodyLen;
111 //! Set flag to ignore nodes without Geometry, TRUE by default.
112 void SetSkipEmptyNodes (bool theToSkip) { myToSkipEmptyNodes = theToSkip; }
114 //! Set flag to use Mesh name in case if Node name is empty, TRUE by default.
115 void SetMeshNameAsFallback (bool theToFallback) { myUseMeshNameAsFallback = theToFallback; }
117 //! Parse glTF document.
118 Standard_EXPORT bool Parse (const Message_ProgressRange& theProgress);
120 //! Return face list for loading triangulation.
121 NCollection_Vector<TopoDS_Face>& FaceList() { return myFaceList; }
124 #ifdef HAVE_RAPIDJSON
125 //! Search mandatory root elements in the document.
126 //! Return FALSE if some mandatory element is missing.
127 Standard_EXPORT bool gltfParseRoots();
129 //! Parse default scene.
130 Standard_EXPORT bool gltfParseScene (const Message_ProgressRange& theProgress);
132 //! Parse document metadata.
133 Standard_EXPORT void gltfParseAsset();
137 //! Parse materials defined in the document.
138 Standard_EXPORT void gltfParseMaterials();
140 //! Parse standard material.
141 Standard_EXPORT bool gltfParseStdMaterial (Handle(RWGltf_MaterialCommon)& theMat,
142 const RWGltf_JsonValue& theMatNode);
144 //! Parse pbrMetallicRoughness material.
145 Standard_EXPORT bool gltfParsePbrMaterial (Handle(RWGltf_MaterialMetallicRoughness)& theMat,
146 const RWGltf_JsonValue& theMatNode);
148 //! Parse common material (KHR_materials_common extension).
149 Standard_EXPORT bool gltfParseCommonMaterial (Handle(RWGltf_MaterialCommon)& theMat,
150 const RWGltf_JsonValue& theMatNode);
152 //! Parse texture definition.
153 Standard_EXPORT bool gltfParseTexture (Handle(Image_Texture)& theTexture,
154 const RWGltf_JsonValue* theTextureId);
156 //! Parse texture definition in binary buffer of GLB file.
157 Standard_EXPORT bool gltfParseTexturInGlbBuffer (Handle(Image_Texture)& theTexture,
158 const RWGltf_JsonValue& theBinVal,
159 const TCollection_AsciiString& theBufferViewId,
160 const RWGltf_JsonValue& theBufferViewName);
162 //! Parse texture definition in binary buffer of glTF file.
163 Standard_EXPORT bool gltfParseTextureInBufferView (Handle(Image_Texture)& theTexture,
164 const TCollection_AsciiString& theSourceId,
165 const TCollection_AsciiString& theBufferViewhId,
166 const RWGltf_JsonValue& theBufferView);
168 //! Bind material definition to the map.
169 Standard_EXPORT void gltfBindMaterial (const Handle(RWGltf_MaterialMetallicRoughness)& theMatPbr,
170 const Handle(RWGltf_MaterialCommon)& theMatCommon);
174 //! Parse scene array of nodes recursively.
175 Standard_EXPORT bool gltfParseSceneNodes (TopTools_SequenceOfShape& theShapeSeq,
176 const RWGltf_JsonValue& theSceneNodes,
177 const Message_ProgressRange& theProgress);
179 //! Parse scene node recursively.
180 Standard_EXPORT bool gltfParseSceneNode (TopoDS_Shape& theNodeShape,
181 const TCollection_AsciiString& theSceneNodeId,
182 const RWGltf_JsonValue& theSceneNode,
183 const Message_ProgressRange& theProgress);
185 //! Parse mesh element.
186 Standard_EXPORT bool gltfParseMesh (TopoDS_Shape& theMeshShape,
187 const TCollection_AsciiString& theMeshId,
188 const RWGltf_JsonValue& theMesh);
190 //! Parse primitive array.
191 Standard_EXPORT bool gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
192 const TCollection_AsciiString& theMeshName,
193 const RWGltf_JsonValue& thePrimArray);
196 Standard_EXPORT bool gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
197 const TCollection_AsciiString& theName,
198 const RWGltf_JsonValue& theAccessor,
199 const RWGltf_GltfArrayType theType,
200 const RWGltf_JsonValue* theCompBuffView);
202 //! Parse buffer view.
203 Standard_EXPORT bool gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
204 const TCollection_AsciiString& theName,
205 const RWGltf_JsonValue& theBufferView,
206 const RWGltf_GltfAccessor& theAccessor,
207 const RWGltf_GltfArrayType theType);
210 Standard_EXPORT bool gltfParseBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
211 const TCollection_AsciiString& theName,
212 const RWGltf_JsonValue& theBuffer,
213 const RWGltf_GltfAccessor& theAccessor,
214 const RWGltf_GltfBufferView& theView,
215 const RWGltf_GltfArrayType theType);
219 //! Read vec4 from specified item.
220 static bool gltfReadVec4 (Graphic3d_Vec4d& theVec4,
221 const RWGltf_JsonValue* theVal)
224 || !theVal->IsArray()
225 || theVal->Size() != 4)
230 for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
232 const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
233 if (!aGenVal.IsNumber())
237 theVec4[aCompIter] = aGenVal.GetDouble();
243 static bool validateColor4 (const Graphic3d_Vec4d& theVec)
245 return theVec.r() >= 0.0 && theVec.r() <= 1.0
246 && theVec.g() >= 0.0 && theVec.g() <= 1.0
247 && theVec.b() >= 0.0 && theVec.b() <= 1.0
248 && theVec.a() >= 0.0 && theVec.a() <= 1.0;
251 //! Read vec3 from specified item.
252 static bool gltfReadVec3 (Graphic3d_Vec3d& theVec3,
253 const RWGltf_JsonValue* theVal)
256 || !theVal->IsArray()
257 || theVal->Size() != 3)
262 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
264 const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
265 if (!aGenVal.IsNumber())
269 theVec3[aCompIter] = aGenVal.GetDouble();
275 static bool validateColor3 (const Graphic3d_Vec3d& theVec)
277 return theVec.r() >= 0.0 && theVec.r() <= 1.0
278 && theVec.g() >= 0.0 && theVec.g() <= 1.0
279 && theVec.b() >= 0.0 && theVec.b() <= 1.0;
284 //! Groups for re-using shapes.
287 ShapeMapGroup_Nodes, //!< nodes
288 ShapeMapGroup_Meshes, //!< meshes
291 //! Bind name attribute.
292 void bindNodeShape (TopoDS_Shape& theShape,
293 const TopLoc_Location& theLoc,
294 const TCollection_AsciiString& theNodeId,
295 const RWGltf_JsonValue* theUserName)
297 bindNamedShape (theShape, ShapeMapGroup_Nodes, theLoc, theNodeId, theUserName);
300 //! Bind name attribute.
301 void bindMeshShape (TopoDS_Shape& theShape,
302 const TCollection_AsciiString& theMeshId,
303 const RWGltf_JsonValue* theUserName)
305 bindNamedShape (theShape, ShapeMapGroup_Meshes, TopLoc_Location(), theMeshId, theUserName);
308 //! Find named shape.
309 bool findNodeShape (TopoDS_Shape& theShape,
310 const TCollection_AsciiString& theNodeId) const
312 return findNamedShape (theShape, ShapeMapGroup_Nodes, theNodeId);
315 //! Find named shape.
316 bool findMeshShape (TopoDS_Shape& theShape,
317 const TCollection_AsciiString& theMeshId) const
319 return findNamedShape (theShape, ShapeMapGroup_Meshes, theMeshId);
322 //! Bind name attribute.
323 Standard_EXPORT void bindNamedShape (TopoDS_Shape& theShape,
324 ShapeMapGroup theGroup,
325 const TopLoc_Location& theLoc,
326 const TCollection_AsciiString& theId,
327 const RWGltf_JsonValue* theUserName);
329 //! Find named shape.
330 bool findNamedShape (TopoDS_Shape& theShape,
331 ShapeMapGroup theGroup,
332 const TCollection_AsciiString& theId) const
334 return myShapeMap[theGroup].Find (theId, theShape);
337 //! Return the string representation of the key.
338 static TCollection_AsciiString getKeyString (const RWGltf_JsonValue& theValue)
340 if (theValue.IsString())
342 return TCollection_AsciiString (theValue.GetString());
344 else if (theValue.IsInt())
346 return TCollection_AsciiString (theValue.GetInt());
348 return TCollection_AsciiString();
353 //! Auxiliary structure for fast look-up of document sub-nodes of specified node.
358 //! Empty constructor.
359 GltfElementMap() : myRoot (NULL) {}
361 //! Return TRUE if this element is NULL.
362 bool IsNull() const { return myRoot == NULL; }
364 //! Access this node.
365 const RWGltf_JsonValue* Root() const { return myRoot; }
367 //! Find the child node with specified key.
368 const RWGltf_JsonValue* FindChild (const TCollection_AsciiString& theKey)
370 const RWGltf_JsonValue* aNode = NULL;
371 return myChildren.Find (theKey, aNode)
376 //! Find the child node with specified key.
377 const RWGltf_JsonValue* FindChild (const RWGltf_JsonValue& theKey)
379 const TCollection_AsciiString aKey = getKeyString (theKey);
385 const RWGltf_JsonValue* aNode = NULL;
386 return myChildren.Find (aKey, aNode)
391 //! Initialize the element.
392 void Init (const TCollection_AsciiString& theRootName,
393 const RWGltf_JsonValue* theRoot);
397 NCollection_DataMap<TCollection_AsciiString, const RWGltf_JsonValue*, TCollection_AsciiString> myChildren;
398 const RWGltf_JsonValue* myRoot;
404 //! Print message about invalid glTF syntax.
405 void reportGltfSyntaxProblem (const TCollection_AsciiString& theMsg, Message_Gravity theGravity);
409 TopTools_SequenceOfShape* myRootShapes; //!< sequence of result root shapes
410 RWMesh_NodeAttributeMap* myAttribMap; //!< shape attributes
411 NCollection_IndexedMap<TCollection_AsciiString>*
412 myExternalFiles; //!< list of external file references
413 RWMesh_CoordinateSystemConverter myCSTrsf; //!< transformation from glTF to OCCT coordinate system
414 TColStd_IndexedDataMapOfStringString* myMetadata; //!< file metadata
416 NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialMetallicRoughness)> myMaterialsPbr;
417 NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialCommon)> myMaterialsCommon;
418 NCollection_DataMap<TCollection_AsciiString, Handle(XCAFDoc_VisMaterial)> myMaterials;
419 NCollection_DataMap<TCollection_AsciiString, TopoDS_Shape> myShapeMap[2];
421 NCollection_DataMap<TCollection_AsciiString, bool> myProbedFiles;
422 NCollection_DataMap<TCollection_AsciiString, Handle(NCollection_Buffer)> myDecodedBuffers;
423 NCollection_Vector<TopoDS_Face> myFaceList; //!< face list for loading triangulation
425 TCollection_AsciiString myFilePath; //!< file path
426 TCollection_AsciiString myFolder; //!< folder
427 TCollection_AsciiString myErrorPrefix; //!< invalid syntax error prefix
428 int64_t myBinBodyOffset; //!< offset to binary body
429 int64_t myBinBodyLen; //!< binary body length
430 bool myIsBinary; //!< binary document
431 bool myIsGltf1; //!< obsolete glTF 1.0 version format
432 bool myToSkipEmptyNodes; //!< ignore nodes without Geometry
433 bool myUseMeshNameAsFallback; //!< flag to use Mesh name in case if Node name is empty, TRUE by default
434 bool myToProbeHeader; //!< flag to probe header without full reading, FALSE by default
436 #ifdef HAVE_RAPIDJSON
437 GltfElementMap myGltfRoots[RWGltf_GltfRootElement_NB]; //!< glTF format root elements
442 #endif // _RWGltf_GltfJsonParser_HeaderFile