diff --git a/code/glTFAsset.h b/code/glTFAsset.h index f09e97902..e34b05f5c 100644 --- a/code/glTFAsset.h +++ b/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); }; diff --git a/code/glTFAssetWriter.h b/code/glTFAssetWriter.h index 370d2c0ab..4d2d3c919 100644 --- a/code/glTFAssetWriter.h +++ b/code/glTFAssetWriter.h @@ -79,6 +79,7 @@ public: AssetWriter(Asset& asset); void WriteFile(const char* path); + void WriteGLBFile(const char* path); }; } diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl index 88a92c440..119ebc937 100644 --- a/code/glTFAssetWriter.inl +++ b/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(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 jsonOutFile(mAsset.OpenFile(path, "wt", true)); - std::unique_ptr outfile - (mAsset.OpenFile(path, isBinary ? "wb" : "wt", true)); + if (jsonOutFile == 0) { + throw DeadlyExportError("Could not open output file: " + std::string(path)); + } + + StringBuffer docBuffer; + + PrettyWriter writer(docBuffer); + mDoc.Accept(writer); + + if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { + throw DeadlyExportError("Failed to write scene data!"); + } + + // Write buffer data to separate .bin files + for (unsigned int i = 0; i < mAsset.buffers.Size(); ++i) { + Ref b = mAsset.buffers.Get(i); + + std::string binPath = b->GetURI(); + + std::unique_ptr 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); + } + } + } + } + + inline void AssetWriter::WriteGLBFile(const char* path) + { + std::unique_ptr outfile(mAsset.OpenFile(path, "wb", true)); if (outfile == 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); - } + // we will write the header later, skip its size + outfile->Seek(sizeof(GLB_Header), aiOrigin_SET); StringBuffer docBuffer; - - bool pretty = true; - if (!isBinary && pretty) { - PrettyWriter writer(docBuffer); - mDoc.Accept(writer); - } - else { - Writer writer(docBuffer); - mDoc.Accept(writer); - } + Writer 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 // diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 58defed3b..708570577 100644 --- a/code/glTFExporter.cpp +++ b/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 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 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(); 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; + // 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 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. + // 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 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"); + std::string fname = std::string(mFilename); + std::string bufferIdPrefix = fname.substr(0, fname.find(".")); + std::string bufferId = mAsset->FindUniqueID("", bufferIdPrefix.c_str()); - Ref b = mAsset->GetBodyBuffer(); - if (!b) { - b = mAsset->buffers.Create(bufferId); - } + Ref 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];