From 11c23250dc3f19c7962251ef4ec01a080049591b Mon Sep 17 00:00:00 2001 From: kgv Date: Wed, 11 Aug 2021 18:48:23 +0300 Subject: [PATCH] 0032530: Data Exchange, RWGltf_CafWriter - add option merging Faces within the Part Added RWGltf_CafWriter::ToMergeFaces() property disabled by default. RWMesh_MaterialMap - fixed creation of texture folder within working dir ".". XCAFDoc_VisMaterial::FillMaterialAspect() - added clamping of too small shininess values. Added options -mergefaces and -splitindices16 to WriteGltf for new feature. Added -systemCoordSys option to WriteGltf for consistency with WriteObj. --- src/RWGltf/RWGltf_CafWriter.cxx | 605 ++++++++++++++++------------ src/RWGltf/RWGltf_CafWriter.hxx | 32 +- src/RWGltf/RWGltf_GltfFace.hxx | 14 +- src/RWMesh/RWMesh_FaceIterator.cxx | 22 + src/RWMesh/RWMesh_FaceIterator.hxx | 7 + src/RWMesh/RWMesh_MaterialMap.cxx | 6 + src/TopExp/FILES | 1 - src/TopExp/TopExp_Explorer.cxx | 5 +- src/TopExp/TopExp_Explorer.hxx | 62 ++- src/TopExp/TopExp_Explorer.lxx | 54 --- src/TopoDS/FILES | 1 - src/TopoDS/TopoDS_Iterator.cxx | 3 +- src/TopoDS/TopoDS_Iterator.hxx | 53 +-- src/TopoDS/TopoDS_Iterator.lxx | 58 --- src/XCAFDoc/XCAFDoc_VisMaterial.cxx | 5 + src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx | 96 +++-- tests/de_mesh/gltf_write/as1 | 24 ++ 17 files changed, 568 insertions(+), 480 deletions(-) delete mode 100644 src/TopExp/TopExp_Explorer.lxx delete mode 100644 src/TopoDS/TopoDS_Iterator.lxx create mode 100644 tests/de_mesh/gltf_write/as1 diff --git a/src/RWGltf/RWGltf_CafWriter.cxx b/src/RWGltf/RWGltf_CafWriter.cxx index f06f8034af..b8a50cd59d 100644 --- a/src/RWGltf/RWGltf_CafWriter.cxx +++ b/src/RWGltf/RWGltf_CafWriter.cxx @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +98,8 @@ RWGltf_CafWriter::RWGltf_CafWriter (const TCollection_AsciiString& theFile, myIsBinary (theIsBinary), myIsForcedUVExport (false), myToEmbedTexturesInGlb (true), + myToMergeFaces (false), + myToSplitIndices16 (false), myBinDataLen64 (0) { myCSTrsf.SetOutputLengthUnit (1.0); // meters @@ -146,11 +151,19 @@ void RWGltf_CafWriter::saveNodes (RWGltf_GltfFace& theGltfFace, const RWMesh_FaceIterator& theFaceIter, Standard_Integer& theAccessorNb) const { - theGltfFace.NodePos.Id = theAccessorNb++; - theGltfFace.NodePos.Count = theFaceIter.NbNodes(); - theGltfFace.NodePos.ByteOffset = (int64_t )theBinFile.tellp() - myBuffViewPos.ByteOffset; - theGltfFace.NodePos.Type = RWGltf_GltfAccessorLayout_Vec3; - theGltfFace.NodePos.ComponentType = RWGltf_GltfAccessorCompType_Float32; + if (theGltfFace.NodePos.Id == RWGltf_GltfAccessor::INVALID_ID) + { + theGltfFace.NodePos.Id = theAccessorNb++; + theGltfFace.NodePos.ByteOffset = (int64_t )theBinFile.tellp() - myBuffViewPos.ByteOffset; + theGltfFace.NodePos.Type = RWGltf_GltfAccessorLayout_Vec3; + theGltfFace.NodePos.ComponentType = RWGltf_GltfAccessorCompType_Float32; + } + else + { + const int64_t aPos = theGltfFace.NodePos.ByteOffset + myBuffViewPos.ByteOffset + theGltfFace.NodePos.Count * sizeof(Graphic3d_Vec3); + Standard_ASSERT_RAISE (aPos == (int64_t )theBinFile.tellp(), "wrong offset"); + } + theGltfFace.NodePos.Count += theFaceIter.NbNodes(); const Standard_Integer aNodeUpper = theFaceIter.NodeUpper(); for (Standard_Integer aNodeIter = theFaceIter.NodeLower(); aNodeIter <= aNodeUpper; ++aNodeIter) @@ -176,11 +189,19 @@ void RWGltf_CafWriter::saveNormals (RWGltf_GltfFace& theGltfFace, return; } - theGltfFace.NodeNorm.Id = theAccessorNb++; - theGltfFace.NodeNorm.Count = theFaceIter.NbNodes(); - theGltfFace.NodeNorm.ByteOffset = (int64_t )theBinFile.tellp() - myBuffViewNorm.ByteOffset; - theGltfFace.NodeNorm.Type = RWGltf_GltfAccessorLayout_Vec3; - theGltfFace.NodeNorm.ComponentType = RWGltf_GltfAccessorCompType_Float32; + if (theGltfFace.NodeNorm.Id == RWGltf_GltfAccessor::INVALID_ID) + { + theGltfFace.NodeNorm.Id = theAccessorNb++; + theGltfFace.NodeNorm.ByteOffset = (int64_t )theBinFile.tellp() - myBuffViewNorm.ByteOffset; + theGltfFace.NodeNorm.Type = RWGltf_GltfAccessorLayout_Vec3; + theGltfFace.NodeNorm.ComponentType = RWGltf_GltfAccessorCompType_Float32; + } + else + { + const int64_t aPos = theGltfFace.NodeNorm.ByteOffset + myBuffViewNorm.ByteOffset + theGltfFace.NodeNorm.Count * sizeof(Graphic3d_Vec3); + Standard_ASSERT_RAISE (aPos == (int64_t )theBinFile.tellp(), "wrong offset"); + } + theGltfFace.NodeNorm.Count += theFaceIter.NbNodes(); const Standard_Integer aNodeUpper = theFaceIter.NodeUpper(); for (Standard_Integer aNodeIter = theFaceIter.NodeLower(); aNodeIter <= aNodeUpper; ++aNodeIter) @@ -222,11 +243,20 @@ void RWGltf_CafWriter::saveTextCoords (RWGltf_GltfFace& theGltfFace, } } - theGltfFace.NodeUV.Id = theAccessorNb++; - theGltfFace.NodeUV.Count = theFaceIter.NbNodes(); - theGltfFace.NodeUV.ByteOffset = (int64_t )theBinFile.tellp() - myBuffViewTextCoord.ByteOffset; - theGltfFace.NodeUV.Type = RWGltf_GltfAccessorLayout_Vec2; - theGltfFace.NodeUV.ComponentType = RWGltf_GltfAccessorCompType_Float32; + if (theGltfFace.NodeUV.Id == RWGltf_GltfAccessor::INVALID_ID) + { + theGltfFace.NodeUV.Id = theAccessorNb++; + theGltfFace.NodeUV.ByteOffset = (int64_t )theBinFile.tellp() - myBuffViewTextCoord.ByteOffset; + theGltfFace.NodeUV.Type = RWGltf_GltfAccessorLayout_Vec2; + theGltfFace.NodeUV.ComponentType = RWGltf_GltfAccessorCompType_Float32; + } + else + { + const int64_t aPos = theGltfFace.NodeUV.ByteOffset + myBuffViewTextCoord.ByteOffset + theGltfFace.NodeUV.Count * sizeof(Graphic3d_Vec2); + Standard_ASSERT_RAISE (aPos == (int64_t )theBinFile.tellp(), "wrong offset"); + } + theGltfFace.NodeUV.Count += theFaceIter.NbNodes(); + const Standard_Integer aNodeUpper = theFaceIter.NodeUpper(); for (Standard_Integer aNodeIter = theFaceIter.NodeLower(); aNodeIter <= aNodeUpper; ++aNodeIter) { @@ -245,22 +275,36 @@ void RWGltf_CafWriter::saveIndices (RWGltf_GltfFace& theGltfFace, const RWMesh_FaceIterator& theFaceIter, Standard_Integer& theAccessorNb) { - theGltfFace.Indices.Id = theAccessorNb++; - theGltfFace.Indices.Count = theFaceIter.NbTriangles() * 3; - theGltfFace.Indices.ByteOffset = (int64_t )theBinFile.tellp() - myBuffViewInd.ByteOffset; - theGltfFace.Indices.Type = RWGltf_GltfAccessorLayout_Scalar; - theGltfFace.Indices.ComponentType = theGltfFace.NodePos.Count > std::numeric_limits::max() - ? RWGltf_GltfAccessorCompType_UInt32 - : RWGltf_GltfAccessorCompType_UInt16; + if (theGltfFace.Indices.Id == RWGltf_GltfAccessor::INVALID_ID) + { + theGltfFace.Indices.Id = theAccessorNb++; + theGltfFace.Indices.ByteOffset = (int64_t )theBinFile.tellp() - myBuffViewInd.ByteOffset; + theGltfFace.Indices.Type = RWGltf_GltfAccessorLayout_Scalar; + theGltfFace.Indices.ComponentType = theGltfFace.NodePos.Count > std::numeric_limits::max() + ? RWGltf_GltfAccessorCompType_UInt32 + : RWGltf_GltfAccessorCompType_UInt16; + } + else + { + const int64_t aRefPos = (int64_t )theBinFile.tellp(); + const int64_t aPos = theGltfFace.Indices.ByteOffset + + myBuffViewInd.ByteOffset + + theGltfFace.Indices.Count * (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt32 ? sizeof(uint32_t) : sizeof(uint16_t)); + Standard_ASSERT_RAISE (aPos == aRefPos, "wrong offset"); + } + + const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes - theFaceIter.ElemLower(); + theGltfFace.NbIndexedNodes += theFaceIter.NbNodes(); + theGltfFace.Indices.Count += theFaceIter.NbTriangles() * 3; const Standard_Integer anElemLower = theFaceIter.ElemLower(); const Standard_Integer anElemUpper = theFaceIter.ElemUpper(); for (Standard_Integer anElemIter = anElemLower; anElemIter <= anElemUpper; ++anElemIter) { Poly_Triangle aTri = theFaceIter.TriangleOriented (anElemIter); - aTri(1) -= anElemLower; - aTri(2) -= anElemLower; - aTri(3) -= anElemLower; + aTri(1) += aNodeFirst; + aTri(2) += aNodeFirst; + aTri(3) += aNodeFirst; if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16) { writeTriangle16 (theBinFile, NCollection_Vec3((uint16_t)aTri(1), (uint16_t)aTri(2), (uint16_t)aTri(3))); @@ -270,16 +314,6 @@ void RWGltf_CafWriter::saveIndices (RWGltf_GltfFace& theGltfFace, writeTriangle32 (theBinFile, Graphic3d_Vec3i (aTri(1), aTri(2), aTri(3))); } } - if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16) - { - // alignment by 4 bytes - int64_t aContentLen64 = (int64_t)theBinFile.tellp(); - while (aContentLen64 % 4 != 0) - { - theBinFile.write (" ", 1); - ++aContentLen64; - } - } } // ======================================================================= @@ -369,11 +403,16 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument } Message_ProgressScope aPSentryBin (theProgress, "Binary data", 4); + const RWGltf_GltfArrayType anArrTypes[4] = + { + RWGltf_GltfArrayType_Position, + RWGltf_GltfArrayType_Normal, + RWGltf_GltfArrayType_TCoord0, + RWGltf_GltfArrayType_Indices + }; - Standard_Integer aNbAccessors = 0; - - // write positions - myBuffViewPos.ByteOffset = aBinFile->tellp(); + // dispatch faces + NCollection_DataMap aMergedFaces; for (XCAFPrs_DocumentExplorer aDocExplorer (theDocument, theRootLabels, XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes); aDocExplorer.More() && aPSentryBin.More(); aDocExplorer.Next()) { @@ -385,149 +424,165 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument } // transformation will be stored at scene nodes - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) + aMergedFaces.Clear (false); + + RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + if (myToMergeFaces) { - if (myBinDataMap.IsBound (aFaceIter.Face()) - || toSkipFaceMesh (aFaceIter)) + if (myBinDataMap.Contains (aFaceIter.ExploredShape())) { continue; } - RWGltf_GltfFace aGltfFace; - saveNodes (aGltfFace, *aBinFile, aFaceIter, aNbAccessors); - - if (!aBinFile->good()) + Handle(RWGltf_GltfFaceList) aGltfFaceList = new RWGltf_GltfFaceList(); + myBinDataMap.Add (aFaceIter.ExploredShape(), aGltfFaceList); + for (; aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) { - Message::SendFail (TCollection_AsciiString ("File '") + myBinFileNameFull + "' can not be written"); - return false; - } + if (toSkipFaceMesh (aFaceIter)) + { + continue; + } - myBinDataMap.Bind (aFaceIter.Face(), aGltfFace); + Handle(RWGltf_GltfFace) aGltfFace; + if (!aMergedFaces.Find (aFaceIter.FaceStyle(), aGltfFace)) + { + aGltfFace = new RWGltf_GltfFace(); + aGltfFaceList->Append (aGltfFace); + aGltfFace->Shape = aFaceIter.Face(); + aGltfFace->Style = aFaceIter.FaceStyle(); + aGltfFace->NbIndexedNodes = aFaceIter.NbNodes(); + aMergedFaces.Bind (aFaceIter.FaceStyle(), aGltfFace); + } + else if (myToSplitIndices16 + && aGltfFace->NbIndexedNodes < std::numeric_limits::max() + && (aGltfFace->NbIndexedNodes + aFaceIter.NbNodes()) >= std::numeric_limits::max()) + { + aMergedFaces.UnBind (aFaceIter.FaceStyle()); + aGltfFace = new RWGltf_GltfFace(); + aGltfFaceList->Append (aGltfFace); + aGltfFace->Shape = aFaceIter.Face(); + aGltfFace->Style = aFaceIter.FaceStyle(); + aGltfFace->NbIndexedNodes = aFaceIter.NbNodes(); + aMergedFaces.Bind (aFaceIter.FaceStyle(), aGltfFace); + } + else + { + if (aGltfFace->Shape.ShapeType() != TopAbs_COMPOUND) + { + TopoDS_Shape anOldShape = aGltfFace->Shape; + TopoDS_Compound aComp; + BRep_Builder().MakeCompound (aComp); + BRep_Builder().Add (aComp, anOldShape); + aGltfFace->Shape = aComp; + } + BRep_Builder().Add (aGltfFace->Shape, aFaceIter.Face()); + aGltfFace->NbIndexedNodes += aFaceIter.NbNodes(); + } + } + } + else + { + for (; aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) + { + if (toSkipFaceMesh (aFaceIter) + || myBinDataMap.Contains (aFaceIter.Face())) + { + continue; + } + + Handle(RWGltf_GltfFaceList) aGltfFaceList = new RWGltf_GltfFaceList(); + Handle(RWGltf_GltfFace) aGltfFace = new RWGltf_GltfFace(); + aGltfFace->Shape = aFaceIter.Face(); + aGltfFace->Style = aFaceIter.FaceStyle(); + aGltfFaceList->Append (aGltfFace); + myBinDataMap.Add (aFaceIter.Face(), aGltfFaceList); + } } } - myBuffViewPos.ByteLength = (int64_t )aBinFile->tellp() - myBuffViewPos.ByteOffset; - if (!aPSentryBin.More()) + + Standard_Integer aNbAccessors = 0; + NCollection_Map aWrittenFaces; + for (Standard_Integer aTypeIter = 0; aTypeIter < 4; ++aTypeIter) { - return false; - } - aPSentryBin.Next(); - - // write normals - myBuffViewNorm.ByteOffset = aBinFile->tellp(); - for (XCAFPrs_DocumentExplorer aDocExplorer (theDocument, theRootLabels, XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes); - aDocExplorer.More() && aPSentryBin.More(); aDocExplorer.Next()) - { - const XCAFPrs_DocumentNode& aDocNode = aDocExplorer.Current(); - if (theLabelFilter != NULL - && !theLabelFilter->Contains (aDocNode.Id)) + const RWGltf_GltfArrayType anArrType = (RWGltf_GltfArrayType )anArrTypes[aTypeIter]; + RWGltf_GltfBufferView* aBuffView = NULL; + switch (anArrType) { - continue; + case RWGltf_GltfArrayType_Position: aBuffView = &myBuffViewPos; break; + case RWGltf_GltfArrayType_Normal: aBuffView = &myBuffViewNorm; break; + case RWGltf_GltfArrayType_TCoord0: aBuffView = &myBuffViewTextCoord; break; + case RWGltf_GltfArrayType_Indices: aBuffView = &myBuffViewInd; break; + default: break; } - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) + aBuffView->ByteOffset = aBinFile->tellp(); + aWrittenFaces.Clear (false); + for (ShapeToGltfFaceMap::Iterator aBinDataIter (myBinDataMap); aBinDataIter.More() && aPSentryBin.More(); aBinDataIter.Next()) { - if (toSkipFaceMesh (aFaceIter)) + const Handle(RWGltf_GltfFaceList)& aGltfFaceList = aBinDataIter.Value(); + if (!aWrittenFaces.Add (aGltfFaceList)) // skip repeating faces { continue; } - RWGltf_GltfFace& aGltfFace = myBinDataMap.ChangeFind (aFaceIter.Face()); - if (aGltfFace.NodeNorm.Id != RWGltf_GltfAccessor::INVALID_ID) + for (RWGltf_GltfFaceList::Iterator aGltfFaceIter (*aGltfFaceList); aGltfFaceIter.More() && aPSentryBin.More(); aGltfFaceIter.Next()) { - continue; - } + const Handle(RWGltf_GltfFace)& aGltfFace = aGltfFaceIter.Value(); + for (RWMesh_FaceIterator aFaceIter (aGltfFace->Shape, aGltfFace->Style); aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) + { + switch (anArrType) + { + case RWGltf_GltfArrayType_Position: + { + aGltfFace->NbIndexedNodes = 0; // reset to zero before RWGltf_GltfArrayType_Indices step + saveNodes (*aGltfFace, *aBinFile, aFaceIter, aNbAccessors); + break; + } + case RWGltf_GltfArrayType_Normal: + { + saveNormals (*aGltfFace, *aBinFile, aFaceIter, aNbAccessors); + break; + } + case RWGltf_GltfArrayType_TCoord0: + { + saveTextCoords (*aGltfFace, *aBinFile, aFaceIter, aNbAccessors); + break; + } + case RWGltf_GltfArrayType_Indices: + { + saveIndices (*aGltfFace, *aBinFile, aFaceIter, aNbAccessors); + break; + } + default: + { + break; + } + } - saveNormals (aGltfFace, *aBinFile, aFaceIter, aNbAccessors); + if (!aBinFile->good()) + { + Message::SendFail (TCollection_AsciiString ("File '") + myBinFileNameFull + "' cannot be written"); + return false; + } + } - if (!aBinFile->good()) - { - Message::SendFail (TCollection_AsciiString ("File '") + myBinFileNameFull + "' can not be written"); - return false; + // add alignment by 4 bytes (might happen on RWGltf_GltfAccessorCompType_UInt16 indices) + int64_t aContentLen64 = (int64_t)aBinFile->tellp(); + while (aContentLen64 % 4 != 0) + { + aBinFile->write (" ", 1); + ++aContentLen64; + } } } - } - myBuffViewNorm.ByteLength = (int64_t )aBinFile->tellp() - myBuffViewNorm.ByteOffset; - if (!aPSentryBin.More()) - { - return false; - } - aPSentryBin.Next(); - // write texture coordinates - myBuffViewTextCoord.ByteOffset = aBinFile->tellp(); - for (XCAFPrs_DocumentExplorer aDocExplorer (theDocument, theRootLabels, XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes); - aDocExplorer.More() && aPSentryBin.More(); aDocExplorer.Next()) - { - const XCAFPrs_DocumentNode& aDocNode = aDocExplorer.Current(); - if (theLabelFilter != NULL - && !theLabelFilter->Contains (aDocNode.Id)) + aBuffView->ByteLength = (int64_t )aBinFile->tellp() - aBuffView->ByteOffset; + if (!aPSentryBin.More()) { - continue; + return false; } - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) - { - if (toSkipFaceMesh (aFaceIter)) - { - continue; - } - - RWGltf_GltfFace& aGltfFace = myBinDataMap.ChangeFind (aFaceIter.Face()); - if (aGltfFace.NodeUV.Id != RWGltf_GltfAccessor::INVALID_ID) - { - continue; - } - - saveTextCoords (aGltfFace, *aBinFile, aFaceIter, aNbAccessors); - - if (!aBinFile->good()) - { - Message::SendFail (TCollection_AsciiString ("File '") + myBinFileNameFull + "' can not be written"); - return false; - } - } + aPSentryBin.Next(); } - myBuffViewTextCoord.ByteLength = (int64_t )aBinFile->tellp() - myBuffViewTextCoord.ByteOffset; - if (!aPSentryBin.More()) - { - return false; - } - aPSentryBin.Next(); - - // write indices - myBuffViewInd.ByteOffset = aBinFile->tellp(); - for (XCAFPrs_DocumentExplorer aDocExplorer (theDocument, theRootLabels, XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes); - aDocExplorer.More() && aPSentryBin.More(); aDocExplorer.Next()) - { - const XCAFPrs_DocumentNode& aDocNode = aDocExplorer.Current(); - if (theLabelFilter != NULL - && !theLabelFilter->Contains (aDocNode.Id)) - { - continue; - } - - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) - { - if (toSkipFaceMesh (aFaceIter)) - { - continue; - } - - RWGltf_GltfFace& aGltfFace = myBinDataMap.ChangeFind (aFaceIter.Face()); - if (aGltfFace.Indices.Id != RWGltf_GltfAccessor::INVALID_ID) - { - continue; - } - - saveIndices (aGltfFace, *aBinFile, aFaceIter, aNbAccessors); - - if (!aBinFile->good()) - { - Message::SendFail (TCollection_AsciiString ("File '") + myBinFileNameFull + "' can not be written"); - return false; - } - } - } - myBuffViewInd.ByteLength = (int64_t )aBinFile->tellp() - myBuffViewInd.ByteOffset; if (myIsBinary && myToEmbedTexturesInGlb) @@ -579,7 +634,7 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument aBinFile->flush(); if (!aBinFile->good()) { - Message::SendFail (TCollection_AsciiString ("File '") + myBinFileNameFull + "' can not be written"); + Message::SendFail (TCollection_AsciiString ("File '") + myBinFileNameFull + "' cannot be written"); return false; } aBinFile.reset(); @@ -788,7 +843,7 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument, // function : writeAccessors // purpose : // ======================================================================= -void RWGltf_CafWriter::writeAccessors (const RWGltf_GltfSceneNodeMap& theSceneNodeMap) +void RWGltf_CafWriter::writeAccessors (const RWGltf_GltfSceneNodeMap& ) { #ifdef HAVE_RAPIDJSON Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeAccessors()"); @@ -796,74 +851,61 @@ void RWGltf_CafWriter::writeAccessors (const RWGltf_GltfSceneNodeMap& theSceneNo myWriter->Key (RWGltf_GltfRootElementName (RWGltf_GltfRootElement_Accessors)); myWriter->StartArray(); - NCollection_Map aWrittenFaces; - for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter (theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next()) + const RWGltf_GltfArrayType anArrTypes[4] = { - const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) + RWGltf_GltfArrayType_Position, + RWGltf_GltfArrayType_Normal, + RWGltf_GltfArrayType_TCoord0, + RWGltf_GltfArrayType_Indices + }; + NCollection_Map aWrittenFaces; + for (Standard_Integer aTypeIter = 0; aTypeIter < 4; ++aTypeIter) + { + const RWGltf_GltfArrayType anArrType = (RWGltf_GltfArrayType )anArrTypes[aTypeIter]; + aWrittenFaces.Clear (false); + for (ShapeToGltfFaceMap::Iterator aBinDataIter (myBinDataMap); aBinDataIter.More(); aBinDataIter.Next()) { - if (!aWrittenFaces.Add (aFaceIter.Face()) // skip repeating faces - || toSkipFaceMesh (aFaceIter)) + const Handle(RWGltf_GltfFaceList)& aGltfFaceList = aBinDataIter.Value(); + if (!aWrittenFaces.Add (aGltfFaceList)) // skip repeating faces { continue; } - const RWGltf_GltfFace& aGltfFace = myBinDataMap.Find (aFaceIter.Face()); - writePositions (aGltfFace); - } - } - aWrittenFaces.Clear(); - for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter (theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next()) - { - const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) - { - if (!aWrittenFaces.Add (aFaceIter.Face()) // skip repeating faces - || toSkipFaceMesh (aFaceIter)) + for (RWGltf_GltfFaceList::Iterator aFaceIter (*aGltfFaceList); aFaceIter.More(); aFaceIter.Next()) { - continue; + const Handle(RWGltf_GltfFace)& aGltfFace = aFaceIter.Value(); + switch (anArrType) + { + case RWGltf_GltfArrayType_Position: + { + writePositions (*aGltfFace); + break; + } + case RWGltf_GltfArrayType_Normal: + { + writeNormals (*aGltfFace); + break; + } + case RWGltf_GltfArrayType_TCoord0: + { + writeTextCoords (*aGltfFace); + break; + } + case RWGltf_GltfArrayType_Indices: + { + writeIndices (*aGltfFace); + break; + } + default: + { + break; + } + } } - - const RWGltf_GltfFace& aGltfFace = myBinDataMap.Find (aFaceIter.Face()); - writeNormals (aGltfFace); - } - } - aWrittenFaces.Clear(); - for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter (theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next()) - { - const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) - { - if (!aWrittenFaces.Add (aFaceIter.Face()) // skip repeating faces - || toSkipFaceMesh (aFaceIter)) - { - continue; - } - - const RWGltf_GltfFace& aGltfFace = myBinDataMap.Find (aFaceIter.Face()); - writeTextCoords (aGltfFace); - } - } - aWrittenFaces.Clear(); - for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter (theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next()) - { - const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) - { - if (!aWrittenFaces.Add (aFaceIter.Face()) // skip repeating faces - || toSkipFaceMesh (aFaceIter)) - { - continue; - } - - const RWGltf_GltfFace& aGltfFace = myBinDataMap.Find (aFaceIter.Face()); - writeIndices (aGltfFace); } } myWriter->EndArray(); -#else - (void )theSceneNodeMap; #endif } @@ -1280,6 +1322,67 @@ void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNo #endif } +// ======================================================================= +// function : writePrimArray +// purpose : +// ======================================================================= +void RWGltf_CafWriter::writePrimArray (const RWGltf_GltfFace& theGltfFace, + const TCollection_AsciiString& theName, + bool& theToStartPrims) +{ +#ifdef HAVE_RAPIDJSON + if (theToStartPrims) + { + theToStartPrims = false; + myWriter->StartObject(); + if (!theName.IsEmpty()) + { + myWriter->Key ("name"); + myWriter->String (theName.ToCString()); + } + myWriter->Key ("primitives"); + myWriter->StartArray(); + } + + const TCollection_AsciiString aMatId = myMaterialMap->FindMaterial (theGltfFace.Style); + myWriter->StartObject(); + { + myWriter->Key ("attributes"); + myWriter->StartObject(); + { + if (theGltfFace.NodeNorm.Id != RWGltf_GltfAccessor::INVALID_ID) + { + myWriter->Key ("NORMAL"); + myWriter->Int (theGltfFace.NodeNorm.Id); + } + myWriter->Key ("POSITION"); + myWriter->Int (theGltfFace.NodePos.Id); + if (theGltfFace.NodeUV.Id != RWGltf_GltfAccessor::INVALID_ID) + { + myWriter->Key ("TEXCOORD_0"); + myWriter->Int (theGltfFace.NodeUV.Id); + } + } + myWriter->EndObject(); + + myWriter->Key ("indices"); + myWriter->Int (theGltfFace.Indices.Id); + if (!aMatId.IsEmpty()) + { + myWriter->Key ("material"); + myWriter->Int (aMatId.IntegerValue()); + } + myWriter->Key ("mode"); + myWriter->Int (RWGltf_GltfPrimitiveMode_Triangles); + } + myWriter->EndObject(); +#else + (void )theGltfFace; + (void )theName; + (void )theToStartPrims; +#endif +} + // ======================================================================= // function : writeMeshes // purpose : @@ -1292,6 +1395,7 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM myWriter->Key (RWGltf_GltfRootElementName (RWGltf_GltfRootElement_Meshes)); myWriter->StartArray(); + NCollection_Map aWrittenFaces; for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter (theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next()) { const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); @@ -1299,59 +1403,48 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM bool toStartPrims = true; Standard_Integer aNbFacesInNode = 0; - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next(), ++aNbFacesInNode) + aWrittenFaces.Clear (false); + if (myToMergeFaces) { - if (toSkipFaceMesh (aFaceIter)) + TopoDS_Shape aShape; + if (!XCAFDoc_ShapeTool::GetShape (aDocNode.RefLabel, aShape) + || aShape.IsNull()) { continue; } - if (toStartPrims) + Handle(RWGltf_GltfFaceList) aGltfFaceList; + aShape.Location (TopLoc_Location()); + myBinDataMap.FindFromKey (aShape, aGltfFaceList); + if (!aWrittenFaces.Add (aGltfFaceList)) { - toStartPrims = false; - myWriter->StartObject(); - if (!aNodeName.IsEmpty()) - { - myWriter->Key ("name"); - myWriter->String (aNodeName.ToCString()); - } - myWriter->Key ("primitives"); - myWriter->StartArray(); + continue; } - const RWGltf_GltfFace& aGltfFace = myBinDataMap.Find (aFaceIter.Face()); - const TCollection_AsciiString aMatId = myMaterialMap->FindMaterial (aFaceIter.FaceStyle()); - myWriter->StartObject(); + for (RWGltf_GltfFaceList::Iterator aFaceGroupIter (*aGltfFaceList); aFaceGroupIter.More(); aFaceGroupIter.Next()) { - myWriter->Key ("attributes"); - myWriter->StartObject(); - { - if (aGltfFace.NodeNorm.Id != RWGltf_GltfAccessor::INVALID_ID) - { - myWriter->Key ("NORMAL"); - myWriter->Int (aGltfFace.NodeNorm.Id); - } - myWriter->Key ("POSITION"); - myWriter->Int (aGltfFace.NodePos.Id); - if (aGltfFace.NodeUV.Id != RWGltf_GltfAccessor::INVALID_ID) - { - myWriter->Key ("TEXCOORD_0"); - myWriter->Int (aGltfFace.NodeUV.Id); - } - } - myWriter->EndObject(); - - myWriter->Key ("indices"); - myWriter->Int (aGltfFace.Indices.Id); - if (!aMatId.IsEmpty()) - { - myWriter->Key ("material"); - myWriter->Int (aMatId.IntegerValue()); - } - myWriter->Key ("mode"); - myWriter->Int (RWGltf_GltfPrimitiveMode_Triangles); + const Handle(RWGltf_GltfFace)& aGltfFace = aFaceGroupIter.Value(); + writePrimArray (*aGltfFace, aNodeName, toStartPrims); + } + } + else + { + for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next(), ++aNbFacesInNode) + { + if (toSkipFaceMesh (aFaceIter)) + { + continue; + } + + const Handle(RWGltf_GltfFaceList)& aGltfFaceList = myBinDataMap.FindFromKey (aFaceIter.Face()); + if (!aWrittenFaces.Add (aGltfFaceList)) + { + continue; + } + + const Handle(RWGltf_GltfFace)& aGltfFace = aGltfFaceList->First(); + writePrimArray (*aGltfFace, aNodeName, toStartPrims); } - myWriter->EndObject(); } if (!toStartPrims) diff --git a/src/RWGltf/RWGltf_CafWriter.hxx b/src/RWGltf/RWGltf_CafWriter.hxx index 5aad88a326..bfc5119177 100644 --- a/src/RWGltf/RWGltf_CafWriter.hxx +++ b/src/RWGltf/RWGltf_CafWriter.hxx @@ -99,6 +99,21 @@ public: //! Set flag to write image textures into GLB file (binary gltf export). void SetToEmbedTexturesInGlb (Standard_Boolean theToEmbedTexturesInGlb) { myToEmbedTexturesInGlb = theToEmbedTexturesInGlb; } + //! Return flag to merge faces within a single part; FALSE by default. + bool ToMergeFaces() const { return myToMergeFaces; } + + //! Set flag to merge faces within a single part. + //! May reduce JSON size thanks to smaller number of primitive arrays. + void SetMergeFaces (bool theToMerge) { myToMergeFaces = theToMerge; } + + //! Return flag to prefer keeping 16-bit indexes while merging face; FALSE by default. + bool ToSplitIndices16() const { return myToSplitIndices16; } + + //! Set flag to prefer keeping 16-bit indexes while merging face. + //! Has effect only with ToMergeFaces() option turned ON. + //! May reduce binary data size thanks to smaller triangle indexes. + void SetSplitIndices16 (bool theToSplit) { myToSplitIndices16 = theToSplit; } + //! Write glTF file and associated binary file. //! Triangulation data should be precomputed within shapes! //! @param theDocument [in] input document @@ -262,6 +277,14 @@ protected: //! @param theMaterialMap [in] map of materials Standard_EXPORT virtual void writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeMap); + //! Write a primitive array to RWGltf_GltfRootElement_Meshes section. + //! @param[in] theGltfFace face to write + //! @param[in] theName primitive array name + //! @param[in,out] theToStartPrims flag indicating that primitive array has been started + Standard_EXPORT virtual void writePrimArray (const RWGltf_GltfFace& theGltfFace, + const TCollection_AsciiString& theName, + bool& theToStartPrims); + //! Write RWGltf_GltfRootElement_Nodes section. //! @param theDocument [in] input document //! @param theRootLabels [in] list of root shapes to export @@ -293,6 +316,10 @@ protected: //! @param theMaterialMap [out] map of materials, filled with textures Standard_EXPORT virtual void writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNodeMap); +protected: + + typedef NCollection_IndexedDataMap ShapeToGltfFaceMap; + protected: TCollection_AsciiString myFile; //!< output glTF file @@ -304,6 +331,8 @@ protected: Standard_Boolean myIsBinary; //!< flag to write into binary glTF format (.glb) Standard_Boolean myIsForcedUVExport; //!< export UV coordinates even if there are no mapped texture Standard_Boolean myToEmbedTexturesInGlb; //!< flag to write image textures into GLB file + Standard_Boolean myToMergeFaces; //!< flag to merge faces within a single part + Standard_Boolean myToSplitIndices16; //!< flag to prefer keeping 16-bit indexes while merging face RWMesh_CoordinateSystemConverter myCSTrsf; //!< transformation from OCCT to glTF coordinate system XCAFPrs_Style myDefaultStyle; //!< default material definition to be used for nodes with only color defined @@ -314,8 +343,7 @@ protected: RWGltf_GltfBufferView myBuffViewNorm; //!< current buffer view with nodes normals RWGltf_GltfBufferView myBuffViewTextCoord; //!< current buffer view with nodes UV coordinates RWGltf_GltfBufferView myBuffViewInd; //!< current buffer view with triangulation indexes - NCollection_DataMap myBinDataMap; //!< map for TopoDS_Face to glTF face (merging duplicates) + ShapeToGltfFaceMap myBinDataMap; //!< map for TopoDS_Face to glTF face (merging duplicates) int64_t myBinDataLen64; //!< length of binary file }; diff --git a/src/RWGltf/RWGltf_GltfFace.hxx b/src/RWGltf/RWGltf_GltfFace.hxx index c90a9c1478..0c4298c2ff 100644 --- a/src/RWGltf/RWGltf_GltfFace.hxx +++ b/src/RWGltf/RWGltf_GltfFace.hxx @@ -15,15 +15,27 @@ #ifndef _RWGltf_GltfFace_HeaderFile #define _RWGltf_GltfFace_HeaderFile +#include +#include #include +#include +#include //! Low-level glTF data structure holding single Face (one primitive array) definition. -struct RWGltf_GltfFace +class RWGltf_GltfFace : public Standard_Transient { +public: RWGltf_GltfAccessor NodePos; //!< accessor for nodal positions RWGltf_GltfAccessor NodeNorm; //!< accessor for nodal normals RWGltf_GltfAccessor NodeUV; //!< accessor for nodal UV texture coordinates RWGltf_GltfAccessor Indices; //!< accessor for indexes + TopoDS_Shape Shape; //!< original Face or face list + XCAFPrs_Style Style; //!< face style + Standard_Integer NbIndexedNodes; //!< transient variable for merging several faces into one while writing Indices + + RWGltf_GltfFace() : NbIndexedNodes (0) {} }; +typedef NCollection_Shared> RWGltf_GltfFaceList; + #endif // _RWGltf_GltfFace_HeaderFile diff --git a/src/RWMesh/RWMesh_FaceIterator.cxx b/src/RWMesh/RWMesh_FaceIterator.cxx index cdcd5241d7..a19ee16920 100644 --- a/src/RWMesh/RWMesh_FaceIterator.cxx +++ b/src/RWMesh/RWMesh_FaceIterator.cxx @@ -53,6 +53,28 @@ RWMesh_FaceIterator::RWMesh_FaceIterator (const TDF_Label& theLabel, Next(); } +// ======================================================================= +// function : RWMesh_FaceIterator +// purpose : +// ======================================================================= +RWMesh_FaceIterator::RWMesh_FaceIterator (const TopoDS_Shape& theShape, + const XCAFPrs_Style& theStyle) +: myDefStyle (theStyle), + myToMapColors (true), + mySLTool (1, 1e-12), + myHasNormals (false), + myIsMirrored (false), + myHasFaceColor (false) +{ + if (theShape.IsNull()) + { + return; + } + + myFaceIter.Init (theShape, TopAbs_FACE); + Next(); +} + // ======================================================================= // function : dispatchStyles // purpose : diff --git a/src/RWMesh/RWMesh_FaceIterator.hxx b/src/RWMesh/RWMesh_FaceIterator.hxx index f70b378610..3a74040af6 100644 --- a/src/RWMesh/RWMesh_FaceIterator.hxx +++ b/src/RWMesh/RWMesh_FaceIterator.hxx @@ -39,6 +39,13 @@ public: const Standard_Boolean theToMapColors = false, const XCAFPrs_Style& theStyle = XCAFPrs_Style()); + //! Auxiliary constructor. + Standard_EXPORT RWMesh_FaceIterator (const TopoDS_Shape& theShape, + const XCAFPrs_Style& theStyle = XCAFPrs_Style()); + + //! Return explored shape. + const TopoDS_Shape& ExploredShape() const { return myFaceIter.ExploredShape(); } + //! Return true if iterator points to the valid triangulation. bool More() const { return !myPolyTriang.IsNull(); } diff --git a/src/RWMesh/RWMesh_MaterialMap.cxx b/src/RWMesh/RWMesh_MaterialMap.cxx index 1a8f2e93f5..457d9622c7 100644 --- a/src/RWMesh/RWMesh_MaterialMap.cxx +++ b/src/RWMesh/RWMesh_MaterialMap.cxx @@ -38,6 +38,10 @@ RWMesh_MaterialMap::RWMesh_MaterialMap (const TCollection_AsciiString& theFile) TCollection_AsciiString aFileName, aFileExt; OSD_Path::FolderAndFileFromPath (theFile, myFolder, aFileName); OSD_Path::FileNameAndExtension (aFileName, myShortFileNameBase, aFileExt); + if (myFolder.IsEmpty()) + { + myFolder = "."; + } } // ======================================================================= @@ -216,6 +220,7 @@ bool RWMesh_MaterialMap::CreateTextureFolder() OSD_Directory aResDir (aResFolderPath); if (!aResDir.Exists()) { + Message::SendFail() << "Failed to create textures folder '" << myFolder << "'"; return false; } const OSD_Protection aParentProt = aResDir.Protection(); @@ -233,6 +238,7 @@ bool RWMesh_MaterialMap::CreateTextureFolder() if (aTexDir.Failed()) { // fallback to the same folder as output model file + Message::SendFail() << "Failed to create textures folder '" << myTexFolder << "'"; myTexFolder = myFolder; myTexFolderShort.Clear(); return true; diff --git a/src/TopExp/FILES b/src/TopExp/FILES index 7d56a6d55f..cace9690df 100644 --- a/src/TopExp/FILES +++ b/src/TopExp/FILES @@ -2,5 +2,4 @@ TopExp.cxx TopExp.hxx TopExp_Explorer.cxx TopExp_Explorer.hxx -TopExp_Explorer.lxx TopExp_Stack.hxx diff --git a/src/TopExp/TopExp_Explorer.cxx b/src/TopExp/TopExp_Explorer.cxx index f698f928cc..569f5f21b1 100644 --- a/src/TopExp/TopExp_Explorer.cxx +++ b/src/TopExp/TopExp_Explorer.cxx @@ -17,14 +17,11 @@ #define No_Standard_NoMoreObject #define No_Standard_NoSuchObject +#include -#include #include #include #include -#include -#include -#include // macro to compare two types of shapes // always True if the first one is SHAPE diff --git a/src/TopExp/TopExp_Explorer.hxx b/src/TopExp/TopExp_Explorer.hxx index 33daa37ff6..a49d3f15e7 100644 --- a/src/TopExp/TopExp_Explorer.hxx +++ b/src/TopExp/TopExp_Explorer.hxx @@ -17,19 +17,8 @@ #ifndef _TopExp_Explorer_HeaderFile #define _TopExp_Explorer_HeaderFile -#include -#include -#include - #include -#include #include -#include -#include -class Standard_NoMoreObject; -class Standard_NoSuchObject; -class TopoDS_Shape; - //! An Explorer is a Tool to visit a Topological Data //! Structure form the TopoDS package. @@ -117,10 +106,9 @@ public: //! ToFind it has no effect on the search. Standard_EXPORT void Init (const TopoDS_Shape& S, const TopAbs_ShapeEnum ToFind, const TopAbs_ShapeEnum ToAvoid = TopAbs_SHAPE); - //! Returns True if there are more shapes in the - //! exploration. - Standard_Boolean More() const; - + //! Returns True if there are more shapes in the exploration. + Standard_Boolean More() const { return hasMore; } + //! Moves to the next Shape in the exploration. //! Exceptions //! Standard_NoMoreObject if there are no more shapes to explore. @@ -135,15 +123,17 @@ public: //! Exceptions //! Standard_NoSuchObject if this explorer has no more shapes to explore. Standard_EXPORT const TopoDS_Shape& Current() const; - - //! Reinitialize the exploration with the original - //! arguments. + + //! Reinitialize the exploration with the original arguments. Standard_EXPORT void ReInit(); - + + //! Return explored shape. + const TopoDS_Shape& ExploredShape() const { return myShape; } + //! Returns the current depth of the exploration. 0 is //! the shape to explore itself. - Standard_Integer Depth() const; - + Standard_Integer Depth() const { return myTop; } + //! Clears the content of the explorer. It will return //! False on More(). void Clear(); @@ -154,19 +144,8 @@ public: Destroy(); } - - - -protected: - - - - - private: - - TopExp_Stack myStack; Standard_Integer myTop; Standard_Integer mySizeOfStack; @@ -175,14 +154,21 @@ private: TopAbs_ShapeEnum toFind; TopAbs_ShapeEnum toAvoid; - }; +#include -#include - - - - +inline void TopExp_Explorer::Clear() +{ + hasMore = Standard_False; + if (myTop > 0) + { + for (int i = 1; i <= myTop; i++) + { + myStack[i].~TopoDS_Iterator(); + } + } + myTop = 0; +} #endif // _TopExp_Explorer_HeaderFile diff --git a/src/TopExp/TopExp_Explorer.lxx b/src/TopExp/TopExp_Explorer.lxx deleted file mode 100644 index 3f263778a3..0000000000 --- a/src/TopExp/TopExp_Explorer.lxx +++ /dev/null @@ -1,54 +0,0 @@ -// Created on: 1993-01-18 -// Created by: Remi LEQUETTE -// Copyright (c) 1993-1999 Matra Datavision -// Copyright (c) 1999-2014 OPEN CASCADE SAS -// -// This file is part of Open CASCADE Technology software library. -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License version 2.1 as published -// by the Free Software Foundation, with special exception defined in the file -// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT -// distribution for complete text of the license and disclaimer of any warranty. -// -// Alternatively, this file may be used under the terms of Open CASCADE -// commercial license or contractual agreement. - -#include - -//======================================================================= -//function : More -//purpose : -//======================================================================= - -inline Standard_Boolean TopExp_Explorer::More()const -{ - return hasMore; -} - - -//======================================================================= -//function : Depth -//purpose : -//======================================================================= - -inline Standard_Integer TopExp_Explorer::Depth()const -{ - return myTop; -} - - -//======================================================================= -//function : Clear -//purpose : -//======================================================================= - -inline void TopExp_Explorer::Clear() -{ - hasMore = Standard_False; - if(myTop >0) { - for(int i=1;i<= myTop; i++) - myStack[i].~TopoDS_Iterator(); - } - myTop = 0; -} diff --git a/src/TopoDS/FILES b/src/TopoDS/FILES index 27345a189f..1fd91a9eea 100644 --- a/src/TopoDS/FILES +++ b/src/TopoDS/FILES @@ -19,7 +19,6 @@ TopoDS_HShape.hxx TopoDS_HShape.lxx TopoDS_Iterator.cxx TopoDS_Iterator.hxx -TopoDS_Iterator.lxx TopoDS_ListIteratorOfListOfShape.hxx TopoDS_ListOfShape.hxx TopoDS_LockedShape.hxx diff --git a/src/TopoDS/TopoDS_Iterator.cxx b/src/TopoDS/TopoDS_Iterator.cxx index eb5aab9010..ca51b61d00 100644 --- a/src/TopoDS/TopoDS_Iterator.cxx +++ b/src/TopoDS/TopoDS_Iterator.cxx @@ -16,11 +16,10 @@ #define No_Standard_NoSuchObject +#include #include #include -#include -#include //======================================================================= //function : Initialize diff --git a/src/TopoDS/TopoDS_Iterator.hxx b/src/TopoDS/TopoDS_Iterator.hxx index 473c1e193d..b1ab7c4929 100644 --- a/src/TopoDS/TopoDS_Iterator.hxx +++ b/src/TopoDS/TopoDS_Iterator.hxx @@ -17,19 +17,11 @@ #ifndef _TopoDS_Iterator_HeaderFile #define _TopoDS_Iterator_HeaderFile -#include -#include -#include - +#include #include #include #include #include -#include -class Standard_NoMoreObject; -class Standard_NoSuchObject; -class TopoDS_Shape; - //! Iterates on the underlying shape underlying a given //! TopoDS_Shape object, providing access to its @@ -42,10 +34,9 @@ public: DEFINE_STANDARD_ALLOC - //! Creates an empty Iterator. - TopoDS_Iterator(); - + TopoDS_Iterator() {} + //! Creates an Iterator on sub-shapes. //! Note: //! - If cumOri is true, the function composes all @@ -53,8 +44,13 @@ public: //! - If cumLoc is true, the function multiplies all //! sub-shapes by the location of S, i.e. it applies to //! each sub-shape the transformation that is associated with S. - TopoDS_Iterator(const TopoDS_Shape& S, const Standard_Boolean cumOri = Standard_True, const Standard_Boolean cumLoc = Standard_True); - + TopoDS_Iterator (const TopoDS_Shape& S, + const Standard_Boolean cumOri = Standard_True, + const Standard_Boolean cumLoc = Standard_True) + { + Initialize (S, cumOri,cumLoc); + } + //! Initializes this iterator with shape S. //! Note: //! - If cumOri is true, the function composes all @@ -66,8 +62,8 @@ public: //! Returns true if there is another sub-shape in the //! shape which this iterator is scanning. - Standard_Boolean More() const; - + Standard_Boolean More() const { return myShapes.More(); } + //! Moves on to the next sub-shape in the shape which //! this iterator is scanning. //! Exceptions @@ -78,34 +74,19 @@ public: //! this iterator is scanning. //! Exceptions //! Standard_NoSuchObject if there is no current sub-shape. - const TopoDS_Shape& Value() const; - - - - -protected: - - - - + const TopoDS_Shape& Value() const + { + Standard_NoSuchObject_Raise_if(!More(),"TopoDS_Iterator::Value"); + return myShape; + } private: - - TopoDS_Shape myShape; TopoDS_ListIteratorOfListOfShape myShapes; TopAbs_Orientation myOrientation; TopLoc_Location myLocation; - }; - -#include - - - - - #endif // _TopoDS_Iterator_HeaderFile diff --git a/src/TopoDS/TopoDS_Iterator.lxx b/src/TopoDS/TopoDS_Iterator.lxx deleted file mode 100644 index b005ad00f9..0000000000 --- a/src/TopoDS/TopoDS_Iterator.lxx +++ /dev/null @@ -1,58 +0,0 @@ -// Created on: 1993-01-21 -// Created by: Remi LEQUETTE -// Copyright (c) 1993-1999 Matra Datavision -// Copyright (c) 1999-2014 OPEN CASCADE SAS -// -// This file is part of Open CASCADE Technology software library. -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License version 2.1 as published -// by the Free Software Foundation, with special exception defined in the file -// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT -// distribution for complete text of the license and disclaimer of any warranty. -// -// Alternatively, this file may be used under the terms of Open CASCADE -// commercial license or contractual agreement. - -#include - -//======================================================================= -//function : TopoDS_Iterator -//purpose : -//======================================================================= - -inline TopoDS_Iterator::TopoDS_Iterator() -{} - -//======================================================================= -//function : TopoDS_Iterator -//purpose : -//======================================================================= - -inline TopoDS_Iterator::TopoDS_Iterator(const TopoDS_Shape& S, - const Standard_Boolean cumOri, - const Standard_Boolean cumLoc) -{ - Initialize(S,cumOri,cumLoc); -} - -//======================================================================= -//function : More -//purpose : -//======================================================================= - -inline Standard_Boolean TopoDS_Iterator::More() const -{ - return myShapes.More(); -} - -//======================================================================= -//function : Value -//purpose : -//======================================================================= - -inline const TopoDS_Shape& TopoDS_Iterator::Value() const -{ - Standard_NoSuchObject_Raise_if(!More(),"TopoDS_Iterator::Value"); - return myShape; -} diff --git a/src/XCAFDoc/XCAFDoc_VisMaterial.cxx b/src/XCAFDoc/XCAFDoc_VisMaterial.cxx index da6bd33cae..847289eb09 100644 --- a/src/XCAFDoc/XCAFDoc_VisMaterial.cxx +++ b/src/XCAFDoc/XCAFDoc_VisMaterial.cxx @@ -240,6 +240,11 @@ void XCAFDoc_VisMaterial::FillMaterialAspect (Graphic3d_MaterialAspect& theAspec theAspect.SetAlpha (myPbrMat.BaseColor.Alpha()); theAspect.SetSpecularColor(Quantity_Color (Graphic3d_Vec3 (myPbrMat.Metallic))); theAspect.SetShininess (1.0f - myPbrMat.Roughness); + if (theAspect.Shininess() < 0.01f) + { + // clamp too small shininess values causing visual artifacts on corner view angles + theAspect.SetShininess (0.01f); + } theAspect.SetEmissiveColor (Quantity_Color (myPbrMat.EmissiveFactor.cwiseMin (Graphic3d_Vec3 (1.0f)))); } diff --git a/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx b/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx index 6a847af543..20c6ee9389 100644 --- a/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx +++ b/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx @@ -148,6 +148,27 @@ static bool parseNameFormat (const char* theArg, return true; } +//! Parse RWMesh_CoordinateSystem enumeration. +static bool parseCoordinateSystem (const char* theArg, + RWMesh_CoordinateSystem& theSystem) +{ + TCollection_AsciiString aCSStr (theArg); + aCSStr.LowerCase(); + if (aCSStr == "zup") + { + theSystem = RWMesh_CoordinateSystem_Zup; + } + else if (aCSStr == "yup") + { + theSystem = RWMesh_CoordinateSystem_Yup; + } + else + { + return Standard_False; + } + return Standard_True; +} + //============================================================================= //function : ReadGltf //purpose : Reads glTF file @@ -333,7 +354,9 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI, Handle(TDocStd_Application) anApp = DDocStd::GetApplication(); TColStd_IndexedDataMapOfStringString aFileInfo; RWGltf_WriterTrsfFormat aTrsfFormat = RWGltf_WriterTrsfFormat_Compact; + RWMesh_CoordinateSystem aSystemCoordSys = RWMesh_CoordinateSystem_Zup; bool toForceUVExport = false, toEmbedTexturesInGlb = true; + bool toMergeFaces = false, toSplitIndices16 = false; RWMesh_NameFormat aNodeNameFormat = RWMesh_NameFormat_InstanceOrProduct; RWMesh_NameFormat aMeshNameFormat = RWMesh_NameFormat_Product; for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter) @@ -360,6 +383,40 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI, ++anArgIter; } } + else if (anArgCase == "-mergefaces") + { + toMergeFaces = true; + if (anArgIter + 1 < theNbArgs + && Draw::ParseOnOff (theArgVec[anArgIter + 1], toMergeFaces)) + { + ++anArgIter; + } + } + else if (anArgCase == "-splitindices16" + || anArgCase == "-splitindexes16" + || anArgCase == "-splitindices" + || anArgCase == "-splitindexes" + || anArgCase == "-splitind") + { + toSplitIndices16 = true; + if (anArgIter + 1 < theNbArgs + && Draw::ParseOnOff (theArgVec[anArgIter + 1], toSplitIndices16)) + { + ++anArgIter; + } + } + else if (anArgIter + 1 < theNbArgs + && (anArgCase == "-systemcoordinatesystem" + || anArgCase == "-systemcoordsystem" + || anArgCase == "-systemcoordsys" + || anArgCase == "-syscoordsys")) + { + if (!parseCoordinateSystem (theArgVec[++anArgIter], aSystemCoordSys)) + { + Message::SendFail() << "Syntax error: unknown coordinate system '" << theArgVec[anArgIter] << "'"; + return 1; + } + } else if (anArgCase == "-trsfformat" && anArgIter + 1 < theNbArgs) { @@ -456,8 +513,10 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI, aWriter.SetMeshNameFormat (aMeshNameFormat); aWriter.SetForcedUVExport (toForceUVExport); aWriter.SetToEmbedTexturesInGlb (toEmbedTexturesInGlb); + aWriter.SetMergeFaces (toMergeFaces); + aWriter.SetSplitIndices16 (toSplitIndices16); aWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit (aSystemUnitFactor); - aWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem (RWMesh_CoordinateSystem_Zup); + aWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem (aSystemCoordSys); aWriter.Perform (aDoc, aFileInfo, aProgress->Start()); return 0; } @@ -550,27 +609,6 @@ static Standard_Integer readstl(Draw_Interpretor& theDI, return 0; } -//! Parse RWMesh_CoordinateSystem enumeration. -static Standard_Boolean parseCoordinateSystem (const char* theArg, - RWMesh_CoordinateSystem& theSystem) -{ - TCollection_AsciiString aCSStr (theArg); - aCSStr.LowerCase(); - if (aCSStr == "zup") - { - theSystem = RWMesh_CoordinateSystem_Zup; - } - else if (aCSStr == "yup") - { - theSystem = RWMesh_CoordinateSystem_Yup; - } - else - { - return Standard_False; - } - return Standard_True; -} - //============================================================================= //function : ReadObj //purpose : Reads OBJ file @@ -1985,14 +2023,18 @@ void XSDRAWSTLVRML::InitCommands (Draw_Interpretor& theCommands) "\n\t\t: Same as ReadGltf but reads glTF file into a shape instead of a document.", __FILE__, ReadGltf, g); theCommands.Add ("WriteGltf", - "WriteGltf Doc file [-trsfFormat {compact|TRS|mat4}=compact]" + "WriteGltf Doc file [-trsfFormat {compact|TRS|mat4}]=compact" + "\n\t\t: [-systemCoordSys {Zup|Yup}]=Zup" "\n\t\t: [-comments Text] [-author Name]" - "\n\t\t: [-forceUVExport] [-texturesSeparate]" - "\n\t\t: [-nodeNameFormat {empty|product|instance|instOrProd|prodOrInst|prodAndInst|verbose}=instOrProd]" - "\n\t\t: [-meshNameFormat {empty|product|instance|instOrProd|prodOrInst|prodAndInst|verbose}=product]" + "\n\t\t: [-forceUVExport]=0 [-texturesSeparate]=0 [-mergeFaces]=0 [-splitIndices16]=0" + "\n\t\t: [-nodeNameFormat {empty|product|instance|instOrProd|prodOrInst|prodAndInst|verbose}]=instOrProd" + "\n\t\t: [-meshNameFormat {empty|product|instance|instOrProd|prodOrInst|prodAndInst|verbose}]=product" "\n\t\t: Write XDE document into glTF file." "\n\t\t: -trsfFormat preferred transformation format" - "\n\t\t: -forceUVExport always export UV coordinates" + "\n\t\t: -systemCoordSys system coordinate system; Zup when not specified" + "\n\t\t: -mergeFaces merge Faces within the same Mesh" + "\n\t\t: -splitIndices16 split Faces to keep 16-bit indices when -mergeFaces is enabled" + "\n\t\t: -forceUVExport always export UV coordinates" "\n\t\t: -texturesSeparate write textures to separate files" "\n\t\t: -nodeNameFormat name format for Nodes" "\n\t\t: -meshNameFormat name format for Meshes", diff --git a/tests/de_mesh/gltf_write/as1 b/tests/de_mesh/gltf_write/as1 new file mode 100644 index 0000000000..3efb8b1ea4 --- /dev/null +++ b/tests/de_mesh/gltf_write/as1 @@ -0,0 +1,24 @@ +puts "========" +puts "0032530: Data Exchange, RWGltf_CafWriter - add option merging Faces within the Part" +puts "========" + +Close D0 -silent +ReadStep D0 [locate_data_file as1-oc-214-mat.stp] +XGetOneShape ss D0 +incmesh ss 1.0 + +set aTmpGltf1 "${imagedir}/${casename}_tmp1.glb" +set aTmpGltf2 "${imagedir}/${casename}_tmp2.glb" +lappend occ_tmp_files $aTmpGltf1 +lappend occ_tmp_files $aTmpGltf2 + +WriteGltf D0 "$aTmpGltf1" +WriteGltf D0 "$aTmpGltf2" -mergeFaces + +ReadGltf D1 "$aTmpGltf1" +XGetOneShape s1 D1 +checknbshapes s1 -face 160 -compound 28 + +ReadGltf D "$aTmpGltf2" +XGetOneShape s2 D +checknbshapes s2 -face 18 -compound 10