0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[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
803bdcdf 108 //! Set flag to ignore nodes without Geometry, TRUE by default.
109 void SetSkipEmptyNodes (bool theToSkip) { myToSkipEmptyNodes = theToSkip; }
110
111 //! Set flag to use Mesh name in case if Node name is empty, TRUE by default.
112 void SetMeshNameAsFallback (bool theToFallback) { myUseMeshNameAsFallback = theToFallback; }
113
0a419c51 114 //! Parse glTF document.
115 Standard_EXPORT bool Parse (const Handle(Message_ProgressIndicator)& theProgress);
116
0a419c51 117 //! Return face list for loading triangulation.
118 NCollection_Vector<TopoDS_Face>& FaceList() { return myFaceList; }
119
120protected:
121#ifdef HAVE_RAPIDJSON
122 //! Search mandatory root elements in the document.
123 //! Return FALSE if some mandatory element is missing.
124 Standard_EXPORT bool gltfParseRoots();
125
126 //! Parse default scene.
127 Standard_EXPORT bool gltfParseScene (const Handle(Message_ProgressIndicator)& theProgress);
128
129 //! Parse document metadata.
130 Standard_EXPORT void gltfParseAsset();
131
132protected:
133
134 //! Parse materials defined in the document.
135 Standard_EXPORT void gltfParseMaterials();
136
137 //! Parse standard material.
138 Standard_EXPORT bool gltfParseStdMaterial (Handle(RWGltf_MaterialCommon)& theMat,
139 const RWGltf_JsonValue& theMatNode);
140
141 //! Parse pbrMetallicRoughness material.
142 Standard_EXPORT bool gltfParsePbrMaterial (Handle(RWGltf_MaterialMetallicRoughness)& theMat,
143 const RWGltf_JsonValue& theMatNode);
144
145 //! Parse common material (KHR_materials_common extension).
146 Standard_EXPORT bool gltfParseCommonMaterial (Handle(RWGltf_MaterialCommon)& theMat,
147 const RWGltf_JsonValue& theMatNode);
148
149 //! Parse texture definition.
150 Standard_EXPORT bool gltfParseTexture (Handle(Image_Texture)& theTexture,
151 const RWGltf_JsonValue* theTextureId);
152
6216ed57 153 //! Parse texture definition in binary buffer of GLB file.
154 Standard_EXPORT bool gltfParseTexturInGlbBuffer (Handle(Image_Texture)& theTexture,
155 const RWGltf_JsonValue& theBinVal,
156 const TCollection_AsciiString& theBufferViewId,
157 const RWGltf_JsonValue& theBufferViewName);
158
159 //! Parse texture definition in binary buffer of glTF file.
160 Standard_EXPORT bool gltfParseTextureInBufferView (Handle(Image_Texture)& theTexture,
161 const TCollection_AsciiString& theSourceId,
162 const TCollection_AsciiString& theBufferViewhId,
163 const RWGltf_JsonValue& theBufferView);
164
a4815d55 165 //! Bind material definition to the map.
166 Standard_EXPORT void gltfBindMaterial (const Handle(RWGltf_MaterialMetallicRoughness)& theMatPbr,
167 const Handle(RWGltf_MaterialCommon)& theMatCommon);
168
0a419c51 169protected:
170
171 //! Parse scene array of nodes recursively.
172 Standard_EXPORT bool gltfParseSceneNodes (TopTools_SequenceOfShape& theShapeSeq,
173 const RWGltf_JsonValue& theSceneNodes,
174 const Handle(Message_ProgressIndicator)& theProgress);
175
176 //! Parse scene node recursively.
177 Standard_EXPORT bool gltfParseSceneNode (TopoDS_Shape& theNodeShape,
178 const TCollection_AsciiString& theSceneNodeId,
179 const RWGltf_JsonValue& theSceneNode,
180 const Handle(Message_ProgressIndicator)& theProgress);
181
182 //! Parse mesh element.
183 Standard_EXPORT bool gltfParseMesh (TopoDS_Shape& theMeshShape,
184 const TCollection_AsciiString& theMeshId,
185 const RWGltf_JsonValue& theMesh,
186 const Handle(Message_ProgressIndicator)& theProgress);
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 const Handle(Message_ProgressIndicator)& theProgress);
193
194 //! Parse accessor.
195 Standard_EXPORT bool gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
196 const TCollection_AsciiString& theName,
197 const RWGltf_JsonValue& theAccessor,
198 const RWGltf_GltfArrayType theType);
199
200 //! Parse buffer view.
201 Standard_EXPORT bool gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
202 const TCollection_AsciiString& theName,
203 const RWGltf_JsonValue& theBufferView,
204 const RWGltf_GltfAccessor& theAccessor,
205 const RWGltf_GltfArrayType theType);
206
207 //! Parse buffer.
208 Standard_EXPORT bool gltfParseBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
209 const TCollection_AsciiString& theName,
210 const RWGltf_JsonValue& theBuffer,
211 const RWGltf_GltfAccessor& theAccessor,
212 const RWGltf_GltfBufferView& theView,
213 const RWGltf_GltfArrayType theType);
214
215protected:
216
217 //! Read vec4 from specified item.
218 static bool gltfReadVec4 (Graphic3d_Vec4d& theVec4,
219 const RWGltf_JsonValue* theVal)
220 {
221 if (theVal == NULL
222 || !theVal->IsArray()
223 || theVal->Size() != 4)
224 {
225 return false;
226 }
227
228 for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
229 {
230 const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
231 if (!aGenVal.IsNumber())
232 {
233 return false;
234 }
235 theVec4[aCompIter] = aGenVal.GetDouble();
236 }
237 return true;
238 }
239
240 //! Validate color
241 static bool validateColor4 (const Graphic3d_Vec4d& theVec)
242 {
243 return theVec.r() >= 0.0 && theVec.r() <= 1.0
244 && theVec.g() >= 0.0 && theVec.g() <= 1.0
245 && theVec.b() >= 0.0 && theVec.b() <= 1.0
246 && theVec.a() >= 0.0 && theVec.a() <= 1.0;
247 }
248
249 //! Read vec3 from specified item.
250 static bool gltfReadVec3 (Graphic3d_Vec3d& theVec3,
251 const RWGltf_JsonValue* theVal)
252 {
253 if (theVal == NULL
254 || !theVal->IsArray()
255 || theVal->Size() != 3)
256 {
257 return false;
258 }
259
260 for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
261 {
262 const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
263 if (!aGenVal.IsNumber())
264 {
265 return false;
266 }
267 theVec3[aCompIter] = aGenVal.GetDouble();
268 }
269 return true;
270 }
271
272 //! Validate color
273 static bool validateColor3 (const Graphic3d_Vec3d& theVec)
274 {
275 return theVec.r() >= 0.0 && theVec.r() <= 1.0
276 && theVec.g() >= 0.0 && theVec.g() <= 1.0
277 && theVec.b() >= 0.0 && theVec.b() <= 1.0;
278 }
279
280protected:
281
282 //! Groups for re-using shapes.
283 enum ShapeMapGroup
284 {
285 ShapeMapGroup_Nodes, //!< nodes
286 ShapeMapGroup_Meshes, //!< meshes
287 };
288
289 //! Bind name attribute.
290 void bindNodeShape (TopoDS_Shape& theShape,
291 const TopLoc_Location& theLoc,
292 const TCollection_AsciiString& theNodeId,
293 const RWGltf_JsonValue* theUserName)
294 {
295 bindNamedShape (theShape, ShapeMapGroup_Nodes, theLoc, theNodeId, theUserName);
296 }
297
298 //! Bind name attribute.
299 void bindMeshShape (TopoDS_Shape& theShape,
300 const TCollection_AsciiString& theMeshId,
301 const RWGltf_JsonValue* theUserName)
302 {
303 bindNamedShape (theShape, ShapeMapGroup_Meshes, TopLoc_Location(), theMeshId, theUserName);
304 }
305
306 //! Find named shape.
307 bool findNodeShape (TopoDS_Shape& theShape,
308 const TCollection_AsciiString& theNodeId) const
309 {
310 return findNamedShape (theShape, ShapeMapGroup_Nodes, theNodeId);
311 }
312
313 //! Find named shape.
314 bool findMeshShape (TopoDS_Shape& theShape,
315 const TCollection_AsciiString& theMeshId) const
316 {
317 return findNamedShape (theShape, ShapeMapGroup_Meshes, theMeshId);
318 }
319
320 //! Bind name attribute.
321 Standard_EXPORT void bindNamedShape (TopoDS_Shape& theShape,
322 ShapeMapGroup theGroup,
323 const TopLoc_Location& theLoc,
324 const TCollection_AsciiString& theId,
325 const RWGltf_JsonValue* theUserName);
326
327 //! Find named shape.
328 bool findNamedShape (TopoDS_Shape& theShape,
329 ShapeMapGroup theGroup,
330 const TCollection_AsciiString& theId) const
331 {
332 return myShapeMap[theGroup].Find (theId, theShape);
333 }
334
335 //! Return the string representation of the key.
336 static TCollection_AsciiString getKeyString (const RWGltf_JsonValue& theValue)
337 {
338 if (theValue.IsString())
339 {
340 return TCollection_AsciiString (theValue.GetString());
341 }
342 else if (theValue.IsInt())
343 {
344 return TCollection_AsciiString (theValue.GetInt());
345 }
346 return TCollection_AsciiString();
347 }
348
349protected:
350
351 //! Auxiliary structure for fast look-up of document sub-nodes of specified node.
352 class GltfElementMap
353 {
354 public:
355
356 //! Empty constructor.
357 GltfElementMap() : myRoot (NULL) {}
358
359 //! Return TRUE if this element is NULL.
360 bool IsNull() const { return myRoot == NULL; }
361
362 //! Access this node.
363 const RWGltf_JsonValue* Root() const { return myRoot; }
364
365 //! Find the child node with specified key.
366 const RWGltf_JsonValue* FindChild (const TCollection_AsciiString& theKey)
367 {
368 const RWGltf_JsonValue* aNode = NULL;
369 return myChildren.Find (theKey, aNode)
370 ? aNode
371 : NULL;
372 }
373
374 //! Find the child node with specified key.
375 const RWGltf_JsonValue* FindChild (const RWGltf_JsonValue& theKey)
376 {
377 const TCollection_AsciiString aKey = getKeyString (theKey);
378 if (aKey.IsEmpty())
379 {
380 return NULL;
381 }
382
383 const RWGltf_JsonValue* aNode = NULL;
384 return myChildren.Find (aKey, aNode)
385 ? aNode
386 : NULL;
387 }
388
389 //! Initialize the element.
390 void Init (const TCollection_AsciiString& theRootName,
391 const RWGltf_JsonValue* theRoot);
392
393 private:
394
395 NCollection_DataMap<TCollection_AsciiString, const RWGltf_JsonValue*, TCollection_AsciiString> myChildren;
396 const RWGltf_JsonValue* myRoot;
397
398 };
399#endif
400protected:
401
402 //! Print message about invalid glTF syntax.
403 void reportGltfSyntaxProblem (const TCollection_AsciiString& theMsg, Message_Gravity theGravity);
404
405protected:
406
407 TopTools_SequenceOfShape* myRootShapes; //!< sequence of result root shapes
408 RWMesh_NodeAttributeMap* myAttribMap; //!< shape attributes
409 NCollection_IndexedMap<TCollection_AsciiString>*
410 myExternalFiles; //!< list of external file references
411 RWMesh_CoordinateSystemConverter myCSTrsf; //!< transformation from glTF to OCCT coordinate system
82c59511 412 TColStd_IndexedDataMapOfStringString* myMetadata; //!< file metadata
0a419c51 413
0a419c51 414 NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialMetallicRoughness)> myMaterialsPbr;
415 NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialCommon)> myMaterialsCommon;
a4815d55 416 NCollection_DataMap<TCollection_AsciiString, Handle(XCAFDoc_VisMaterial)> myMaterials;
0a419c51 417 NCollection_DataMap<TCollection_AsciiString, TopoDS_Shape> myShapeMap[2];
418
419 NCollection_DataMap<TCollection_AsciiString, bool> myProbedFiles;
420 NCollection_DataMap<TCollection_AsciiString, Handle(NCollection_Buffer)> myDecodedBuffers;
421 NCollection_Vector<TopoDS_Face> myFaceList; //!< face list for loading triangulation
422
423 TCollection_AsciiString myFilePath; //!< file path
424 TCollection_AsciiString myFolder; //!< folder
425 TCollection_AsciiString myErrorPrefix; //!< invalid syntax error prefix
426 int64_t myBinBodyOffset; //!< offset to binary body
427 int64_t myBinBodyLen; //!< binary body length
428 bool myIsBinary; //!< binary document
429 bool myIsGltf1; //!< obsolete glTF 1.0 version format
430 bool myToSkipEmptyNodes; //!< ignore nodes without Geometry
803bdcdf 431 bool myUseMeshNameAsFallback; //!< flag to use Mesh name in case if Node name is empty, TRUE by default
0a419c51 432 bool myToProbeHeader; //!< flag to probe header without full reading, FALSE by default
433
434#ifdef HAVE_RAPIDJSON
435 GltfElementMap myGltfRoots[RWGltf_GltfRootElement_NB]; //!< glTF format root elements
436#endif
437
438};
439
440#endif // _RWGltf_GltfJsonParser_HeaderFile