From 47f274b16114ce8b49301f80100de4fcff03adf4 Mon Sep 17 00:00:00 2001 From: mzernova Date: Sun, 5 Jan 2025 22:47:18 +0000 Subject: [PATCH] GLTF Import - Edge and Vertex support #242 Added functionality to import Points and Lines from GLTF format --- src/RWGltf/RWGltf_GltfJsonParser.cxx | 125 ++++++++++++--- src/RWGltf/RWGltf_GltfLatePrimitiveArray.cxx | 2 +- src/RWGltf/RWGltf_GltfLatePrimitiveArray.hxx | 2 +- src/RWGltf/RWGltf_TriangulationReader.cxx | 85 ++++++---- src/RWGltf/RWGltf_TriangulationReader.hxx | 18 +-- src/RWMesh/RWMesh_TriangulationReader.cxx | 159 ++++++++++++++++++- src/RWMesh/RWMesh_TriangulationReader.hxx | 129 +++++---------- src/RWMesh/RWMesh_TriangulationSource.cxx | 17 +- src/RWMesh/RWMesh_TriangulationSource.hxx | 42 ++++- tests/de_mesh/gltf_write/empty | 2 +- tests/de_mesh/gltf_write/primitives | 39 +++++ 11 files changed, 456 insertions(+), 164 deletions(-) create mode 100644 tests/de_mesh/gltf_write/primitives diff --git a/src/RWGltf/RWGltf_GltfJsonParser.cxx b/src/RWGltf/RWGltf_GltfJsonParser.cxx index f6073feee4..22014bcd1b 100644 --- a/src/RWGltf/RWGltf_GltfJsonParser.cxx +++ b/src/RWGltf/RWGltf_GltfJsonParser.cxx @@ -15,7 +15,7 @@ #include "RWGltf_GltfJsonParser.hxx" #include -#include +#include #include #include #include @@ -24,11 +24,13 @@ #include #include #include -#include +#include #include #include #include +#include #include +#include #include @@ -1530,7 +1532,9 @@ bool RWGltf_GltfJsonParser::gltfParseSceneNodes (TopTools_SequenceOfShape& theSh continue; } else if (myToSkipEmptyNodes - && !TopExp_Explorer (aNodeShape, TopAbs_FACE).More()) + && !TopExp_Explorer (aNodeShape, TopAbs_FACE).More() + && !TopExp_Explorer (aNodeShape, TopAbs_EDGE).More() + && !TopExp_Explorer (aNodeShape, TopAbs_VERTEX).More()) { continue; } @@ -1782,7 +1786,9 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (TopoDS_Shape& thePrimArrayShape, return false; } } - if (aMode != RWGltf_GltfPrimitiveMode_Triangles) + if (aMode != RWGltf_GltfPrimitiveMode_Triangles + && aMode != RWGltf_GltfPrimitiveMode_Lines + && aMode != RWGltf_GltfPrimitiveMode_Points) { Message::SendWarning (TCollection_AsciiString() + "Primitive array within Mesh '" + theMeshId + "' skipped due to unsupported mode"); return true; @@ -1827,19 +1833,15 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (TopoDS_Shape& thePrimArrayShape, { if (myAttribMap != NULL) { - // 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())); + // make a located Shape copy + TopoDS_Shape aShapeCopy = thePrimArrayShape; + aShapeCopy.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; + myAttribMap->Bind (aShapeCopy, aShapeAttribs); + myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayIdWithMat, aShapeCopy); + thePrimArrayShape = aShapeCopy; } return true; } @@ -1906,32 +1908,95 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (TopoDS_Shape& thePrimArrayShape, return false; } } - else + else if (aMode == RWGltf_GltfPrimitiveMode_Triangles) { aMeshData->SetNbDeferredTriangles (aMeshData->NbDeferredNodes() / 3); } + else + { + aMeshData->SetNbDeferredTriangles (0); + } if (!aMeshData->Data().IsEmpty()) { - TopoDS_Face aFace; - BRep_Builder aBuilder; - aBuilder.MakeFace (aFace, aMeshData); + if (aMode != RWGltf_GltfPrimitiveMode_Triangles) + { + Message::SendWarning("Deferred loading is available only for triangulations. Other elements " + "will be loaded immediately."); + Handle(RWGltf_TriangulationReader) aReader = new RWGltf_TriangulationReader(); + aReader->SetCoordinateSystemConverter(myCSTrsf); + aMeshData->SetReader(aReader); + aMeshData->LoadDeferredData(); + } + + TopoDS_Shape aShape; + switch (aMode) + { + case RWGltf_GltfPrimitiveMode_Points: { + BRep_Builder aBuilder; + TopoDS_Compound aVertices; + aBuilder.MakeCompound(aVertices); + for (Standard_Integer aNodeIdx = 1; aNodeIdx <= aMeshData->NbNodes(); ++aNodeIdx) + { + //gp_Pnt point = aMeshData->Node(aNodeIdx); + //Message::SendInfo() << "Node Points " << i << ": (" << point.X() << ", " << point.Y() + // << ", " << point.Z() << ")"; + + TopoDS_Vertex aVertex; + aBuilder.MakeVertex(aVertex, aMeshData->Node(aNodeIdx), Precision::Confusion()); + aBuilder.Add(aVertices, aVertex); + } + aShape = aVertices; + break; + } + case RWGltf_GltfPrimitiveMode_Lines: { + TColgp_Array1OfPnt aNodes(1, aMeshData->NbEdges()); + for (Standard_Integer anEdgeIdx = 1; anEdgeIdx <= aMeshData->NbEdges(); ++anEdgeIdx) + { + Standard_Integer aNodeIdx = aMeshData->Edge(anEdgeIdx); + aNodes.SetValue(anEdgeIdx, aMeshData->Node(aNodeIdx)); + + //gp_Pnt point = aMeshData->Node(aNodeIdx); + //Message::SendInfo() << "Node Lines " << aNodeIdx << ": (" << point.X() << ", " + // << point.Y() << ", " << point.Z() << ")"; + } + TopoDS_Edge anEdge; + BRep_Builder aBuilder; + Handle(Poly_Polygon3D) aPoly = new Poly_Polygon3D(aNodes); + aBuilder.MakeEdge(anEdge, aPoly); + + aShape = anEdge; + break; + } + case RWGltf_GltfPrimitiveMode_Triangles: { + TopoDS_Face aFace; + BRep_Builder aBuilder; + aBuilder.MakeFace(aFace, aMeshData); + aShape = aFace; + myFaceList.Append(aFace); + break; + } + default: { + Message::SendFail("Unsupported primitive mode."); + return false; + break; + } + } if (myAttribMap != NULL - && aMeshData->HasStyle()) + && aMeshData->HasStyle()) { RWMesh_NodeAttributes aShapeAttribs; aShapeAttribs.RawName = theMeshName; // assign material and not color //aShapeAttribs.Style.SetColorSurf (aMeshData->BaseColor()); - aShapeAttribs.Style.SetMaterial (aMat); + aShapeAttribs.Style.SetMaterial(aMat); - myAttribMap->Bind (aFace, aShapeAttribs); + myAttribMap->Bind (aShape, aShapeAttribs); } - myFaceList.Append (aFace); - myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayId, aFace); - myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayIdWithMat, aFace); - thePrimArrayShape = aFace; + myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayId, aShape); + myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayIdWithMat, aShape); + thePrimArrayShape = aShape; } return true; } @@ -2085,7 +2150,15 @@ bool RWGltf_GltfJsonParser::gltfParseAccessor (const Handle(RWGltf_GltfLatePrimi } else if (theType == RWGltf_GltfArrayType_Indices) { - theMeshData->SetNbDeferredTriangles ((Standard_Integer )(aStruct.Count / 3)); + if (theMeshData->PrimitiveMode() == RWGltf_GltfPrimitiveMode_Triangles) + { + theMeshData->SetNbDeferredTriangles ((Standard_Integer)(aStruct.Count / 3)); + } + else + { + theMeshData->SetNbDeferredNodes ((Standard_Integer)(aStruct.Count)); + theMeshData->SetNbDeferredTriangles (0); + } } const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName); diff --git a/src/RWGltf/RWGltf_GltfLatePrimitiveArray.cxx b/src/RWGltf/RWGltf_GltfLatePrimitiveArray.cxx index ebca9dc366..808699add3 100644 --- a/src/RWGltf/RWGltf_GltfLatePrimitiveArray.cxx +++ b/src/RWGltf/RWGltf_GltfLatePrimitiveArray.cxx @@ -103,7 +103,7 @@ Handle(Poly_Triangulation) RWGltf_GltfLatePrimitiveArray::LoadStreamData() const { return Handle(Poly_Triangulation)(); } - Handle(Poly_Triangulation) aResult = createNewEntity(); + Handle(RWMesh_TriangulationSource) aResult = new RWMesh_TriangulationSource(); if (!aGltfReader->LoadStreamData (this, aResult)) { return Handle(Poly_Triangulation)(); diff --git a/src/RWGltf/RWGltf_GltfLatePrimitiveArray.hxx b/src/RWGltf/RWGltf_GltfLatePrimitiveArray.hxx index 10e2d299b7..fd88b637f9 100644 --- a/src/RWGltf/RWGltf_GltfLatePrimitiveArray.hxx +++ b/src/RWGltf/RWGltf_GltfLatePrimitiveArray.hxx @@ -82,7 +82,7 @@ public: //! that can be loaded using LoadDeferredData(). virtual Standard_Boolean HasDeferredData() const Standard_OVERRIDE { - return !myData.IsEmpty() && RWMesh_TriangulationSource::HasDeferredData(); + return !myData.IsEmpty() && (NbDeferredTriangles() > 0 || NbDeferredNodes() > 0); } //! Load primitive array saved as stream buffer to new triangulation object. diff --git a/src/RWGltf/RWGltf_TriangulationReader.cxx b/src/RWGltf/RWGltf_TriangulationReader.cxx index c528ae6134..b4d8e8c5ce 100644 --- a/src/RWGltf/RWGltf_TriangulationReader.cxx +++ b/src/RWGltf/RWGltf_TriangulationReader.cxx @@ -107,7 +107,7 @@ void RWGltf_TriangulationReader::reportError (const TCollection_AsciiString& the // purpose : // ======================================================================= bool RWGltf_TriangulationReader::LoadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh) const + const Handle(RWMesh_TriangulationSource)& theDestMesh) const { Standard_ASSERT_RETURN (!theDestMesh.IsNull(), "The destination mesh should be initialized before loading data to it", false); theDestMesh->Clear(); @@ -132,7 +132,7 @@ bool RWGltf_TriangulationReader::LoadStreamData (const Handle(RWMesh_Triangulati // ======================================================================= bool RWGltf_TriangulationReader::readStreamData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh, const RWGltf_GltfPrimArrayData& theGltfData, - const Handle(Poly_Triangulation)& theDestMesh) const + const Handle(RWMesh_TriangulationSource)& theDestMesh) const { Standard_ArrayStreamBuffer aStreamBuffer ((const char* )theGltfData.StreamData->Data(), theGltfData.StreamData->Size()); std::istream aStream (&aStreamBuffer); @@ -150,7 +150,7 @@ bool RWGltf_TriangulationReader::readStreamData (const Handle(RWGltf_GltfLatePri // ======================================================================= bool RWGltf_TriangulationReader::readFileData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh, const RWGltf_GltfPrimArrayData& theGltfData, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, const Handle(OSD_FileSystem)& theFileSystem) const { const Handle(OSD_FileSystem)& aFileSystem = !theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem(); @@ -174,7 +174,7 @@ bool RWGltf_TriangulationReader::readFileData (const Handle(RWGltf_GltfLatePrimi // purpose : // ======================================================================= bool RWGltf_TriangulationReader::loadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, bool theToResetStream) const { const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh); @@ -210,7 +210,7 @@ bool RWGltf_TriangulationReader::loadStreamData (const Handle(RWMesh_Triangulati // ======================================================================= bool RWGltf_TriangulationReader::readDracoBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh, const RWGltf_GltfPrimArrayData& theGltfData, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, const Handle(OSD_FileSystem)& theFileSystem) const { const TCollection_AsciiString& aName = theSourceGltfMesh->Id(); @@ -422,7 +422,7 @@ bool RWGltf_TriangulationReader::readDracoBuffer (const Handle(RWGltf_GltfLatePr // purpose : // ======================================================================= bool RWGltf_TriangulationReader::load (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, const Handle(OSD_FileSystem)& theFileSystem) const { const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh); @@ -477,7 +477,7 @@ bool RWGltf_TriangulationReader::load (const Handle(RWMesh_TriangulationSource)& // purpose : // ======================================================================= bool RWGltf_TriangulationReader::finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh) const + const Handle(RWMesh_TriangulationSource)& theDestMesh) const { if (theDestMesh->NbNodes() < 1) { @@ -514,16 +514,19 @@ bool RWGltf_TriangulationReader::finalizeLoading (const Handle(RWMesh_Triangulat // purpose : // ======================================================================= bool RWGltf_TriangulationReader::readBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, std::istream& theStream, const RWGltf_GltfAccessor& theAccessor, RWGltf_GltfArrayType theType) const { - const TCollection_AsciiString& aName = theSourceMesh->Id(); - if (theSourceMesh->PrimitiveMode() != RWGltf_GltfPrimitiveMode_Triangles) + const TCollection_AsciiString& aName = theSourceMesh->Id(); + const RWGltf_GltfPrimitiveMode aPrimMode = theSourceMesh->PrimitiveMode(); + if (aPrimMode != RWGltf_GltfPrimitiveMode_Triangles && aPrimMode != RWGltf_GltfPrimitiveMode_Lines + && aPrimMode != RWGltf_GltfPrimitiveMode_Points) { - Message::SendWarning (TCollection_AsciiString("Buffer '") + aName + "' skipped unsupported primitive array"); + Message::SendWarning(TCollection_AsciiString("Buffer '") + aName + + "' skipped unsupported primitive array"); return true; } @@ -545,8 +548,12 @@ bool RWGltf_TriangulationReader::readBuffer (const Handle(RWGltf_GltfLatePrimiti return false; } - const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3); - if (!setNbTriangles (theDestMesh, aNbTris)) + const Standard_Boolean isTriangles = aPrimMode == RWGltf_GltfPrimitiveMode_Triangles; + const Standard_Integer aCounter = isTriangles + ? (Standard_Integer )(theAccessor.Count / 3) + : (Standard_Integer )(theAccessor.Count); + if ((isTriangles && !setNbTriangles(theDestMesh, aCounter)) + || !setNbEdges(theDestMesh, aCounter)) { return false; } @@ -554,41 +561,51 @@ bool RWGltf_TriangulationReader::readBuffer (const Handle(RWGltf_GltfLatePrimiti ? theAccessor.ByteStride : sizeof(uint16_t); Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride); - Standard_Integer aLastTriIndex = 0; - for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter) + Standard_Integer aLastIndex = 0; + for (Standard_Integer aTriIter = 0; aTriIter < aCounter; ++aTriIter) { - if (const uint16_t* anIndex0 = aBuffer.ReadChunk (theStream)) - { - aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + *anIndex0; - } - if (const uint16_t* anIndex1 = aBuffer.ReadChunk (theStream)) - { - aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + *anIndex1; - } - if (const uint16_t* anIndex2 = aBuffer.ReadChunk (theStream)) - { - aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + *anIndex2; + Standard_Integer wasSet = false; + if (isTriangles) + { + for (Standard_Integer anIter = 1; anIter <= 3; ++anIter) + { + const uint16_t* anIndex = aBuffer.ReadChunk(theStream); + if (anIndex == nullptr) + { + reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error."); + return false; + } + aVec3.ChangeValue(anIter) = THE_LOWER_NODE_INDEX + *anIndex; + } + wasSet = setTriangle(theDestMesh, THE_LOWER_TRI_INDEX + aLastIndex, aVec3); } else { - reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error."); - return false; + const uint16_t* anIndex = aBuffer.ReadChunk(theStream); + if (anIndex == nullptr) + { + reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error."); + return false; + } + wasSet = setEdge(theDestMesh, + THE_LOWER_TRI_INDEX + aLastIndex, + THE_LOWER_NODE_INDEX + *anIndex); } - const Standard_Integer wasSet = setTriangle (theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3); if (!wasSet) { - reportError (TCollection_AsciiString ("Buffer '") + aName + "' refers to invalid indices."); + reportError(TCollection_AsciiString("Buffer '") + aName + + "' refers to invalid indices."); } if (wasSet > 0) { - aLastTriIndex++; + aLastIndex++; } } - const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex; + const Standard_Integer aNbDegenerate = aCounter - aLastIndex; if (aNbDegenerate > 0) { - if (aNbDegenerate == aNbTris) + if (aNbDegenerate == aCounter) { Message::SendWarning (TCollection_AsciiString("Buffer '") + aName + "' has been skipped (all elements are degenerative in)"); return false; @@ -599,7 +616,7 @@ bool RWGltf_TriangulationReader::readBuffer (const Handle(RWGltf_GltfLatePrimiti Message::SendTrace (TCollection_AsciiString() + aNbDegenerate + " degenerate triangles have been skipped while reading glTF triangulation '" + aName + "'"); } - if (!setNbTriangles (theDestMesh, aLastTriIndex, true)) + if (!setNbTriangles (theDestMesh, aLastIndex, true)) { return false; } diff --git a/src/RWGltf/RWGltf_TriangulationReader.hxx b/src/RWGltf/RWGltf_TriangulationReader.hxx index 649b8f3456..c627fe0eca 100644 --- a/src/RWGltf/RWGltf_TriangulationReader.hxx +++ b/src/RWGltf/RWGltf_TriangulationReader.hxx @@ -34,7 +34,7 @@ public: //! Loads only primitive arrays saved as stream buffer //! (it is primarily glTF data encoded in base64 saved to temporary buffer during glTF file reading). Standard_EXPORT bool LoadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh) const; + const Handle(RWMesh_TriangulationSource)& theDestMesh) const; protected: @@ -47,14 +47,14 @@ protected: //! @param theFileSystem shared file system to read from //! Note: this method skips "stream data" that should be loaded by LoadStreamData() call. Standard_EXPORT virtual bool load (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, const Handle(OSD_FileSystem)& theFileSystem) const Standard_OVERRIDE; //! Performs additional actions to finalize data loading. //! @param theSourceMesh source triangulation //! @param theDestMesh triangulation to be modified Standard_EXPORT virtual bool finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh) const Standard_OVERRIDE; + const Handle(RWMesh_TriangulationSource)& theDestMesh) const Standard_OVERRIDE; //! Loads only primitive arrays saved as stream buffer //! (it is primarily glTF data encoded in base64 saved to temporary buffer during glTF file reading). @@ -62,7 +62,7 @@ protected: //! @param theDestMesh triangulation to be modified //! @param theToResetStream if TRUE reset input stream data buffer after its loading. Standard_EXPORT bool loadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, bool theToResetStream = true) const; //! Reads primitive array from stream data. @@ -71,7 +71,7 @@ protected: //! @param theDestMesh triangulation to be modified Standard_EXPORT bool readStreamData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh, const RWGltf_GltfPrimArrayData& theGltfData, - const Handle(Poly_Triangulation)& theDestMesh) const; + const Handle(RWMesh_TriangulationSource)& theDestMesh) const; //! Reads primitive array from file data. //! @param theSourceGltfMesh source glTF triangulation @@ -80,7 +80,7 @@ protected: //! @param theFileSystem shared file system to read from Standard_EXPORT bool readFileData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh, const RWGltf_GltfPrimArrayData& theGltfData, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, const Handle(OSD_FileSystem)& theFileSystem) const; //! Fills triangulation data and ignore non-triangulation primitives. @@ -91,7 +91,7 @@ protected: //! @param theType array type //! @return FALSE on error Standard_EXPORT virtual bool readBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, std::istream& theStream, const RWGltf_GltfAccessor& theAccessor, RWGltf_GltfArrayType theType) const; @@ -103,12 +103,12 @@ protected: //! @param theFileSystem shared file system to read from Standard_EXPORT virtual bool readDracoBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh, const RWGltf_GltfPrimArrayData& theGltfData, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, const Handle(OSD_FileSystem)& theFileSystem) const; protected: - Handle(Poly_Triangulation) myTriangulation; + Handle(RWMesh_TriangulationSource) myTriangulation; }; diff --git a/src/RWMesh/RWMesh_TriangulationReader.cxx b/src/RWMesh/RWMesh_TriangulationReader.cxx index bc001ffe73..99b79fd840 100644 --- a/src/RWMesh/RWMesh_TriangulationReader.cxx +++ b/src/RWMesh/RWMesh_TriangulationReader.cxx @@ -97,7 +97,7 @@ RWMesh_TriangulationReader::~RWMesh_TriangulationReader() // purpose : // ======================================================================= bool RWMesh_TriangulationReader::Load (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, const Handle(OSD_FileSystem)& theFileSystem) const { Standard_ASSERT_RETURN (!theDestMesh.IsNull(), "The destination mesh should be initialized before loading data to it", false); @@ -122,7 +122,7 @@ bool RWMesh_TriangulationReader::Load (const Handle(RWMesh_TriangulationSource)& // purpose : // ======================================================================= bool RWMesh_TriangulationReader::finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh) const + const Handle(RWMesh_TriangulationSource)& theDestMesh) const { if (!theSourceMesh->CachedMinMax().IsVoid()) { @@ -147,3 +147,158 @@ bool RWMesh_TriangulationReader::finalizeLoading (const Handle(RWMesh_Triangulat } return true; } + +// ======================================================================= +// function : setNbPositionNodes +// purpose : +// ======================================================================= +bool RWMesh_TriangulationReader::setNbPositionNodes( + const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theNbNodes, + Standard_Boolean theToCopyData) const +{ + if (theNbNodes <= 0) + { + return false; + } + theMesh->ResizeNodes(theNbNodes, theToCopyData); + return true; +} + +// ======================================================================= +// function : setNodePosition +// purpose : +// ======================================================================= +void RWMesh_TriangulationReader::setNodePosition(const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theIndex, + const gp_Pnt& thePnt) const +{ + theMesh->SetNode(theIndex, thePnt); +} + +// ======================================================================= +// function : setNbUVNodes +// purpose : +// ======================================================================= +bool RWMesh_TriangulationReader::setNbUVNodes(const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theNbNodes) const +{ + if (theNbNodes <= 0 || theMesh->NbNodes() != theNbNodes) + { + return false; + } + theMesh->AddUVNodes(); + return true; +} + +// ======================================================================= +// function : setNodeUV +// purpose : +// ======================================================================= +void RWMesh_TriangulationReader::setNodeUV(const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theIndex, + const gp_Pnt2d& theUV) const +{ + theMesh->SetUVNode(theIndex, theUV); +} + +// ======================================================================= +// function : setNbNormalNodes +// purpose : +// ======================================================================= +bool RWMesh_TriangulationReader::setNbNormalNodes(const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theNbNodes) const +{ + if (theNbNodes <= 0 || theMesh->NbNodes() != theNbNodes) + { + return false; + } + theMesh->AddNormals(); + return true; +} + +// ======================================================================= +// function : setNodeNormal +// purpose : +// ======================================================================= +void RWMesh_TriangulationReader::setNodeNormal(const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theIndex, + const gp_Vec3f& theNormal) const +{ + theMesh->SetNormal(theIndex, theNormal); +} + +// ======================================================================= +// function : setNbTriangles +// purpose : +// ======================================================================= +bool RWMesh_TriangulationReader::setNbTriangles(const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theNbTris, + Standard_Boolean theToCopyData) const +{ + if (theNbTris >= 1) + { + theMesh->ResizeTriangles(theNbTris, theToCopyData); + return true; + } + return false; +} + +// ======================================================================= +// function : setTriangle +// purpose : +// ======================================================================= +Standard_Integer RWMesh_TriangulationReader::setTriangle( + const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theIndex, + const Poly_Triangle& theTriangle) const +{ + if (theTriangle.Value(1) < 1 || theTriangle.Value(1) > theMesh->NbNodes() + || theTriangle.Value(2) < 1 || theTriangle.Value(2) > theMesh->NbNodes() + || theTriangle.Value(3) < 1 || theTriangle.Value(3) > theMesh->NbNodes()) + { + return 0; + } + if (myToSkipDegenerateTris + && (theTriangle.Value(1) == theTriangle.Value(2) + || theTriangle.Value(1) == theTriangle.Value(3) + || theTriangle.Value(2) == theTriangle.Value(3))) + { + return -1; + } + theMesh->SetTriangle(theIndex, theTriangle); + return 1; +} + +// ======================================================================= +// function : setNbEdges +// purpose : +// ======================================================================= +bool RWMesh_TriangulationReader::setNbEdges(const Handle(RWMesh_TriangulationSource)& theMesh, + const Standard_Integer theNbTris, + const Standard_Boolean theToCopyData) const +{ + if (theNbTris >= 1) + { + theMesh->ResizeEdges(theNbTris, theToCopyData); + return true; + } + return false; +} + +// ======================================================================= +// function : setEdge +// purpose : +// ======================================================================= +Standard_Integer RWMesh_TriangulationReader::setEdge( + const Handle(RWMesh_TriangulationSource)& theMesh, + const Standard_Integer theIndex, + const Standard_Integer theEdge) const +{ + if (theEdge < 1 || theEdge > theMesh->NbNodes()) + { + return 0; + } + theMesh->SetEdge(theIndex, theEdge); + return 1; +} diff --git a/src/RWMesh/RWMesh_TriangulationReader.hxx b/src/RWMesh/RWMesh_TriangulationReader.hxx index c3b3b1def1..b6a275ad1a 100644 --- a/src/RWMesh/RWMesh_TriangulationReader.hxx +++ b/src/RWMesh/RWMesh_TriangulationReader.hxx @@ -126,19 +126,19 @@ public: //! Loads primitive array. Standard_EXPORT bool Load (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, const Handle(OSD_FileSystem)& theFileSystem) const; protected: //! Loads primitive array. Standard_EXPORT virtual bool load (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh, + const Handle(RWMesh_TriangulationSource)& theDestMesh, const Handle(OSD_FileSystem)& theFileSystem) const = 0; //! Performs additional actions to finalize data loading. Standard_EXPORT virtual bool finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh, - const Handle(Poly_Triangulation)& theDestMesh) const; + const Handle(RWMesh_TriangulationSource)& theDestMesh) const; protected: //! @name interface for filling triangulation data @@ -147,99 +147,56 @@ protected: //! @name interface for filling triangulation data //! @param[in] theNbNodes nodes number //! @param[in] theToCopyData copy old nodes into new array //! @return TRUE in case of success operation - virtual bool setNbPositionNodes (const Handle(Poly_Triangulation)& theMesh, - Standard_Integer theNbNodes, - Standard_Boolean theToCopyData = false) const - { - if (theNbNodes <= 0) - { - return false; - } - theMesh->ResizeNodes (theNbNodes, theToCopyData); - return true; - } + Standard_EXPORT virtual bool setNbPositionNodes (const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theNbNodes, + Standard_Boolean theToCopyData = false) const; //! Sets node position. //! @param[in] theMesh triangulation to be modified //! @param[in] theIndex node index starting from 1 //! @param[in] thePnt node position - virtual void setNodePosition (const Handle(Poly_Triangulation)& theMesh, - Standard_Integer theIndex, - const gp_Pnt& thePnt) const - { - theMesh->SetNode (theIndex, thePnt); - } + Standard_EXPORT virtual void setNodePosition (const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theIndex, + const gp_Pnt& thePnt) const; //! Resizes array of UV nodes to specified size. //! @param[in] theMesh triangulation to be modified //! @param[in] theNbNodes nodes number //! @return TRUE in case of success operation - virtual bool setNbUVNodes (const Handle(Poly_Triangulation)& theMesh, - Standard_Integer theNbNodes) const - { - if (theNbNodes <= 0 - || theMesh->NbNodes() != theNbNodes) - { - return false; - } - theMesh->AddUVNodes(); - return true; - } + Standard_EXPORT virtual bool setNbUVNodes (const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theNbNodes) const; //! Sets node UV texture coordinates. //! @param[in] theMesh triangulation to be modified //! @param[in] theIndex node index starting from 1 //! @param[in] theUV node UV coordinates - virtual void setNodeUV (const Handle(Poly_Triangulation)& theMesh, - Standard_Integer theIndex, - const gp_Pnt2d& theUV) const - { - theMesh->SetUVNode (theIndex, theUV); - } + Standard_EXPORT virtual void setNodeUV (const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theIndex, + const gp_Pnt2d& theUV) const; //! Resizes array of nodes normals to specified size. //! @param[in] theMesh triangulation to be modified //! @param[in] theNbNodes nodes number //! @return TRUE in case of success operation - virtual bool setNbNormalNodes (const Handle(Poly_Triangulation)& theMesh, - Standard_Integer theNbNodes) const - { - if (theNbNodes <= 0 - || theMesh->NbNodes() != theNbNodes) - { - return false; - } - theMesh->AddNormals(); - return true; - } + Standard_EXPORT virtual bool setNbNormalNodes (const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theNbNodes) const; //! Sets node normal. //! @param[in] theMesh triangulation to be modified //! @param theIndex node index starting from 1 //! @param theNormal node normal vector - virtual void setNodeNormal (const Handle(Poly_Triangulation)& theMesh, - Standard_Integer theIndex, - const gp_Vec3f& theNormal) const - { - theMesh->SetNormal (theIndex, theNormal); - } + Standard_EXPORT virtual void setNodeNormal (const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theIndex, + const gp_Vec3f& theNormal) const; //! Resizes array of triangles to specified size. //! @param[in] theMesh triangulation to be modified //! @param[in] theNbTris elements number //! @param[in] theToCopyData copy old triangles into new array //! @return TRUE in case of success operation - virtual bool setNbTriangles (const Handle(Poly_Triangulation)& theMesh, - Standard_Integer theNbTris, - Standard_Boolean theToCopyData = false) const - { - if (theNbTris >= 1) - { - theMesh->ResizeTriangles (theNbTris, theToCopyData); - return true; - } - return false; - } + Standard_EXPORT virtual bool setNbTriangles (const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theNbTris, + Standard_Boolean theToCopyData = false) const; //! Adds triangle element. //! @param[in] theMesh triangulation to be modified @@ -248,26 +205,28 @@ protected: //! @name interface for filling triangulation data //! @return 0 if node indexes are out of range, //! -1 if triangle is degenerated and should be skipped, //! 1 in case of success operation. - virtual Standard_Integer setTriangle (const Handle(Poly_Triangulation)& theMesh, - Standard_Integer theIndex, - const Poly_Triangle& theTriangle) const - { - if (theTriangle.Value (1) < 1 || theTriangle.Value (1) > theMesh->NbNodes() - || theTriangle.Value (2) < 1 || theTriangle.Value (2) > theMesh->NbNodes() - || theTriangle.Value (3) < 1 || theTriangle.Value (3) > theMesh->NbNodes()) - { - return 0; - } - if (myToSkipDegenerateTris - && (theTriangle.Value (1) == theTriangle.Value (2) - || theTriangle.Value (1) == theTriangle.Value (3) - || theTriangle.Value (2) == theTriangle.Value (3))) - { - return -1; - } - theMesh->SetTriangle (theIndex, theTriangle); - return 1; - } + Standard_EXPORT virtual Standard_Integer setTriangle (const Handle(RWMesh_TriangulationSource)& theMesh, + Standard_Integer theIndex, + const Poly_Triangle& theTriangle) const; + + //! Resizes array of edges to specified size. + //! @param[in] theMesh triangulation source to be modified + //! @param[in] theNbEdges elements number + //! @param[in] theToCopyData copy old edges into new array + //! @return TRUE in case of success operation + Standard_EXPORT virtual bool setNbEdges (const Handle(RWMesh_TriangulationSource)& theMesh, + const Standard_Integer theNbEdges, + const Standard_Boolean theToCopyData = false) const; + + //! Adds edge element. + //! @param[in] theMesh triangulation source to be modified + //! @param theIndex edge index starting from 1 + //! @param theEdge edge nodes starting from 1 + //! @return 0 if node indexes are out of range, + //! 1 in case of success operation. + Standard_EXPORT virtual Standard_Integer setEdge (const Handle(RWMesh_TriangulationSource)& theMesh, + const Standard_Integer theIndex, + const Standard_Integer theEdge) const; protected: diff --git a/src/RWMesh/RWMesh_TriangulationSource.cxx b/src/RWMesh/RWMesh_TriangulationSource.cxx index 39beb673d1..ac8eb691dc 100644 --- a/src/RWMesh/RWMesh_TriangulationSource.cxx +++ b/src/RWMesh/RWMesh_TriangulationSource.cxx @@ -49,9 +49,24 @@ Standard_Boolean RWMesh_TriangulationSource::loadDeferredData (const Handle(OSD_ { return false; } - if (myReader->Load (this, theDestTriangulation, theFileSystem)) + Handle(RWMesh_TriangulationSource) aDestTriangulation = Handle(RWMesh_TriangulationSource)::DownCast (theDestTriangulation); + if (aDestTriangulation.IsNull()) + { + return false; + } + if (myReader->Load (this, aDestTriangulation, theFileSystem)) { return true; } return false; } + +// ======================================================================= +// function : ResizeEdges +// purpose : +// ======================================================================= +void RWMesh_TriangulationSource::ResizeEdges (Standard_Integer theNbEdges, + Standard_Boolean theToCopyOld) +{ + myEdges.Resize (1, theNbEdges, theToCopyOld); +} diff --git a/src/RWMesh/RWMesh_TriangulationSource.hxx b/src/RWMesh/RWMesh_TriangulationSource.hxx index cab9293d7e..f3e2d45c6d 100644 --- a/src/RWMesh/RWMesh_TriangulationSource.hxx +++ b/src/RWMesh/RWMesh_TriangulationSource.hxx @@ -15,6 +15,7 @@ #define _RWMesh_TriangulationSource_HeaderFile #include +#include class RWMesh_TriangulationReader; @@ -44,6 +45,28 @@ public: //! Gets access to number of degenerated triangles to collect them during data reading. Standard_Integer& ChangeDegeneratedTriNb() { return myStatisticOfDegeneratedTriNb; } + //! Returns TRUE if triangulation has some geometry. + virtual Standard_Boolean HasGeometry() const Standard_OVERRIDE + { + return !myNodes.IsEmpty() && (!myTriangles.IsEmpty() || !myEdges.IsEmpty()); + } + + //! Returns the number of edges for this triangulation. + Standard_Integer NbEdges() const { return myEdges.Length(); } + + //! Returns edge at the given index. + //! @param[in] theIndex edge index within [1, NbEdges()] range + //! @return edge node indices, with each node defined within [1, NbNodes()] range + Standard_Integer Edge (Standard_Integer theIndex) const { return myEdges.Value (theIndex); } + + //! Sets an edge. + //! @param[in] theIndex edge index within [1, NbEdges()] range + //! @param[in] theEdge edge node indices, with each node defined within [1, NbNodes()] range + void SetEdge (Standard_Integer theIndex, Standard_Integer theEdge) + { + myEdges.SetValue (theIndex, theEdge); + } + public: //! @name late-load deferred data interface //! Returns number of nodes for deferred loading. @@ -64,6 +87,16 @@ public: //! @name late-load deferred data interface //! Sets number of triangles for deferred loading. void SetNbDeferredTriangles (const Standard_Integer theNbTris) { myNbDefTriangles = theNbTris; } + //! Returns an internal array of edges. + //! Edge()/SetEdge() should be used instead in portable code. + NCollection_Array1& InternalEdges() { return myEdges; } + + //! Method resizing an internal array of triangles. + //! @param[in] theNbTriangles new number of triangles + //! @param[in] theToCopyOld copy old triangles into the new array + Standard_EXPORT void ResizeEdges (Standard_Integer theNbEdges, + Standard_Boolean theToCopyOld); + protected: //! Loads triangulation data from deferred storage using specified shared input file system. @@ -72,10 +105,11 @@ protected: protected: - Handle(RWMesh_TriangulationReader) myReader; - Standard_Integer myNbDefNodes; - Standard_Integer myNbDefTriangles; - mutable Standard_Integer myStatisticOfDegeneratedTriNb; + Handle(RWMesh_TriangulationReader) myReader; + NCollection_Array1 myEdges; + Standard_Integer myNbDefNodes; + Standard_Integer myNbDefTriangles; + mutable Standard_Integer myStatisticOfDegeneratedTriNb; }; diff --git a/tests/de_mesh/gltf_write/empty b/tests/de_mesh/gltf_write/empty index 50daa2f2e6..c53aa16f37 100644 --- a/tests/de_mesh/gltf_write/empty +++ b/tests/de_mesh/gltf_write/empty @@ -19,7 +19,7 @@ Close DD ReadGltf D "$aTmpGltf" XGetOneShape s D -checknbshapes s -face 6 -compound 2 +checknbshapes s -face 6 -vertex 8 -compound 11 set THE_REF_DUMP { ASSEMBLY COMPOUND 0:1:1:1 "empty_tmp.glb" diff --git a/tests/de_mesh/gltf_write/primitives b/tests/de_mesh/gltf_write/primitives new file mode 100644 index 0000000000..1aacab6d1e --- /dev/null +++ b/tests/de_mesh/gltf_write/primitives @@ -0,0 +1,39 @@ +puts "========" +puts "Data Exchange, RWGltf_CafReader - Edge and Vertex support" +puts "========" + +vclear +vclose ALL +Close * + +set aTmpGltf "${imagedir}/${casename}_tmp.glb" + +vertex v1 2 0 0 +vertex v2 2 1 0 +vertex v3 3 1 0 +vertex v4 3 0 0 + +polygon3d p1 2 0 0 0 1 1 0 +mkedge e1 p1 +polygon3d p2 2 0 1 0 1 0 0 +mkedge e2 p2 + +XNewDoc D +XAddShape D e1 +XAddShape D e2 +XAddShape D v1 +XAddShape D v2 +XAddShape D v3 +XAddShape D v4 +SetName D [XFindShape D e1] "edge_1" +SetName D [XFindShape D e2] "edge_2" +SetName D [XFindShape D v1] "vertex_1" +SetName D [XFindShape D v2] "vertex_2" +SetName D [XFindShape D v3] "vertex_3" +SetName D [XFindShape D v4] "vertex_4" + +WriteGltf D "$aTmpGltf" + +ReadGltf D1 "$aTmpGltf" +XGetOneShape s D1 +checknbshapes s -vertex 4 -edge 2