#include <NCollection_DataMap.hxx>
#include <OSD_FileSystem.hxx>
#include <OSD_File.hxx>
+#include <OSD_Parallel.hxx>
#include <OSD_Path.hxx>
#include <OSD_Timer.hxx>
#include <RWGltf_GltfAccessorLayout.hxx>
#endif
}
+#ifdef HAVE_DRACO
+//! Functor for parallel execution of encoding meshes to Draco buffers.
+class DracoEncodingFunctor
+{
+public:
+
+ DracoEncodingFunctor (const Message_ProgressRange& theProgress,
+ draco::Encoder& theDracoEncoder,
+ const std::vector<std::shared_ptr<RWGltf_CafWriter::Mesh>>& theMeshes,
+ std::vector<std::shared_ptr<draco::EncoderBuffer>>& theEncoderBuffers)
+ : myProgress(theProgress, "Draco compression", Max(1, int(theMeshes.size()))),
+ myDracoEncoder(&theDracoEncoder),
+ myRanges(0, int(theMeshes.size()) - 1),
+ myMeshes(&theMeshes),
+ myEncoderBuffers(&theEncoderBuffers)
+ {
+ for (int anIndex = 0; anIndex != int(theMeshes.size()); ++anIndex)
+ {
+ myRanges.SetValue(anIndex, myProgress.Next());
+ }
+ }
+
+ void operator () (int theMeshIndex) const
+ {
+ const std::shared_ptr<RWGltf_CafWriter::Mesh>& aCurrentMesh = myMeshes->at(theMeshIndex);
+ if (aCurrentMesh->NodesVec.empty())
+ {
+ return;
+ }
+
+ Message_ProgressScope aScope(myRanges[theMeshIndex], NULL, 1);
+
+ draco::Mesh aMesh;
+ writeNodesToDracoMesh (aMesh, aCurrentMesh->NodesVec);
+
+ if (!aCurrentMesh->NormalsVec.empty())
+ {
+ writeNormalsToDracoMesh (aMesh, aCurrentMesh->NormalsVec);
+ }
+
+ if (!aCurrentMesh->TexCoordsVec.empty())
+ {
+ writeTexCoordsToDracoMesh (aMesh, aCurrentMesh->TexCoordsVec);
+ }
+
+ writeIndicesToDracoMesh (aMesh, aCurrentMesh->IndicesVec);
+
+ std::shared_ptr<draco::EncoderBuffer> anEncoderBuffer = std::make_shared<draco::EncoderBuffer>();
+ draco::Status aStatus = myDracoEncoder->EncodeMeshToBuffer (aMesh, anEncoderBuffer.get());
+ if (aStatus.ok())
+ {
+ myEncoderBuffers->at(theMeshIndex) = anEncoderBuffer;
+ }
+
+ aScope.Next();
+ }
+
+private:
+ Message_ProgressScope myProgress;
+ draco::Encoder* myDracoEncoder;
+ NCollection_Array1<Message_ProgressRange> myRanges;
+ const std::vector<std::shared_ptr<RWGltf_CafWriter::Mesh>>* myMeshes;
+ std::vector<std::shared_ptr<draco::EncoderBuffer>>* myEncoderBuffers;
+};
+#endif
+
//================================================================
// Function : Constructor
// Purpose :
myToEmbedTexturesInGlb (true),
myToMergeFaces (false),
myToSplitIndices16 (false),
- myBinDataLen64 (0)
+ myBinDataLen64 (0),
+ myToParallel (false)
{
myCSTrsf.SetOutputLengthUnit (1.0); // meters
myCSTrsf.SetOutputCoordinateSystem (RWMesh_CoordinateSystem_glTF);
myBinDataMap.Clear();
myBinDataLen64 = 0;
+ Message_ProgressScope aScope(theProgress, "Write binary data", myDracoParameters.DracoCompression ? 2 : 1);
+
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::ostream> aBinFile = aFileSystem->OpenOStream (myBinFileNameFull, std::ios::out | std::ios::binary);
if (aBinFile.get() == NULL
return false;
}
- Message_ProgressScope aPSentryBin (theProgress, "Binary data", 4);
+ Message_ProgressScope aPSentryBin (aScope.Next(), "Binary data", 4);
const RWGltf_GltfArrayType anArrTypes[4] =
{
RWGltf_GltfArrayType_Position,
#ifdef HAVE_DRACO
OSD_Timer aDracoTimer;
aDracoTimer.Start();
- int aBuffId = 0;
draco::Encoder aDracoEncoder;
aDracoEncoder.SetAttributeQuantization (draco::GeometryAttribute::POSITION, myDracoParameters.QuantizePositionBits);
aDracoEncoder.SetAttributeQuantization (draco::GeometryAttribute::NORMAL, myDracoParameters.QuantizeNormalBits);
aDracoEncoder.SetAttributeQuantization (draco::GeometryAttribute::COLOR, myDracoParameters.QuantizeColorBits);
aDracoEncoder.SetAttributeQuantization (draco::GeometryAttribute::GENERIC, myDracoParameters.QuantizeGenericBits);
aDracoEncoder.SetSpeedOptions (myDracoParameters.CompressionLevel, myDracoParameters.CompressionLevel);
- for (size_t aMeshInd = 0; aMeshInd != aMeshes.size(); ++aMeshInd)
- {
- const std::shared_ptr<RWGltf_CafWriter::Mesh>& aCurrentMesh = aMeshes[aMeshInd];
- if (aCurrentMesh->NodesVec.empty())
- {
- continue;
- }
- draco::Mesh aDracoMesh;
- writeNodesToDracoMesh (aDracoMesh, aCurrentMesh->NodesVec);
- if (!aCurrentMesh->NormalsVec.empty())
- {
- writeNormalsToDracoMesh (aDracoMesh, aCurrentMesh->NormalsVec);
- }
- if (!aCurrentMesh->TexCoordsVec.empty())
- {
- writeTexCoordsToDracoMesh (aDracoMesh, aCurrentMesh->TexCoordsVec);
- }
- writeIndicesToDracoMesh (aDracoMesh, aCurrentMesh->IndicesVec);
+ std::vector<std::shared_ptr<draco::EncoderBuffer>> anEncoderBuffers(aMeshes.size());
+ DracoEncodingFunctor aFunctor (aScope.Next(), aDracoEncoder, aMeshes, anEncoderBuffers);
+ OSD_Parallel::For (0, int(aMeshes.size()), aFunctor, !myToParallel);
- draco::EncoderBuffer anEncoderBuff;
- draco::Status aStatus = aDracoEncoder.EncodeMeshToBuffer (aDracoMesh, &anEncoderBuff);
- if (!aStatus.ok())
+ for (size_t aBuffInd = 0; aBuffInd != anEncoderBuffers.size(); ++aBuffInd)
+ {
+ if (anEncoderBuffers.at(aBuffInd).get() == nullptr)
{
- Message::SendFail (TCollection_AsciiString("Error: mesh cannot be encoded in draco buffer."));
+ Message::SendFail(TCollection_AsciiString("Error: mesh not encoded in draco buffer."));
return false;
}
-
RWGltf_GltfBufferView aBuffViewDraco;
- aBuffViewDraco.Id = aBuffId++;
+ aBuffViewDraco.Id = (int)aBuffInd;
aBuffViewDraco.ByteOffset = aBinFile->tellp();
- aBinFile->write (anEncoderBuff.data(), std::streamsize(anEncoderBuff.size()));
+ const draco::EncoderBuffer& anEncoderBuff = *anEncoderBuffers.at(aBuffInd);
+ aBinFile->write(anEncoderBuff.data(), std::streamsize(anEncoderBuff.size()));
if (!aBinFile->good())
{
Message::SendFail (TCollection_AsciiString("File '") + myBinFileNameFull + "' cannot be written");
RWMesh_CoordinateSystem aSystemCoordSys = RWMesh_CoordinateSystem_Zup;
bool toForceUVExport = false, toEmbedTexturesInGlb = true;
bool toMergeFaces = false, toSplitIndices16 = false;
+ bool isParallel = false;
RWMesh_NameFormat aNodeNameFormat = RWMesh_NameFormat_InstanceOrProduct;
RWMesh_NameFormat aMeshNameFormat = RWMesh_NameFormat_Product;
RWGltf_DracoParameters aDracoParameters;
{
aDracoParameters.UnifiedQuantization = Draw::ParseOnOffIterator(theNbArgs, theArgVec, anArgIter);
}
+ else if (anArgCase == "-parallel")
+ {
+ isParallel = Draw::ParseOnOffIterator(theNbArgs, theArgVec, anArgIter);
+ }
else
{
Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
aWriter.SetToEmbedTexturesInGlb (toEmbedTexturesInGlb);
aWriter.SetMergeFaces (toMergeFaces);
aWriter.SetSplitIndices16 (toSplitIndices16);
+ aWriter.SetParallel(isParallel);
aWriter.SetCompressionParameters(aDracoParameters);
aWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit (aScaleFactorM);
aWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem (aSystemCoordSys);
"\n\t\t: [-meshNameFormat {empty|product|instance|instOrProd|prodOrInst|prodAndInst|verbose}]=product"
"\n\t\t: [-draco]=0 [-compressionLevel {0-10}]=7 [-quantizePositionBits Value]=14 [-quantizeNormalBits Value]=10"
"\n\t\t: [-quantizeTexcoordBits Value]=12 [-quantizeColorBits Value]=8 [-quantizeGenericBits Value]=12"
- "\n\t\t: [-unifiedQuantization]=0"
+ "\n\t\t: [-unifiedQuantization]=0 [-parallel]=0"
"\n\t\t: Write XDE document into glTF file."
"\n\t\t: -trsfFormat preferred transformation format"
"\n\t\t: -systemCoordSys system coordinate system; Zup when not specified"
"\n\t\t: -texturesSeparate write textures to separate files"
"\n\t\t: -nodeNameFormat name format for Nodes"
"\n\t\t: -meshNameFormat name format for Meshes"
- "\n\t\t: -draco use Draco compression 3D geometric meshes"
+ "\n\t\t: -draco use Draco compression 3D geometric meshes"
"\n\t\t: -compressionLevel draco compression level [0-10] (by default 7), a value of 0 will apply sequential encoding and preserve face order"
"\n\t\t: -quantizePositionBits quantization bits for position attribute when using Draco compression (by default 14)"
"\n\t\t: -quantizeNormalBits quantization bits for normal attribute when using Draco compression (by default 10)"
"\n\t\t: -quantizeColorBits quantization bits for color attribute when using Draco compression (by default 8)"
"\n\t\t: -quantizeGenericBits quantization bits for skinning attribute (joint indices and joint weights)"
"\n and custom attributes when using Draco compression (by default 12)"
- "\n\t\t: -unifiedQuantization quantization is applied on each primitive separately if this option is false",
+ "\n\t\t: -unifiedQuantization quantization is applied on each primitive separately if this option is false"
+ "\n\t\t: -parallel use multithreading for Draco compression",
__FILE__, WriteGltf, g);
theCommands.Add ("writegltf",
"writegltf shape file",