diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index b2e8e4a91..ebe7ac4e6 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -436,6 +436,19 @@ private: aiScene* const out; const FBX::Document& doc; + + bool FindTextureIndexByFilename(const Video& video, unsigned int& index) { + index = 0; + const char* videoFileName = video.FileName().c_str(); + for (auto texture = textures_converted.begin(); texture != textures_converted.end(); ++texture) + { + if (!strcmp(texture->first->FileName().c_str(), videoFileName)) { + return true; + } + index++; + } + return false; + } }; Converter::Converter( aiScene* out, const Document& doc ) @@ -1749,7 +1762,7 @@ unsigned int Converter::ConvertVideo( const Video& video ) out_tex->mWidth = static_cast( video.ContentLength() ); // total data size out_tex->mHeight = 0; // fixed to 0 - // steal the data from the Video to avoid an additional copy + // steal the data from the Video to avoid an additional copy out_tex->pcData = reinterpret_cast( const_cast( video ).RelinquishContent() ); // try to extract a hint from the file extension @@ -1783,22 +1796,32 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap& path.Set( tex->RelativeFilename() ); const Video* media = tex->Media(); - if ( media != 0 && media->ContentLength() > 0 ) { - unsigned int index; + if (media != 0) { + bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found) + unsigned int index; - VideoMap::const_iterator it = textures_converted.find( media ); - if ( it != textures_converted.end() ) { - index = ( *it ).second; - } - else { - index = ConvertVideo( *media ); - textures_converted[ media ] = index; - } + VideoMap::const_iterator it = textures_converted.find(media); + if (it != textures_converted.end()) { + index = (*it).second; + textureReady = true; + } + else { + if (media->ContentLength() > 0) { + index = ConvertVideo(*media); + textures_converted[media] = index; + textureReady = true; + } + else if (doc.Settings().searchEmbeddedTextures) { //try to find the texture on the already-loaded textures by the filename, if the flag is on + textureReady = FindTextureIndexByFilename(*media, index); + } + } - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) - path.data[ 0 ] = '*'; - path.length = 1 + ASSIMP_itoa10( path.data + 1, MAXLEN - 1, index ); - } + // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready + if (textureReady) { + path.data[0] = '*'; + path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); + } + } out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, 0 ); diff --git a/code/FBXImportSettings.h b/code/FBXImportSettings.h index ca7435f4c..53fa64ec6 100644 --- a/code/FBXImportSettings.h +++ b/code/FBXImportSettings.h @@ -63,6 +63,7 @@ struct ImportSettings , readWeights(true) , preservePivots(true) , optimizeEmptyAnimationCurves(true) + , searchEmbeddedTextures(false) {} @@ -137,6 +138,10 @@ struct ImportSettings * values matching the corresponding node transformation. * The default value is true. */ bool optimizeEmptyAnimationCurves; + + /** search for embedded loaded textures, where no embedded texture data is provided. + * The default value is false. */ + bool searchEmbeddedTextures; }; diff --git a/code/FBXImporter.cpp b/code/FBXImporter.cpp index 7078fde58..0ebf13e7d 100644 --- a/code/FBXImporter.cpp +++ b/code/FBXImporter.cpp @@ -131,6 +131,7 @@ void FBXImporter::SetupProperties(const Importer* pImp) settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false); settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true); settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true); + settings.searchEmbeddedTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES, false); } // ------------------------------------------------------------------------------------------------ diff --git a/code/FBXMaterial.cpp b/code/FBXMaterial.cpp index 5391c0a45..a80f243ba 100644 --- a/code/FBXMaterial.cpp +++ b/code/FBXMaterial.cpp @@ -281,7 +281,7 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std const Scope& sc = GetRequiredScope(element); const Element* const Type = sc["Type"]; - const Element* const FileName = sc["FileName"]; + const Element* const FileName = sc.FindElementCaseInsensitive("FileName"); //some files retain the information as "Filename", others "FileName", who knows const Element* const RelativeFilename = sc["RelativeFilename"]; const Element* const Content = sc["Content"]; @@ -291,35 +291,40 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std if(FileName) { fileName = ParseTokenAsString(GetRequiredToken(*FileName,0)); - } + } if(RelativeFilename) { relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0)); } if(Content) { - const Token& token = GetRequiredToken(*Content, 0); - const char* data = token.begin(); - if(!token.IsBinary()) { - DOMWarning("video content is not binary data, ignoring", &element); - } - else if(static_cast(token.end() - data) < 5) { - DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element); - } - else if(*data != 'R') { - DOMWarning("video content is not raw binary data, ignoring", &element); - } - else { - // read number of elements - uint32_t len = 0; - ::memcpy(&len, data + 1, sizeof(len)); - AI_SWAP4(len); + //this field is ommited when the embedded texture is already loaded, let's ignore if itīs not found + try { + const Token& token = GetRequiredToken(*Content, 0); + const char* data = token.begin(); + if (!token.IsBinary()) { + DOMWarning("video content is not binary data, ignoring", &element); + } + else if (static_cast(token.end() - data) < 5) { + DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element); + } + else if (*data != 'R') { + DOMWarning("video content is not raw binary data, ignoring", &element); + } + else { + // read number of elements + uint32_t len = 0; + ::memcpy(&len, data + 1, sizeof(len)); + AI_SWAP4(len); - contentLength = len; + contentLength = len; - content = new uint8_t[len]; - ::memcpy(content, data + 5, len); - } + content = new uint8_t[len]; + ::memcpy(content, data + 5, len); + } + } catch (runtime_error runtimeError) { + //we donīt need the content data for contents that has already been loaded + } } props = GetPropertyTable(doc,"Video.FbxVideo",element,sc); diff --git a/code/FBXParser.h b/code/FBXParser.h index d2b2c8bb5..b0683ccd1 100644 --- a/code/FBXParser.h +++ b/code/FBXParser.h @@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include "LogAux.h" +#include "fast_atof.h" #include "FBXCompileConfig.h" #include "FBXTokenizer.h" @@ -137,6 +138,17 @@ public: return it == elements.end() ? NULL : (*it).second; } + const Element* FindElementCaseInsensitive(const std::string& elementName) const { + const char* elementNameCStr = elementName.c_str(); + for (auto element = elements.begin(); element != elements.end(); ++element) + { + if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, MAXLEN)) { + return element->second; + } + } + return NULL; + } + ElementCollection GetCollection(const std::string& index) const { return elements.equal_range(index); } diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index db197822e..00fe7b593 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team All rights reserved. @@ -632,8 +632,15 @@ enum aiComponent #define AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES \ "IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES" - - +// --------------------------------------------------------------------------- +/** @brief Set whether the fbx importer will search for embedded loaded textures, where no embedded texture data is provided. +* +* The default value is false (0) +* Property type: bool +*/ +#define AI_CONFIG_IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES \ + "IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES" + // --------------------------------------------------------------------------- /** @brief Set the vertex animation keyframe to be imported *