0030811: Data Exchange, RWGltf_CafReader - fix inaccessibility of properties
[occt.git] / src / RWGltf / RWGltf_GltfJsonParser.pxx
CommitLineData
0a419c51 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 <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>
32
33// workaround name collisions with XLib
34#ifdef None
35 #undef None
36#endif
37#ifdef Bool
38 #undef Bool
39#endif
40
41#ifdef HAVE_RAPIDJSON
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>
48
49 typedef rapidjson::Document::ValueType RWGltf_JsonValue;
50#endif
51
52class Message_ProgressIndicator;
53
54//! INTERNAL tool for parsing glTF document (JSON structure).
55class RWGltf_GltfJsonParser
56#ifdef HAVE_RAPIDJSON
57: public rapidjson::Document
58#endif
59{
60public:
61
62#ifdef HAVE_RAPIDJSON
63 //! Auxiliary method for formatting error code.
64 Standard_EXPORT static const char* FormatParseError (rapidjson::ParseErrorCode theCode);
65#endif
66
67public:
68
69 //! Empty constructor.
70 Standard_EXPORT RWGltf_GltfJsonParser (TopTools_SequenceOfShape& theRootShapes);
71
72 //! Set file path.
73 Standard_EXPORT void SetFilePath (const TCollection_AsciiString& theFilePath);
74
75 //! Set flag for probing file without complete reading.
76 void SetProbeHeader (bool theToProbe) { myToProbeHeader = theToProbe; }
77
78 //! Return prefix for reporting issues.
79 const TCollection_AsciiString& ErrorPrefix() const { return myErrorPrefix; }
80
81 //! Set prefix for reporting issues.
82 void SetErrorPrefix (const TCollection_AsciiString& theErrPrefix) { myErrorPrefix = theErrPrefix; }
83
84 //! Set map for storing node attributes.
85 void SetAttributeMap (RWMesh_NodeAttributeMap& theAttribMap) { myAttribMap = &theAttribMap; }
86
87 //! Set list for storing external files.
88 void SetExternalFiles (NCollection_IndexedMap<TCollection_AsciiString>& theExternalFiles) { myExternalFiles = &theExternalFiles; }
89
82c59511 90 //! Set metadata map.
91 void SetMetadata (TColStd_IndexedDataMapOfStringString& theMetadata) { myMetadata = &theMetadata; }
92
0a419c51 93 //! Return transformation from glTF to OCCT coordinate system.
94 const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCSTrsf; }
95
96 //! Set transformation from glTF to OCCT coordinate system.
97 void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCSTrsf = theConverter; }
98
99 //! Initialize binary format.
100 void SetBinaryFormat (int64_t theBinBodyOffset,
101 int64_t theBinBodyLen)
102 {
103 myIsBinary = true;
104 myBinBodyOffset = theBinBodyOffset;
105 myBinBodyLen = theBinBodyLen;
106 }
107
108 //! Parse glTF document.
109 Standard_EXPORT bool Parse (const Handle(Message_ProgressIndicator)& theProgress);
110
0a419c51 111 //! Return face list for loading triangulation.
112 NCollection_Vector<TopoDS_Face>& FaceList() { return myFaceList; }
113
114protected:
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();
119
120 //! Parse default scene.
121 Standard_EXPORT bool gltfParseScene (const Handle(Message_ProgressIndicator)& theProgress);
122
123 //! Parse document metadata.
124 Standard_EXPORT void gltfParseAsset();
125
126protected:
127
128 //! Parse materials defined in the document.
129 Standard_EXPORT void gltfParseMaterials();
130
131 //! Parse standard material.
132 Standard_EXPORT bool gltfParseStdMaterial (Handle(RWGltf_MaterialCommon)& theMat,
133 const RWGltf_JsonValue& theMatNode);
134
135 //! Parse pbrMetallicRoughness material.
136 Standard_EXPORT bool gltfParsePbrMaterial (Handle(RWGltf_MaterialMetallicRoughness)& theMat,
137 const RWGltf_JsonValue& theMatNode);
138
139 //! Parse common material (KHR_materials_common extension).
140 Standard_EXPORT bool gltfParseCommonMaterial (Handle(RWGltf_MaterialCommon)& theMat,
141 const RWGltf_JsonValue& theMatNode);
142
143 //! Parse texture definition.
144 Standard_EXPORT bool gltfParseTexture (Handle(Image_Texture)& theTexture,
145 const RWGltf_JsonValue* theTextureId);
146
147protected:
148
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);
153
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);
159
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);
165
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);
171
172 //! Parse accessor.
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);
177
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);
184
185 //! Parse buffer.
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);
192
193protected:
194
195 //! Read vec4 from specified item.
196 static bool gltfReadVec4 (Graphic3d_Vec4d& theVec4,
197 const RWGltf_JsonValue* theVal)
198 {
199 if (theVal == NULL
200 || !theVal->IsArray()
201 || theVal->Size() != 4)
202 {
203 return false;
204 }
205
206 for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
207 {
208 const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
209 if (!aGenVal.IsNumber())
210 {
211 return false;
212 }
213 theVec4[aCompIter] = aGenVal.GetDouble();
214 }
215 return true;
216 }
217
218 //! Validate color
219 static bool validateColor4 (const Graphic3d_Vec4d& theVec)
220 {
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;
225 }
226
227 //! Read vec3 from specified item.
228 static bool gltfReadVec3 (Graphic3d_Vec3d& theVec3,
229 const RWGltf_JsonValue* theVal)
230 {
231 if (theVal == NULL
232 || !theVal->IsArray()
233 || theVal->Size() != 3)
234 {
235 return false;
236 }
237
238 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
239 {
240 const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
241 if (!aGenVal.IsNumber())
242 {
243 return false;
244 }
245 theVec3[aCompIter] = aGenVal.GetDouble();
246 }
247 return true;
248 }
249
250 //! Validate color
251 static bool validateColor3 (const Graphic3d_Vec3d& theVec)
252 {
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;
256 }
257
258protected:
259
260 //! Groups for re-using shapes.
261 enum ShapeMapGroup
262 {
263 ShapeMapGroup_Nodes, //!< nodes
264 ShapeMapGroup_Meshes, //!< meshes
265 };
266
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)
272 {
273 bindNamedShape (theShape, ShapeMapGroup_Nodes, theLoc, theNodeId, theUserName);
274 }
275
276 //! Bind name attribute.
277 void bindMeshShape (TopoDS_Shape& theShape,
278 const TCollection_AsciiString& theMeshId,
279 const RWGltf_JsonValue* theUserName)
280 {
281 bindNamedShape (theShape, ShapeMapGroup_Meshes, TopLoc_Location(), theMeshId, theUserName);
282 }
283
284 //! Find named shape.
285 bool findNodeShape (TopoDS_Shape& theShape,
286 const TCollection_AsciiString& theNodeId) const
287 {
288 return findNamedShape (theShape, ShapeMapGroup_Nodes, theNodeId);
289 }
290
291 //! Find named shape.
292 bool findMeshShape (TopoDS_Shape& theShape,
293 const TCollection_AsciiString& theMeshId) const
294 {
295 return findNamedShape (theShape, ShapeMapGroup_Meshes, theMeshId);
296 }
297
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);
304
305 //! Find named shape.
306 bool findNamedShape (TopoDS_Shape& theShape,
307 ShapeMapGroup theGroup,
308 const TCollection_AsciiString& theId) const
309 {
310 return myShapeMap[theGroup].Find (theId, theShape);
311 }
312
313 //! Return the string representation of the key.
314 static TCollection_AsciiString getKeyString (const RWGltf_JsonValue& theValue)
315 {
316 if (theValue.IsString())
317 {
318 return TCollection_AsciiString (theValue.GetString());
319 }
320 else if (theValue.IsInt())
321 {
322 return TCollection_AsciiString (theValue.GetInt());
323 }
324 return TCollection_AsciiString();
325 }
326
327protected:
328
329 //! Auxiliary structure for fast look-up of document sub-nodes of specified node.
330 class GltfElementMap
331 {
332 public:
333
334 //! Empty constructor.
335 GltfElementMap() : myRoot (NULL) {}
336
337 //! Return TRUE if this element is NULL.
338 bool IsNull() const { return myRoot == NULL; }
339
340 //! Access this node.
341 const RWGltf_JsonValue* Root() const { return myRoot; }
342
343 //! Find the child node with specified key.
344 const RWGltf_JsonValue* FindChild (const TCollection_AsciiString& theKey)
345 {
346 const RWGltf_JsonValue* aNode = NULL;
347 return myChildren.Find (theKey, aNode)
348 ? aNode
349 : NULL;
350 }
351
352 //! Find the child node with specified key.
353 const RWGltf_JsonValue* FindChild (const RWGltf_JsonValue& theKey)
354 {
355 const TCollection_AsciiString aKey = getKeyString (theKey);
356 if (aKey.IsEmpty())
357 {
358 return NULL;
359 }
360
361 const RWGltf_JsonValue* aNode = NULL;
362 return myChildren.Find (aKey, aNode)
363 ? aNode
364 : NULL;
365 }
366
367 //! Initialize the element.
368 void Init (const TCollection_AsciiString& theRootName,
369 const RWGltf_JsonValue* theRoot);
370
371 private:
372
373 NCollection_DataMap<TCollection_AsciiString, const RWGltf_JsonValue*, TCollection_AsciiString> myChildren;
374 const RWGltf_JsonValue* myRoot;
375
376 };
377#endif
378protected:
379
380 //! Print message about invalid glTF syntax.
381 void reportGltfSyntaxProblem (const TCollection_AsciiString& theMsg, Message_Gravity theGravity);
382
383protected:
384
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
82c59511 390 TColStd_IndexedDataMapOfStringString* myMetadata; //!< file metadata
0a419c51 391
0a419c51 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];
395
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
399
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
409
410#ifdef HAVE_RAPIDJSON
411 GltfElementMap myGltfRoots[RWGltf_GltfRootElement_NB]; //!< glTF format root elements
412#endif
413
414};
415
416#endif // _RWGltf_GltfJsonParser_HeaderFile