From 4925946065623cf361f4becab3cec2c96cde2110 Mon Sep 17 00:00:00 2001 From: kgv Date: Mon, 18 Jan 2021 14:58:22 +0300 Subject: [PATCH] 0032061: Data Exchange, RWGltf_CafWriter - exporting XBF file produces an invalid glTF document Empty Nodes are now skipped while filling in Scene node map. --- src/RWGltf/RWGltf_CafWriter.cxx | 69 ++++++++++++++++++---------- src/RWGltf/RWGltf_GltfJsonParser.cxx | 3 +- tests/de_mesh/gltf_write/empty | 21 +++++++++ 3 files changed, 68 insertions(+), 25 deletions(-) create mode 100644 tests/de_mesh/gltf_write/empty diff --git a/src/RWGltf/RWGltf_CafWriter.cxx b/src/RWGltf/RWGltf_CafWriter.cxx index 99b2e271f0..aebe94348d 100644 --- a/src/RWGltf/RWGltf_CafWriter.cxx +++ b/src/RWGltf/RWGltf_CafWriter.cxx @@ -639,7 +639,29 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument, { continue; } - aSceneNodeMap.Add (aDocNode); + + bool hasMeshData = false; + if (!aDocNode.IsAssembly) + { + for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) + { + if (!toSkipFaceMesh (aFaceIter)) + { + hasMeshData = true; + break; + } + } + } + if (hasMeshData) + { + aSceneNodeMap.Add (aDocNode); + } + else + { + // glTF disallows empty meshes / primitive arrays + const TCollection_AsciiString aNodeName = readNameAttribute (aDocNode.RefLabel); + Message::SendWarning (TCollection_AsciiString("RWGltf_CafWriter skipped node '") + aNodeName + "' without triangulation data"); + } } rapidjson::OStreamWrapper aFileStream (aGltfContentFile); @@ -1273,20 +1295,8 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM { const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); const TCollection_AsciiString aNodeName = readNameAttribute (aDocNode.RefLabel); - { - RWMesh_FaceIterator aFaceIter(aDocNode.RefLabel, TopLoc_Location(), false); - if (!aFaceIter.More()) - { - Message::SendWarning (TCollection_AsciiString("RWGltf_CafWriter skipped node '") + aNodeName + "' without triangulation data"); - continue; - } - } - myWriter->StartObject(); - myWriter->Key ("name"); - myWriter->String (aNodeName.ToCString()); - myWriter->Key ("primitives"); - myWriter->StartArray(); + bool toStartPrims = true; Standard_Integer aNbFacesInNode = 0; for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next(), ++aNbFacesInNode) { @@ -1295,6 +1305,16 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM continue; } + if (toStartPrims) + { + toStartPrims = false; + myWriter->StartObject(); + myWriter->Key ("name"); + myWriter->String (aNodeName.ToCString()); + myWriter->Key ("primitives"); + myWriter->StartArray(); + } + const RWGltf_GltfFace& aGltfFace = myBinDataMap.Find (aFaceIter.Face()); const TCollection_AsciiString aMatId = myMaterialMap->FindMaterial (aFaceIter.FaceStyle()); myWriter->StartObject(); @@ -1329,8 +1349,12 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM } myWriter->EndObject(); } - myWriter->EndArray(); - myWriter->EndObject(); + + if (!toStartPrims) + { + myWriter->EndArray(); + myWriter->EndObject(); + } } myWriter->EndArray(); #else @@ -1357,19 +1381,16 @@ void RWGltf_CafWriter::writeNodes (const Handle(TDocStd_Document)& theDocument, aDocExplorer.More(); aDocExplorer.Next()) { const XCAFPrs_DocumentNode& aDocNode = aDocExplorer.Current(); - { - RWMesh_FaceIterator aFaceIter(aDocNode.RefLabel, TopLoc_Location(), false); - if (!aFaceIter.More()) - { - continue; - } - } if (theLabelFilter != NULL && !theLabelFilter->Contains (aDocNode.Id)) { continue; } + // keep empty nodes + //RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), false); + //if (!aFaceIter.More()) { continue; } + Standard_Integer aNodeIndex = aSceneNodeMapWithChildren.Add (aDocNode); if (aDocExplorer.CurrentDepth() == 0) { @@ -1490,11 +1511,11 @@ void RWGltf_CafWriter::writeNodes (const Handle(TDocStd_Document)& theDocument, } if (!aDocNode.IsAssembly) { - myWriter->Key ("mesh"); // Mesh order of current node is equal to order of this node in scene nodes map Standard_Integer aMeshIdx = theSceneNodeMap.FindIndex (aDocNode.Id); if (aMeshIdx > 0) { + myWriter->Key ("mesh"); myWriter->Int (aMeshIdx - 1); } } diff --git a/src/RWGltf/RWGltf_GltfJsonParser.cxx b/src/RWGltf/RWGltf_GltfJsonParser.cxx index 9d2add6d21..c2ea361ffb 100644 --- a/src/RWGltf/RWGltf_GltfJsonParser.cxx +++ b/src/RWGltf/RWGltf_GltfJsonParser.cxx @@ -1317,7 +1317,8 @@ bool RWGltf_GltfJsonParser::gltfParseMesh (TopoDS_Shape& theMeshShape, { const RWGltf_JsonValue* aName = findObjectMember (theMesh, "name"); const RWGltf_JsonValue* aPrims = findObjectMember (theMesh, "primitives"); - if (!aPrims->IsArray()) + if (aPrims == NULL + || !aPrims->IsArray()) { reportGltfError ("Primitive array attributes within Mesh '" + theMeshId + "' is not an array."); return false; diff --git a/tests/de_mesh/gltf_write/empty b/tests/de_mesh/gltf_write/empty new file mode 100644 index 0000000000..e10954505a --- /dev/null +++ b/tests/de_mesh/gltf_write/empty @@ -0,0 +1,21 @@ +puts "========" +puts "0032061: Data Exchange, RWGltf_CafWriter - exporting XBF file produces an invalid glTF document" +puts "========" + +set aTmpGltf "${imagedir}/${casename}_tmp.glb" +pload MODELING OCAF XDE VISUALIZATION + +# create a document with one shape without triangulation +box b1 0 0 0 1 2 3 +box b2 3 3 3 1 2 3 +compound ce +compound b1 b2 ce cc +incmesh b2 1 +XNewDoc DD +XAddShape DD cc 1 +WriteGltf DD "$aTmpGltf" +Close DD + +ReadGltf D "$aTmpGltf" +XGetOneShape s D +checknbshapes s -face 6 -compound 1