1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-24 13:50:49 +03:00

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.
This commit is contained in:
mkrylova
2020-11-06 11:33:58 +03:00
committed by bugmaster
parent a2cb8561eb
commit 6eb502b27b
12 changed files with 477 additions and 151 deletions

View File

@@ -207,6 +207,36 @@ Handle(Image_PixMap) Image_Texture::loadImageOffset (const TCollection_AsciiStri
return anImage; 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 // Function : ProbeImageFileFormat
// Purpose : // Purpose :
@@ -285,58 +315,92 @@ TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const
// ================================================================ // ================================================================
Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFile) Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFile)
{ {
Handle(NCollection_Buffer) aBuffer = myBuffer; std::ofstream aFileOut;
if (myBuffer.IsNull()) 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 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 ("File '") + theFile + "' cannot be written");
return false;
}
return true;
}
std::ifstream aFileIn; std::ifstream aFileIn;
OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary); OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary);
if (!aFileIn) if (!aFileIn)
{ {
Message::SendFail (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!"); Message::SendFail (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!");
return Standard_False; return false;
} }
Standard_Size aLen = (Standard_Size )myLength; int64_t aLen = myLength;
if (myOffset >= 0) if (myOffset >= 0)
{ {
aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg); aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg);
if (!aFileIn.good()) if (!aFileIn.good())
{ {
Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'"); Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'");
return Standard_False; return false;
} }
} }
else else
{ {
aFileIn.seekg (0, std::ios_base::end); aFileIn.seekg (0, std::ios_base::end);
aLen = (Standard_Size )aFileIn.tellg(); aLen = (int64_t )aFileIn.tellg();
aFileIn.seekg (0, std::ios_base::beg); aFileIn.seekg (0, std::ios_base::beg);
} }
aBuffer = new NCollection_Buffer (NCollection_BaseAllocator::CommonBaseAllocator(), aLen); Standard_Integer aChunkSize = 4096;
if (!aFileIn.read ((char* )aBuffer->ChangeData(), aBuffer->Size())) NCollection_Array1<Standard_Byte> aBuffer (0, aChunkSize - 1);
for (int64_t aChunkIter = 0; aChunkIter < aLen; aChunkIter += aChunkSize)
{
if (aChunkIter + aChunkSize >= aLen)
{
aChunkSize = Standard_Integer(aLen - aChunkIter);
}
if (!aFileIn.read ((char* )&aBuffer.ChangeFirst(), aChunkSize))
{ {
Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'"); Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'");
return Standard_False; return false;
} }
theStream.write ((const char* )&aBuffer.First(), aChunkSize);
} }
if (!theStream.good())
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 + "'"); Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' can not be written");
return Standard_False; return false;
} }
return true;
aFileOut.write ((const char* )aBuffer->Data(), aBuffer->Size());
aFileOut.close();
if (!aFileOut.good())
{
Message::SendFail (TCollection_AsciiString ("Error: Unable to write file '") + theFile + "'");
return Standard_False;
}
return Standard_True;
} }
//======================================================================= //=======================================================================

View File

@@ -56,6 +56,9 @@ public:
//! Return buffer holding encoded image content. //! Return buffer holding encoded image content.
const Handle(NCollection_Buffer)& DataBuffer() const { return myBuffer; } 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. //! Return image file format.
Standard_EXPORT TCollection_AsciiString ProbeImageFileFormat() const; Standard_EXPORT TCollection_AsciiString ProbeImageFileFormat() const;
@@ -68,6 +71,10 @@ public:
//! Write image to specified file without decoding data. //! Write image to specified file without decoding data.
Standard_EXPORT virtual Standard_Boolean WriteImage (const TCollection_AsciiString& theFile); 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 public: //! @name hasher interface
//! Hash value, for Map interface. //! Hash value, for Map interface.

View File

@@ -103,6 +103,8 @@ RWGltf_CafWriter::RWGltf_CafWriter (const TCollection_AsciiString& theFile,
: myFile (theFile), : myFile (theFile),
myTrsfFormat (RWGltf_WriterTrsfFormat_Compact), myTrsfFormat (RWGltf_WriterTrsfFormat_Compact),
myIsBinary (theIsBinary), myIsBinary (theIsBinary),
myIsForcedUVExport (false),
myToEmbedTexturesInGlb (true),
myBinDataLen64 (0) myBinDataLen64 (0)
{ {
myCSTrsf.SetOutputLengthUnit (1.0); // meters myCSTrsf.SetOutputLengthUnit (1.0); // meters
@@ -303,6 +305,10 @@ bool RWGltf_CafWriter::Perform (const Handle(TDocStd_Document)& theDocument,
const TColStd_IndexedDataMapOfStringString& theFileInfo, const TColStd_IndexedDataMapOfStringString& theFileInfo,
const Message_ProgressRange& theProgress) 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); Message_ProgressScope aPSentry (theProgress, "Writing glTF file", 2);
if (!writeBinData (theDocument, theRootLabels, theLabelFilter, aPSentry.Next())) 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 TColStd_MapOfAsciiString* theLabelFilter,
const Message_ProgressRange& theProgress) const Message_ProgressRange& theProgress)
{ {
myBuffViewPos.Id = RWGltf_GltfAccessor::INVALID_ID;
myBuffViewPos.ByteOffset = 0; myBuffViewPos.ByteOffset = 0;
myBuffViewPos.ByteLength = 0; myBuffViewPos.ByteLength = 0;
myBuffViewPos.ByteStride = 12; myBuffViewPos.ByteStride = 12;
myBuffViewPos.Target = RWGltf_GltfBufferViewTarget_ARRAY_BUFFER; myBuffViewPos.Target = RWGltf_GltfBufferViewTarget_ARRAY_BUFFER;
myBuffViewNorm.Id = RWGltf_GltfAccessor::INVALID_ID;
myBuffViewNorm.ByteOffset = 0; myBuffViewNorm.ByteOffset = 0;
myBuffViewNorm.ByteLength = 0; myBuffViewNorm.ByteLength = 0;
myBuffViewNorm.ByteStride = 12; myBuffViewNorm.ByteStride = 12;
myBuffViewNorm.Target = RWGltf_GltfBufferViewTarget_ARRAY_BUFFER; myBuffViewNorm.Target = RWGltf_GltfBufferViewTarget_ARRAY_BUFFER;
myBuffViewTextCoord.Id = RWGltf_GltfAccessor::INVALID_ID;
myBuffViewTextCoord.ByteOffset = 0; myBuffViewTextCoord.ByteOffset = 0;
myBuffViewTextCoord.ByteLength = 0; myBuffViewTextCoord.ByteLength = 0;
myBuffViewTextCoord.ByteStride = 8; myBuffViewTextCoord.ByteStride = 8;
myBuffViewTextCoord.Target = RWGltf_GltfBufferViewTarget_ARRAY_BUFFER; myBuffViewTextCoord.Target = RWGltf_GltfBufferViewTarget_ARRAY_BUFFER;
myBuffViewInd.Id = RWGltf_GltfAccessor::INVALID_ID;
myBuffViewInd.ByteOffset = 0; myBuffViewInd.ByteOffset = 0;
myBuffViewInd.ByteLength = 0; myBuffViewInd.ByteLength = 0;
myBuffViewInd.Target = RWGltf_GltfBufferViewTarget_ELEMENT_ARRAY_BUFFER; 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; 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; int aBuffViewId = 0;
if (myBuffViewPos.ByteLength > 0) if (myBuffViewPos.ByteLength > 0)
{ {
@@ -532,6 +572,7 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument
{ {
myBuffViewInd.Id = aBuffViewId++; myBuffViewInd.Id = aBuffViewId++;
} }
// myMaterialMap->FlushGlbBufferViews() will put image bufferView's IDs at the end of list
myBinDataLen64 = aBinFile.tellp(); myBinDataLen64 = aBinFile.tellp();
aBinFile.close(); aBinFile.close();
@@ -560,7 +601,6 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument,
Message_ProgressScope aPSentryBin (theProgress, "Header data", 2); Message_ProgressScope aPSentryBin (theProgress, "Header data", 2);
const Standard_Integer aBinDataBufferId = 0; const Standard_Integer aBinDataBufferId = 0;
const Standard_Integer aDefSamplerId = 0;
const Standard_Integer aDefSceneId = 0; const Standard_Integer aDefSceneId = 0;
const TCollection_AsciiString aFileNameGltf = myFile; const TCollection_AsciiString aFileNameGltf = myFile;
@@ -612,13 +652,11 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument,
writeAsset (theFileInfo); writeAsset (theFileInfo);
writeBufferViews (aBinDataBufferId); writeBufferViews (aBinDataBufferId);
writeBuffers(); writeBuffers();
writeExtensions (); writeExtensions();
RWGltf_GltfMaterialMap aMaterialMap (myFile, aDefSamplerId); writeImages (aSceneNodeMap);
aMaterialMap.SetDefaultStyle (myDefaultStyle); writeMaterials (aSceneNodeMap);
writeImages (aSceneNodeMap, aMaterialMap); writeMeshes (aSceneNodeMap);
writeMaterials (aSceneNodeMap, aMaterialMap);
writeMeshes (aSceneNodeMap, aMaterialMap);
aPSentryBin.Next(); aPSentryBin.Next();
if (!aPSentryBin.More()) if (!aPSentryBin.More())
@@ -629,11 +667,11 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument,
// root nodes indices starting from 0 // root nodes indices starting from 0
NCollection_Sequence<Standard_Integer> aSceneRootNodeInds; NCollection_Sequence<Standard_Integer> aSceneRootNodeInds;
writeNodes (theDocument, theRootLabels, theLabelFilter, aSceneNodeMap, aSceneRootNodeInds); writeNodes (theDocument, theRootLabels, theLabelFilter, aSceneNodeMap, aSceneRootNodeInds);
writeSamplers (aMaterialMap); writeSamplers();
writeScene (aDefSceneId); writeScene (aDefSceneId);
writeScenes (aSceneRootNodeInds); writeScenes (aSceneRootNodeInds);
writeSkins(); writeSkins();
writeTextures (aSceneNodeMap, aMaterialMap); writeTextures (aSceneNodeMap);
myWriter->EndObject(); myWriter->EndObject();
@@ -1044,10 +1082,12 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer
#ifdef HAVE_RAPIDJSON #ifdef HAVE_RAPIDJSON
Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeBufferViews()"); Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeBufferViews()");
int aBuffViewId = 0;
myWriter->Key (RWGltf_GltfRootElementName (RWGltf_GltfRootElement_BufferViews)); myWriter->Key (RWGltf_GltfRootElementName (RWGltf_GltfRootElement_BufferViews));
myWriter->StartArray(); myWriter->StartArray();
if (myBuffViewPos.Id != RWGltf_GltfAccessor::INVALID_ID) if (myBuffViewPos.Id != RWGltf_GltfAccessor::INVALID_ID)
{ {
aBuffViewId++;
myWriter->StartObject(); myWriter->StartObject();
myWriter->Key ("buffer"); myWriter->Key ("buffer");
myWriter->Int (theBinDataBufferId); myWriter->Int (theBinDataBufferId);
@@ -1063,6 +1103,7 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer
} }
if (myBuffViewNorm.Id != RWGltf_GltfAccessor::INVALID_ID) if (myBuffViewNorm.Id != RWGltf_GltfAccessor::INVALID_ID)
{ {
aBuffViewId++;
myWriter->StartObject(); myWriter->StartObject();
myWriter->Key ("buffer"); myWriter->Key ("buffer");
myWriter->Int (theBinDataBufferId); myWriter->Int (theBinDataBufferId);
@@ -1078,6 +1119,7 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer
} }
if (myBuffViewTextCoord.Id != RWGltf_GltfAccessor::INVALID_ID) if (myBuffViewTextCoord.Id != RWGltf_GltfAccessor::INVALID_ID)
{ {
aBuffViewId++;
myWriter->StartObject(); myWriter->StartObject();
myWriter->Key ("buffer"); myWriter->Key ("buffer");
myWriter->Int (theBinDataBufferId); myWriter->Int (theBinDataBufferId);
@@ -1093,6 +1135,7 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer
} }
if (myBuffViewInd.Id != RWGltf_GltfAccessor::INVALID_ID) if (myBuffViewInd.Id != RWGltf_GltfAccessor::INVALID_ID)
{ {
aBuffViewId++;
myWriter->StartObject(); myWriter->StartObject();
myWriter->Key ("buffer"); myWriter->Key ("buffer");
myWriter->Int (theBinDataBufferId); myWriter->Int (theBinDataBufferId);
@@ -1104,6 +1147,9 @@ void RWGltf_CafWriter::writeBufferViews (const Standard_Integer theBinDataBuffer
myWriter->Int (myBuffViewInd.Target); myWriter->Int (myBuffViewInd.Target);
myWriter->EndObject(); myWriter->EndObject();
} }
myMaterialMap->FlushGlbBufferViews (myWriter.get(), theBinDataBufferId, aBuffViewId);
myWriter->EndArray(); myWriter->EndArray();
#else #else
(void )theBinDataBufferId; (void )theBinDataBufferId;
@@ -1125,8 +1171,7 @@ void RWGltf_CafWriter::writeBuffers()
myWriter->StartObject(); myWriter->StartObject();
{ {
myWriter->Key ("byteLength"); myWriter->Key ("byteLength");
myWriter->Int64 (myBuffViewPos.ByteLength + myBuffViewNorm.ByteLength + myWriter->Int64 (myBinDataLen64);
myBuffViewTextCoord.ByteLength + myBuffViewInd.ByteLength);
if (!myIsBinary) if (!myIsBinary)
{ {
myWriter->Key ("uri"); myWriter->Key ("uri");
@@ -1152,29 +1197,35 @@ void RWGltf_CafWriter::writeExtensions()
// function : writeImages // function : writeImages
// purpose : // purpose :
// ======================================================================= // =======================================================================
void RWGltf_CafWriter::writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, void RWGltf_CafWriter::writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeMap)
RWGltf_GltfMaterialMap& theMaterialMap)
{ {
#ifdef HAVE_RAPIDJSON #ifdef HAVE_RAPIDJSON
Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeImages()"); 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 // empty RWGltf_GltfRootElement_Images section should NOT be written to avoid validator errors
if (myIsBinary
&& myToEmbedTexturesInGlb)
{
myMaterialMap->FlushGlbImages (myWriter.get());
}
else
{
bool anIsStarted = false; bool anIsStarted = false;
for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter (theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next()) for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter(theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next())
{ {
const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value();
for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next())
{ {
theMaterialMap.AddImages (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); myMaterialMap->AddImages (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted);
} }
} }
if (anIsStarted) if (anIsStarted)
{ {
myWriter->EndArray(); myWriter->EndArray();
} }
}
#else #else
(void )theSceneNodeMap; (void )theSceneNodeMap;
(void )theMaterialMap;
#endif #endif
} }
@@ -1182,8 +1233,7 @@ void RWGltf_CafWriter::writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeM
// function : writeMaterials // function : writeMaterials
// purpose : // purpose :
// ======================================================================= // =======================================================================
void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNodeMap)
RWGltf_GltfMaterialMap& theMaterialMap)
{ {
#ifdef HAVE_RAPIDJSON #ifdef HAVE_RAPIDJSON
Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeMaterials()"); 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(); const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value();
for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) 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) if (anIsStarted)
@@ -1204,7 +1254,6 @@ void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNo
} }
#else #else
(void )theSceneNodeMap; (void )theSceneNodeMap;
(void )theMaterialMap;
#endif #endif
} }
@@ -1212,8 +1261,7 @@ void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNo
// function : writeMeshes // function : writeMeshes
// purpose : // purpose :
// ======================================================================= // =======================================================================
void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeMap)
const RWGltf_GltfMaterialMap& theMaterialMap)
{ {
#ifdef HAVE_RAPIDJSON #ifdef HAVE_RAPIDJSON
Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeMeshes()"); 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 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->StartObject();
{ {
myWriter->Key ("attributes"); myWriter->Key ("attributes");
@@ -1287,7 +1335,6 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM
myWriter->EndArray(); myWriter->EndArray();
#else #else
(void )theSceneNodeMap; (void )theSceneNodeMap;
(void )theMaterialMap;
#endif #endif
} }
@@ -1476,11 +1523,11 @@ void RWGltf_CafWriter::writeNodes (const Handle(TDocStd_Document)& theDocument,
// function : writeSamplers // function : writeSamplers
// purpose : // purpose :
// ======================================================================= // =======================================================================
void RWGltf_CafWriter::writeSamplers (const RWGltf_GltfMaterialMap& theMaterialMap) void RWGltf_CafWriter::writeSamplers()
{ {
#ifdef HAVE_RAPIDJSON #ifdef HAVE_RAPIDJSON
Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeSamplers()"); Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeSamplers()");
if (theMaterialMap.NbImages() == 0) if (myMaterialMap->NbImages() == 0)
{ {
return; return;
} }
@@ -1498,8 +1545,6 @@ void RWGltf_CafWriter::writeSamplers (const RWGltf_GltfMaterialMap& theMaterialM
myWriter->EndObject(); myWriter->EndObject();
} }
myWriter->EndArray(); myWriter->EndArray();
#else
(void )theMaterialMap;
#endif #endif
} }
@@ -1565,8 +1610,7 @@ void RWGltf_CafWriter::writeSkins()
// function : writeTextures // function : writeTextures
// purpose : // purpose :
// ======================================================================= // =======================================================================
void RWGltf_CafWriter::writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, void RWGltf_CafWriter::writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNodeMap)
RWGltf_GltfMaterialMap& theMaterialMap)
{ {
#ifdef HAVE_RAPIDJSON #ifdef HAVE_RAPIDJSON
Standard_ProgramError_Raise_if (myWriter.get() == NULL, "Internal error: RWGltf_CafWriter::writeTextures()"); 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(); const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value();
for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) 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) if (anIsStarted)
@@ -1587,6 +1631,5 @@ void RWGltf_CafWriter::writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNod
} }
#else #else
(void )theSceneNodeMap; (void )theSceneNodeMap;
(void )theMaterialMap;
#endif #endif
} }

View File

@@ -78,6 +78,14 @@ public:
//! Set default material definition to be used for nodes with only color defined. //! Set default material definition to be used for nodes with only color defined.
void SetDefaultStyle (const XCAFPrs_Style& theStyle) { myDefaultStyle = theStyle; } 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. //! Write glTF file and associated binary file.
//! Triangulation data should be precomputed within shapes! //! Triangulation data should be precomputed within shapes!
//! @param theDocument [in] input document //! @param theDocument [in] input document
@@ -221,20 +229,17 @@ protected:
//! Write RWGltf_GltfRootElement_Images section. //! Write RWGltf_GltfRootElement_Images section.
//! @param theSceneNodeMap [in] ordered map of scene nodes //! @param theSceneNodeMap [in] ordered map of scene nodes
//! @param theMaterialMap [out] map of materials, filled with image files used by textures //! @param theMaterialMap [out] map of materials, filled with image files used by textures
Standard_EXPORT virtual void writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, Standard_EXPORT virtual void writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeMap);
RWGltf_GltfMaterialMap& theMaterialMap);
//! Write RWGltf_GltfRootElement_Materials section. //! Write RWGltf_GltfRootElement_Materials section.
//! @param theSceneNodeMap [in] ordered map of scene nodes //! @param theSceneNodeMap [in] ordered map of scene nodes
//! @param theMaterialMap [out] map of materials, filled with materials //! @param theMaterialMap [out] map of materials, filled with materials
Standard_EXPORT virtual void writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, Standard_EXPORT virtual void writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNodeMap);
RWGltf_GltfMaterialMap& theMaterialMap);
//! Write RWGltf_GltfRootElement_Meshes section. //! Write RWGltf_GltfRootElement_Meshes section.
//! @param theSceneNodeMap [in] ordered map of scene nodes //! @param theSceneNodeMap [in] ordered map of scene nodes
//! @param theMaterialMap [in] map of materials //! @param theMaterialMap [in] map of materials
Standard_EXPORT virtual void writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, Standard_EXPORT virtual void writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeMap);
const RWGltf_GltfMaterialMap& theMaterialMap);
//! Write RWGltf_GltfRootElement_Nodes section. //! Write RWGltf_GltfRootElement_Nodes section.
//! @param theDocument [in] input document //! @param theDocument [in] input document
@@ -249,7 +254,7 @@ protected:
NCollection_Sequence<Standard_Integer>& theSceneRootNodeInds); NCollection_Sequence<Standard_Integer>& theSceneRootNodeInds);
//! Write RWGltf_GltfRootElement_Samplers section. //! Write RWGltf_GltfRootElement_Samplers section.
Standard_EXPORT virtual void writeSamplers (const RWGltf_GltfMaterialMap& theMaterialMap); Standard_EXPORT virtual void writeSamplers();
//! Write RWGltf_GltfRootElement_Scene section. //! Write RWGltf_GltfRootElement_Scene section.
//! @param theDefSceneId [in] index of default scene (0) //! @param theDefSceneId [in] index of default scene (0)
@@ -265,8 +270,7 @@ protected:
//! Write RWGltf_GltfRootElement_Textures section. //! Write RWGltf_GltfRootElement_Textures section.
//! @param theSceneNodeMap [in] ordered map of scene nodes //! @param theSceneNodeMap [in] ordered map of scene nodes
//! @param theMaterialMap [out] map of materials, filled with textures //! @param theMaterialMap [out] map of materials, filled with textures
Standard_EXPORT virtual void writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNodeMap, Standard_EXPORT virtual void writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNodeMap);
RWGltf_GltfMaterialMap& theMaterialMap);
protected: protected:
@@ -276,11 +280,13 @@ protected:
RWGltf_WriterTrsfFormat myTrsfFormat; //!< transformation format to write into glTF file RWGltf_WriterTrsfFormat myTrsfFormat; //!< transformation format to write into glTF file
Standard_Boolean myIsBinary; //!< flag to write into binary glTF format (.glb) 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 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 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 XCAFPrs_Style myDefaultStyle; //!< default material definition to be used for nodes with only color defined
opencascade::std::shared_ptr<RWGltf_GltfOStreamWriter> opencascade::std::shared_ptr<RWGltf_GltfOStreamWriter>
myWriter; //!< JSON writer myWriter; //!< JSON writer
Handle(RWGltf_GltfMaterialMap) myMaterialMap; //!< map of defined materials
RWGltf_GltfBufferView myBuffViewPos; //!< current buffer view with nodes positions RWGltf_GltfBufferView myBuffViewPos; //!< current buffer view with nodes positions
RWGltf_GltfBufferView myBuffViewNorm; //!< current buffer view with nodes normals RWGltf_GltfBufferView myBuffViewNorm; //!< current buffer view with nodes normals
RWGltf_GltfBufferView myBuffViewTextCoord; //!< current buffer view with nodes UV coordinates RWGltf_GltfBufferView myBuffViewTextCoord; //!< current buffer view with nodes UV coordinates

View File

@@ -24,9 +24,9 @@ struct RWGltf_GltfBufferView
static const int INVALID_ID = -1; static const int INVALID_ID = -1;
public: public:
int Id; int Id; //!< index of bufferView in the array of bufferViews
int64_t ByteOffset; int64_t ByteOffset; //!< offset to the beginning of the data in buffer
int64_t ByteLength; int64_t ByteLength; //!< length of the data
int32_t ByteStride; //!< [0, 255] int32_t ByteStride; //!< [0, 255]
RWGltf_GltfBufferViewTarget Target; RWGltf_GltfBufferViewTarget Target;

View File

@@ -13,12 +13,17 @@
#include <RWGltf_GltfMaterialMap.hxx> #include <RWGltf_GltfMaterialMap.hxx>
#include <Message.hxx>
#include <NCollection_Array1.hxx>
#include <OSD_OpenFile.hxx>
#include <RWGltf_GltfRootElement.hxx> #include <RWGltf_GltfRootElement.hxx>
#ifdef HAVE_RAPIDJSON #ifdef HAVE_RAPIDJSON
#include <RWGltf_GltfOStreamWriter.hxx> #include <RWGltf_GltfOStreamWriter.hxx>
#endif #endif
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_GltfMaterialMap, RWMesh_MaterialMap)
// ======================================================================= // =======================================================================
// function : baseColorTexture // function : baseColorTexture
// purpose : // purpose :
@@ -51,8 +56,7 @@ RWGltf_GltfMaterialMap::RWGltf_GltfMaterialMap (const TCollection_AsciiString& t
const Standard_Integer theDefSamplerId) const Standard_Integer theDefSamplerId)
: RWMesh_MaterialMap (theFile), : RWMesh_MaterialMap (theFile),
myWriter (NULL), myWriter (NULL),
myDefSamplerId (theDefSamplerId), myDefSamplerId (theDefSamplerId)
myNbImages (0)
{ {
myMatNameAsKey = false; myMatNameAsKey = false;
} }
@@ -88,6 +92,26 @@ void RWGltf_GltfMaterialMap::AddImages (RWGltf_GltfOStreamWriter* theWriter,
addImage (theWriter, theStyle.Material()->PbrMaterial().OcclusionTexture, theIsStarted); 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 // function : addImage
// purpose : // purpose :
@@ -98,27 +122,20 @@ void RWGltf_GltfMaterialMap::addImage (RWGltf_GltfOStreamWriter* theWriter,
{ {
#ifdef HAVE_RAPIDJSON #ifdef HAVE_RAPIDJSON
if (theTexture.IsNull() if (theTexture.IsNull()
|| myImageMap.IsBound1 (theTexture) || myImageMap.Contains (theTexture)
|| myImageFailMap.Contains (theTexture)) || myImageFailMap.Contains (theTexture))
{ {
return; return;
} }
TCollection_AsciiString aGltfImgKey = myNbImages; const TCollection_AsciiString aGltfImgKey = myImageMap.Extent();
++myNbImages;
for (; myImageMap.IsBound2 (aGltfImgKey); ++myNbImages)
{
aGltfImgKey = myNbImages;
}
TCollection_AsciiString aTextureUri; TCollection_AsciiString aTextureUri;
if (!CopyTexture (aTextureUri, theTexture, aGltfImgKey)) if (!CopyTexture (aTextureUri, theTexture, aGltfImgKey))
{ {
myImageFailMap.Add (theTexture); myImageFailMap.Add (theTexture);
return; return;
} }
myImageMap.Add (theTexture, RWGltf_GltfBufferView());
myImageMap.Bind (theTexture, aGltfImgKey);
if (!theIsStarted) if (!theIsStarted)
{ {
@@ -140,6 +157,133 @@ void RWGltf_GltfMaterialMap::addImage (RWGltf_GltfOStreamWriter* theWriter,
#endif #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<Handle(Image_Texture), RWGltf_GltfBufferView, Image_Texture>::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<Handle(Image_Texture), RWGltf_GltfBufferView, Image_Texture>::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 // function : AddMaterial
// purpose : // purpose :
@@ -205,17 +349,13 @@ void RWGltf_GltfMaterialMap::addTexture (RWGltf_GltfOStreamWriter* theWriter,
#ifdef HAVE_RAPIDJSON #ifdef HAVE_RAPIDJSON
if (theTexture.IsNull() if (theTexture.IsNull()
|| myTextureMap.Contains (theTexture) || myTextureMap.Contains (theTexture)
|| !myImageMap .IsBound1 (theTexture)) || !myImageMap .Contains (theTexture))
{ {
return; return;
} }
const TCollection_AsciiString anImgKey = myImageMap.Find1 (theTexture); const Standard_Integer anImgKey = myImageMap.FindIndex (theTexture) - 1; // glTF indexation starts from 0
myTextureMap.Add (theTexture); myTextureMap.Add (theTexture);
if (anImgKey.IsEmpty())
{
return;
}
if (!theIsStarted) if (!theIsStarted)
{ {
@@ -229,7 +369,7 @@ void RWGltf_GltfMaterialMap::addTexture (RWGltf_GltfOStreamWriter* theWriter,
theWriter->Key ("sampler"); theWriter->Key ("sampler");
theWriter->Int (myDefSamplerId); // mandatory field by specs theWriter->Int (myDefSamplerId); // mandatory field by specs
theWriter->Key ("source"); theWriter->Key ("source");
theWriter->Int (anImgKey.IntegerValue()); theWriter->Int (anImgKey);
} }
theWriter->EndObject(); theWriter->EndObject();
#else #else
@@ -303,17 +443,14 @@ void RWGltf_GltfMaterialMap::DefineMaterial (const XCAFPrs_Style& theStyle,
if (const Handle(Image_Texture)& aBaseTexture = baseColorTexture (theStyle.Material())) 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->Key ("baseColorTexture");
myWriter->StartObject(); myWriter->StartObject();
{ {
myWriter->Key ("index"); myWriter->Key ("index");
const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aBaseTexture); myWriter->Int (aBaseImageIdx);
if (!anImageIdx.IsEmpty())
{
myWriter->Int (anImageIdx.IntegerValue());
}
} }
myWriter->EndObject(); myWriter->EndObject();
} }
@@ -326,18 +463,16 @@ void RWGltf_GltfMaterialMap::DefineMaterial (const XCAFPrs_Style& theStyle,
myWriter->Double (aPbrMat.Metallic); myWriter->Double (aPbrMat.Metallic);
} }
if (!aPbrMat.MetallicRoughnessTexture.IsNull() const Standard_Integer aMetRoughImageIdx = !aPbrMat.MetallicRoughnessTexture.IsNull()
&& myImageMap.IsBound1 (aPbrMat.MetallicRoughnessTexture)) ? myImageMap.FindIndex (aPbrMat.MetallicRoughnessTexture) - 1
: -1;
if (aMetRoughImageIdx != -1)
{ {
myWriter->Key ("metallicRoughnessTexture"); myWriter->Key ("metallicRoughnessTexture");
myWriter->StartObject(); myWriter->StartObject();
{ {
myWriter->Key ("index"); myWriter->Key ("index");
const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.MetallicRoughnessTexture); myWriter->Int (aMetRoughImageIdx);
if (!anImageIdx.IsEmpty())
{
myWriter->Int (anImageIdx.IntegerValue());
}
} }
myWriter->EndObject(); myWriter->EndObject();
} }
@@ -405,50 +540,45 @@ void RWGltf_GltfMaterialMap::DefineMaterial (const XCAFPrs_Style& theStyle,
} }
myWriter->EndArray(); 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->Key ("emissiveTexture");
myWriter->StartObject(); myWriter->StartObject();
{ {
myWriter->Key ("index"); myWriter->Key ("index");
const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.EmissiveTexture); myWriter->Int (anEmissImageIdx);
if (!anImageIdx.IsEmpty())
{
myWriter->Int (anImageIdx.IntegerValue());
}
} }
myWriter->EndObject(); myWriter->EndObject();
} }
if (!aPbrMat.NormalTexture.IsNull() const Standard_Integer aNormImageIdx = !aPbrMat.NormalTexture.IsNull()
&& myImageMap.IsBound1 (aPbrMat.NormalTexture)) ? myImageMap.FindIndex (aPbrMat.NormalTexture) - 1
: -1;
if (aNormImageIdx != -1)
{ {
myWriter->Key ("normalTexture"); myWriter->Key ("normalTexture");
myWriter->StartObject(); myWriter->StartObject();
{ {
myWriter->Key ("index"); myWriter->Key ("index");
const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.NormalTexture); myWriter->Int (aNormImageIdx);
if (!anImageIdx.IsEmpty())
{
myWriter->Int (anImageIdx.IntegerValue());
}
} }
myWriter->EndObject(); myWriter->EndObject();
} }
if (!aPbrMat.OcclusionTexture.IsNull() const Standard_Integer anOcclusImageIdx = !aPbrMat.OcclusionTexture.IsNull()
&& myImageMap.IsBound1 (aPbrMat.OcclusionTexture)) ? myImageMap.FindIndex (aPbrMat.OcclusionTexture) - 1
: -1;
if (anOcclusImageIdx != -1)
{ {
myWriter->Key ("occlusionTexture"); myWriter->Key ("occlusionTexture");
myWriter->StartObject(); myWriter->StartObject();
{ {
myWriter->Key ("index"); myWriter->Key ("index");
const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.OcclusionTexture); myWriter->Int (anOcclusImageIdx);
if (!anImageIdx.IsEmpty())
{
myWriter->Int (anImageIdx.IntegerValue());
}
} }
myWriter->EndObject(); myWriter->EndObject();
} }

View File

@@ -15,12 +15,14 @@
#define _RWGltf_GltfMaterialMap_HeaderFile #define _RWGltf_GltfMaterialMap_HeaderFile
#include <RWMesh_MaterialMap.hxx> #include <RWMesh_MaterialMap.hxx>
#include <RWGltf_GltfBufferView.hxx>
class RWGltf_GltfOStreamWriter; class RWGltf_GltfOStreamWriter;
//! Material manager for exporting into glTF format. //! Material manager for exporting into glTF format.
class RWGltf_GltfMaterialMap : public RWMesh_MaterialMap class RWGltf_GltfMaterialMap : public RWMesh_MaterialMap
{ {
DEFINE_STANDARD_RTTIEXT(RWGltf_GltfMaterialMap, RWMesh_MaterialMap)
public: public:
//! Main constructor. //! Main constructor.
@@ -30,7 +32,26 @@ public:
//! Destructor. //! Destructor.
Standard_EXPORT virtual ~RWGltf_GltfMaterialMap(); 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, Standard_EXPORT void AddImages (RWGltf_GltfOStreamWriter* theWriter,
const XCAFPrs_Style& theStyle, const XCAFPrs_Style& theStyle,
Standard_Boolean& theIsStarted); Standard_Boolean& theIsStarted);
@@ -62,6 +83,12 @@ protected:
const Handle(Image_Texture)& theTexture, const Handle(Image_Texture)& theTexture,
Standard_Boolean& theIsStarted); 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. //! Add texture.
Standard_EXPORT void addTexture (RWGltf_GltfOStreamWriter* theWriter, Standard_EXPORT void addTexture (RWGltf_GltfOStreamWriter* theWriter,
const Handle(Image_Texture)& theTexture, const Handle(Image_Texture)& theTexture,
@@ -78,10 +105,10 @@ protected:
protected: protected:
RWGltf_GltfOStreamWriter* myWriter; RWGltf_GltfOStreamWriter* myWriter;
NCollection_DoubleMap<Handle(Image_Texture), TCollection_AsciiString, Image_Texture, TCollection_AsciiString> myImageMap; NCollection_IndexedDataMap<Handle(Image_Texture), RWGltf_GltfBufferView, Image_Texture> myImageMap;
NCollection_Map<Handle(Image_Texture), Image_Texture> myTextureMap; NCollection_Map<Handle(Image_Texture), Image_Texture> myTextureMap;
Standard_Integer myDefSamplerId; Standard_Integer myDefSamplerId;
Standard_Integer myNbImages;
}; };

View File

@@ -22,6 +22,8 @@
#include <TDataStd_Name.hxx> #include <TDataStd_Name.hxx>
#include <TDF_Label.hxx> #include <TDF_Label.hxx>
IMPLEMENT_STANDARD_RTTIEXT(RWMesh_MaterialMap, Standard_Transient)
// ======================================================================= // =======================================================================
// function : RWMesh_MaterialMap // function : RWMesh_MaterialMap
// purpose : // purpose :

View File

@@ -21,8 +21,9 @@
//! Material manager. //! Material manager.
//! Provides an interface for collecting all materials within the document before writing it into file, //! 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. //! 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: public:
//! Main constructor. //! Main constructor.

View File

@@ -221,7 +221,7 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI,
Handle(TDocStd_Application) anApp = DDocStd::GetApplication(); Handle(TDocStd_Application) anApp = DDocStd::GetApplication();
TColStd_IndexedDataMapOfStringString aFileInfo; TColStd_IndexedDataMapOfStringString aFileInfo;
RWGltf_WriterTrsfFormat aTrsfFormat = RWGltf_WriterTrsfFormat_Compact; RWGltf_WriterTrsfFormat aTrsfFormat = RWGltf_WriterTrsfFormat_Compact;
bool toForceUVExport = false; bool toForceUVExport = false, toEmbedTexturesInGlb = true;
for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter) for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
{ {
TCollection_AsciiString anArgCase (theArgVec[anArgIter]); TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
@@ -291,6 +291,10 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI,
{ {
aGltfFilePath = theArgVec[anArgIter]; aGltfFilePath = theArgVec[anArgIter];
} }
else if (anArgCase == "-texturesSeparate")
{
toEmbedTexturesInGlb = false;
}
else else
{ {
Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'"; 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")); RWGltf_CafWriter aWriter (aGltfFilePath, anExt.EndsWith (".glb"));
aWriter.SetTransformationFormat (aTrsfFormat); aWriter.SetTransformationFormat (aTrsfFormat);
aWriter.SetForcedUVExport (toForceUVExport); aWriter.SetForcedUVExport (toForceUVExport);
aWriter.SetToEmbedTexturesInGlb (toEmbedTexturesInGlb);
aWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit (aSystemUnitFactor); aWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit (aSystemUnitFactor);
aWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem (RWMesh_CoordinateSystem_Zup); aWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem (RWMesh_CoordinateSystem_Zup);
aWriter.Perform (aDoc, aFileInfo, aProgress->Start()); 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.", "\n\t\t: Same as ReadGltf but reads glTF file into a shape instead of a document.",
__FILE__, ReadGltf, g); __FILE__, ReadGltf, g);
theCommands.Add ("WriteGltf", 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: Write XDE document into glTF file."
"\n\t\t: -trsfFormat preferred transformation format" "\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); __FILE__, WriteGltf, g);
theCommands.Add ("writegltf", theCommands.Add ("writegltf",
"writegltf shape file", "writegltf shape file",

View File

@@ -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

View File

@@ -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