From: Elias Cohenca Date: Fri, 23 May 2025 11:24:13 +0000 (+0300) Subject: Data Exchange, GLTF - fix saving edges when Merge Faces is enabled #554 X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=4f2d4c1f4b0a737e19c165d535e093e43677cc1d;p=occt.git Data Exchange, GLTF - fix saving edges when Merge Faces is enabled #554 Removed check for LineStrip mode to force use of Lines for merged faces Updated primitive mode checks by removing LineStrip references Added getShapeType to correctly determine the underlying shape type from compounds and updated index calculation logic --- diff --git a/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.cxx b/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.cxx index d2cff43a66..630eca3d5a 100644 --- a/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.cxx +++ b/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.cxx @@ -278,6 +278,23 @@ TCollection_AsciiString RWGltf_CafWriter::formatName(RWMesh_NameFormat theFormat //================================================================================================= +TopAbs_ShapeEnum RWGltf_CafWriter::getShapeType(const TopoDS_Shape& theShape) const +{ + TopAbs_ShapeEnum aShapeType = theShape.ShapeType(); + if (aShapeType == TopAbs_COMPOUND) + { + // Compounds are created in the case of merged faces. + // Assuming that all shapes in the compound are of the same type + TopoDS_Iterator it(theShape); + Standard_ProgramError_Raise_if(!it.More(), "Empty compound"); + aShapeType = it.Value().ShapeType(); + } + + return aShapeType; +} + +//================================================================================================= + Standard_Boolean RWGltf_CafWriter::toSkipShape(const RWMesh_ShapeIterator& theShapeIter) const { return theShapeIter.IsEmpty(); @@ -287,19 +304,17 @@ Standard_Boolean RWGltf_CafWriter::toSkipShape(const RWMesh_ShapeIterator& theSh Standard_Boolean RWGltf_CafWriter::hasTriangulation(const RWGltf_GltfFace& theGltfFace) const { - switch (theGltfFace.Shape.ShapeType()) + TopAbs_ShapeEnum shapeType = getShapeType(theGltfFace.Shape); + + switch (shapeType) { - case TopAbs_COMPOUND: - case TopAbs_COMPSOLID: - case TopAbs_SOLID: - case TopAbs_SHELL: case TopAbs_FACE: return true; - case TopAbs_WIRE: case TopAbs_EDGE: case TopAbs_VERTEX: - default: return false; + default: + throw Standard_ProgramError("Unsupported shape type"); } } @@ -499,21 +514,29 @@ void RWGltf_CafWriter::saveTriangleIndices(RWGltf_GltfFace& theGltfFac void RWGltf_CafWriter::saveEdgeIndices(RWGltf_GltfFace& theGltfFace, std::ostream& theBinFile, - const RWMesh_EdgeIterator& theFaceIter) + const RWMesh_EdgeIterator& theEdgeIter) { - const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes - theFaceIter.ElemLower(); - theGltfFace.NbIndexedNodes += theFaceIter.NbNodes(); - theGltfFace.Indices.Count += theFaceIter.NbNodes(); - for (Standard_Integer anElemIter = theFaceIter.ElemLower(); anElemIter <= theFaceIter.ElemUpper(); - ++anElemIter) + const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes; + theGltfFace.NbIndexedNodes += theEdgeIter.NbNodes(); + + const Standard_Integer numSegments = Max(0, theEdgeIter.NbNodes() - 1); + // each segment writes two indices + theGltfFace.Indices.Count += numSegments * 2; + + for (Standard_Integer i = 0; i < numSegments; ++i) { + Standard_Integer i0 = aNodeFirst + i; + Standard_Integer i1 = aNodeFirst + i + 1; + if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16) { - writeVertex(theBinFile, (uint16_t)(anElemIter + aNodeFirst)); + writeVertex(theBinFile, (uint16_t)i0); + writeVertex(theBinFile, (uint16_t)i1); } else { - writeVertex(theBinFile, anElemIter + aNodeFirst); + writeVertex(theBinFile, i0); + writeVertex(theBinFile, i1); } } } @@ -522,12 +545,13 @@ void RWGltf_CafWriter::saveEdgeIndices(RWGltf_GltfFace& theGltfFace, void RWGltf_CafWriter::saveVertexIndices(RWGltf_GltfFace& theGltfFace, std::ostream& theBinFile, - const RWMesh_VertexIterator& theFaceIter) + const RWMesh_VertexIterator& theVertexIter) { - const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes - theFaceIter.ElemLower(); - theGltfFace.NbIndexedNodes += theFaceIter.NbNodes(); - theGltfFace.Indices.Count += theFaceIter.NbNodes(); - for (Standard_Integer anElemIter = theFaceIter.ElemLower(); anElemIter <= theFaceIter.ElemUpper(); + const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes - theVertexIter.ElemLower(); + theGltfFace.NbIndexedNodes += theVertexIter.NbNodes(); + theGltfFace.Indices.Count += theVertexIter.NbNodes(); + for (Standard_Integer anElemIter = theVertexIter.ElemLower(); + anElemIter <= theVertexIter.ElemUpper(); ++anElemIter) { if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16) @@ -545,7 +569,7 @@ void RWGltf_CafWriter::saveVertexIndices(RWGltf_GltfFace& theGltfFac void RWGltf_CafWriter::saveIndices(RWGltf_GltfFace& theGltfFace, std::ostream& theBinFile, - const RWMesh_ShapeIterator& theFaceIter, + const RWMesh_ShapeIterator& theShapeIter, Standard_Integer& theAccessorNb, const std::shared_ptr& theMesh) { @@ -574,17 +598,18 @@ void RWGltf_CafWriter::saveIndices(RWGltf_GltfFace& } } - if (const RWMesh_FaceIterator* aFaceIter = dynamic_cast(&theFaceIter)) + if (const RWMesh_FaceIterator* aFaceIter = + dynamic_cast(&theShapeIter)) { saveTriangleIndices(theGltfFace, theBinFile, *aFaceIter, theMesh); } else if (const RWMesh_EdgeIterator* anEdgeIter = - dynamic_cast(&theFaceIter)) + dynamic_cast(&theShapeIter)) { saveEdgeIndices(theGltfFace, theBinFile, *anEdgeIter); } else if (const RWMesh_VertexIterator* aVertexIter = - dynamic_cast(&theFaceIter)) + dynamic_cast(&theShapeIter)) { saveVertexIndices(theGltfFace, theBinFile, *aVertexIter); } @@ -963,7 +988,9 @@ bool RWGltf_CafWriter::writeBinData(const Handle(TDocStd_Document)& theDocument, aWrittenPrimData.Bind(aGltfFace->Shape, aGltfFace); Standard_Boolean wasWrittenNonFace = Standard_False; - switch (aGltfFace->Shape.ShapeType()) + TopAbs_ShapeEnum shapeType = getShapeType(aGltfFace->Shape); + + switch (shapeType) { case TopAbs_EDGE: { RWMesh_EdgeIterator anIter(aGltfFace->Shape, aGltfFace->Style); @@ -2027,10 +2054,13 @@ void RWGltf_CafWriter::writePrimArray(const RWGltf_GltfFace& theGltfFace } myWriter->Key("mode"); - switch (theGltfFace.Shape.ShapeType()) + + TopAbs_ShapeEnum shapeType = getShapeType(theGltfFace.Shape); + + switch (shapeType) { case TopAbs_EDGE: - myWriter->Int(RWGltf_GltfPrimitiveMode_LineStrip); + myWriter->Int(RWGltf_GltfPrimitiveMode_Lines); break; case TopAbs_VERTEX: myWriter->Int(RWGltf_GltfPrimitiveMode_Points); diff --git a/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.hxx b/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.hxx index b06838fb45..5c4f8e0be6 100644 --- a/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.hxx +++ b/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.hxx @@ -209,6 +209,9 @@ protected: const Message_ProgressRange& theProgress); protected: + //! Returns the underlying shape in case of a compound. + Standard_EXPORT virtual TopAbs_ShapeEnum getShapeType(const TopoDS_Shape& theShape) const; + //! Return TRUE if face shape should be skipped (e.g. because it is invalid or empty). Standard_EXPORT virtual Standard_Boolean toSkipShape( const RWMesh_ShapeIterator& theShapeIter) const; diff --git a/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_GltfJsonParser.cxx b/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_GltfJsonParser.cxx index 922ac6d27f..e517be7bf5 100644 --- a/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_GltfJsonParser.cxx +++ b/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_GltfJsonParser.cxx @@ -1808,7 +1808,7 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray(TopoDS_Shape& th } } if (aMode != RWGltf_GltfPrimitiveMode_Triangles && aMode != RWGltf_GltfPrimitiveMode_Lines - && aMode != RWGltf_GltfPrimitiveMode_LineStrip && aMode != RWGltf_GltfPrimitiveMode_Points) + && aMode != RWGltf_GltfPrimitiveMode_Points) { Message::SendWarning(TCollection_AsciiString() + "Primitive array within Mesh '" + theMeshId + "' skipped due to unsupported mode"); @@ -1976,8 +1976,7 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray(TopoDS_Shape& th aShape = aVertices; break; } - case RWGltf_GltfPrimitiveMode_Lines: - case RWGltf_GltfPrimitiveMode_LineStrip: { + case RWGltf_GltfPrimitiveMode_Lines: { TColgp_Array1OfPnt aNodes(1, aMeshData->NbEdges()); for (Standard_Integer anEdgeIdx = 1; anEdgeIdx <= aMeshData->NbEdges(); ++anEdgeIdx) { @@ -2012,7 +2011,7 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray(TopoDS_Shape& th aShapeAttribs.RawName = theMeshName; // assign material and not color - if (aMode == RWGltf_GltfPrimitiveMode_Lines || aMode == RWGltf_GltfPrimitiveMode_LineStrip) + if (aMode == RWGltf_GltfPrimitiveMode_Lines) { aShapeAttribs.Style.SetColorCurv(aMeshData->BaseColor().GetRGB()); } diff --git a/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_TriangulationReader.cxx b/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_TriangulationReader.cxx index 3542a26375..77dfdf4a3a 100644 --- a/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_TriangulationReader.cxx +++ b/src/DataExchange/TKDEGLTF/RWGltf/RWGltf_TriangulationReader.cxx @@ -579,7 +579,6 @@ bool RWGltf_TriangulationReader::ReadStream( const TCollection_AsciiString& aName = theSourceMesh->Id(); const RWGltf_GltfPrimitiveMode aPrimMode = theSourceMesh->PrimitiveMode(); if (aPrimMode != RWGltf_GltfPrimitiveMode_Triangles && aPrimMode != RWGltf_GltfPrimitiveMode_Lines - && aPrimMode != RWGltf_GltfPrimitiveMode_LineStrip && aPrimMode != RWGltf_GltfPrimitiveMode_Points) { Message::SendWarning(TCollection_AsciiString("Buffer '") + aName