0032107: Data Exchange, RWGltf_CafReader - reading glTF document back loses sharing
authorkgv <kgv@opencascade.com>
Sun, 5 Sep 2021 15:40:55 +0000 (18:40 +0300)
committersmoskvin <smoskvin@opencascade.com>
Fri, 10 Sep 2021 17:22:59 +0000 (20:22 +0300)
RWGltf_CafWriter has been fixed to write shared Faces having a different style.
RWGltf_GltfJsonParser::gltfParsePrimArray() now tries to create a shared TopoDS_Face
from the same primitive array definition.

RWGltf_CafReader - improved name generation.

src/RWGltf/RWGltf_CafWriter.cxx
src/RWGltf/RWGltf_CafWriter.hxx
src/RWGltf/RWGltf_GltfJsonParser.cxx
src/RWGltf/RWGltf_GltfJsonParser.hxx
src/RWMesh/RWMesh_CafReader.cxx
src/RWMesh/RWMesh_FaceIterator.cxx
tests/de_mesh/gltf_write/as1
tests/de_mesh/gltf_write/spheres [new file with mode: 0644]

index 71f88bb..b54198f 100644 (file)
@@ -434,13 +434,14 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument
     RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style);
     if (myToMergeFaces)
     {
-      if (myBinDataMap.Contains (aFaceIter.ExploredShape()))
+      RWGltf_StyledShape aStyledShape (aFaceIter.ExploredShape(), aDocNode.Style);
+      if (myBinDataMap.Contains (aStyledShape))
       {
         continue;
       }
 
       Handle(RWGltf_GltfFaceList) aGltfFaceList = new RWGltf_GltfFaceList();
-      myBinDataMap.Add (aFaceIter.ExploredShape(), aGltfFaceList);
+      myBinDataMap.Add (aStyledShape, aGltfFaceList);
       for (; aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next())
       {
         if (toSkipFaceMesh (aFaceIter))
@@ -489,8 +490,9 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument
     {
       for (; aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next())
       {
+        RWGltf_StyledShape aStyledShape (aFaceIter.Face(), aFaceIter.FaceStyle());
         if (toSkipFaceMesh (aFaceIter)
-         || myBinDataMap.Contains (aFaceIter.Face()))
+         || myBinDataMap.Contains (aStyledShape))
         {
           continue;
         }
@@ -500,13 +502,14 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument
         aGltfFace->Shape = aFaceIter.Face();
         aGltfFace->Style = aFaceIter.FaceStyle();
         aGltfFaceList->Append (aGltfFace);
-        myBinDataMap.Add (aFaceIter.Face(), aGltfFaceList);
+        myBinDataMap.Add (aStyledShape, aGltfFaceList);
       }
     }
   }
 
   Standard_Integer aNbAccessors = 0;
   NCollection_Map<Handle(RWGltf_GltfFaceList)> aWrittenFaces;
+  NCollection_DataMap<TopoDS_Shape, Handle(RWGltf_GltfFace), TopTools_ShapeMapHasher> aWrittenPrimData;
   for (Standard_Integer aTypeIter = 0; aTypeIter < 4; ++aTypeIter)
   {
     const RWGltf_GltfArrayType anArrType = (RWGltf_GltfArrayType )anArrTypes[aTypeIter];
@@ -521,6 +524,7 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument
     }
     aBuffView->ByteOffset = aBinFile->tellp();
     aWrittenFaces.Clear (false);
+    aWrittenPrimData.Clear (false);
     for (ShapeToGltfFaceMap::Iterator aBinDataIter (myBinDataMap); aBinDataIter.More() && aPSentryBin.More(); aBinDataIter.Next())
     {
       const Handle(RWGltf_GltfFaceList)& aGltfFaceList = aBinDataIter.Value();
@@ -532,6 +536,41 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument
       for (RWGltf_GltfFaceList::Iterator aGltfFaceIter (*aGltfFaceList); aGltfFaceIter.More() && aPSentryBin.More(); aGltfFaceIter.Next())
       {
         const Handle(RWGltf_GltfFace)& aGltfFace = aGltfFaceIter.Value();
+
+        Handle(RWGltf_GltfFace) anOldGltfFace;
+        if (aWrittenPrimData.Find (aGltfFace->Shape, anOldGltfFace))
+        {
+          switch (anArrType)
+          {
+            case RWGltf_GltfArrayType_Position:
+            {
+              aGltfFace->NodePos = anOldGltfFace->NodePos;
+              break;
+            }
+            case RWGltf_GltfArrayType_Normal:
+            {
+              aGltfFace->NodeNorm = anOldGltfFace->NodeNorm;
+              break;
+            }
+            case RWGltf_GltfArrayType_TCoord0:
+            {
+              aGltfFace->NodeUV = anOldGltfFace->NodeUV;
+              break;
+            }
+            case RWGltf_GltfArrayType_Indices:
+            {
+              aGltfFace->Indices = anOldGltfFace->Indices;
+              break;
+            }
+            default:
+            {
+              break;
+            }
+          }
+          continue;
+        }
+        aWrittenPrimData.Bind (aGltfFace->Shape, aGltfFace);
+
         for (RWMesh_FaceIterator aFaceIter (aGltfFace->Shape, aGltfFace->Style); aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next())
         {
           switch (anArrType)
@@ -864,6 +903,8 @@ void RWGltf_CafWriter::writeAccessors (const RWGltf_GltfSceneNodeMap& )
     RWGltf_GltfArrayType_Indices
   };
   NCollection_Map<Handle(RWGltf_GltfFaceList)> aWrittenFaces;
+  NCollection_Map<int> aWrittenIds;
+  int aNbAccessors = 0;
   for (Standard_Integer aTypeIter = 0; aTypeIter < 4; ++aTypeIter)
   {
     const RWGltf_GltfArrayType anArrType = (RWGltf_GltfArrayType )anArrTypes[aTypeIter];
@@ -883,21 +924,71 @@ void RWGltf_CafWriter::writeAccessors (const RWGltf_GltfSceneNodeMap& )
         {
           case RWGltf_GltfArrayType_Position:
           {
+            const int anAccessorId = aGltfFace->NodePos.Id;
+            if (anAccessorId == RWGltf_GltfAccessor::INVALID_ID
+            || !aWrittenIds.Add (anAccessorId))
+            {
+              break;
+            }
+
+            if (anAccessorId != aNbAccessors)
+            {
+              throw Standard_ProgramError ("Internal error: RWGltf_CafWriter::writeAccessors()");
+            }
+            ++aNbAccessors;
             writePositions (*aGltfFace);
             break;
           }
           case RWGltf_GltfArrayType_Normal:
           {
+            const int anAccessorId = aGltfFace->NodeNorm.Id;
+            if (anAccessorId == RWGltf_GltfAccessor::INVALID_ID
+            || !aWrittenIds.Add (anAccessorId))
+            {
+              break;
+            }
+
+            if (anAccessorId != aNbAccessors)
+            {
+              throw Standard_ProgramError ("Internal error: RWGltf_CafWriter::writeAccessors()");
+            }
+            ++aNbAccessors;
             writeNormals (*aGltfFace);
             break;
           }
           case RWGltf_GltfArrayType_TCoord0:
           {
+            const int anAccessorId = aGltfFace->NodeUV.Id;
+            if (anAccessorId == RWGltf_GltfAccessor::INVALID_ID
+            || !aWrittenIds.Add (anAccessorId)
+             )
+            {
+              break;
+            }
+
+            if (anAccessorId != aNbAccessors)
+            {
+              throw Standard_ProgramError ("Internal error: RWGltf_CafWriter::writeAccessors()");
+            }
+            ++aNbAccessors;
             writeTextCoords (*aGltfFace);
             break;
           }
           case RWGltf_GltfArrayType_Indices:
           {
+            const int anAccessorId = aGltfFace->Indices.Id;
+            if (anAccessorId == RWGltf_GltfAccessor::INVALID_ID
+            || !aWrittenIds.Add (anAccessorId)
+             )
+            {
+              break;
+            }
+
+            if (anAccessorId != aNbAccessors)
+            {
+              throw Standard_ProgramError ("Internal error: RWGltf_CafWriter::writeAccessors()");
+            }
+            ++aNbAccessors;
             writeIndices (*aGltfFace);
             break;
           }
@@ -1420,7 +1511,8 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM
 
       Handle(RWGltf_GltfFaceList) aGltfFaceList;
       aShape.Location (TopLoc_Location());
-      myBinDataMap.FindFromKey (aShape, aGltfFaceList);
+      RWGltf_StyledShape aStyledShape (aShape, aDocNode.Style);
+      myBinDataMap.FindFromKey (aStyledShape, aGltfFaceList);
       if (!aWrittenFaces.Add (aGltfFaceList))
       {
         continue;
@@ -1441,7 +1533,8 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM
           continue;
         }
 
-        const Handle(RWGltf_GltfFaceList)& aGltfFaceList = myBinDataMap.FindFromKey (aFaceIter.Face());
+        RWGltf_StyledShape aStyledShape (aFaceIter.Face(), aFaceIter.FaceStyle());
+        const Handle(RWGltf_GltfFaceList)& aGltfFaceList = myBinDataMap.FindFromKey (aStyledShape);
         if (!aWrittenFaces.Add (aGltfFaceList))
         {
           continue;
index bfc5119..328c1b7 100644 (file)
@@ -318,7 +318,31 @@ protected:
 
 protected:
 
-  typedef NCollection_IndexedDataMap<TopoDS_Shape, Handle(RWGltf_GltfFaceList), TopTools_ShapeMapHasher> ShapeToGltfFaceMap;
+  //! Shape + Style pair.
+  struct RWGltf_StyledShape
+  {
+    TopoDS_Shape  Shape;
+    XCAFPrs_Style Style;
+
+    RWGltf_StyledShape() {}
+    explicit RWGltf_StyledShape (const TopoDS_Shape& theShape) : Shape (theShape) {}
+    explicit RWGltf_StyledShape (const TopoDS_Shape&  theShape,
+                                 const XCAFPrs_Style& theStyle) : Shape (theShape), Style (theStyle) {}
+  public:
+    //! Computes a hash code.
+    static Standard_Integer HashCode (const RWGltf_StyledShape& theShape, Standard_Integer theUpperBound)
+    {
+      return theShape.Shape.HashCode (theUpperBound);
+    }
+    //! Equality comparison.
+    static Standard_Boolean IsEqual (const RWGltf_StyledShape& theS1, const RWGltf_StyledShape& theS2)
+    {
+      return theS1.Shape.IsSame (theS2.Shape)
+          && theS1.Style.IsEqual(theS2.Style);
+    }
+  };
+
+  typedef NCollection_IndexedDataMap<RWGltf_StyledShape, Handle(RWGltf_GltfFaceList), RWGltf_StyledShape> ShapeToGltfFaceMap;
 
 protected:
 
index 9974cfa..e29b4b4 100644 (file)
@@ -1340,51 +1340,27 @@ bool RWGltf_GltfJsonParser::gltfParseMesh (TopoDS_Shape& theMeshShape,
     return true;
   }
 
+  const TCollection_AsciiString aUserName ((aName != NULL && aName->IsString()) ? aName->GetString() : "");
+
   BRep_Builder aBuilder;
   TopoDS_Compound aMeshShape;
   int aNbFaces = 0;
   for (rapidjson::Value::ConstValueIterator aPrimArrIter = aPrims->Begin();
        aPrimArrIter != aPrims->End(); ++aPrimArrIter)
   {
-    TCollection_AsciiString aUserName;
-    if (aName != NULL
-     && aName->IsString())
-    {
-      aUserName = aName->GetString();
-    }
-
-    Handle(RWGltf_GltfLatePrimitiveArray) aMeshData = new RWGltf_GltfLatePrimitiveArray (theMeshId, aUserName);
-    if (!gltfParsePrimArray (aMeshData, theMeshId, *aPrimArrIter))
+    TopoDS_Shape aFace;
+    if (!gltfParsePrimArray (aFace, theMeshId, aUserName, *aPrimArrIter))
     {
       return false;
     }
 
-    if (!aMeshData->Data().IsEmpty())
+    if (!aFace.IsNull())
     {
       if (aMeshShape.IsNull())
       {
         aBuilder.MakeCompound (aMeshShape);
       }
-
-      TopoDS_Face aFace;
-      aBuilder.MakeFace (aFace, aMeshData);
       aBuilder.Add (aMeshShape, aFace);
-      if (myAttribMap != NULL
-       && aMeshData->HasStyle())
-      {
-        RWMesh_NodeAttributes aShapeAttribs;
-        aShapeAttribs.RawName = aUserName;
-
-        // assign material and not color
-        //aShapeAttribs.Style.SetColorSurf (aMeshData->BaseColor());
-
-        Handle(XCAFDoc_VisMaterial) aMat;
-        myMaterials.Find (!aMeshData->MaterialPbr().IsNull() ? aMeshData->MaterialPbr()->Id : aMeshData->MaterialCommon()->Id, aMat);
-        aShapeAttribs.Style.SetMaterial (aMat);
-
-        myAttribMap->Bind (aFace, aShapeAttribs);
-      }
-      myFaceList.Append (aFace);
       ++aNbFaces;
     }
   }
@@ -1405,8 +1381,9 @@ bool RWGltf_GltfJsonParser::gltfParseMesh (TopoDS_Shape& theMeshShape,
 // function : gltfParsePrimArray
 // purpose  :
 // =======================================================================
-bool RWGltf_GltfJsonParser::gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
+bool RWGltf_GltfJsonParser::gltfParsePrimArray (TopoDS_Shape& thePrimArrayShape,
                                                 const TCollection_AsciiString& theMeshId,
+                                                const TCollection_AsciiString& theMeshName,
                                                 const RWGltf_JsonValue& thePrimArray)
 {
   const RWGltf_JsonValue* anAttribs = findObjectMember (thePrimArray, "attributes");
@@ -1447,22 +1424,69 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (const Handle(RWGltf_GltfLatePrim
     Message::SendWarning (TCollection_AsciiString() + "Primitive array within Mesh '" + theMeshId + "' skipped due to unsupported mode");
     return true;
   }
-  theMeshData->SetPrimitiveMode (aMode);
 
-  // assign material
+  const TCollection_AsciiString aMatId      = aMaterial != NULL ? getKeyString (*aMaterial) : TCollection_AsciiString();
+  const TCollection_AsciiString anIndicesId = anIndices != NULL ? getKeyString (*anIndices) : TCollection_AsciiString();
+  Handle(RWGltf_MaterialMetallicRoughness) aMatPbr;
+  Handle(RWGltf_MaterialCommon) aMatCommon;
+  Handle(XCAFDoc_VisMaterial) aMat;
   if (aMaterial != NULL)
   {
-    Handle(RWGltf_MaterialMetallicRoughness) aMatPbr;
-    if (myMaterialsPbr.Find (getKeyString (*aMaterial), aMatPbr))
+    if (myMaterialsPbr.Find (aMatId, aMatPbr))
     {
-      theMeshData->SetMaterialPbr (aMatPbr);
+      myMaterials.Find (aMatPbr->Id, aMat);
     }
+    if (myMaterialsCommon.Find (aMatId, aMatCommon))
+    {
+      if (aMat.IsNull())
+      {
+        myMaterials.Find (aMatCommon->Id, aMat);
+      }
+    }
+  }
 
-    Handle(RWGltf_MaterialCommon) aMatCommon;
-    if (myMaterialsCommon.Find (getKeyString (*aMaterial), aMatCommon))
+  // try reusing already loaded primitive array - generate a unique id
+  TCollection_AsciiString aPrimArrayId, aPrimArrayIdWithMat;
+  aPrimArrayId += TCollection_AsciiString (aMode);
+  aPrimArrayId += TCollection_AsciiString (":") + anIndicesId;
+  for (rapidjson::Value::ConstMemberIterator anAttribIter = anAttribs->MemberBegin();
+       anAttribIter != anAttribs->MemberEnd(); ++anAttribIter)
+  {
+    const TCollection_AsciiString anAttribId = getKeyString (anAttribIter->value);
+    aPrimArrayId += TCollection_AsciiString (":") + anAttribId;
+  }
+  aPrimArrayIdWithMat = aPrimArrayId + TCollection_AsciiString ("::") + aMatId;
+  if (myShapeMap[ShapeMapGroup_PrimArray].Find (aPrimArrayIdWithMat, thePrimArrayShape))
+  {
+    return true;
+  }
+  else if (myShapeMap[ShapeMapGroup_PrimArray].Find (aPrimArrayId, thePrimArrayShape))
+  {
+    if (myAttribMap != NULL)
     {
-      theMeshData->SetMaterialCommon (aMatCommon);
+      // sharing just triangulation is not much useful
+      //Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (TopoDS::Face (thePrimArrayShape), aDummy));
+      //TopoDS_Face aFaceCopy; BRep_Builder().MakeFace (aFaceCopy, aLateData);
+
+      // make a located Face copy
+      TopoDS_Shape aFaceCopy = thePrimArrayShape;
+      aFaceCopy.Location (TopLoc_Location (gp_Trsf()));
+      RWMesh_NodeAttributes aShapeAttribs;
+      aShapeAttribs.RawName = theMeshName;
+      aShapeAttribs.Style.SetMaterial (aMat);
+      myAttribMap->Bind (aFaceCopy, aShapeAttribs);
+      myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayIdWithMat, aFaceCopy);
+      thePrimArrayShape = aFaceCopy;
     }
+    return true;
+  }
+
+  Handle(RWGltf_GltfLatePrimitiveArray) aMeshData = new RWGltf_GltfLatePrimitiveArray (theMeshId, theMeshName);
+  aMeshData->SetPrimitiveMode (aMode);
+  if (aMaterial != NULL)
+  {
+    aMeshData->SetMaterialPbr (aMatPbr);
+    aMeshData->SetMaterialCommon (aMatCommon);
   }
 
   bool hasPositions = false;
@@ -1490,7 +1514,7 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (const Handle(RWGltf_GltfLatePrim
       reportGltfError ("Primitive array attribute accessor key '" + anAttribId + "' points to non-existing object.");
       return false;
     }
-    else if (!gltfParseAccessor (theMeshData, anAttribId, *anAccessor, aType, aDracoBuf))
+    else if (!gltfParseAccessor (aMeshData, anAttribId, *anAccessor, aType, aDracoBuf))
     {
       return false;
     }
@@ -1507,7 +1531,6 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (const Handle(RWGltf_GltfLatePrim
 
   if (anIndices != NULL)
   {
-    const TCollection_AsciiString anIndicesId = getKeyString (*anIndices);
     const RWGltf_JsonValue* anAccessor = myGltfRoots[RWGltf_GltfRootElement_Accessors].FindChild (*anIndices);
     if (anAccessor == NULL
     || !anAccessor->IsObject())
@@ -1515,16 +1538,38 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (const Handle(RWGltf_GltfLatePrim
       reportGltfError ("Primitive array indices accessor key '" + anIndicesId + "' points to non-existing object.");
       return false;
     }
-    else if (!gltfParseAccessor (theMeshData, anIndicesId, *anAccessor, RWGltf_GltfArrayType_Indices, aDracoBuf))
+    else if (!gltfParseAccessor (aMeshData, anIndicesId, *anAccessor, RWGltf_GltfArrayType_Indices, aDracoBuf))
     {
       return false;
     }
   }
   else
   {
-    theMeshData->SetNbDeferredTriangles (theMeshData->NbDeferredNodes() / 3);
+    aMeshData->SetNbDeferredTriangles (aMeshData->NbDeferredNodes() / 3);
   }
 
+  if (!aMeshData->Data().IsEmpty())
+  {
+    TopoDS_Face aFace;
+    BRep_Builder aBuilder;
+    aBuilder.MakeFace (aFace, aMeshData);
+    if (myAttribMap != NULL
+     && aMeshData->HasStyle())
+    {
+      RWMesh_NodeAttributes aShapeAttribs;
+      aShapeAttribs.RawName = theMeshName;
+
+      // assign material and not color
+      //aShapeAttribs.Style.SetColorSurf (aMeshData->BaseColor());
+      aShapeAttribs.Style.SetMaterial (aMat);
+
+      myAttribMap->Bind (aFace, aShapeAttribs);
+    }
+    myFaceList.Append (aFace);
+    myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayId, aFace);
+    myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayIdWithMat, aFace);
+    thePrimArrayShape = aFace;
+  }
   return true;
 }
 
@@ -1873,6 +1918,7 @@ void RWGltf_GltfJsonParser::bindNamedShape (TopoDS_Shape& theShape,
     return;
   }
 
+  TopoDS_Shape aShape = theShape;
   if (!theLoc.IsIdentity())
   {
     if (!theShape.Location().IsIdentity())
@@ -1896,31 +1942,32 @@ void RWGltf_GltfJsonParser::bindNamedShape (TopoDS_Shape& theShape,
     aUserName = theId;
   }
 
-  myShapeMap[theGroup].Bind (theId, theShape);
   if (myAttribMap != NULL)
   {
     RWMesh_NodeAttributes aShapeAttribs;
-    aShapeAttribs.Name    = aUserName;
-    aShapeAttribs.RawName = theId;
+    aShapeAttribs.Name = aUserName;
+    if (myIsGltf1)
+    {
+      aShapeAttribs.RawName = theId;
+    }
     if (theShape.ShapeType() == TopAbs_FACE)
     {
-      TopLoc_Location aDummy;
-      if (Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (TopoDS::Face (theShape), aDummy)))
+      RWMesh_NodeAttributes aFaceAttribs;
+      if (myAttribMap->Find (aShape, aFaceAttribs))
       {
-        if (aLateData->HasStyle())
-        {
-          // assign material and not color
-          //aShapeAttribs.Style.SetColorSurf (aLateData->BaseColor());
-
-          Handle(XCAFDoc_VisMaterial) aMat;
-          myMaterials.Find (!aLateData->MaterialPbr().IsNull() ? aLateData->MaterialPbr()->Id : aLateData->MaterialCommon()->Id, aMat);
-          aShapeAttribs.Style.SetMaterial (aMat);
-        }
+        aShapeAttribs.Style.SetMaterial (aFaceAttribs.Style.Material());
         if (aShapeAttribs.Name.IsEmpty()
          && myUseMeshNameAsFallback)
         {
           // fallback using Mesh name
-          aShapeAttribs.Name = aLateData->Name();
+          aShapeAttribs.Name = aFaceAttribs.RawName;
+        }
+        else if (!aFaceAttribs.Name.IsEmpty()
+               && theLoc.IsIdentity()
+               && theGroup == ShapeMapGroup_Nodes)
+        {
+          // keep Product name (from Mesh) separated from Instance name (from Node)
+          theShape.Location (TopLoc_Location (gp_Trsf()) * theShape.Location(), Standard_False);
         }
       }
     }
@@ -1955,8 +2002,20 @@ void RWGltf_GltfJsonParser::bindNamedShape (TopoDS_Shape& theShape,
         aShapeAttribs.Name = aMeshName;
       }
     }
+    else if (!aShapeAttribs.Name.IsEmpty()
+           && theGroup == ShapeMapGroup_Nodes)
+    {
+      RWMesh_NodeAttributes anOldAttribs;
+      if (myAttribMap->Find (aShape, anOldAttribs)
+      && !anOldAttribs.Name.IsEmpty())
+      {
+        // keep Product name (from Mesh) separated from Instance name (from Node)
+        theShape.Location (TopLoc_Location (gp_Trsf()) * theShape.Location(), Standard_False);
+      }
+    }
     myAttribMap->Bind (theShape, aShapeAttribs);
   }
+  myShapeMap[theGroup].Bind (theId, theShape);
 }
 #endif
 
index b285932..922b979 100644 (file)
@@ -188,7 +188,8 @@ protected:
                                       const RWGltf_JsonValue& theMesh);
 
   //! Parse primitive array.
-  Standard_EXPORT bool gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
+  Standard_EXPORT bool gltfParsePrimArray (TopoDS_Shape& thePrimArrayShape,
+                                           const TCollection_AsciiString& theMeshId,
                                            const TCollection_AsciiString& theMeshName,
                                            const RWGltf_JsonValue& thePrimArray);
 
@@ -284,8 +285,9 @@ protected:
   //! Groups for re-using shapes.
   enum ShapeMapGroup
   {
-    ShapeMapGroup_Nodes,  //!< nodes
-    ShapeMapGroup_Meshes, //!< meshes
+    ShapeMapGroup_Nodes,     //!< nodes
+    ShapeMapGroup_Meshes,    //!< meshes
+    ShapeMapGroup_PrimArray, //!< primitive array
   };
 
   //! Bind name attribute.
@@ -416,7 +418,7 @@ protected:
   NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialMetallicRoughness)> myMaterialsPbr;
   NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialCommon)> myMaterialsCommon;
   NCollection_DataMap<TCollection_AsciiString, Handle(XCAFDoc_VisMaterial)> myMaterials;
-  NCollection_DataMap<TCollection_AsciiString, TopoDS_Shape> myShapeMap[2];
+  NCollection_DataMap<TCollection_AsciiString, TopoDS_Shape> myShapeMap[3];
 
   NCollection_DataMap<TCollection_AsciiString, bool> myProbedFiles;
   NCollection_DataMap<TCollection_AsciiString, Handle(NCollection_Buffer)> myDecodedBuffers;
index f998d3b..64c9b6e 100644 (file)
@@ -402,6 +402,12 @@ Standard_Boolean RWMesh_CafReader::addShapeIntoDoc (CafDocumentTools& theTools,
         hasProductName = true;
         setShapeName (aNewRefLabel, aShapeType, aShapeAttribs.Name, theLabel, theParentName);
       }
+      else if (aShapeAttribs.Name.IsEmpty()
+           && !aRefShapeAttribs.Name.IsEmpty())
+      {
+        // copy name from Product
+        setShapeName (aNewLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
+      }
     }
     else
     {
index a19ee16..a7f6d58 100644 (file)
@@ -42,12 +42,13 @@ RWMesh_FaceIterator::RWMesh_FaceIterator (const TDF_Label&       theLabel,
     return;
   }
 
-  aShape.Location (theLocation);
+  aShape.Location (theLocation, false);
   myFaceIter.Init (aShape, TopAbs_FACE);
 
   if (theToMapColors)
   {
     dispatchStyles (theLabel, theLocation, theStyle);
+    myStyles.Bind (aShape, theStyle);
   }
 
   Next();
index 3efb8b1..eda810b 100644 (file)
@@ -17,8 +17,8 @@ WriteGltf D0 "$aTmpGltf2" -mergeFaces
 
 ReadGltf D1 "$aTmpGltf1"
 XGetOneShape s1 D1
-checknbshapes s1 -face 160 -compound 28
+checknbshapes s1 -face 53 -compound 28
 
 ReadGltf D "$aTmpGltf2"
 XGetOneShape s2 D
-checknbshapes s2 -face 18 -compound 10
+checknbshapes s2 -face 5 -compound 10
diff --git a/tests/de_mesh/gltf_write/spheres b/tests/de_mesh/gltf_write/spheres
new file mode 100644 (file)
index 0000000..ec01a88
--- /dev/null
@@ -0,0 +1,56 @@
+puts "========"
+puts "0032107: Data Exchange, RWGltf_CafReader - reading glTF document back loses sharing"
+puts "========"
+
+vclear
+vclose ALL
+Close *
+source $env(CSF_OCCTSamplesPath)/tcl/vis_pbr_spheres.tcl
+vdump "${imagedir}/${casename}_0.png"
+
+set aTmpGltf1  "${imagedir}/${casename}_tmp1.glb"
+set aTmpGltf1m "${imagedir}/${casename}_tmp1m.glb"
+set aTmpGltf2  "${imagedir}/${casename}_tmp2.glb"
+set aTmpGltf2m "${imagedir}/${casename}_tmp2m.glb"
+lappend occ_tmp_files $aTmpGltf1
+lappend occ_tmp_files $aTmpGltf1m
+lappend occ_tmp_files $aTmpGltf2
+lappend occ_tmp_files $aTmpGltf2m
+
+WriteGltf D "$aTmpGltf1"
+puts [file size "$aTmpGltf1"]
+WriteGltf D "$aTmpGltf1m" -mergeFaces
+puts [file size "$aTmpGltf1m"]
+
+ReadGltf D1 "$aTmpGltf1"
+XGetOneShape s1 D1
+checknbshapes s1 -face 26 -compound 22
+vclear
+XDisplay D1 -dispMode 1
+vdump "${imagedir}/${casename}_1.png"
+
+ReadGltf D1m "$aTmpGltf1m"
+XGetOneShape s1m D1m
+checknbshapes s1m -face 5 -compound 18
+vclear
+XDisplay D1m -dispMode 1
+vdump "${imagedir}/${casename}_1m.png"
+
+WriteGltf D1  "$aTmpGltf2"
+puts [file size "$aTmpGltf2"]
+WriteGltf D1m "$aTmpGltf2m" -mergeFaces
+puts [file size "$aTmpGltf2m"]
+
+ReadGltf D2 "$aTmpGltf2"
+XGetOneShape s2 D2
+checknbshapes s2 -face 26 -compound 22
+vclear
+XDisplay D2 -dispMode 1
+vdump "${imagedir}/${casename}_2.png"
+
+ReadGltf D2m "$aTmpGltf2m"
+XGetOneShape s2m D2m
+checknbshapes s2m -face 5 -compound 18
+vclear
+XDisplay D2m -dispMode 1
+vdump "${imagedir}/${casename}_2m.png"