diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 5b3ca6a88..f2a71002e 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -525,6 +525,8 @@ SET( PostProcessing_SRCS ComputeUVMappingProcess.h ConvertToLHProcess.cpp ConvertToLHProcess.h + EmbedTexturesProcess.cpp + EmbedTexturesProcess.h FindDegenerates.cpp FindDegenerates.h FindInstancesProcess.cpp @@ -940,8 +942,8 @@ if (APPLE) # PUBLIC_HEADER option does not support directory structure creation # add ./Compiler/*.h to assimp.framework via copy command - ADD_CUSTOM_COMMAND(TARGET assimp POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy_directory + ADD_CUSTOM_COMMAND(TARGET assimp POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_directory "../${HEADER_PATH}/Compiler" assimp.framework/Headers/Compiler COMMENT "Copying public ./Compiler/ header files to framework bundle's Headers/Compiler/") diff --git a/code/EmbedTexturesProcess.cpp b/code/EmbedTexturesProcess.cpp new file mode 100644 index 000000000..5d40ec16e --- /dev/null +++ b/code/EmbedTexturesProcess.cpp @@ -0,0 +1,147 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +#include "EmbedTexturesProcess.h" +#include "ParsingUtils.h" +#include "ProcessHelper.h" + +#include + +using namespace Assimp; + +EmbedTexturesProcess::EmbedTexturesProcess() +: BaseProcess() { +} + +EmbedTexturesProcess::~EmbedTexturesProcess() { +} + +bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const { + return (pFlags & aiProcess_EmbedTextures) != 0; +} + +void EmbedTexturesProcess::SetupProperties(const Importer* pImp) { + mRootPath = pImp->GetPropertyString("sourceFilePath"); + mRootPath = mRootPath.substr(0, mRootPath.find_last_of("\\/") + 1u); +} + +void EmbedTexturesProcess::Execute(aiScene* pScene) { + if (pScene == nullptr || pScene->mRootNode == nullptr) return; + + aiString path; + + uint32_t embeddedTexturesCount = 0u; + + for (auto matId = 0u; matId < pScene->mNumMaterials; ++matId) { + auto material = pScene->mMaterials[matId]; + + for (auto ttId = 1u; ttId < AI_TEXTURE_TYPE_MAX; ++ttId) { + auto tt = static_cast(ttId); + auto texturesCount = material->GetTextureCount(tt); + + for (auto texId = 0u; texId < texturesCount; ++texId) { + material->GetTexture(tt, texId, &path); + if (path.data[0] == '*') continue; // Already embedded + + // Indeed embed + if (addTexture(pScene, path.data)) { + auto embeddedTextureId = pScene->mNumTextures - 1u; + ::ai_snprintf(path.data, 1024, "*%u", embeddedTextureId); + material->AddProperty(&path, AI_MATKEY_TEXTURE(tt, texId)); + embeddedTexturesCount++; + } + } + } + } + + char stringBuffer[128]; + ::ai_snprintf(stringBuffer, 128, "EmbedTexturesProcess finished. Embedded %u textures.", embeddedTexturesCount); + DefaultLogger::get()->info(stringBuffer); +} + +bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const { + uint32_t imageSize = 0; + std::string imagePath = path; + + // Test path directly + std::ifstream file(imagePath, std::ios::binary | std::ios::ate); + if ((imageSize = file.tellg()) == -1u) { + DefaultLogger::get()->warn("EmbedTexturesProcess: Cannot find image: " + imagePath + ". Will try to find it in root folder."); + + // Test path in root path + imagePath = mRootPath + path; + file.open(imagePath, std::ios::binary | std::ios::ate); + if ((imageSize = file.tellg()) == -1u) { + // Test path basename in root path + imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u); + file.open(imagePath, std::ios::binary | std::ios::ate); + if ((imageSize = file.tellg()) == -1u) { + DefaultLogger::get()->error("EmbedTexturesProcess: Unable to embed texture: " + path + "."); + return false; + } + } + } + + aiTexel* imageContent = new aiTexel[1u + imageSize / sizeof(aiTexel)]; + file.seekg(0, std::ios::beg); + file.read(reinterpret_cast(imageContent), imageSize); + + // Enlarging the textures table + auto textureId = pScene->mNumTextures++; + auto oldTextures = pScene->mTextures; + pScene->mTextures = new aiTexture*[pScene->mNumTextures]; + memmove(pScene->mTextures, oldTextures, sizeof(aiTexture*) * (pScene->mNumTextures - 1u)); + + // Add the new texture + auto pTexture = new aiTexture(); + pTexture->mHeight = 0; // Means that this is still compressed + pTexture->mWidth = imageSize; + pTexture->pcData = imageContent; + + auto extension = path.substr(path.find_last_of('.') + 1u); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + if (extension == "jpeg") extension = "jpg"; + strcpy(pTexture->achFormatHint, extension.c_str()); + + pScene->mTextures[textureId] = pTexture; + + return true; +} diff --git a/code/EmbedTexturesProcess.h b/code/EmbedTexturesProcess.h new file mode 100644 index 000000000..5a472f644 --- /dev/null +++ b/code/EmbedTexturesProcess.h @@ -0,0 +1,84 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +#pragma once + +#include "BaseProcess.h" + +#include + +struct aiNode; + +namespace Assimp { + +/** + * Force embedding of textures (using the path = "*1" convention). + * If a texture's file does not exist at the specified path + * (due, for instance, to an absolute path generated on another system), + * it will check if a file with the same name exists at the root folder + * of the imported model. And if so, it uses that. + */ +class ASSIMP_API EmbedTexturesProcess : public BaseProcess { +public: + /// The default class constructor. + EmbedTexturesProcess(); + + /// The class destructor. + virtual ~EmbedTexturesProcess(); + + /// Overwritten, @see BaseProcess + virtual bool IsActive(unsigned int pFlags) const; + + /// Overwritten, @see BaseProcess + virtual void SetupProperties(const Importer* pImp); + + /// Overwritten, @see BaseProcess + virtual void Execute(aiScene* pScene); + +private: + // Resolve the path and add the file content to the scene as a texture. + bool addTexture(aiScene* pScene, std::string path) const; + +private: + std::string mRootPath; +}; + +} // namespace Assimp diff --git a/code/Importer.cpp b/code/Importer.cpp index c6c6f0edd..bde937b44 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -677,6 +677,8 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) profiler->EndRegion("import"); } + SetPropertyString("sourceFilePath", pFile); + // If successful, apply all active post processing steps to the imported data if( pimpl->mScene) { diff --git a/code/PostStepRegistry.cpp b/code/PostStepRegistry.cpp index c80c373e5..eaae1447b 100644 --- a/code/PostStepRegistry.cpp +++ b/code/PostStepRegistry.cpp @@ -91,6 +91,9 @@ corresponding preprocessor flag to selectively disable steps. #ifndef ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS # include "RemoveRedundantMaterials.h" #endif +#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS) +# include "EmbedTexturesProcess.h" +#endif #ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS # include "FindInvalidDataProcess.h" #endif @@ -132,7 +135,7 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out) // of sequence it is executed. Steps that are added here are not // validated - as RegisterPPStep() does - all dependencies must be given. // ---------------------------------------------------------------------------- - out.reserve(25); + out.reserve(30); #if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS) out.push_back( new MakeLeftHandedProcess()); #endif @@ -148,6 +151,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out) #if (!defined ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS) out.push_back( new RemoveRedundantMatsProcess()); #endif +#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS) + out.push_back( new EmbedTexturesProcess()); +#endif #if (!defined ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS) out.push_back( new FindInstancesProcess()); #endif diff --git a/include/assimp/defs.h b/include/assimp/defs.h index 20b234f90..0adea90e8 100644 --- a/include/assimp/defs.h +++ b/include/assimp/defs.h @@ -112,6 +112,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * TRANSFORMTEXCOORDS * GENUVCOORDS * ENTITYMESHBUILDER + * EMBEDTEXTURES * MAKELEFTHANDED * FLIPUVS * FLIPWINDINGORDER diff --git a/include/assimp/postprocess.h b/include/assimp/postprocess.h index 970df8e8a..dfb26d5ed 100644 --- a/include/assimp/postprocess.h +++ b/include/assimp/postprocess.h @@ -535,7 +535,18 @@ enum aiPostProcessSteps * * Use #AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY to control this. */ - aiProcess_GlobalScale = 0x8000000 + aiProcess_GlobalScale = 0x8000000, + + // ------------------------------------------------------------------------- + /**
A postprocessing step to embed of textures. + * + * This will remove external data dependencies for textures. + * If a texture's file does not exist at the specified path + * (due, for instance, to an absolute path generated on another system), + * it will check if a file with the same name exists at the root folder + * of the imported model. And if so, it uses that. + */ + aiProcess_EmbedTextures = 0x10000000, // aiProcess_GenEntityMeshes = 0x100000, // aiProcess_OptimizeAnimations = 0x200000