]> OCCT Git - occt.git/commitdiff
0032248: Visualization - load "false" deferred glTF data immediately
authorosa <osa@opencascade.com>
Fri, 26 Mar 2021 12:02:41 +0000 (15:02 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 31 Mar 2021 17:44:30 +0000 (20:44 +0300)
src/Poly/Poly_Triangulation.cxx
src/RWGltf/RWGltf_CafReader.cxx
src/RWGltf/RWGltf_CafReader.hxx
src/RWGltf/RWGltf_GltfLatePrimitiveArray.cxx
src/RWGltf/RWGltf_GltfLatePrimitiveArray.hxx
src/RWGltf/RWGltf_TriangulationReader.cxx
src/RWGltf/RWGltf_TriangulationReader.hxx
tests/de_mesh/gltf_lateload/helmet [new file with mode: 0644]

index 95f369ee62f1ea3eb73a238c9cfb291fca7d1535..62e3aef70b10ec7ddae1c6a3c51b07481fd27bc6 100644 (file)
@@ -542,11 +542,11 @@ Handle(Poly_Triangulation) Poly_Triangulation::DetachedLoadDeferredData (const H
     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;
 }
 
index 05bef91d6362126a66a0226b2a3debfb25e1b65a..90f1b01736ac2d4858f2387790d0286f08b43b87 100644 (file)
 
 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)
   {
     //
   }
@@ -60,26 +50,15 @@ public:
   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);
@@ -91,17 +70,97 @@ public:
     }
   }
 
+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  :
@@ -306,8 +365,16 @@ Standard_Boolean RWGltf_CafReader::readLateData (NCollection_Vector<TopoDS_Face>
   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;
   }
 
@@ -317,8 +384,7 @@ Standard_Boolean RWGltf_CafReader::readLateData (NCollection_Vector<TopoDS_Face>
   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();
index b99db7c85c6eff31f1cbcd485076660f2d98a430..6d36cb7504589c3851a1b74412992e453e8e84b1 100644 (file)
@@ -98,7 +98,9 @@ protected:
 
 protected:
 
-  class CafReader_GltfReaderFunctor;
+  class CafReader_GltfBaseLoadingFunctor;
+  class CafReader_GltfFullDataLoadingFunctor;
+  class CafReader_GltfStreamDataLoadingFunctor;
 
 protected:
 
index 8ffadd442da2e8f8e39aea7246f39d8bb1ebd460..ebca9dc366c82646f6d338282468823b09a13b46 100644 (file)
@@ -17,6 +17,7 @@
 #include <RWGltf_GltfPrimArrayData.hxx>
 #include <RWGltf_MaterialMetallicRoughness.hxx>
 #include <RWGltf_MaterialCommon.hxx>
+#include <RWGltf_TriangulationReader.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(RWGltf_GltfLatePrimitiveArray, RWMesh_TriangulationSource)
 
@@ -90,3 +91,23 @@ RWGltf_GltfPrimArrayData& RWGltf_GltfLatePrimitiveArray::AddPrimArrayData (RWGlt
     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;
+}
index a06586fee15cb64bf05efa350d0d1419d98e6142..1c39f4106a3d4c9e2eb57381c439e82491e6e1bd 100644 (file)
@@ -78,13 +78,16 @@ public:
   //! 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;
index 169b76a643b5dca10b76d1d78826ca4c9fc0bb36..09fbf6d3e0854d739bf67a8f2feec5e76b1145ab 100644 (file)
@@ -48,6 +48,107 @@ void RWGltf_TriangulationReader::reportError (const TCollection_AsciiString& the
   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  :
@@ -68,13 +169,8 @@ bool RWGltf_TriangulationReader::load (const Handle(RWMesh_TriangulationSource)&
     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())
@@ -83,14 +179,7 @@ bool RWGltf_TriangulationReader::load (const Handle(RWMesh_TriangulationSource)&
       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;
     }
index ee10f68b123e10d53d5728ef131032cbc1315108..821c08d350622160b5cdf4f8aa35864bf24101b4 100644 (file)
@@ -21,6 +21,7 @@
 #include <RWGltf_GltfPrimitiveMode.hxx>
 
 class RWGltf_GltfLatePrimitiveArray;
+class RWGltf_GltfPrimArrayData;
 
 //! RWMesh_TriangulationReader implementation creating Poly_Triangulation.
 class RWGltf_TriangulationReader : public RWMesh_TriangulationReader
@@ -31,28 +32,66 @@ public:
   //! 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,
diff --git a/tests/de_mesh/gltf_lateload/helmet b/tests/de_mesh/gltf_lateload/helmet
new file mode 100644 (file)
index 0000000..80f26be
--- /dev/null
@@ -0,0 +1,12 @@
+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"
+}