0025748: Parallel version of progress indicator
[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                                       const Message_ProgressRange& theProgress);
188
189   //! Parse primitive array.
190   Standard_EXPORT bool gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
191                                            const TCollection_AsciiString& theMeshName,
192                                            const RWGltf_JsonValue& thePrimArray,
193                                            const Message_ProgressRange& theProgress);
194
195   //! Parse accessor.
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
201   //! Parse buffer view.
202   Standard_EXPORT bool gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
203                                             const TCollection_AsciiString& theName,
204                                             const RWGltf_JsonValue& theBufferView,
205                                             const RWGltf_GltfAccessor& theAccessor,
206                                             const RWGltf_GltfArrayType theType);
207
208   //! Parse buffer.
209   Standard_EXPORT bool gltfParseBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
210                                         const TCollection_AsciiString& theName,
211                                         const RWGltf_JsonValue& theBuffer,
212                                         const RWGltf_GltfAccessor&   theAccessor,
213                                         const RWGltf_GltfBufferView& theView,
214                                         const RWGltf_GltfArrayType   theType);
215
216 protected:
217
218   //! Read vec4 from specified item.
219   static bool gltfReadVec4 (Graphic3d_Vec4d& theVec4,
220                             const RWGltf_JsonValue* theVal)
221   {
222     if (theVal == NULL
223     || !theVal->IsArray()
224     ||  theVal->Size() != 4)
225     {
226       return false;
227     }
228
229     for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
230     {
231       const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
232       if (!aGenVal.IsNumber())
233       {
234         return false;
235       }
236       theVec4[aCompIter] = aGenVal.GetDouble();
237     }
238     return true;
239   }
240
241   //! Validate color
242   static bool validateColor4 (const Graphic3d_Vec4d& theVec)
243   {
244     return theVec.r() >= 0.0 && theVec.r() <= 1.0
245         && theVec.g() >= 0.0 && theVec.g() <= 1.0
246         && theVec.b() >= 0.0 && theVec.b() <= 1.0
247         && theVec.a() >= 0.0 && theVec.a() <= 1.0;
248   }
249
250   //! Read vec3 from specified item.
251   static bool gltfReadVec3 (Graphic3d_Vec3d& theVec3,
252                             const RWGltf_JsonValue* theVal)
253   {
254     if (theVal == NULL
255     || !theVal->IsArray()
256     ||  theVal->Size() != 3)
257     {
258       return false;
259     }
260
261     for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
262     {
263       const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
264       if (!aGenVal.IsNumber())
265       {
266         return false;
267       }
268       theVec3[aCompIter] = aGenVal.GetDouble();
269     }
270     return true;
271   }
272
273   //! Validate color
274   static bool validateColor3 (const Graphic3d_Vec3d& theVec)
275   {
276     return theVec.r() >= 0.0 && theVec.r() <= 1.0
277         && theVec.g() >= 0.0 && theVec.g() <= 1.0
278         && theVec.b() >= 0.0 && theVec.b() <= 1.0;
279   }
280
281 protected:
282
283   //! Groups for re-using shapes.
284   enum ShapeMapGroup
285   {
286     ShapeMapGroup_Nodes,  //!< nodes
287     ShapeMapGroup_Meshes, //!< meshes
288   };
289
290   //! Bind name attribute.
291   void bindNodeShape (TopoDS_Shape& theShape,
292                       const TopLoc_Location& theLoc,
293                       const TCollection_AsciiString& theNodeId,
294                       const RWGltf_JsonValue* theUserName)
295   {
296     bindNamedShape (theShape, ShapeMapGroup_Nodes, theLoc, theNodeId, theUserName);
297   }
298
299   //! Bind name attribute.
300   void bindMeshShape (TopoDS_Shape& theShape,
301                       const TCollection_AsciiString& theMeshId,
302                       const RWGltf_JsonValue* theUserName)
303   {
304     bindNamedShape (theShape, ShapeMapGroup_Meshes, TopLoc_Location(), theMeshId, theUserName);
305   }
306
307   //! Find named shape.
308   bool findNodeShape (TopoDS_Shape& theShape,
309                       const TCollection_AsciiString& theNodeId) const
310   {
311     return findNamedShape (theShape, ShapeMapGroup_Nodes, theNodeId);
312   }
313
314   //! Find named shape.
315   bool findMeshShape (TopoDS_Shape& theShape,
316                       const TCollection_AsciiString& theMeshId) const
317   {
318     return findNamedShape (theShape, ShapeMapGroup_Meshes, theMeshId);
319   }
320
321   //! Bind name attribute.
322   Standard_EXPORT void bindNamedShape (TopoDS_Shape& theShape,
323                                        ShapeMapGroup theGroup,
324                                        const TopLoc_Location& theLoc,
325                                        const TCollection_AsciiString& theId,
326                                        const RWGltf_JsonValue* theUserName);
327
328   //! Find named shape.
329   bool findNamedShape (TopoDS_Shape& theShape,
330                        ShapeMapGroup theGroup,
331                        const TCollection_AsciiString& theId) const
332   {
333     return myShapeMap[theGroup].Find (theId, theShape);
334   }
335
336   //! Return the string representation of the key.
337   static TCollection_AsciiString getKeyString (const RWGltf_JsonValue& theValue)
338   {
339     if (theValue.IsString())
340     {
341       return TCollection_AsciiString (theValue.GetString());
342     }
343     else if (theValue.IsInt())
344     {
345       return TCollection_AsciiString (theValue.GetInt());
346     }
347     return TCollection_AsciiString();
348   }
349
350 protected:
351
352   //! Auxiliary structure for fast look-up of document sub-nodes of specified node.
353   class GltfElementMap
354   {
355   public:
356
357     //! Empty constructor.
358     GltfElementMap() : myRoot (NULL) {}
359
360     //! Return TRUE if this element is NULL.
361     bool IsNull() const { return myRoot == NULL; }
362
363     //! Access this node.
364     const RWGltf_JsonValue* Root() const { return myRoot; }
365
366     //! Find the child node with specified key.
367     const RWGltf_JsonValue* FindChild (const TCollection_AsciiString& theKey)
368     {
369       const RWGltf_JsonValue* aNode = NULL;
370       return myChildren.Find (theKey, aNode)
371            ? aNode
372            : NULL;
373     }
374
375     //! Find the child node with specified key.
376     const RWGltf_JsonValue* FindChild (const RWGltf_JsonValue& theKey)
377     {
378       const TCollection_AsciiString aKey = getKeyString (theKey);
379       if (aKey.IsEmpty())
380       {
381         return NULL;
382       }
383
384       const RWGltf_JsonValue* aNode = NULL;
385       return myChildren.Find (aKey, aNode)
386            ? aNode
387            : NULL;
388     }
389
390     //! Initialize the element.
391     void Init (const TCollection_AsciiString& theRootName,
392                const RWGltf_JsonValue* theRoot);
393
394   private:
395
396     NCollection_DataMap<TCollection_AsciiString, const RWGltf_JsonValue*, TCollection_AsciiString> myChildren;
397     const RWGltf_JsonValue* myRoot;
398
399   };
400 #endif
401 protected:
402
403   //! Print message about invalid glTF syntax.
404   void reportGltfSyntaxProblem (const TCollection_AsciiString& theMsg, Message_Gravity theGravity);
405
406 protected:
407
408   TopTools_SequenceOfShape*        myRootShapes;    //!< sequence of result root shapes
409   RWMesh_NodeAttributeMap*         myAttribMap;     //!< shape attributes
410   NCollection_IndexedMap<TCollection_AsciiString>*
411                                    myExternalFiles; //!< list of external file references
412   RWMesh_CoordinateSystemConverter myCSTrsf;        //!< transformation from glTF to OCCT coordinate system
413   TColStd_IndexedDataMapOfStringString* myMetadata; //!< file metadata
414
415   NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialMetallicRoughness)> myMaterialsPbr;
416   NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialCommon)> myMaterialsCommon;
417   NCollection_DataMap<TCollection_AsciiString, Handle(XCAFDoc_VisMaterial)> myMaterials;
418   NCollection_DataMap<TCollection_AsciiString, TopoDS_Shape> myShapeMap[2];
419
420   NCollection_DataMap<TCollection_AsciiString, bool> myProbedFiles;
421   NCollection_DataMap<TCollection_AsciiString, Handle(NCollection_Buffer)> myDecodedBuffers;
422   NCollection_Vector<TopoDS_Face> myFaceList; //!< face list for loading triangulation
423
424   TCollection_AsciiString   myFilePath;       //!< file path
425   TCollection_AsciiString   myFolder;         //!< folder
426   TCollection_AsciiString   myErrorPrefix;    //!< invalid syntax error prefix
427   int64_t                   myBinBodyOffset;  //!< offset to binary body
428   int64_t                   myBinBodyLen;     //!< binary body length
429   bool                      myIsBinary;       //!< binary document
430   bool                      myIsGltf1;        //!< obsolete glTF 1.0 version format
431   bool                      myToSkipEmptyNodes; //!< ignore nodes without Geometry
432   bool                      myUseMeshNameAsFallback; //!< flag to use Mesh name in case if Node name is empty, TRUE by default
433   bool                      myToProbeHeader;  //!< flag to probe header without full reading, FALSE by default
434
435 #ifdef HAVE_RAPIDJSON
436   GltfElementMap myGltfRoots[RWGltf_GltfRootElement_NB]; //!< glTF format root elements
437 #endif
438
439 };
440
441 #endif // _RWGltf_GltfJsonParser_HeaderFile