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

Export glTF buffer data in a separate .bin file
pull/1012/head
Kim Kulling 2016-09-21 19:39:38 +02:00 committed by GitHub
commit 38cbdcd885
4 changed files with 90 additions and 60 deletions

View File

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

View File

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

View File

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

View File

@ -80,20 +80,9 @@ namespace Assimp {
// Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp // 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) 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 // 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) const ExportProperties* pProperties, bool isBinary)
: mFilename(filename) : mFilename(filename)
, mIOSystem(pIOSystem) , mIOSystem(pIOSystem)
, mScene(pScene)
, mProperties(pProperties) , 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(); std::unique_ptr<Asset> asset();
mAsset.reset( new glTF::Asset( pIOSystem ) ); mAsset.reset( new glTF::Asset( pIOSystem ) );
@ -144,9 +146,13 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc
ExportScene(); ExportScene();
glTF::AssetWriter writer(*mAsset); 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() void glTFExporter::ExportMeshes()
{ {
// Not for // Not for
// using IndicesType = decltype(aiFace::mNumIndices); // using IndicesType = decltype(aiFace::mNumIndices);
// But yes for // But yes for
// using IndicesType = unsigned short; // using IndicesType = unsigned short;
// because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification. // because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification.
typedef unsigned short IndicesType; typedef unsigned short IndicesType;
// Variables needed for compression. BEGIN. // Variables needed for compression. BEGIN.
// Indices, not pointers - because pointer to buffer is changin while writing to it. // 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_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. 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. 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. 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. bool comp_allow;// Point that data of current mesh can be compressed.
// Variables needed for compression. END. // 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<Buffer> b = mAsset->GetBodyBuffer(); Ref<Buffer> b = mAsset->GetBodyBuffer();
if (!b) { if (!b) {
b = mAsset->buffers.Create(bufferId); b = mAsset->buffers.Create(bufferId);
} }
for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) { for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
const aiMesh* aim = mScene->mMeshes[idx_mesh]; const aiMesh* aim = mScene->mMeshes[idx_mesh];