Browse Source

Merge pull request #1001 from johnmaf/feature/glTF/separate-bin

Export glTF buffer data in a separate .bin file
Kim Kulling 9 năm trước cách đây
mục cha
commit
38cbdcd885
4 tập tin đã thay đổi với 92 bổ sung62 xóa
  1. 3 0
      code/glTFAsset.h
  2. 1 0
      code/glTFAssetWriter.h
  3. 43 25
      code/glTFAssetWriter.inl
  4. 45 37
      code/glTFExporter.cpp

+ 3 - 0
code/glTFAsset.h

@@ -571,6 +571,9 @@ namespace glTF
         bool IsSpecial() const
             { return mIsSpecial; }
 
+        std::string GetURI()
+            { return std::string(this->id) + ".bin"; }
+
         static const char* TranslateId(Asset& r, const char* id);
     };
 

+ 1 - 0
code/glTFAssetWriter.h

@@ -79,6 +79,7 @@ public:
     AssetWriter(Asset& asset);
 
     void WriteFile(const char* path);
+    void WriteGLBFile(const char* path);
 };
 
 }

+ 43 - 25
code/glTFAssetWriter.inl

@@ -94,9 +94,6 @@ namespace glTF {
 
     inline void Write(Value& obj, Buffer& b, AssetWriter& w)
     {
-        std::string dataURI = "data:application/octet-stream;base64,";
-        Util::EncodeBase64(b.GetPointer(), b.byteLength, dataURI);
-
         const char* type;
         switch (b.type) {
             case Buffer::Type_text:
@@ -107,7 +104,7 @@ namespace glTF {
 
         obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl);
         obj.AddMember("type", StringRef(type), w.mAl);
-        obj.AddMember("uri", Value(dataURI, w.mAl).Move(), w.mAl);
+        obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl);
     }
 
     inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
@@ -382,39 +379,61 @@ namespace glTF {
 
     inline void AssetWriter::WriteFile(const char* path)
     {
-        bool isBinary = mAsset.extensionsUsed.KHR_binary_glTF;
-
-        std::unique_ptr<IOStream> outfile
-            (mAsset.OpenFile(path, isBinary ? "wb" : "wt", true));
+        std::unique_ptr<IOStream> jsonOutFile(mAsset.OpenFile(path, "wt", true));
 
-        if (outfile == 0) {
+        if (jsonOutFile == 0) {
             throw DeadlyExportError("Could not open output file: " + std::string(path));
         }
 
-        if (isBinary) {
-            // we will write the header later, skip its size
-            outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
+        StringBuffer docBuffer;
+
+        PrettyWriter<StringBuffer> writer(docBuffer);
+        mDoc.Accept(writer);
+
+        if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
+            throw DeadlyExportError("Failed to write scene data!");
         }
 
-        StringBuffer docBuffer;
+        // Write buffer data to separate .bin files
+        for (unsigned int i = 0; i < mAsset.buffers.Size(); ++i) {
+            Ref<Buffer> b = mAsset.buffers.Get(i);
 
-        bool pretty = true; 
-        if (!isBinary && pretty) {
-            PrettyWriter<StringBuffer> writer(docBuffer);
-            mDoc.Accept(writer);
+            std::string binPath = b->GetURI();
+
+            std::unique_ptr<IOStream> binOutFile(mAsset.OpenFile(binPath, "wb", true));
+
+            if (binOutFile == 0) {
+                throw DeadlyExportError("Could not open output file: " + binPath);
+            }
+
+            if (b->byteLength > 0) {
+                if (binOutFile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
+                    throw DeadlyExportError("Failed to write binary file: " + binPath);
+                }
+            }
         }
-        else {
-            Writer<StringBuffer> writer(docBuffer);
-            mDoc.Accept(writer);
+    }
+
+    inline void AssetWriter::WriteGLBFile(const char* path)
+    {
+        std::unique_ptr<IOStream> outfile(mAsset.OpenFile(path, "wb", true));
+
+        if (outfile == 0) {
+            throw DeadlyExportError("Could not open output file: " + std::string(path));
         }
 
+        // we will write the header later, skip its size
+        outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
+
+        StringBuffer docBuffer;
+        Writer<StringBuffer> writer(docBuffer);
+        mDoc.Accept(writer);
+
         if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
-            throw DeadlyExportError("Failed to write scene data!"); 
+            throw DeadlyExportError("Failed to write scene data!");
         }
 
-        if (isBinary) {
-            WriteBinaryData(outfile.get(), docBuffer.GetSize());
-        }
+        WriteBinaryData(outfile.get(), docBuffer.GetSize());
     }
 
     inline void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength)
@@ -439,7 +458,6 @@ namespace glTF {
             }
         }
 
-
         //
         // write the header
         //

+ 45 - 37
code/glTFExporter.cpp

@@ -80,20 +80,9 @@ namespace Assimp {
     // Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp
     void ExportSceneGLTF(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
     {
-        aiScene* sceneCopy_tmp;
-        SceneCombiner::CopyScene(&sceneCopy_tmp, pScene);
-        std::unique_ptr<aiScene> sceneCopy(sceneCopy_tmp);
-
-        SplitLargeMeshesProcess_Triangle tri_splitter;
-        tri_splitter.SetLimit(0xffff);
-        tri_splitter.Execute(sceneCopy.get());
-
-        SplitLargeMeshesProcess_Vertex vert_splitter;
-        vert_splitter.SetLimit(0xffff);
-        vert_splitter.Execute(sceneCopy.get());
 
         // invoke the exporter
-        glTFExporter exporter(pFile, pIOSystem, sceneCopy.get(), pProperties, false);
+        glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, false);
     }
 
     // ------------------------------------------------------------------------------------------------
@@ -112,9 +101,22 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc
                            const ExportProperties* pProperties, bool isBinary)
     : mFilename(filename)
     , mIOSystem(pIOSystem)
-    , mScene(pScene)
     , mProperties(pProperties)
 {
+    aiScene* sceneCopy_tmp;
+    SceneCombiner::CopyScene(&sceneCopy_tmp, pScene);
+    std::unique_ptr<aiScene> sceneCopy(sceneCopy_tmp);
+
+    SplitLargeMeshesProcess_Triangle tri_splitter;
+    tri_splitter.SetLimit(0xffff);
+    tri_splitter.Execute(sceneCopy.get());
+
+    SplitLargeMeshesProcess_Vertex vert_splitter;
+    vert_splitter.SetLimit(0xffff);
+    vert_splitter.Execute(sceneCopy.get());
+
+    mScene = sceneCopy.get();
+
     std::unique_ptr<Asset> asset();
     mAsset.reset( new glTF::Asset( pIOSystem ) );
 
@@ -144,9 +146,13 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc
 
     ExportScene();
 
-
     glTF::AssetWriter writer(*mAsset);
-    writer.WriteFile(filename);
+
+    if (isBinary) {
+        writer.WriteGLBFile(filename);
+    } else {
+        writer.WriteFile(filename);
+    }
 }
 
 
@@ -274,28 +280,30 @@ void glTFExporter::ExportMaterials()
 
 void glTFExporter::ExportMeshes()
 {
-// Not for
-//     using IndicesType = decltype(aiFace::mNumIndices);
-// But yes for
-//     using IndicesType = unsigned short;
-// because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification.
-typedef unsigned short IndicesType;
-
-// Variables needed for compression. BEGIN.
-// Indices, not pointers - because pointer to buffer is changin while writing to it.
-size_t idx_srcdata_begin;// Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer.
-size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals.
-std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
-size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer.
-bool comp_allow;// Point that data of current mesh can be compressed.
-// Variables needed for compression. END.
-
-	std::string bufferId = mAsset->FindUniqueID("", "buffer");
-
-	Ref<Buffer> b = mAsset->GetBodyBuffer();
-	if (!b) {
-		b = mAsset->buffers.Create(bufferId);
-	}
+    // Not for
+    //     using IndicesType = decltype(aiFace::mNumIndices);
+    // But yes for
+    //     using IndicesType = unsigned short;
+    // because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification.
+    typedef unsigned short IndicesType;
+
+    // Variables needed for compression. BEGIN.
+    // Indices, not pointers - because pointer to buffer is changin while writing to it.
+    size_t idx_srcdata_begin;// Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer.
+    size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals.
+    std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
+    size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer.
+    bool comp_allow;// Point that data of current mesh can be compressed.
+    // Variables needed for compression. END.
+
+    std::string fname = std::string(mFilename);
+    std::string bufferIdPrefix = fname.substr(0, fname.find("."));
+    std::string bufferId = mAsset->FindUniqueID("", bufferIdPrefix.c_str());
+
+    Ref<Buffer> b = mAsset->GetBodyBuffer();
+    if (!b) {
+       b = mAsset->buffers.Create(bufferId);
+    }
 
 	for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
 		const aiMesh* aim = mScene->mMeshes[idx_mesh];