From: mkrylova Date: Fri, 6 Nov 2020 08:33:58 +0000 (+0300) Subject: 0031703: Data Exchange, RWGltf_CafWriter - add option putting textures inside GLB... X-Git-Tag: V7_6_0_beta~349 X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=6eb502b27b4449f31133abab775736da1fdf2253;p=occt.git 0031703: Data Exchange, RWGltf_CafWriter - add option putting textures inside GLB file as alternative to external references RWGltf_CafWriter::ToEmbedTexturesInGlb() - added option embedding textures into GLB file enabled by default. Fixed uninitialized class field RWGltf_CafWriter::myIsForcedUVExport. Image_Texture::MimeType() - added method returning MIME type based on image file format. Image_Texture::WriteImage() - added method writing image into stream. --- diff --git a/src/Image/Image_Texture.cxx b/src/Image/Image_Texture.cxx index ce9d2a540a..7d1a168ac0 100644 --- a/src/Image/Image_Texture.cxx +++ b/src/Image/Image_Texture.cxx @@ -207,6 +207,36 @@ Handle(Image_PixMap) Image_Texture::loadImageOffset (const TCollection_AsciiStri return anImage; } +// ================================================================ +// Function : MimeType +// Purpose : +// ================================================================ +TCollection_AsciiString Image_Texture::MimeType() const +{ + const TCollection_AsciiString aType = ProbeImageFileFormat(); + if (aType == "jpg") + { + return "image/jpeg"; + } + else if (aType == "png" + || aType == "bmp" + || aType == "webp" + || aType == "gif" + || aType == "tiff") + { + return TCollection_AsciiString ("image/") + aType; + } + else if (aType == "dds") + { + return "image/vnd-ms.dds"; + } + else if (!aType.IsEmpty()) + { + return TCollection_AsciiString ("image/x-") + aType; + } + return TCollection_AsciiString(); +} + // ================================================================ // Function : ProbeImageFileFormat // Purpose : @@ -285,58 +315,92 @@ TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const // ================================================================ Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFile) { - Handle(NCollection_Buffer) aBuffer = myBuffer; - if (myBuffer.IsNull()) + std::ofstream aFileOut; + OSD_OpenStream (aFileOut, theFile.ToCString(), std::ios::out | std::ios::binary | std::ios::trunc); + if (!aFileOut) { - std::ifstream aFileIn; - OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary); - if (!aFileIn) + Message::SendFail (TCollection_AsciiString ("Error: Unable to create file '") + theFile + "'"); + return false; + } + + if (!WriteImage (aFileOut, theFile)) + { + return false; + } + + aFileOut.close(); + if (!aFileOut.good()) + { + Message::SendFail (TCollection_AsciiString ("Error: Unable to write file '") + theFile + "'"); + return false; + } + return true; +} + +// ================================================================ +// Function : WriteImage +// Purpose : +// ================================================================ +Standard_Boolean Image_Texture::WriteImage (std::ostream& theStream, + const TCollection_AsciiString& theFile) +{ + if (!myBuffer.IsNull()) + { + theStream.write ((const char* )myBuffer->Data(), myBuffer->Size()); + if (!theStream.good()) { - Message::SendFail (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!"); - return Standard_False; + Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' cannot be written"); + return false; } + return true; + } - Standard_Size aLen = (Standard_Size )myLength; - if (myOffset >= 0) + std::ifstream aFileIn; + OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary); + if (!aFileIn) + { + Message::SendFail (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!"); + return false; + } + + int64_t aLen = myLength; + if (myOffset >= 0) + { + aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg); + if (!aFileIn.good()) { - aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg); - if (!aFileIn.good()) - { - Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'"); - return Standard_False; - } + Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'"); + return false; } - else + } + else + { + aFileIn.seekg (0, std::ios_base::end); + aLen = (int64_t )aFileIn.tellg(); + aFileIn.seekg (0, std::ios_base::beg); + } + + Standard_Integer aChunkSize = 4096; + NCollection_Array1 aBuffer (0, aChunkSize - 1); + for (int64_t aChunkIter = 0; aChunkIter < aLen; aChunkIter += aChunkSize) + { + if (aChunkIter + aChunkSize >= aLen) { - aFileIn.seekg (0, std::ios_base::end); - aLen = (Standard_Size )aFileIn.tellg(); - aFileIn.seekg (0, std::ios_base::beg); + aChunkSize = Standard_Integer(aLen - aChunkIter); } - - aBuffer = new NCollection_Buffer (NCollection_BaseAllocator::CommonBaseAllocator(), aLen); - if (!aFileIn.read ((char* )aBuffer->ChangeData(), aBuffer->Size())) + if (!aFileIn.read ((char* )&aBuffer.ChangeFirst(), aChunkSize)) { Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'"); - return Standard_False; + return false; } + theStream.write ((const char* )&aBuffer.First(), aChunkSize); } - - std::ofstream aFileOut; - OSD_OpenStream (aFileOut, theFile.ToCString(), std::ios::out | std::ios::binary | std::ios::trunc); - if (!aFileOut) - { - Message::SendFail (TCollection_AsciiString ("Error: Unable to create file '") + theFile + "'"); - return Standard_False; - } - - aFileOut.write ((const char* )aBuffer->Data(), aBuffer->Size()); - aFileOut.close(); - if (!aFileOut.good()) + if (!theStream.good()) { - Message::SendFail (TCollection_AsciiString ("Error: Unable to write file '") + theFile + "'"); - return Standard_False; + Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' can not be written"); + return false; } - return Standard_True; + return true; } //======================================================================= diff --git a/src/Image/Image_Texture.hxx b/src/Image/Image_Texture.hxx index 7a6f53be6b..57575a5283 100644 --- a/src/Image/Image_Texture.hxx +++ b/src/Image/Image_Texture.hxx @@ -56,6 +56,9 @@ public: //! Return buffer holding encoded image content. const Handle(NCollection_Buffer)& DataBuffer() const { return myBuffer; } + //! Return mime-type of image file based on ProbeImageFileFormat(). + Standard_EXPORT TCollection_AsciiString MimeType() const; + //! Return image file format. Standard_EXPORT TCollection_AsciiString ProbeImageFileFormat() const; @@ -68,6 +71,10 @@ public: //! Write image to specified file without decoding data. Standard_EXPORT virtual Standard_Boolean WriteImage (const TCollection_AsciiString& theFile); + //! Write image to specified stream without decoding data. + Standard_EXPORT virtual Standard_Boolean WriteImage (std::ostream& theStream, + const TCollection_AsciiString& theFile); + public: //! @name hasher interface //! Hash value, for Map interface. diff --git a/src/RWGltf/RWGltf_CafWriter.cxx b/src/RWGltf/RWGltf_CafWriter.cxx index 0b4f2a0f5c..99b2e271f0 100644 --- a/src/RWGltf/RWGltf_CafWriter.cxx +++ b/src/RWGltf/RWGltf_CafWriter.cxx @@ -103,6 +103,8 @@ RWGltf_CafWriter::RWGltf_CafWriter (const TCollection_AsciiString& theFile, : myFile (theFile), myTrsfFormat (RWGltf_WriterTrsfFormat_Compact), myIsBinary (theIsBinary), + myIsForcedUVExport (false), + myToEmbedTexturesInGlb (true), myBinDataLen64 (0) { myCSTrsf.SetOutputLengthUnit (1.0); // meters @@ -303,6 +305,10 @@ bool RWGltf_CafWriter::Perform (const Handle(TDocStd_Document)& theDocument, const TColStd_IndexedDataMapOfStringString& theFileInfo, const Message_ProgressRange& theProgress) { + const Standard_Integer aDefSamplerId = 0; + myMaterialMap = new RWGltf_GltfMaterialMap (myFile, aDefSamplerId); + myMaterialMap->SetDefaultStyle (myDefaultStyle); + Message_ProgressScope aPSentry (theProgress, "Writing glTF file", 2); if (!writeBinData (theDocument, theRootLabels, theLabelFilter, aPSentry.Next())) { @@ -326,18 +332,25 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument const TColStd_MapOfAsciiString* theLabelFilter, const Message_ProgressRange& theProgress) { + myBuffViewPos.Id = RWGltf_GltfAccessor::INVALID_ID; myBuffViewPos.ByteOffset = 0; myBuffViewPos.ByteLength = 0; myBuffViewPos.ByteStride = 12; myBuffViewPos.Target = RWGltf_GltfBufferViewTarget_ARRAY_BUFFER; + + myBuffViewNorm.Id = RWGltf_GltfAccessor::INVALID_ID; myBuffViewNorm.ByteOffset = 0; myBuffViewNorm.ByteLength = 0; myBuffViewNorm.ByteStride = 12; myBuffViewNorm.Target = RWGltf_GltfBufferViewTarget_ARRAY_BUFFER; + + myBuffViewTextCoord.Id = RWGltf_GltfAccessor::INVALID_ID; myBuffViewTextCoord.ByteOffset = 0; myBuffViewTextCoord.ByteLength = 0; myBuffViewTextCoord.ByteStride = 8; myBuffViewTextCoord.Target = RWGltf_GltfBufferViewTarget_ARRAY_BUFFER; + + myBuffViewInd.Id = RWGltf_GltfAccessor::INVALID_ID; myBuffViewInd.ByteOffset = 0; myBuffViewInd.ByteLength = 0; myBuffViewInd.Target = RWGltf_GltfBufferViewTarget_ELEMENT_ARRAY_BUFFER; @@ -515,6 +528,33 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument } myBuffViewInd.ByteLength = (int64_t )aBinFile.tellp() - myBuffViewInd.ByteOffset; + if (myIsBinary + && myToEmbedTexturesInGlb) + { + // save unique image textures + 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(); aFaceIter.Next()) + { + if (toSkipFaceMesh (aFaceIter)) + { + continue; + } + + myMaterialMap->AddGlbImages (aBinFile, aFaceIter.FaceStyle()); + } + } + } + int aBuffViewId = 0; if (myBuffViewPos.ByteLength > 0) { @@ -532,6 +572,7 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument { myBuffViewInd.Id = aBuffViewId++; } + // myMaterialMap->FlushGlbBufferViews() will put image bufferView's IDs at the end of list myBinDataLen64 = aBinFile.tellp(); aBinFile.close(); @@ -560,7 +601,6 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument, Message_ProgressScope aPSentryBin (theProgress, "Header data", 2); const Standard_Integer aBinDataBufferId = 0; - const Standard_Integer aDefSamplerId = 0; const Standard_Integer aDefSceneId = 0; const TCollection_AsciiString aFileNameGltf = myFile; @@ -612,13 +652,11 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument, writeAsset (theFileInfo); writeBufferViews (aBinDataBufferId); writeBuffers(); - writeExtensions (); + writeExtensions(); - RWGltf_GltfMaterialMap aMaterialMap (myFile, aDefSamplerId); - aMaterialMap.SetDefaultStyle (myDefaultStyle); - writeImages (aSceneNodeMap, aMaterialMap); - writeMaterials (aSceneNodeMap, aMaterialMap); - writeMeshes (aSceneNodeMap, aMaterialMap); + writeImages (aSceneNodeMap); + writeMaterials (aSceneNodeMap); + writeMeshes (aSceneNodeMap); aPSentryBin.Next(); if (!aPSentryBin.More()) @@ -629,11 +667,11 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument, // root nodes indices starting from 0 NCollection_Sequence aSceneRootNodeInds; writeNodes (theDocument, theRootLabels, theLabelFilter, aSceneNodeMap, aSceneRootNodeInds); - writeSamplers (aMaterialMap); + writeSamplers(); writeScene (aDefSceneId); writeScenes (aSceneRootNodeInds); writeSkins(); - writeTextures (aSceneNodeMap, aMaterialMap); + writeTextures (aSceneNodeMap); myWriter->EndObject(); @@ -1044,10 +1082,12 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer #ifdef HAVE_RAPIDJSON Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeBufferViews()"); + int aBuffViewId = 0; myWriter->Key (RWGltf_GltfRootElementName (RWGltf_GltfRootElement_BufferViews)); myWriter->StartArray(); if (myBuffViewPos.Id != RWGltf_GltfAccessor::INVALID_ID) { + aBuffViewId++; myWriter->StartObject(); myWriter->Key ("buffer"); myWriter->Int (theBinDataBufferId); @@ -1063,6 +1103,7 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer } if (myBuffViewNorm.Id != RWGltf_GltfAccessor::INVALID_ID) { + aBuffViewId++; myWriter->StartObject(); myWriter->Key ("buffer"); myWriter->Int (theBinDataBufferId); @@ -1078,6 +1119,7 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer } if (myBuffViewTextCoord.Id != RWGltf_GltfAccessor::INVALID_ID) { + aBuffViewId++; myWriter->StartObject(); myWriter->Key ("buffer"); myWriter->Int (theBinDataBufferId); @@ -1093,6 +1135,7 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer } if (myBuffViewInd.Id != RWGltf_GltfAccessor::INVALID_ID) { + aBuffViewId++; myWriter->StartObject(); myWriter->Key ("buffer"); myWriter->Int (theBinDataBufferId); @@ -1104,6 +1147,9 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer myWriter->Int (myBuffViewInd.Target); myWriter->EndObject(); } + + myMaterialMap->FlushGlbBufferViews (myWriter.get(), theBinDataBufferId, aBuffViewId); + myWriter->EndArray(); #else (void )theBinDataBufferId; @@ -1125,8 +1171,7 @@ void RWGltf_CafWriter::writeBuffers() myWriter->StartObject(); { myWriter->Key ("byteLength"); - myWriter->Int64 (myBuffViewPos.ByteLength + myBuffViewNorm.ByteLength + - myBuffViewTextCoord.ByteLength + myBuffViewInd.ByteLength); + myWriter->Int64 (myBinDataLen64); if (!myIsBinary) { myWriter->Key ("uri"); @@ -1152,29 +1197,35 @@ void RWGltf_CafWriter::writeExtensions() // function : writeImages // purpose : // ======================================================================= -void RWGltf_CafWriter::writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, - RWGltf_GltfMaterialMap& theMaterialMap) +void RWGltf_CafWriter::writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeMap) { #ifdef HAVE_RAPIDJSON Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeImages()"); // empty RWGltf_GltfRootElement_Images section should NOT be written to avoid validator errors - bool anIsStarted = false; - for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter (theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next()) + if (myIsBinary + && myToEmbedTexturesInGlb) { - const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) - { - theMaterialMap.AddImages (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); - } + myMaterialMap->FlushGlbImages (myWriter.get()); } - if (anIsStarted) + else { - myWriter->EndArray(); + bool anIsStarted = false; + 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()) + { + myMaterialMap->AddImages (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); + } + } + if (anIsStarted) + { + myWriter->EndArray(); + } } #else (void )theSceneNodeMap; - (void )theMaterialMap; #endif } @@ -1182,8 +1233,7 @@ void RWGltf_CafWriter::writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeM // function : writeMaterials // purpose : // ======================================================================= -void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, - RWGltf_GltfMaterialMap& theMaterialMap) +void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNodeMap) { #ifdef HAVE_RAPIDJSON Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeMaterials()"); @@ -1195,7 +1245,7 @@ void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNo const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) { - theMaterialMap.AddMaterial (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); + myMaterialMap->AddMaterial (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); } } if (anIsStarted) @@ -1204,7 +1254,6 @@ void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNo } #else (void )theSceneNodeMap; - (void )theMaterialMap; #endif } @@ -1212,8 +1261,7 @@ void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNo // function : writeMeshes // purpose : // ======================================================================= -void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, - const RWGltf_GltfMaterialMap& theMaterialMap) +void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeMap) { #ifdef HAVE_RAPIDJSON Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeMeshes()"); @@ -1248,7 +1296,7 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM } const RWGltf_GltfFace& aGltfFace = myBinDataMap.Find (aFaceIter.Face()); - const TCollection_AsciiString aMatId = theMaterialMap.FindMaterial (aFaceIter.FaceStyle()); + const TCollection_AsciiString aMatId = myMaterialMap->FindMaterial (aFaceIter.FaceStyle()); myWriter->StartObject(); { myWriter->Key ("attributes"); @@ -1287,7 +1335,6 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM myWriter->EndArray(); #else (void )theSceneNodeMap; - (void )theMaterialMap; #endif } @@ -1476,11 +1523,11 @@ void RWGltf_CafWriter::writeNodes (const Handle(TDocStd_Document)& theDocument, // function : writeSamplers // purpose : // ======================================================================= -void RWGltf_CafWriter::writeSamplers (const RWGltf_GltfMaterialMap& theMaterialMap) +void RWGltf_CafWriter::writeSamplers() { #ifdef HAVE_RAPIDJSON Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeSamplers()"); - if (theMaterialMap.NbImages() == 0) + if (myMaterialMap->NbImages() == 0) { return; } @@ -1498,8 +1545,6 @@ void RWGltf_CafWriter::writeSamplers (const RWGltf_GltfMaterialMap& theMaterialM myWriter->EndObject(); } myWriter->EndArray(); -#else - (void )theMaterialMap; #endif } @@ -1565,8 +1610,7 @@ void RWGltf_CafWriter::writeSkins() // function : writeTextures // purpose : // ======================================================================= -void RWGltf_CafWriter::writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, - RWGltf_GltfMaterialMap& theMaterialMap) +void RWGltf_CafWriter::writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNodeMap) { #ifdef HAVE_RAPIDJSON Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeTextures()"); @@ -1578,7 +1622,7 @@ void RWGltf_CafWriter::writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNod const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) { - theMaterialMap.AddTextures (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); + myMaterialMap->AddTextures (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); } } if (anIsStarted) @@ -1587,6 +1631,5 @@ void RWGltf_CafWriter::writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNod } #else (void )theSceneNodeMap; - (void )theMaterialMap; #endif } diff --git a/src/RWGltf/RWGltf_CafWriter.hxx b/src/RWGltf/RWGltf_CafWriter.hxx index 5444fdd458..0d84cb1998 100644 --- a/src/RWGltf/RWGltf_CafWriter.hxx +++ b/src/RWGltf/RWGltf_CafWriter.hxx @@ -78,6 +78,14 @@ public: //! Set default material definition to be used for nodes with only color defined. void SetDefaultStyle (const XCAFPrs_Style& theStyle) { myDefaultStyle = theStyle; } + //! Return flag to write image textures into GLB file (binary gltf export); TRUE by default. + //! When set to FALSE, texture images will be written as separate files. + //! Has no effect on writing into non-binary format. + Standard_Boolean ToEmbedTexturesInGlb() { return myToEmbedTexturesInGlb; } + + //! Set flag to write image textures into GLB file (binary gltf export). + void SetToEmbedTexturesInGlb (Standard_Boolean theToEmbedTexturesInGlb) { myToEmbedTexturesInGlb = theToEmbedTexturesInGlb; } + //! Write glTF file and associated binary file. //! Triangulation data should be precomputed within shapes! //! @param theDocument [in] input document @@ -221,20 +229,17 @@ protected: //! Write RWGltf_GltfRootElement_Images section. //! @param theSceneNodeMap [in] ordered map of scene nodes //! @param theMaterialMap [out] map of materials, filled with image files used by textures - Standard_EXPORT virtual void writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, - RWGltf_GltfMaterialMap& theMaterialMap); + Standard_EXPORT virtual void writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeMap); //! Write RWGltf_GltfRootElement_Materials section. //! @param theSceneNodeMap [in] ordered map of scene nodes //! @param theMaterialMap [out] map of materials, filled with materials - Standard_EXPORT virtual void writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, - RWGltf_GltfMaterialMap& theMaterialMap); + Standard_EXPORT virtual void writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNodeMap); //! Write RWGltf_GltfRootElement_Meshes section. //! @param theSceneNodeMap [in] ordered map of scene nodes //! @param theMaterialMap [in] map of materials - Standard_EXPORT virtual void writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, - const RWGltf_GltfMaterialMap& theMaterialMap); + Standard_EXPORT virtual void writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeMap); //! Write RWGltf_GltfRootElement_Nodes section. //! @param theDocument [in] input document @@ -249,7 +254,7 @@ protected: NCollection_Sequence& theSceneRootNodeInds); //! Write RWGltf_GltfRootElement_Samplers section. - Standard_EXPORT virtual void writeSamplers (const RWGltf_GltfMaterialMap& theMaterialMap); + Standard_EXPORT virtual void writeSamplers(); //! Write RWGltf_GltfRootElement_Scene section. //! @param theDefSceneId [in] index of default scene (0) @@ -265,8 +270,7 @@ protected: //! Write RWGltf_GltfRootElement_Textures section. //! @param theSceneNodeMap [in] ordered map of scene nodes //! @param theMaterialMap [out] map of materials, filled with textures - Standard_EXPORT virtual void writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, - RWGltf_GltfMaterialMap& theMaterialMap); + Standard_EXPORT virtual void writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNodeMap); protected: @@ -276,11 +280,13 @@ protected: RWGltf_WriterTrsfFormat myTrsfFormat; //!< transformation format to write into glTF file 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 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 opencascade::std::shared_ptr myWriter; //!< JSON writer + Handle(RWGltf_GltfMaterialMap) myMaterialMap; //!< map of defined materials RWGltf_GltfBufferView myBuffViewPos; //!< current buffer view with nodes positions RWGltf_GltfBufferView myBuffViewNorm; //!< current buffer view with nodes normals RWGltf_GltfBufferView myBuffViewTextCoord; //!< current buffer view with nodes UV coordinates diff --git a/src/RWGltf/RWGltf_GltfBufferView.hxx b/src/RWGltf/RWGltf_GltfBufferView.hxx index dfdd6aee61..2dbc88a3d9 100644 --- a/src/RWGltf/RWGltf_GltfBufferView.hxx +++ b/src/RWGltf/RWGltf_GltfBufferView.hxx @@ -24,9 +24,9 @@ struct RWGltf_GltfBufferView static const int INVALID_ID = -1; public: - int Id; - int64_t ByteOffset; - int64_t ByteLength; + int Id; //!< index of bufferView in the array of bufferViews + int64_t ByteOffset; //!< offset to the beginning of the data in buffer + int64_t ByteLength; //!< length of the data int32_t ByteStride; //!< [0, 255] RWGltf_GltfBufferViewTarget Target; diff --git a/src/RWGltf/RWGltf_GltfMaterialMap.cxx b/src/RWGltf/RWGltf_GltfMaterialMap.cxx index 763538de82..b143e5b554 100644 --- a/src/RWGltf/RWGltf_GltfMaterialMap.cxx +++ b/src/RWGltf/RWGltf_GltfMaterialMap.cxx @@ -13,12 +13,17 @@ #include +#include +#include +#include #include #ifdef HAVE_RAPIDJSON #include #endif +IMPLEMENT_STANDARD_RTTIEXT(RWGltf_GltfMaterialMap, RWMesh_MaterialMap) + // ======================================================================= // function : baseColorTexture // purpose : @@ -51,8 +56,7 @@ RWGltf_GltfMaterialMap::RWGltf_GltfMaterialMap (const TCollection_AsciiString& t const Standard_Integer theDefSamplerId) : RWMesh_MaterialMap (theFile), myWriter (NULL), - myDefSamplerId (theDefSamplerId), - myNbImages (0) + myDefSamplerId (theDefSamplerId) { myMatNameAsKey = false; } @@ -88,6 +92,26 @@ void RWGltf_GltfMaterialMap::AddImages (RWGltf_GltfOStreamWriter* theWriter, addImage (theWriter, theStyle.Material()->PbrMaterial().OcclusionTexture, theIsStarted); } +// ======================================================================= +// function : AddGlbImages +// purpose : +// ======================================================================= +void RWGltf_GltfMaterialMap::AddGlbImages (std::ostream& theBinFile, + const XCAFPrs_Style& theStyle) +{ + if (theStyle.Material().IsNull() + || theStyle.Material()->IsEmpty()) + { + return; + } + + addGlbImage (theBinFile, baseColorTexture (theStyle.Material())); + addGlbImage (theBinFile, theStyle.Material()->PbrMaterial().MetallicRoughnessTexture); + addGlbImage (theBinFile, theStyle.Material()->PbrMaterial().NormalTexture); + addGlbImage (theBinFile, theStyle.Material()->PbrMaterial().EmissiveTexture); + addGlbImage (theBinFile, theStyle.Material()->PbrMaterial().OcclusionTexture); +} + // ======================================================================= // function : addImage // purpose : @@ -98,27 +122,20 @@ void RWGltf_GltfMaterialMap::addImage (RWGltf_GltfOStreamWriter* theWriter, { #ifdef HAVE_RAPIDJSON if (theTexture.IsNull() - || myImageMap.IsBound1 (theTexture) + || myImageMap.Contains (theTexture) || myImageFailMap.Contains (theTexture)) { return; } - TCollection_AsciiString aGltfImgKey = myNbImages; - ++myNbImages; - for (; myImageMap.IsBound2 (aGltfImgKey); ++myNbImages) - { - aGltfImgKey = myNbImages; - } - + const TCollection_AsciiString aGltfImgKey = myImageMap.Extent(); TCollection_AsciiString aTextureUri; if (!CopyTexture (aTextureUri, theTexture, aGltfImgKey)) { myImageFailMap.Add (theTexture); return; } - - myImageMap.Bind (theTexture, aGltfImgKey); + myImageMap.Add (theTexture, RWGltf_GltfBufferView()); if (!theIsStarted) { @@ -140,6 +157,133 @@ void RWGltf_GltfMaterialMap::addImage (RWGltf_GltfOStreamWriter* theWriter, #endif } +// ======================================================================= +// function : addGlbImage +// purpose : +// ======================================================================= +void RWGltf_GltfMaterialMap::addGlbImage (std::ostream& theBinFile, + const Handle(Image_Texture)& theTexture) +{ + if (theTexture.IsNull() + || myImageMap.Contains (theTexture) + || myImageFailMap.Contains (theTexture)) + { + return; + } + + RWGltf_GltfBufferView aBuffImage; + aBuffImage.ByteOffset = theBinFile.tellp(); + if (!theTexture->WriteImage (theBinFile, myFileName)) + { + myImageFailMap.Add (theTexture); + return; + } + + // alignment by 4 bytes + int64_t aContentLen64 = (int64_t)theBinFile.tellp(); + while (aContentLen64 % 4 != 0) + { + theBinFile.write (" ", 1); + ++aContentLen64; + } + + //aBuffImage.Id = myBuffViewImages.Size(); // id will be corrected later + aBuffImage.ByteLength = (int64_t)theBinFile.tellp() - aBuffImage.ByteOffset; + if (aBuffImage.ByteLength <= 0) + { + myImageFailMap.Add (theTexture); + return; + } + + myImageMap.Add (theTexture, aBuffImage); +} + +// ======================================================================= +// function : FlushBufferViews +// purpose : +// ======================================================================= +void RWGltf_GltfMaterialMap::FlushGlbBufferViews (RWGltf_GltfOStreamWriter* theWriter, + const Standard_Integer theBinDataBufferId, + Standard_Integer& theBuffViewId) +{ +#ifdef HAVE_RAPIDJSON + for (NCollection_IndexedDataMap::Iterator aBufViewIter (myImageMap); + aBufViewIter.More(); aBufViewIter.Next()) + { + RWGltf_GltfBufferView& aBuffView = aBufViewIter.ChangeValue(); + if (aBuffView.ByteLength <= 0) + { + continue; + } + + aBuffView.Id = theBuffViewId++; + theWriter->StartObject(); + theWriter->Key ("buffer"); + theWriter->Int (theBinDataBufferId); + theWriter->Key ("byteLength"); + theWriter->Int64 (aBuffView.ByteLength); + theWriter->Key ("byteOffset"); + theWriter->Int64 (aBuffView.ByteOffset); + theWriter->EndObject(); + } +#else + (void )theWriter; + (void )theBinDataBufferId; + (void )theBuffViewId; +#endif +} + +// ======================================================================= +// function : FlushGlbImages +// purpose : +// ======================================================================= +void RWGltf_GltfMaterialMap::FlushGlbImages (RWGltf_GltfOStreamWriter* theWriter) +{ +#ifdef HAVE_RAPIDJSON + bool isStarted = false; + for (NCollection_IndexedDataMap::Iterator aBufViewIter (myImageMap); + aBufViewIter.More(); aBufViewIter.Next()) + { + const Handle(Image_Texture)& aTexture = aBufViewIter.Key(); + const RWGltf_GltfBufferView& aBuffView = aBufViewIter.Value(); + if (aBuffView.ByteLength <= 0) + { + continue; + } + + if (!isStarted) + { + theWriter->Key (RWGltf_GltfRootElementName (RWGltf_GltfRootElement_Images)); + theWriter->StartArray(); + isStarted = true; + } + + theWriter->StartObject(); + { + const TCollection_AsciiString anImageFormat = aTexture->MimeType(); + if (anImageFormat != "image/png" + && anImageFormat != "image/jpeg") + { + Message::SendWarning (TCollection_AsciiString ("Warning! Non-standard mime-type ") + + anImageFormat + " (texture " + aTexture->TextureId() + + ") within glTF file"); + } + theWriter->Key ("mimeType"); + theWriter->String (anImageFormat.ToCString()); + theWriter->Key ("bufferView"); + theWriter->Int (aBuffView.Id); + } + theWriter->EndObject(); + } + if (isStarted) + { + theWriter->EndArray(); + } +#else + (void )theWriter; +#endif +} + // ======================================================================= // function : AddMaterial // purpose : @@ -205,17 +349,13 @@ void RWGltf_GltfMaterialMap::addTexture (RWGltf_GltfOStreamWriter* theWriter, #ifdef HAVE_RAPIDJSON if (theTexture.IsNull() || myTextureMap.Contains (theTexture) - || !myImageMap .IsBound1 (theTexture)) + || !myImageMap .Contains (theTexture)) { return; } - const TCollection_AsciiString anImgKey = myImageMap.Find1 (theTexture); + const Standard_Integer anImgKey = myImageMap.FindIndex (theTexture) - 1; // glTF indexation starts from 0 myTextureMap.Add (theTexture); - if (anImgKey.IsEmpty()) - { - return; - } if (!theIsStarted) { @@ -229,7 +369,7 @@ void RWGltf_GltfMaterialMap::addTexture (RWGltf_GltfOStreamWriter* theWriter, theWriter->Key ("sampler"); theWriter->Int (myDefSamplerId); // mandatory field by specs theWriter->Key ("source"); - theWriter->Int (anImgKey.IntegerValue()); + theWriter->Int (anImgKey); } theWriter->EndObject(); #else @@ -303,17 +443,14 @@ void RWGltf_GltfMaterialMap::DefineMaterial (const XCAFPrs_Style& theStyle, if (const Handle(Image_Texture)& aBaseTexture = baseColorTexture (theStyle.Material())) { - if (myImageMap.IsBound1 (aBaseTexture)) + const Standard_Integer aBaseImageIdx = myImageMap.FindIndex (aBaseTexture) - 1; + if (aBaseImageIdx != -1) { myWriter->Key ("baseColorTexture"); myWriter->StartObject(); { myWriter->Key ("index"); - const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aBaseTexture); - if (!anImageIdx.IsEmpty()) - { - myWriter->Int (anImageIdx.IntegerValue()); - } + myWriter->Int (aBaseImageIdx); } myWriter->EndObject(); } @@ -326,18 +463,16 @@ void RWGltf_GltfMaterialMap::DefineMaterial (const XCAFPrs_Style& theStyle, myWriter->Double (aPbrMat.Metallic); } - if (!aPbrMat.MetallicRoughnessTexture.IsNull() - && myImageMap.IsBound1 (aPbrMat.MetallicRoughnessTexture)) + const Standard_Integer aMetRoughImageIdx = !aPbrMat.MetallicRoughnessTexture.IsNull() + ? myImageMap.FindIndex (aPbrMat.MetallicRoughnessTexture) - 1 + : -1; + if (aMetRoughImageIdx != -1) { myWriter->Key ("metallicRoughnessTexture"); myWriter->StartObject(); { myWriter->Key ("index"); - const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.MetallicRoughnessTexture); - if (!anImageIdx.IsEmpty()) - { - myWriter->Int (anImageIdx.IntegerValue()); - } + myWriter->Int (aMetRoughImageIdx); } myWriter->EndObject(); } @@ -405,50 +540,45 @@ void RWGltf_GltfMaterialMap::DefineMaterial (const XCAFPrs_Style& theStyle, } myWriter->EndArray(); } - if (!aPbrMat.EmissiveTexture.IsNull() - && myImageMap.IsBound1 (aPbrMat.EmissiveTexture)) + + const Standard_Integer anEmissImageIdx = !aPbrMat.EmissiveTexture.IsNull() + ? myImageMap.FindIndex (aPbrMat.EmissiveTexture) - 1 + : -1; + if (anEmissImageIdx != -1) { myWriter->Key ("emissiveTexture"); myWriter->StartObject(); { myWriter->Key ("index"); - const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.EmissiveTexture); - if (!anImageIdx.IsEmpty()) - { - myWriter->Int (anImageIdx.IntegerValue()); - } + myWriter->Int (anEmissImageIdx); } myWriter->EndObject(); } - if (!aPbrMat.NormalTexture.IsNull() - && myImageMap.IsBound1 (aPbrMat.NormalTexture)) + const Standard_Integer aNormImageIdx = !aPbrMat.NormalTexture.IsNull() + ? myImageMap.FindIndex (aPbrMat.NormalTexture) - 1 + : -1; + if (aNormImageIdx != -1) { myWriter->Key ("normalTexture"); myWriter->StartObject(); { myWriter->Key ("index"); - const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.NormalTexture); - if (!anImageIdx.IsEmpty()) - { - myWriter->Int (anImageIdx.IntegerValue()); - } + myWriter->Int (aNormImageIdx); } myWriter->EndObject(); } - if (!aPbrMat.OcclusionTexture.IsNull() - && myImageMap.IsBound1 (aPbrMat.OcclusionTexture)) + const Standard_Integer anOcclusImageIdx = !aPbrMat.OcclusionTexture.IsNull() + ? myImageMap.FindIndex (aPbrMat.OcclusionTexture) - 1 + : -1; + if (anOcclusImageIdx != -1) { myWriter->Key ("occlusionTexture"); myWriter->StartObject(); { myWriter->Key ("index"); - const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.OcclusionTexture); - if (!anImageIdx.IsEmpty()) - { - myWriter->Int (anImageIdx.IntegerValue()); - } + myWriter->Int (anOcclusImageIdx); } myWriter->EndObject(); } diff --git a/src/RWGltf/RWGltf_GltfMaterialMap.hxx b/src/RWGltf/RWGltf_GltfMaterialMap.hxx index 815999151f..357d5586b7 100644 --- a/src/RWGltf/RWGltf_GltfMaterialMap.hxx +++ b/src/RWGltf/RWGltf_GltfMaterialMap.hxx @@ -15,12 +15,14 @@ #define _RWGltf_GltfMaterialMap_HeaderFile #include +#include class RWGltf_GltfOStreamWriter; //! Material manager for exporting into glTF format. class RWGltf_GltfMaterialMap : public RWMesh_MaterialMap { + DEFINE_STANDARD_RTTIEXT(RWGltf_GltfMaterialMap, RWMesh_MaterialMap) public: //! Main constructor. @@ -30,7 +32,26 @@ public: //! Destructor. Standard_EXPORT virtual ~RWGltf_GltfMaterialMap(); - //! Add material images. +public: + + //! Add material images into GLB stream. + //! @param theBinFile [in] [out] output file stream + //! @param theStyle [in] material images to add + Standard_EXPORT void AddGlbImages (std::ostream& theBinFile, + const XCAFPrs_Style& theStyle); + + //! Add bufferView's into RWGltf_GltfRootElement_BufferViews section with images collected by AddImagesToGlb(). + Standard_EXPORT void FlushGlbBufferViews (RWGltf_GltfOStreamWriter* theWriter, + const Standard_Integer theBinDataBufferId, + Standard_Integer& theBuffViewId); + + //! Write RWGltf_GltfRootElement_Images section with images collected by AddImagesToGlb(). + Standard_EXPORT void FlushGlbImages (RWGltf_GltfOStreamWriter* theWriter); + +public: + + //! Add material images in case of non-GLB file + //! (an alternative to AddImagesToGlb() + FlushBufferViews() + FlushImagesGlb()). Standard_EXPORT void AddImages (RWGltf_GltfOStreamWriter* theWriter, const XCAFPrs_Style& theStyle, Standard_Boolean& theIsStarted); @@ -62,6 +83,12 @@ protected: const Handle(Image_Texture)& theTexture, Standard_Boolean& theIsStarted); + //! Add texture image into GLB stream. + //! @param theBinFile [in] [out] output file stream + //! @param theTexture [in] texture image to add + Standard_EXPORT void addGlbImage (std::ostream& theBinFile, + const Handle(Image_Texture)& theTexture); + //! Add texture. Standard_EXPORT void addTexture (RWGltf_GltfOStreamWriter* theWriter, const Handle(Image_Texture)& theTexture, @@ -78,10 +105,10 @@ protected: protected: RWGltf_GltfOStreamWriter* myWriter; - NCollection_DoubleMap myImageMap; + NCollection_IndexedDataMap myImageMap; NCollection_Map myTextureMap; + Standard_Integer myDefSamplerId; - Standard_Integer myNbImages; }; diff --git a/src/RWMesh/RWMesh_MaterialMap.cxx b/src/RWMesh/RWMesh_MaterialMap.cxx index fcfb73ff3e..1a8f2e93f5 100644 --- a/src/RWMesh/RWMesh_MaterialMap.cxx +++ b/src/RWMesh/RWMesh_MaterialMap.cxx @@ -22,6 +22,8 @@ #include #include +IMPLEMENT_STANDARD_RTTIEXT(RWMesh_MaterialMap, Standard_Transient) + // ======================================================================= // function : RWMesh_MaterialMap // purpose : diff --git a/src/RWMesh/RWMesh_MaterialMap.hxx b/src/RWMesh/RWMesh_MaterialMap.hxx index 2e9034c20a..13aea517b3 100644 --- a/src/RWMesh/RWMesh_MaterialMap.hxx +++ b/src/RWMesh/RWMesh_MaterialMap.hxx @@ -21,8 +21,9 @@ //! Material manager. //! Provides an interface for collecting all materials within the document before writing it into file, //! and for copying associated image files (textures) into sub-folder near by exported model. -class RWMesh_MaterialMap +class RWMesh_MaterialMap : public Standard_Transient { + DEFINE_STANDARD_RTTIEXT(RWMesh_MaterialMap, Standard_Transient) public: //! Main constructor. diff --git a/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx b/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx index 3d8b497b4e..b35f318b41 100644 --- a/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx +++ b/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx @@ -221,7 +221,7 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI, Handle(TDocStd_Application) anApp = DDocStd::GetApplication(); TColStd_IndexedDataMapOfStringString aFileInfo; RWGltf_WriterTrsfFormat aTrsfFormat = RWGltf_WriterTrsfFormat_Compact; - bool toForceUVExport = false; + bool toForceUVExport = false, toEmbedTexturesInGlb = true; for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter) { TCollection_AsciiString anArgCase (theArgVec[anArgIter]); @@ -291,6 +291,10 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI, { aGltfFilePath = theArgVec[anArgIter]; } + else if (anArgCase == "-texturesSeparate") + { + toEmbedTexturesInGlb = false; + } else { Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'"; @@ -313,6 +317,7 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI, RWGltf_CafWriter aWriter (aGltfFilePath, anExt.EndsWith (".glb")); aWriter.SetTransformationFormat (aTrsfFormat); aWriter.SetForcedUVExport (toForceUVExport); + aWriter.SetToEmbedTexturesInGlb (toEmbedTexturesInGlb); aWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit (aSystemUnitFactor); aWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem (RWMesh_CoordinateSystem_Zup); aWriter.Perform (aDoc, aFileInfo, aProgress->Start()); @@ -1724,10 +1729,11 @@ 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] [-comments Text] [-author Name] [-forceUVExport]" + "WriteGltf Doc file [-trsfFormat {compact|TRS|mat4}=compact] [-comments Text] [-author Name] [-forceUVExport] [-texturesSeparate]" "\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: -forceUVExport always export UV coordinates" + "\n\t\t: -texturesSeparate write textures to separate files", __FILE__, WriteGltf, g); theCommands.Add ("writegltf", "writegltf shape file", diff --git a/tests/de_mesh/gltf_write/helmetglb b/tests/de_mesh/gltf_write/helmetglb new file mode 100644 index 0000000000..55c06b8df0 --- /dev/null +++ b/tests/de_mesh/gltf_write/helmetglb @@ -0,0 +1,20 @@ +puts "========" +puts "0031703: Data Exchange, RWGltf_CafWriter - add option putting textures inside GLB file as alternative to external references" +puts "Test case exporting glTF model into GLB file." +puts "========" + +catch { Close D1 } +ReadGltf D1 [locate_data_file bug30691_DamagedHelmet.gltf] + +set aTmpGltfBase "${imagedir}/${casename}_tmp" +set aTmpGltf "${aTmpGltfBase}.glb" +lappend occ_tmp_files $aTmpGltf +lappend occ_tmp_files "${aTmpGltfBase}.bin" +lappend occ_tmp_files "${aTmpGltfBase}_textures" + +WriteGltf D1 "$aTmpGltf" + +ReadGltf D "$aTmpGltf" +XGetOneShape s D +checknbshapes s -face 1 -compound 0 +checktrinfo s -tri 15452 -nod 14556 diff --git a/tests/de_mesh/gltf_write/lanternglb b/tests/de_mesh/gltf_write/lanternglb new file mode 100644 index 0000000000..f8650fabe9 --- /dev/null +++ b/tests/de_mesh/gltf_write/lanternglb @@ -0,0 +1,20 @@ +puts "========" +puts "0031703: Data Exchange, RWGltf_CafWriter - add option putting textures inside GLB file as alternative to external references" +puts "Test case exporting glTF model into GLB file." +puts "========" + +catch { Close D1 } +ReadGltf D1 [locate_data_file bug30691_Lantern.glb] + +set aTmpGltfBase "${imagedir}/${casename}_tmp" +set aTmpGltf "${aTmpGltfBase}.glb" +lappend occ_tmp_files $aTmpGltf +lappend occ_tmp_files "${aTmpGltfBase}.bin" +lappend occ_tmp_files "${aTmpGltfBase}_textures" + +WriteGltf D1 "$aTmpGltf" + +ReadGltf D "$aTmpGltf" +XGetOneShape s D +checknbshapes s -face 3 -compound 1 +checktrinfo s -tri 5394 -nod 4145