return Handle(Poly_Triangulation)();
}
Handle(Poly_Triangulation) aResult = createNewEntity();
- if (!loadDeferredData(theFileSystem, aResult))
+ if (!loadDeferredData (theFileSystem, aResult))
{
return Handle(Poly_Triangulation)();
}
- aResult->SetMeshPurpose(aResult->MeshPurpose() | Poly_MeshPurpose_Loaded);
+ aResult->SetMeshPurpose (aResult->MeshPurpose() | Poly_MeshPurpose_Loaded);
return aResult;
}
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_CafReader, RWMesh_CafReader)
-//! Functor for parallel execution.
-class RWGltf_CafReader::CafReader_GltfReaderFunctor
+//! Abstract base functor for parallel execution of glTF data loading.
+class RWGltf_CafReader::CafReader_GltfBaseLoadingFunctor
{
public:
- struct GltfReaderTLS
- {
- Handle(OSD_FileSystem) FileSystem;
- };
-
//! Main constructor.
- CafReader_GltfReaderFunctor (RWGltf_CafReader* myCafReader,
- NCollection_Vector<TopoDS_Face>& theFaceList,
- const Message_ProgressRange& theProgress,
- const OSD_ThreadPool::Launcher& theThreadPool,
- const TCollection_AsciiString& theErrPrefix)
- : myCafReader (myCafReader),
- myFaceList (&theFaceList),
- myErrPrefix (theErrPrefix),
+ CafReader_GltfBaseLoadingFunctor (NCollection_Vector<TopoDS_Face>& theFaceList,
+ const Message_ProgressRange& theProgress,
+ const OSD_ThreadPool::Launcher& theThreadPool)
+ : myFaceList (&theFaceList),
myProgress (theProgress, "Loading glTF triangulation", Max (1, theFaceList.Size())),
- myThreadPool(theThreadPool),
- myTlsData (theThreadPool.LowerThreadIndex(), theThreadPool.UpperThreadIndex())
+ myThreadPool(theThreadPool)
{
//
}
void operator() (int theThreadIndex,
int theFaceIndex) const
{
- GltfReaderTLS& aTlsData = myTlsData.ChangeValue (theThreadIndex);
- if (aTlsData.FileSystem.IsNull())
- {
- aTlsData.FileSystem = new OSD_CachedFileSystem();
- }
-
TopLoc_Location aDummyLoc;
TopoDS_Face& aFace = myFaceList->ChangeValue (theFaceIndex);
Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (aFace, aDummyLoc));
- if (myCafReader->ToKeepLateData())
+ Handle(Poly_Triangulation) aPolyData = loadData (aLateData, theThreadIndex);
+ if (!aPolyData.IsNull())
{
- aLateData->LoadDeferredData (aTlsData.FileSystem);
- }
- else
- {
- Handle(Poly_Triangulation) aPolyData = aLateData->DetachedLoadDeferredData (aTlsData.FileSystem);
BRep_Builder aBuilder;
aBuilder.UpdateFace (aFace, aPolyData); // replace all "proxy"-triangulations of face by loaded active one.
}
-
if (myThreadPool.HasThreads())
{
Standard_Mutex::Sentry aLock (&myMutex);
}
}
+protected:
+
+ //! Load primitive array.
+ virtual Handle(Poly_Triangulation) loadData (const Handle(RWGltf_GltfLatePrimitiveArray)& theLateData,
+ int theThreadIndex) const = 0;
+
+protected:
+
+ NCollection_Vector<TopoDS_Face>* myFaceList;
+ mutable Standard_Mutex myMutex;
+ mutable Message_ProgressScope myProgress;
+ const OSD_ThreadPool::Launcher& myThreadPool;
+};
+//! Functor for parallel execution of all glTF data loading.
+class RWGltf_CafReader::CafReader_GltfFullDataLoadingFunctor : public RWGltf_CafReader::CafReader_GltfBaseLoadingFunctor
+{
+public:
+
+ struct GltfReaderTLS
+ {
+ Handle(OSD_FileSystem) FileSystem;
+ };
+
+ //! Main constructor.
+ CafReader_GltfFullDataLoadingFunctor (RWGltf_CafReader* myCafReader,
+ NCollection_Vector<TopoDS_Face>& theFaceList,
+ const Message_ProgressRange& theProgress,
+ const OSD_ThreadPool::Launcher& theThreadPool)
+ : CafReader_GltfBaseLoadingFunctor (theFaceList, theProgress, theThreadPool),
+ myCafReader (myCafReader),
+ myTlsData (theThreadPool.LowerThreadIndex(), theThreadPool.UpperThreadIndex())
+ {
+ //
+ }
+
+protected:
+
+ //! Load primitive array.
+ virtual Handle(Poly_Triangulation) loadData (const Handle(RWGltf_GltfLatePrimitiveArray)& theLateData,
+ int theThreadIndex) const Standard_OVERRIDE
+ {
+ GltfReaderTLS& aTlsData = myTlsData.ChangeValue (theThreadIndex);
+ if (aTlsData.FileSystem.IsNull())
+ {
+ aTlsData.FileSystem = new OSD_CachedFileSystem();
+ }
+ // Load stream data if exists
+ if (Handle(Poly_Triangulation) aStreamLoadedData = theLateData->LoadStreamData())
+ {
+ return aStreamLoadedData;
+ }
+ // Load file data
+ if (myCafReader->ToKeepLateData())
+ {
+ theLateData->LoadDeferredData (aTlsData.FileSystem);
+ return Handle(Poly_Triangulation)();
+ }
+ return theLateData->DetachedLoadDeferredData (aTlsData.FileSystem);
+ }
+
private:
RWGltf_CafReader* myCafReader;
- NCollection_Vector<TopoDS_Face>* myFaceList;
- TCollection_AsciiString myErrPrefix;
- mutable Standard_Mutex myMutex;
- mutable Message_ProgressScope myProgress;
- const OSD_ThreadPool::Launcher& myThreadPool;
mutable NCollection_Array1<GltfReaderTLS> myTlsData;
};
+//! Functor for parallel execution of loading of only glTF data saved in stream buffers.
+class RWGltf_CafReader::CafReader_GltfStreamDataLoadingFunctor : public RWGltf_CafReader::CafReader_GltfBaseLoadingFunctor
+{
+public:
+
+ //! Main constructor.
+ CafReader_GltfStreamDataLoadingFunctor (NCollection_Vector<TopoDS_Face>& theFaceList,
+ const Message_ProgressRange& theProgress,
+ const OSD_ThreadPool::Launcher& theThreadPool)
+ : CafReader_GltfBaseLoadingFunctor (theFaceList, theProgress, theThreadPool)
+ {
+ //
+ }
+
+protected:
+
+ //! Load primitive array.
+ virtual Handle(Poly_Triangulation) loadData (const Handle(RWGltf_GltfLatePrimitiveArray)& theLateData,
+ int theThreadIndex) const Standard_OVERRIDE
+ {
+ (void )theThreadIndex;
+ return theLateData->LoadStreamData();
+ }
+};
+
//================================================================
// Function : Constructor
// Purpose :
Handle(RWGltf_TriangulationReader) aReader = Handle(RWGltf_TriangulationReader)::DownCast(createMeshReaderContext());
aReader->SetFileName (theFile);
updateLateDataReader (theFaces, aReader);
+
if (myToSkipLateDataLoading)
{
+ // Load glTF data encoded in base64. It should not be skipped and saved in "proxy" object to be loaded later.
+ const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
+ const int aNbThreads = myToParallel ? Min (theFaces.Size(), aThreadPool->NbDefaultThreadsToLaunch()) : 1;
+ OSD_ThreadPool::Launcher aLauncher(*aThreadPool, aNbThreads);
+ CafReader_GltfStreamDataLoadingFunctor aFunctor(theFaces, theProgress, aLauncher);
+ aLauncher.Perform (theFaces.Lower(), theFaces.Upper() + 1, aFunctor);
+
return Standard_True;
}
const int aNbThreads = myToParallel ? Min (theFaces.Size(), aThreadPool->NbDefaultThreadsToLaunch()) : 1;
OSD_ThreadPool::Launcher aLauncher (*aThreadPool, aNbThreads);
- CafReader_GltfReaderFunctor aFunctor (this, theFaces, theProgress, aLauncher,
- TCollection_AsciiString ("File '") + theFile + "' defines invalid glTF!\n");
+ CafReader_GltfFullDataLoadingFunctor aFunctor (this, theFaces, theProgress, aLauncher);
aLauncher.Perform (theFaces.Lower(), theFaces.Upper() + 1, aFunctor);
aReader->PrintStatistic();
protected:
- class CafReader_GltfReaderFunctor;
+ class CafReader_GltfBaseLoadingFunctor;
+ class CafReader_GltfFullDataLoadingFunctor;
+ class CafReader_GltfStreamDataLoadingFunctor;
protected:
#include <RWGltf_GltfPrimArrayData.hxx>
#include <RWGltf_MaterialMetallicRoughness.hxx>
#include <RWGltf_MaterialCommon.hxx>
+#include <RWGltf_TriangulationReader.hxx>
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_GltfLatePrimitiveArray, RWMesh_TriangulationSource)
return myData.ChangeLast();
}
}
+
+//=======================================================================
+//function : LoadStreamData
+//purpose :
+//=======================================================================
+Handle(Poly_Triangulation) RWGltf_GltfLatePrimitiveArray::LoadStreamData() const
+{
+ Handle(RWGltf_TriangulationReader) aGltfReader = Handle(RWGltf_TriangulationReader)::DownCast(myReader);
+ if (aGltfReader.IsNull())
+ {
+ return Handle(Poly_Triangulation)();
+ }
+ Handle(Poly_Triangulation) aResult = createNewEntity();
+ if (!aGltfReader->LoadStreamData (this, aResult))
+ {
+ return Handle(Poly_Triangulation)();
+ }
+ aResult->SetMeshPurpose (aResult->MeshPurpose() | Poly_MeshPurpose_Loaded);
+ return aResult;
+}
//! Add primitive array data element.
Standard_EXPORT RWGltf_GltfPrimArrayData& AddPrimArrayData (RWGltf_GltfArrayType theType);
- //! Returns TRUE if there is deferred storege and some triangulation data
+ //! Return TRUE if there is deferred storege and some triangulation data
//! that can be loaded using LoadDeferredData().
virtual Standard_Boolean HasDeferredData() const Standard_OVERRIDE
{
return !myData.IsEmpty() && RWMesh_TriangulationSource::HasDeferredData();
}
+ //! Load primitive array saved as stream buffer to new triangulation object.
+ Standard_EXPORT Handle(Poly_Triangulation) LoadStreamData() const;
+
protected:
NCollection_Sequence<RWGltf_GltfPrimArrayData> myData;
Message::SendFail (TCollection_AsciiString("File '") + myFileName + "' defines invalid glTF!\n" + theText);
}
+// =======================================================================
+// function : LoadStreamData
+// purpose :
+// =======================================================================
+bool RWGltf_TriangulationReader::LoadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+ const Handle(Poly_Triangulation)& theDestMesh) const
+{
+ Standard_ASSERT_RETURN (!theDestMesh.IsNull(), "The destination mesh should be initialized before loading data to it", false);
+ theDestMesh->Clear();
+ theDestMesh->SetDoublePrecision (myIsDoublePrecision);
+
+ if (!loadStreamData (theSourceMesh, theDestMesh))
+ {
+ theDestMesh->Clear();
+ return false;
+ }
+ if (!finalizeLoading (theSourceMesh, theDestMesh))
+ {
+ theDestMesh->Clear();
+ return false;
+ }
+ return true;
+}
+
+// =======================================================================
+// function : readStreamData
+// purpose :
+// =======================================================================
+bool RWGltf_TriangulationReader::readStreamData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
+ const RWGltf_GltfPrimArrayData& theGltfData,
+ const Handle(Poly_Triangulation)& theDestMesh) const
+{
+ Standard_ArrayStreamBuffer aStreamBuffer ((const char* )theGltfData.StreamData->Data(), theGltfData.StreamData->Size());
+ std::istream aStream (&aStreamBuffer);
+ aStream.seekg ((std::streamoff )theGltfData.StreamOffset, std::ios_base::beg);
+ if (!readBuffer (theSourceGltfMesh, theDestMesh, aStream, theGltfData.Accessor, theGltfData.Type))
+ {
+ return false;
+ }
+ return true;
+}
+
+// =======================================================================
+// function : readFileData
+// purpose :
+// =======================================================================
+bool RWGltf_TriangulationReader::readFileData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
+ const RWGltf_GltfPrimArrayData& theGltfData,
+ const Handle(Poly_Triangulation)& theDestMesh,
+ const Handle(OSD_FileSystem)& theFileSystem) const
+{
+ const Handle(OSD_FileSystem)& aFileSystem = !theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem();
+ opencascade::std::shared_ptr<std::istream> aSharedStream = aFileSystem->OpenIStream
+ (theGltfData.StreamUri, std::ios::in | std::ios::binary, theGltfData.StreamOffset);
+ if (aSharedStream.get() == NULL)
+ {
+ reportError (TCollection_AsciiString("Buffer '") + theSourceGltfMesh->Id() + "refers to invalid file '" + theGltfData.StreamUri + "'.");
+ return false;
+ }
+ if (!readBuffer (theSourceGltfMesh, theDestMesh, *aSharedStream.get(), theGltfData.Accessor, theGltfData.Type))
+ {
+ return false;
+ }
+ return true;
+}
+
+// =======================================================================
+// function : loadStreamData
+// purpose :
+// =======================================================================
+bool RWGltf_TriangulationReader::loadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+ const Handle(Poly_Triangulation)& theDestMesh,
+ bool theToResetStream) const
+{
+ const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh);
+ if (aSourceGltfMesh.IsNull()
+ || aSourceGltfMesh->PrimitiveMode() == RWGltf_GltfPrimitiveMode_UNKNOWN)
+ {
+ return false;
+ }
+ bool wasLoaded = false;
+ for (NCollection_Sequence<RWGltf_GltfPrimArrayData>::Iterator aDataIter (aSourceGltfMesh->Data()); aDataIter.More(); aDataIter.Next())
+ {
+ RWGltf_GltfPrimArrayData& aData = aDataIter.ChangeValue();
+ if (aData.StreamData.IsNull())
+ {
+ continue;
+ }
+ if (!readStreamData (aSourceGltfMesh, aData, theDestMesh))
+ {
+ return false;
+ }
+ if (theToResetStream)
+ {
+ aData.StreamData.Nullify();
+ }
+ wasLoaded = true;
+ }
+ return wasLoaded;
+}
+
// =======================================================================
// function : load
// purpose :
const RWGltf_GltfPrimArrayData& aData = aDataIter.Value();
if (!aData.StreamData.IsNull())
{
- Standard_ArrayStreamBuffer aStreamBuffer ((const char* )aData.StreamData->Data(), aData.StreamData->Size());
- std::istream aStream (&aStreamBuffer);
- aStream.seekg ((std::streamoff )aData.StreamOffset, std::ios_base::beg);
- if (!readBuffer (aSourceGltfMesh, theDestMesh, aStream, aData.Accessor, aData.Type))
- {
- return false;
- }
+ Message::SendWarning (TCollection_AsciiString("Buffer '") + aSourceGltfMesh->Id() +
+ "' contains stream data that cannot be loaded during deferred data loading.");
continue;
}
else if (aData.StreamUri.IsEmpty())
return false;
}
- const Handle(OSD_FileSystem)& aFileSystem = !theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem();
- opencascade::std::shared_ptr<std::istream> aSharedStream = aFileSystem->OpenIStream (aData.StreamUri, std::ios::in | std::ios::binary, aData.StreamOffset);
- if (aSharedStream.get() == NULL)
- {
- reportError (TCollection_AsciiString ("Buffer '") + aSourceGltfMesh->Id() + "refers to invalid file '" + aData.StreamUri + "'.");
- return false;
- }
- if (!readBuffer (aSourceGltfMesh, theDestMesh, *aSharedStream.get(), aData.Accessor, aData.Type))
+ if (!readFileData (aSourceGltfMesh, aData, theDestMesh, theFileSystem))
{
return false;
}
#include <RWGltf_GltfPrimitiveMode.hxx>
class RWGltf_GltfLatePrimitiveArray;
+class RWGltf_GltfPrimArrayData;
//! RWMesh_TriangulationReader implementation creating Poly_Triangulation.
class RWGltf_TriangulationReader : public RWMesh_TriangulationReader
//! Empty constructor.
Standard_EXPORT RWGltf_TriangulationReader();
+ //! Loads only primitive arrays saved as stream buffer
+ //! (it is primarily glTF data encoded in base64 saved to temporary buffer during glTF file reading).
+ Standard_EXPORT bool LoadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+ const Handle(Poly_Triangulation)& theDestMesh) const;
+
protected:
//! Reports error.
Standard_EXPORT virtual void reportError (const TCollection_AsciiString& theText) const;
- //! Loads primitive array.
+ //! Loads only primitive arrays from file data.
+ //! @param theSourceMesh source triangulation
+ //! @param theDestMesh triangulation to be modified
+ //! @param theFileSystem shared file system to read from
+ //! Note: this method skips "stream data" that should be loaded by LoadStreamData() call.
Standard_EXPORT virtual bool load (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh,
const Handle(OSD_FileSystem)& theFileSystem) const Standard_OVERRIDE;
//! Performs additional actions to finalize data loading.
+ //! @param theSourceMesh source triangulation
+ //! @param theDestMesh triangulation to be modified
Standard_EXPORT virtual bool finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh) const Standard_OVERRIDE;
+ //! Loads only primitive arrays saved as stream buffer
+ //! (it is primarily glTF data encoded in base64 saved to temporary buffer during glTF file reading).
+ //! @param theSourceMesh source triangulation
+ //! @param theDestMesh triangulation to be modified
+ //! @param theToResetStream if TRUE reset input stream data buffer after its loading.
+ Standard_EXPORT bool loadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+ const Handle(Poly_Triangulation)& theDestMesh,
+ bool theToResetStream = true) const;
+
+ //! Reads primitive array from stream data.
+ //! @param theSourceGltfMesh source glTF triangulation
+ //! @param theGltfData primitive array element (stream data should not be NULL)
+ //! @param theDestMesh triangulation to be modified
+ Standard_EXPORT bool readStreamData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
+ const RWGltf_GltfPrimArrayData& theGltfData,
+ const Handle(Poly_Triangulation)& theDestMesh) const;
+
+ //! Reads primitive array from file data.
+ //! @param theSourceGltfMesh source glTF triangulation
+ //! @param theGltfData primitive array element (Uri of file stream should not be empty)
+ //! @param theDestMesh triangulation to be modified
+ //! @param theFileSystem shared file system to read from
+ Standard_EXPORT bool readFileData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
+ const RWGltf_GltfPrimArrayData& theGltfData,
+ const Handle(Poly_Triangulation)& theDestMesh,
+ const Handle(OSD_FileSystem)& theFileSystem) const;
+
//! Fills triangulation data and ignore non-triangulation primitives.
- //! @param theSourceMesh source triangulation
- //! @param theDestMesh triangulation to be modified
- //! @param theStream input stream to read from
- //! @param theAccessor buffer accessor
- //! @param theType array type
+ //! @param theSourceGltfMesh source glTF triangulation
+ //! @param theDestMesh triangulation to be modified
+ //! @param theStream input stream to read from
+ //! @param theAccessor buffer accessor
+ //! @param theType array type
//! @return FALSE on error
- Standard_EXPORT virtual bool readBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceMesh,
+ Standard_EXPORT virtual bool readBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
const Handle(Poly_Triangulation)& theDestMesh,
std::istream& theStream,
const RWGltf_GltfAccessor& theAccessor,
--- /dev/null
+puts "========"
+puts "0032248: Visualization - load false deferred glTF data immediately"
+puts "========"
+
+ReadGltf D [locate_data_file bug30691_DamagedHelmet.gltf] -skiplateloading 1
+XGetOneShape s D
+
+set info [trinfo s -lods]
+if {![regexp {([0-9]+) +triangles.*Types: Poly_Triangulation \(1\)} $info dummy triangles_nb]
+ || $triangles_nb != 15452} {
+ puts "Fail: incorrect loading file with stream data"
+}