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 <NCollection_DataMap.hxx>
21 #include <NCollection_IndexedMap.hxx>
22 #include <RWGltf_GltfLatePrimitiveArray.hxx>
23 #include <RWGltf_GltfBufferView.hxx>
24 #include <RWGltf_GltfRootElement.hxx>
25 #include <RWGltf_MaterialCommon.hxx>
26 #include <RWGltf_MaterialMetallicRoughness.hxx>
27 #include <RWMesh_CoordinateSystemConverter.hxx>
28 #include <RWMesh_NodeAttributes.hxx>
29 #include <TColStd_IndexedDataMapOfStringString.hxx>
30 #include <TopoDS_Face.hxx>
31 #include <TopTools_SequenceOfShape.hxx>
33 // workaround name collisions with XLib
42 //#define RAPIDJSON_ASSERT
43 #include <rapidjson/document.h>
44 #include <rapidjson/prettywriter.h>
45 #include <rapidjson/stringbuffer.h>
46 #include <rapidjson/istreamwrapper.h>
47 #include <rapidjson/ostreamwrapper.h>
49 typedef rapidjson::Document::ValueType RWGltf_JsonValue;
52 class Message_ProgressIndicator;
54 //! INTERNAL tool for parsing glTF document (JSON structure).
55 class RWGltf_GltfJsonParser
57 : public rapidjson::Document
63 //! Auxiliary method for formatting error code.
64 Standard_EXPORT static const char* FormatParseError (rapidjson::ParseErrorCode theCode);
69 //! Empty constructor.
70 Standard_EXPORT RWGltf_GltfJsonParser (TopTools_SequenceOfShape& theRootShapes);
73 Standard_EXPORT void SetFilePath (const TCollection_AsciiString& theFilePath);
75 //! Set flag for probing file without complete reading.
76 void SetProbeHeader (bool theToProbe) { myToProbeHeader = theToProbe; }
78 //! Return prefix for reporting issues.
79 const TCollection_AsciiString& ErrorPrefix() const { return myErrorPrefix; }
81 //! Set prefix for reporting issues.
82 void SetErrorPrefix (const TCollection_AsciiString& theErrPrefix) { myErrorPrefix = theErrPrefix; }
84 //! Set map for storing node attributes.
85 void SetAttributeMap (RWMesh_NodeAttributeMap& theAttribMap) { myAttribMap = &theAttribMap; }
87 //! Set list for storing external files.
88 void SetExternalFiles (NCollection_IndexedMap<TCollection_AsciiString>& theExternalFiles) { myExternalFiles = &theExternalFiles; }
90 //! Return transformation from glTF to OCCT coordinate system.
91 const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCSTrsf; }
93 //! Set transformation from glTF to OCCT coordinate system.
94 void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCSTrsf = theConverter; }
96 //! Initialize binary format.
97 void SetBinaryFormat (int64_t theBinBodyOffset,
98 int64_t theBinBodyLen)
101 myBinBodyOffset = theBinBodyOffset;
102 myBinBodyLen = theBinBodyLen;
105 //! Parse glTF document.
106 Standard_EXPORT bool Parse (const Handle(Message_ProgressIndicator)& theProgress);
108 //! Return metadata map.
109 const TColStd_IndexedDataMapOfStringString& Metadata() const { return myMetadata; }
111 //! Return face list for loading triangulation.
112 NCollection_Vector<TopoDS_Face>& FaceList() { return myFaceList; }
115 #ifdef HAVE_RAPIDJSON
116 //! Search mandatory root elements in the document.
117 //! Return FALSE if some mandatory element is missing.
118 Standard_EXPORT bool gltfParseRoots();
120 //! Parse default scene.
121 Standard_EXPORT bool gltfParseScene (const Handle(Message_ProgressIndicator)& theProgress);
123 //! Parse document metadata.
124 Standard_EXPORT void gltfParseAsset();
128 //! Parse materials defined in the document.
129 Standard_EXPORT void gltfParseMaterials();
131 //! Parse standard material.
132 Standard_EXPORT bool gltfParseStdMaterial (Handle(RWGltf_MaterialCommon)& theMat,
133 const RWGltf_JsonValue& theMatNode);
135 //! Parse pbrMetallicRoughness material.
136 Standard_EXPORT bool gltfParsePbrMaterial (Handle(RWGltf_MaterialMetallicRoughness)& theMat,
137 const RWGltf_JsonValue& theMatNode);
139 //! Parse common material (KHR_materials_common extension).
140 Standard_EXPORT bool gltfParseCommonMaterial (Handle(RWGltf_MaterialCommon)& theMat,
141 const RWGltf_JsonValue& theMatNode);
143 //! Parse texture definition.
144 Standard_EXPORT bool gltfParseTexture (Handle(Image_Texture)& theTexture,
145 const RWGltf_JsonValue* theTextureId);
149 //! Parse scene array of nodes recursively.
150 Standard_EXPORT bool gltfParseSceneNodes (TopTools_SequenceOfShape& theShapeSeq,
151 const RWGltf_JsonValue& theSceneNodes,
152 const Handle(Message_ProgressIndicator)& theProgress);
154 //! Parse scene node recursively.
155 Standard_EXPORT bool gltfParseSceneNode (TopoDS_Shape& theNodeShape,
156 const TCollection_AsciiString& theSceneNodeId,
157 const RWGltf_JsonValue& theSceneNode,
158 const Handle(Message_ProgressIndicator)& theProgress);
160 //! Parse mesh element.
161 Standard_EXPORT bool gltfParseMesh (TopoDS_Shape& theMeshShape,
162 const TCollection_AsciiString& theMeshId,
163 const RWGltf_JsonValue& theMesh,
164 const Handle(Message_ProgressIndicator)& theProgress);
166 //! Parse primitive array.
167 Standard_EXPORT bool gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
168 const TCollection_AsciiString& theMeshName,
169 const RWGltf_JsonValue& thePrimArray,
170 const Handle(Message_ProgressIndicator)& theProgress);
173 Standard_EXPORT bool gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
174 const TCollection_AsciiString& theName,
175 const RWGltf_JsonValue& theAccessor,
176 const RWGltf_GltfArrayType theType);
178 //! Parse buffer view.
179 Standard_EXPORT bool gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
180 const TCollection_AsciiString& theName,
181 const RWGltf_JsonValue& theBufferView,
182 const RWGltf_GltfAccessor& theAccessor,
183 const RWGltf_GltfArrayType theType);
186 Standard_EXPORT bool gltfParseBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
187 const TCollection_AsciiString& theName,
188 const RWGltf_JsonValue& theBuffer,
189 const RWGltf_GltfAccessor& theAccessor,
190 const RWGltf_GltfBufferView& theView,
191 const RWGltf_GltfArrayType theType);
195 //! Read vec4 from specified item.
196 static bool gltfReadVec4 (Graphic3d_Vec4d& theVec4,
197 const RWGltf_JsonValue* theVal)
200 || !theVal->IsArray()
201 || theVal->Size() != 4)
206 for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
208 const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
209 if (!aGenVal.IsNumber())
213 theVec4[aCompIter] = aGenVal.GetDouble();
219 static bool validateColor4 (const Graphic3d_Vec4d& theVec)
221 return theVec.r() >= 0.0 && theVec.r() <= 1.0
222 && theVec.g() >= 0.0 && theVec.g() <= 1.0
223 && theVec.b() >= 0.0 && theVec.b() <= 1.0
224 && theVec.a() >= 0.0 && theVec.a() <= 1.0;
227 //! Read vec3 from specified item.
228 static bool gltfReadVec3 (Graphic3d_Vec3d& theVec3,
229 const RWGltf_JsonValue* theVal)
232 || !theVal->IsArray()
233 || theVal->Size() != 3)
238 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
240 const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
241 if (!aGenVal.IsNumber())
245 theVec3[aCompIter] = aGenVal.GetDouble();
251 static bool validateColor3 (const Graphic3d_Vec3d& theVec)
253 return theVec.r() >= 0.0 && theVec.r() <= 1.0
254 && theVec.g() >= 0.0 && theVec.g() <= 1.0
255 && theVec.b() >= 0.0 && theVec.b() <= 1.0;
260 //! Groups for re-using shapes.
263 ShapeMapGroup_Nodes, //!< nodes
264 ShapeMapGroup_Meshes, //!< meshes
267 //! Bind name attribute.
268 void bindNodeShape (TopoDS_Shape& theShape,
269 const TopLoc_Location& theLoc,
270 const TCollection_AsciiString& theNodeId,
271 const RWGltf_JsonValue* theUserName)
273 bindNamedShape (theShape, ShapeMapGroup_Nodes, theLoc, theNodeId, theUserName);
276 //! Bind name attribute.
277 void bindMeshShape (TopoDS_Shape& theShape,
278 const TCollection_AsciiString& theMeshId,
279 const RWGltf_JsonValue* theUserName)
281 bindNamedShape (theShape, ShapeMapGroup_Meshes, TopLoc_Location(), theMeshId, theUserName);
284 //! Find named shape.
285 bool findNodeShape (TopoDS_Shape& theShape,
286 const TCollection_AsciiString& theNodeId) const
288 return findNamedShape (theShape, ShapeMapGroup_Nodes, theNodeId);
291 //! Find named shape.
292 bool findMeshShape (TopoDS_Shape& theShape,
293 const TCollection_AsciiString& theMeshId) const
295 return findNamedShape (theShape, ShapeMapGroup_Meshes, theMeshId);
298 //! Bind name attribute.
299 Standard_EXPORT void bindNamedShape (TopoDS_Shape& theShape,
300 ShapeMapGroup theGroup,
301 const TopLoc_Location& theLoc,
302 const TCollection_AsciiString& theId,
303 const RWGltf_JsonValue* theUserName);
305 //! Find named shape.
306 bool findNamedShape (TopoDS_Shape& theShape,
307 ShapeMapGroup theGroup,
308 const TCollection_AsciiString& theId) const
310 return myShapeMap[theGroup].Find (theId, theShape);
313 //! Return the string representation of the key.
314 static TCollection_AsciiString getKeyString (const RWGltf_JsonValue& theValue)
316 if (theValue.IsString())
318 return TCollection_AsciiString (theValue.GetString());
320 else if (theValue.IsInt())
322 return TCollection_AsciiString (theValue.GetInt());
324 return TCollection_AsciiString();
329 //! Auxiliary structure for fast look-up of document sub-nodes of specified node.
334 //! Empty constructor.
335 GltfElementMap() : myRoot (NULL) {}
337 //! Return TRUE if this element is NULL.
338 bool IsNull() const { return myRoot == NULL; }
340 //! Access this node.
341 const RWGltf_JsonValue* Root() const { return myRoot; }
343 //! Find the child node with specified key.
344 const RWGltf_JsonValue* FindChild (const TCollection_AsciiString& theKey)
346 const RWGltf_JsonValue* aNode = NULL;
347 return myChildren.Find (theKey, aNode)
352 //! Find the child node with specified key.
353 const RWGltf_JsonValue* FindChild (const RWGltf_JsonValue& theKey)
355 const TCollection_AsciiString aKey = getKeyString (theKey);
361 const RWGltf_JsonValue* aNode = NULL;
362 return myChildren.Find (aKey, aNode)
367 //! Initialize the element.
368 void Init (const TCollection_AsciiString& theRootName,
369 const RWGltf_JsonValue* theRoot);
373 NCollection_DataMap<TCollection_AsciiString, const RWGltf_JsonValue*, TCollection_AsciiString> myChildren;
374 const RWGltf_JsonValue* myRoot;
380 //! Print message about invalid glTF syntax.
381 void reportGltfSyntaxProblem (const TCollection_AsciiString& theMsg, Message_Gravity theGravity);
385 TopTools_SequenceOfShape* myRootShapes; //!< sequence of result root shapes
386 RWMesh_NodeAttributeMap* myAttribMap; //!< shape attributes
387 NCollection_IndexedMap<TCollection_AsciiString>*
388 myExternalFiles; //!< list of external file references
389 RWMesh_CoordinateSystemConverter myCSTrsf; //!< transformation from glTF to OCCT coordinate system
391 TColStd_IndexedDataMapOfStringString myMetadata; //!< file metadata
392 NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialMetallicRoughness)> myMaterialsPbr;
393 NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialCommon)> myMaterialsCommon;
394 NCollection_DataMap<TCollection_AsciiString, TopoDS_Shape> myShapeMap[2];
396 NCollection_DataMap<TCollection_AsciiString, bool> myProbedFiles;
397 NCollection_DataMap<TCollection_AsciiString, Handle(NCollection_Buffer)> myDecodedBuffers;
398 NCollection_Vector<TopoDS_Face> myFaceList; //!< face list for loading triangulation
400 TCollection_AsciiString myFilePath; //!< file path
401 TCollection_AsciiString myFolder; //!< folder
402 TCollection_AsciiString myErrorPrefix; //!< invalid syntax error prefix
403 int64_t myBinBodyOffset; //!< offset to binary body
404 int64_t myBinBodyLen; //!< binary body length
405 bool myIsBinary; //!< binary document
406 bool myIsGltf1; //!< obsolete glTF 1.0 version format
407 bool myToSkipEmptyNodes; //!< ignore nodes without Geometry
408 bool myToProbeHeader; //!< flag to probe header without full reading, FALSE by default
410 #ifdef HAVE_RAPIDJSON
411 GltfElementMap myGltfRoots[RWGltf_GltfRootElement_NB]; //!< glTF format root elements
416 #endif // _RWGltf_GltfJsonParser_HeaderFile