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:
@@ -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::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 Standard_False;
|
||||
}
|
||||
|
||||
Standard_Size aLen = (Standard_Size )myLength;
|
||||
if (myOffset >= 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFileIn.seekg (0, std::ios_base::end);
|
||||
aLen = (Standard_Size )aFileIn.tellg();
|
||||
aFileIn.seekg (0, std::ios_base::beg);
|
||||
}
|
||||
|
||||
aBuffer = new NCollection_Buffer (NCollection_BaseAllocator::CommonBaseAllocator(), aLen);
|
||||
if (!aFileIn.read ((char* )aBuffer->ChangeData(), aBuffer->Size()))
|
||||
{
|
||||
Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'");
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WriteImage (aFileOut, theFile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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 false;
|
||||
}
|
||||
return Standard_True;
|
||||
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;
|
||||
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())
|
||||
{
|
||||
Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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<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 + "'");
|
||||
return false;
|
||||
}
|
||||
theStream.write ((const char* )&aBuffer.First(), aChunkSize);
|
||||
}
|
||||
if (!theStream.good())
|
||||
{
|
||||
Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' can not be written");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
@@ -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.
|
||||
|
@@ -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<Standard_Integer> 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
|
||||
}
|
||||
|
@@ -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<Standard_Integer>& 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<RWGltf_GltfOStreamWriter>
|
||||
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
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -13,12 +13,17 @@
|
||||
|
||||
#include <RWGltf_GltfMaterialMap.hxx>
|
||||
|
||||
#include <Message.hxx>
|
||||
#include <NCollection_Array1.hxx>
|
||||
#include <OSD_OpenFile.hxx>
|
||||
#include <RWGltf_GltfRootElement.hxx>
|
||||
|
||||
#ifdef HAVE_RAPIDJSON
|
||||
#include <RWGltf_GltfOStreamWriter.hxx>
|
||||
#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<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
|
||||
// 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();
|
||||
}
|
||||
|
@@ -15,12 +15,14 @@
|
||||
#define _RWGltf_GltfMaterialMap_HeaderFile
|
||||
|
||||
#include <RWMesh_MaterialMap.hxx>
|
||||
#include <RWGltf_GltfBufferView.hxx>
|
||||
|
||||
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<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;
|
||||
|
||||
Standard_Integer myDefSamplerId;
|
||||
Standard_Integer myNbImages;
|
||||
|
||||
};
|
||||
|
||||
|
@@ -22,6 +22,8 @@
|
||||
#include <TDataStd_Name.hxx>
|
||||
#include <TDF_Label.hxx>
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(RWMesh_MaterialMap, Standard_Transient)
|
||||
|
||||
// =======================================================================
|
||||
// function : RWMesh_MaterialMap
|
||||
// purpose :
|
||||
|
@@ -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.
|
||||
|
@@ -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",
|
||||
|
20
tests/de_mesh/gltf_write/helmetglb
Normal file
20
tests/de_mesh/gltf_write/helmetglb
Normal 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
|
20
tests/de_mesh/gltf_write/lanternglb
Normal file
20
tests/de_mesh/gltf_write/lanternglb
Normal 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
|
Reference in New Issue
Block a user