From 54e4c6b20b3ae2982ab9dad08190f85b9193e2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Terziman?= Date: Thu, 5 Dec 2013 17:54:12 +0100 Subject: [PATCH] In Collada: first preliminary support for export of embeded textures --- code/ColladaExporter.cpp | 87 ++++++++++++++++++++++++++++++++++++++-- code/ColladaExporter.h | 17 ++++++-- 2 files changed, 97 insertions(+), 7 deletions(-) diff --git a/code/ColladaExporter.cpp b/code/ColladaExporter.cpp index 7672b92d8..11faaaab9 100644 --- a/code/ColladaExporter.cpp +++ b/code/ColladaExporter.cpp @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER #include "ColladaExporter.h" +#include "fast_atof.h" #include "SceneCombiner.h" #include @@ -58,8 +59,24 @@ namespace Assimp // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene) { + std::string path = ""; + + const char* end_path = strrchr(pFile, '/'); + + if(end_path != NULL) { + path = std::string(pFile, end_path + 1 - pFile); + } else { + // We need to test both types of folder separators because pIOSystem->getOsSeparator() is not reliable. + // Moreover, the path given by some applications is not even consistent with the OS specific type of separator. + end_path = strrchr(pFile, '\\'); + + if(end_path != NULL) { + path = std::string(pFile, end_path + 1 - pFile); + } + } + // invoke the exporter - ColladaExporter iDoTheExportThing( pScene); + ColladaExporter iDoTheExportThing( pScene, pIOSystem, path); // we're still here - export successfully completed. Write result to the given IOSYstem boost::scoped_ptr outfile (pIOSystem->Open(pFile,"wt")); @@ -76,7 +93,7 @@ void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pS // ------------------------------------------------------------------------------------------------ // Constructor for a specific scene to export -ColladaExporter::ColladaExporter( const aiScene* pScene) +ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path) : mIOSystem(pIOSystem), mPath(path) { // make sure that all formatting happens using the standard, C locale and not the user's current locale mOutput.imbue( std::locale("C") ); @@ -110,6 +127,7 @@ void ColladaExporter::WriteFile() mOutput << "" << endstr; PushTag(); + WriteTextures(); WriteHeader(); WriteMaterials(); @@ -161,7 +179,7 @@ void ColladaExporter::WriteHeader() float scale = 1.0; if(std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) { - scale = scaling.x; + scale = (float) ((((double) scaling.x) + ((double) scaling.y) + ((double) scaling.z)) / 3.0); } else { add_root_node = true; } @@ -221,6 +239,41 @@ void ColladaExporter::WriteHeader() mOutput << startstr << "" << endstr; } +// ------------------------------------------------------------------------------------------------ +// Write the embedded textures +void ColladaExporter::WriteTextures() { + static const unsigned int buffer_size = 1024; + char str[buffer_size]; + + if(mScene->HasTextures()) { + for(unsigned int i = 0; i < mScene->mNumTextures; i++) { + // It would be great to be able to create a directory in portable standard C++, but it's not the case, + // so we just write the textures in the current directory. + + aiTexture* texture = mScene->mTextures[i]; + + ASSIMP_itoa10(str, buffer_size, i); + + std::string name = std::string("Texture_") + str + "." + ((const char*) texture->achFormatHint); + + boost::scoped_ptr outfile(mIOSystem->Open(mPath + name, "wb")); + if(outfile == NULL) { + throw DeadlyExportError("could not open output texture file: " + mPath + name); + } + + if(texture->mHeight == 0) { + outfile->Write((void*) texture->pcData, texture->mWidth, 1); + } else { + //TODO + } + + outfile->Flush(); + + textures.insert(std::make_pair(i, name)); + } + } +} + // ------------------------------------------------------------------------------------------------ // Reads a single surface entry from the given material keys void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex) @@ -230,7 +283,33 @@ void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* aiString texfile; unsigned int uvChannel = 0; pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel); - poSurface.texture = texfile.C_Str(); + + std::string index_str(texfile.C_Str()); + + if(index_str.size() != 0 && index_str[0] == '*') + { + unsigned int index; + + index_str = index_str.substr(1, std::string::npos); + + try { + index = (unsigned int) strtoul10_64(index_str.c_str()); + } catch(std::exception& error) { + throw DeadlyExportError(error.what()); + } + + std::map::const_iterator name = textures.find(index); + + if(name != textures.end()) { + poSurface.texture = name->second; + } else { + throw DeadlyExportError("could not find embedded texture at index " + index_str); + } + } else + { + poSurface.texture = texfile.C_Str(); + } + poSurface.channel = uvChannel; poSurface.exist = true; } else diff --git a/code/ColladaExporter.h b/code/ColladaExporter.h index 9760f481b..336a3fa6f 100644 --- a/code/ColladaExporter.h +++ b/code/ColladaExporter.h @@ -59,7 +59,7 @@ class ColladaExporter { public: /// Constructor for a specific scene to export - ColladaExporter( const aiScene* pScene); + ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path); /// Destructor virtual ~ColladaExporter(); @@ -71,8 +71,11 @@ protected: /// Writes the asset header void WriteHeader(); - /// Writes the material setup - void WriteMaterials(); + /// Writes the embedded textures + void WriteTextures(); + + /// Writes the material setup + void WriteMaterials(); /// Writes the geometry library void WriteGeometryLibrary(); @@ -104,6 +107,12 @@ public: std::stringstream mOutput; protected: + /// The IOSystem for output + IOSystem* mIOSystem; + + /// Path of the directory where the scene will be exported + std::string mPath; + /// The scene to be written const aiScene* mScene; bool mSceneOwned; @@ -143,6 +152,8 @@ protected: std::vector materials; + std::map textures; + protected: /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions /// Reads a single surface entry from the given material keys