0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / RWGltf / RWGltf_GltfJsonParser.pxx
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 #ifndef _RWGltf_GltfJsonParser_HeaderFile
16 #define _RWGltf_GltfJsonParser_HeaderFile
17
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_GltfLatePrimitiveArray.hxx>
24 #include <RWGltf_GltfBufferView.hxx>
25 #include <RWGltf_GltfRootElement.hxx>
26 #include <RWGltf_MaterialCommon.hxx>
27 #include <RWGltf_MaterialMetallicRoughness.hxx>
28 #include <RWMesh_CoordinateSystemConverter.hxx>
29 #include <RWMesh_NodeAttributes.hxx>
30 #include <TColStd_IndexedDataMapOfStringString.hxx>
31 #include <TopoDS_Face.hxx>
32 #include <TopTools_SequenceOfShape.hxx>
33
34 // workaround name collisions with XLib
35 #ifdef None
36   #undef None
37 #endif
38 #ifdef Bool
39   #undef Bool
40 #endif
41
42 #ifdef HAVE_RAPIDJSON
43   //#define RAPIDJSON_ASSERT
44   #include <rapidjson/document.h>
45   #include <rapidjson/prettywriter.h>
46   #include <rapidjson/stringbuffer.h>
47   #include <rapidjson/istreamwrapper.h>
48   #include <rapidjson/ostreamwrapper.h>
49
50   typedef rapidjson::Document::ValueType RWGltf_JsonValue;
51 #endif
52
53 class Message_ProgressIndicator;
54
55 //! INTERNAL tool for parsing glTF document (JSON structure).
56 class RWGltf_GltfJsonParser
57 #ifdef HAVE_RAPIDJSON
58 : public rapidjson::Document
59 #endif
60 {
61 public:
62
63 #ifdef HAVE_RAPIDJSON
64   //! Auxiliary method for formatting error code.
65   Standard_EXPORT static const char* FormatParseError (rapidjson::ParseErrorCode theCode);
66 #endif
67
68 public:
69
70   //! Empty constructor.
71   Standard_EXPORT RWGltf_GltfJsonParser (TopTools_SequenceOfShape& theRootShapes);
72
73   //! Set file path.
74   Standard_EXPORT void SetFilePath (const TCollection_AsciiString& theFilePath);
75
76   //! Set flag for probing file without complete reading.
77   void SetProbeHeader (bool theToProbe) { myToProbeHeader = theToProbe; }
78
79   //! Return prefix for reporting issues.
80   const TCollection_AsciiString& ErrorPrefix() const { return myErrorPrefix; }
81
82   //! Set prefix for reporting issues.
83   void SetErrorPrefix (const TCollection_AsciiString& theErrPrefix) { myErrorPrefix = theErrPrefix; }
84
85   //! Set map for storing node attributes.
86   void SetAttributeMap (RWMesh_NodeAttributeMap& theAttribMap) { myAttribMap = &theAttribMap; }
87
88   //! Set list for storing external files.
89   void SetExternalFiles (NCollection_IndexedMap<TCollection_AsciiString>& theExternalFiles) { myExternalFiles = &theExternalFiles; }
90
91   //! Set metadata map.
92   void SetMetadata (TColStd_IndexedDataMapOfStringString& theMetadata) { myMetadata = &theMetadata; }
93
94   //! Return transformation from glTF to OCCT coordinate system.
95   const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCSTrsf; }
96
97   //! Set transformation from glTF to OCCT coordinate system.
98   void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCSTrsf = theConverter; }
99
100   //! Initialize binary format.
101   void SetBinaryFormat (int64_t theBinBodyOffset,
102                         int64_t theBinBodyLen)
103   {
104     myIsBinary      = true;
105     myBinBodyOffset = theBinBodyOffset;
106     myBinBodyLen    = theBinBodyLen;
107   }
108
109   //! Set flag to ignore nodes without Geometry, TRUE by default.
110   void SetSkipEmptyNodes (bool theToSkip) { myToSkipEmptyNodes = theToSkip; }
111
112   //! Set flag to use Mesh name in case if Node name is empty, TRUE by default.
113   void SetMeshNameAsFallback (bool theToFallback) { myUseMeshNameAsFallback = theToFallback; }
114
115   //! Parse glTF document.
116   Standard_EXPORT bool Parse (const Message_ProgressRange& theProgress);
117
118   //! Return face list for loading triangulation.
119   NCollection_Vector<TopoDS_Face>& FaceList() { return myFaceList; }
120
121 protected:
122 #ifdef HAVE_RAPIDJSON
123   //! Search mandatory root elements in the document.
124   //! Return FALSE if some mandatory element is missing.
125   Standard_EXPORT bool gltfParseRoots();
126
127   //! Parse default scene.
128   Standard_EXPORT bool gltfParseScene (const Message_ProgressRange& theProgress);
129
130   //! Parse document metadata.
131   Standard_EXPORT void gltfParseAsset();
132
133 protected:
134
135   //! Parse materials defined in the document.
136   Standard_EXPORT void gltfParseMaterials();
137
138   //! Parse standard material.
139   Standard_EXPORT bool gltfParseStdMaterial (Handle(RWGltf_MaterialCommon)& theMat,
140                                              const RWGltf_JsonValue& theMatNode);
141
142   //! Parse pbrMetallicRoughness material.
143   Standard_EXPORT bool gltfParsePbrMaterial (Handle(RWGltf_MaterialMetallicRoughness)& theMat,
144                                              const RWGltf_JsonValue& theMatNode);
145
146   //! Parse common material (KHR_materials_common extension).
147   Standard_EXPORT bool gltfParseCommonMaterial (Handle(RWGltf_MaterialCommon)& theMat,
148                                                 const RWGltf_JsonValue& theMatNode);
149
150   //! Parse texture definition.
151   Standard_EXPORT bool gltfParseTexture (Handle(Image_Texture)& theTexture,
152                                          const RWGltf_JsonValue* theTextureId);
153
154   //! Parse texture definition in binary buffer of GLB file.
155   Standard_EXPORT bool gltfParseTexturInGlbBuffer (Handle(Image_Texture)& theTexture,
156                                                    const RWGltf_JsonValue& theBinVal,
157                                                    const TCollection_AsciiString& theBufferViewId,
158                                                    const RWGltf_JsonValue& theBufferViewName);
159
160   //! Parse texture definition in binary buffer of glTF file.
161   Standard_EXPORT bool gltfParseTextureInBufferView (Handle(Image_Texture)& theTexture,
162                                                      const TCollection_AsciiString& theSourceId,
163                                                      const TCollection_AsciiString& theBufferViewhId,
164                                                      const RWGltf_JsonValue& theBufferView);
165
166   //! Bind material definition to the map.
167   Standard_EXPORT void gltfBindMaterial (const Handle(RWGltf_MaterialMetallicRoughness)& theMatPbr,
168                                          const Handle(RWGltf_MaterialCommon)& theMatCommon);
169
170 protected:
171
172   //! Parse scene array of nodes recursively.
173   Standard_EXPORT bool gltfParseSceneNodes (TopTools_SequenceOfShape& theShapeSeq,
174                                             const RWGltf_JsonValue& theSceneNodes,
175                                             const Message_ProgressRange& theProgress);
176
177   //! Parse scene node recursively.
178   Standard_EXPORT bool gltfParseSceneNode (TopoDS_Shape& theNodeShape,
179                                            const TCollection_AsciiString& theSceneNodeId,
180                                            const RWGltf_JsonValue& theSceneNode,
181                                            const Message_ProgressRange& theProgress);
182
183   //! Parse mesh element.
184   Standard_EXPORT bool gltfParseMesh (TopoDS_Shape& theMeshShape,
185                                       const TCollection_AsciiString& theMeshId,
186                                       const RWGltf_JsonValue& theMesh);
187
188   //! Parse primitive array.
189   Standard_EXPORT bool gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
190                                            const TCollection_AsciiString& theMeshName,
191                                            const RWGltf_JsonValue& thePrimArray);
192
193   //! Parse accessor.
194   Standard_EXPORT bool gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
195                                           const TCollection_AsciiString& theName,
196                                           const RWGltf_JsonValue& theAccessor,
197                                           const RWGltf_GltfArrayType theType);
198
199   //! Parse buffer view.
200   Standard_EXPORT bool gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
201                                             const TCollection_AsciiString& theName,
202                                             const RWGltf_JsonValue& theBufferView,
203                                             const RWGltf_GltfAccessor& theAccessor,
204                                             const RWGltf_GltfArrayType theType);
205
206   //! Parse buffer.
207   Standard_EXPORT bool gltfParseBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
208                                         const TCollection_AsciiString& theName,
209                                         const RWGltf_JsonValue& theBuffer,
210                                         const RWGltf_GltfAccessor&   theAccessor,
211                                         const RWGltf_GltfBufferView& theView,
212                                         const RWGltf_GltfArrayType   theType);
213
214 protected:
215
216   //! Read vec4 from specified item.
217   static bool gltfReadVec4 (Graphic3d_Vec4d& theVec4,
218                             const RWGltf_JsonValue* theVal)
219   {
220     if (theVal == NULL
221     || !theVal->IsArray()
222     ||  theVal->Size() != 4)
223     {
224       return false;
225     }
226
227     for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
228     {
229       const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
230       if (!aGenVal.IsNumber())
231       {
232         return false;
233       }
234       theVec4[aCompIter] = aGenVal.GetDouble();
235     }
236     return true;
237   }
238
239   //! Validate color
240   static bool validateColor4 (const Graphic3d_Vec4d& theVec)
241   {
242     return theVec.r() >= 0.0 && theVec.r() <= 1.0
243         && theVec.g() >= 0.0 && theVec.g() <= 1.0
244         && theVec.b() >= 0.0 && theVec.b() <= 1.0
245         && theVec.a() >= 0.0 && theVec.a() <= 1.0;
246   }
247
248   //! Read vec3 from specified item.
249   static bool gltfReadVec3 (Graphic3d_Vec3d& theVec3,
250                             const RWGltf_JsonValue* theVal)
251   {
252     if (theVal == NULL
253     || !theVal->IsArray()
254     ||  theVal->Size() != 3)
255     {
256       return false;
257     }
258
259     for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
260     {
261       const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
262       if (!aGenVal.IsNumber())
263       {
264         return false;
265       }
266       theVec3[aCompIter] = aGenVal.GetDouble();
267     }
268     return true;
269   }
270
271   //! Validate color
272   static bool validateColor3 (const Graphic3d_Vec3d& theVec)
273   {
274     return theVec.r() >= 0.0 && theVec.r() <= 1.0
275         && theVec.g() >= 0.0 && theVec.g() <= 1.0
276         && theVec.b() >= 0.0 && theVec.b() <= 1.0;
277   }
278
279 protected:
280
281   //! Groups for re-using shapes.
282   enum ShapeMapGroup
283   {
284     ShapeMapGroup_Nodes,  //!< nodes
285     ShapeMapGroup_Meshes, //!< meshes
286   };
287
288   //! Bind name attribute.
289   void bindNodeShape (TopoDS_Shape& theShape,
290                       const TopLoc_Location& theLoc,
291                       const TCollection_AsciiString& theNodeId,
292                       const RWGltf_JsonValue* theUserName)
293   {
294     bindNamedShape (theShape, ShapeMapGroup_Nodes, theLoc, theNodeId, theUserName);
295   }
296
297   //! Bind name attribute.
298   void bindMeshShape (TopoDS_Shape& theShape,
299                       const TCollection_AsciiString& theMeshId,
300                       const RWGltf_JsonValue* theUserName)
301   {
302     bindNamedShape (theShape, ShapeMapGroup_Meshes, TopLoc_Location(), theMeshId, theUserName);
303   }
304
305   //! Find named shape.
306   bool findNodeShape (TopoDS_Shape& theShape,
307                       const TCollection_AsciiString& theNodeId) const
308   {
309     return findNamedShape (theShape, ShapeMapGroup_Nodes, theNodeId);
310   }
311
312   //! Find named shape.
313   bool findMeshShape (TopoDS_Shape& theShape,
314                       const TCollection_AsciiString& theMeshId) const
315   {
316     return findNamedShape (theShape, ShapeMapGroup_Meshes, theMeshId);
317   }
318
319   //! Bind name attribute.
320   Standard_EXPORT void bindNamedShape (TopoDS_Shape& theShape,
321                                        ShapeMapGroup theGroup,
322                                        const TopLoc_Location& theLoc,
323                                        const TCollection_AsciiString& theId,
324                                        const RWGltf_JsonValue* theUserName);
325
326   //! Find named shape.
327   bool findNamedShape (TopoDS_Shape& theShape,
328                        ShapeMapGroup theGroup,
329                        const TCollection_AsciiString& theId) const
330   {
331     return myShapeMap[theGroup].Find (theId, theShape);
332   }
333
334   //! Return the string representation of the key.
335   static TCollection_AsciiString getKeyString (const RWGltf_JsonValue& theValue)
336   {
337     if (theValue.IsString())
338     {
339       return TCollection_AsciiString (theValue.GetString());
340     }
341     else if (theValue.IsInt())
342     {
343       return TCollection_AsciiString (theValue.GetInt());
344     }
345     return TCollection_AsciiString();
346   }
347
348 protected:
349
350   //! Auxiliary structure for fast look-up of document sub-nodes of specified node.
351   class GltfElementMap
352   {
353   public:
354
355     //! Empty constructor.
356     GltfElementMap() : myRoot (NULL) {}
357
358     //! Return TRUE if this element is NULL.
359     bool IsNull() const { return myRoot == NULL; }
360
361     //! Access this node.
362     const RWGltf_JsonValue* Root() const { return myRoot; }
363
364     //! Find the child node with specified key.
365     const RWGltf_JsonValue* FindChild (const TCollection_AsciiString& theKey)
366     {
367       const RWGltf_JsonValue* aNode = NULL;
368       return myChildren.Find (theKey, aNode)
369            ? aNode
370            : NULL;
371     }
372
373     //! Find the child node with specified key.
374     const RWGltf_JsonValue* FindChild (const RWGltf_JsonValue& theKey)
375     {
376       const TCollection_AsciiString aKey = getKeyString (theKey);
377       if (aKey.IsEmpty())
378       {
379         return NULL;
380       }
381
382       const RWGltf_JsonValue* aNode = NULL;
383       return myChildren.Find (aKey, aNode)
384            ? aNode
385            : NULL;
386     }
387
388     //! Initialize the element.
389     void Init (const TCollection_AsciiString& theRootName,
390                const RWGltf_JsonValue* theRoot);
391
392   private:
393
394     NCollection_DataMap<TCollection_AsciiString, const RWGltf_JsonValue*, TCollection_AsciiString> myChildren;
395     const RWGltf_JsonValue* myRoot;
396
397   };
398 #endif
399 protected:
400
401   //! Print message about invalid glTF syntax.
402   void reportGltfSyntaxProblem (const TCollection_AsciiString& theMsg, Message_Gravity theGravity);
403
404 protected:
405
406   TopTools_SequenceOfShape*        myRootShapes;    //!< sequence of result root shapes
407   RWMesh_NodeAttributeMap*         myAttribMap;     //!< shape attributes
408   NCollection_IndexedMap<TCollection_AsciiString>*
409                                    myExternalFiles; //!< list of external file references
410   RWMesh_CoordinateSystemConverter myCSTrsf;        //!< transformation from glTF to OCCT coordinate system
411   TColStd_IndexedDataMapOfStringString* myMetadata; //!< file metadata
412
413   NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialMetallicRoughness)> myMaterialsPbr;
414   NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialCommon)> myMaterialsCommon;
415   NCollection_DataMap<TCollection_AsciiString, Handle(XCAFDoc_VisMaterial)> myMaterials;
416   NCollection_DataMap<TCollection_AsciiString, TopoDS_Shape> myShapeMap[2];
417
418   NCollection_DataMap<TCollection_AsciiString, bool> myProbedFiles;
419   NCollection_DataMap<TCollection_AsciiString, Handle(NCollection_Buffer)> myDecodedBuffers;
420   NCollection_Vector<TopoDS_Face> myFaceList; //!< face list for loading triangulation
421
422   TCollection_AsciiString   myFilePath;       //!< file path
423   TCollection_AsciiString   myFolder;         //!< folder
424   TCollection_AsciiString   myErrorPrefix;    //!< invalid syntax error prefix
425   int64_t                   myBinBodyOffset;  //!< offset to binary body
426   int64_t                   myBinBodyLen;     //!< binary body length
427   bool                      myIsBinary;       //!< binary document
428   bool                      myIsGltf1;        //!< obsolete glTF 1.0 version format
429   bool                      myToSkipEmptyNodes; //!< ignore nodes without Geometry
430   bool                      myUseMeshNameAsFallback; //!< flag to use Mesh name in case if Node name is empty, TRUE by default
431   bool                      myToProbeHeader;  //!< flag to probe header without full reading, FALSE by default
432
433 #ifdef HAVE_RAPIDJSON
434   GltfElementMap myGltfRoots[RWGltf_GltfRootElement_NB]; //!< glTF format root elements
435 #endif
436
437 };
438
439 #endif // _RWGltf_GltfJsonParser_HeaderFile