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