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