diff --git a/Build.md b/Build.md index d5b443a79..7c908606d 100644 --- a/Build.md +++ b/Build.md @@ -1,32 +1,32 @@ -# Install CMake +# Build Instructions +## Install CMake Asset-Importer-Lib can be build for a lot of different platforms. We are using cmake to generate the build environment for these via cmake. So you have to make sure that you have a working cmake-installation on your system. You can download it at https://cmake.org/ or for linux install it via -``` +```bash sudo apt-get install cmake ``` -# Get the source +## Get the source Make sure you have a working git-installation. Open a command prompt and clone the Asset-Importer-Lib via: -``` +```bash git clone https://github.com/assimp/assimp.git ``` -# Build instructions for Windows with Visual-Studio +## Build instructions for Windows with Visual-Studio First you have to install Visual-Studio on your windows-system. You can get the Community-Version for free here: https://visualstudio.microsoft.com/de/downloads/ To generate the build environment for your IDE open a command prompt, navigate to your repo and type: -``` -> cmake CMakeLists.txt +```bash +cmake CMakeLists.txt ``` This will generate the project files for the visual studio. All dependencies used to build Asset-IMporter-Lib shall be part of the repo. If you want to use you own zlib.installation this is possible as well. Check the options for it. -# Build instructions for Windows with UWP -See https://stackoverflow.com/questions/40803170/cmake-uwp-using-cmake-to-build-universal-windows-app +## Build instructions for Windows with UWP +See - -# Build instrcutions for Linux / Unix +## Build instructions for Linux / Unix Open a terminal and got to your repository. You can generate the makefiles and build the library via: -``` +```bash cmake CMakeLists.txt make -j4 ``` @@ -34,7 +34,23 @@ The option -j descripes the number of parallel processes for the build. In this If you want to use a IDE for linux you can try QTCreator for instance. -# CMake build options +## Build instructions for MinGW + Older versions of MinGW's compiler (e.g. 5.1.0) do not support the -mbig_obj flag +required to compile some of assimp's files, especially for debug builds. +Version 7.3.0 of g++-mingw-w64 & gcc-mingw-w64 appears to work. + +Please see [CMake Cross Compiling](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling) for general information on CMake Toolchains. + +Some users have had success building assimp using MinGW on Linux using [polly](https://github.com/ruslo/polly/). + +The following toolchain, which is not maintained by assimp, seems to work on Linux: [linux-mingw-w64-gnuxx11.cmake](https://github.com/ruslo/polly/blob/master/linux-mingw-w64-gnuxx11.cmake) + +The following toolchain may or may not be helpful for building assimp using MinGW on Windows (untested): + [mingw-cxx17.cmake](https://github.com/ruslo/polly/blob/master/mingw-cxx17.cmake) + +Besides the toolchain, compilation should be the same as for Linux / Unix. + +## CMake build options The cmake-build-environment provides options to configure the build. The following options can be used: - **BUILD_SHARED_LIBS ( default ON )**: Generation of shared libs ( dll for windows, so for Linux ). Set this to OFF to get a static lib. - **BUILD_FRAMEWORK ( default OFF, MacOnly)**: Build package as Mac OS X Framework bundle @@ -55,4 +71,3 @@ The cmake-build-environment provides options to configure the build. The followi - **INJECT_DEBUG_POSTFIX( default ON )**: Inject debug postfix in .a/.so lib names - **IGNORE_GIT_HASH ( default OFF )**: Don't call git to get the hash. - **ASSIMP_INSTALL_PDB ( default ON )**: Install MSVC debug files. - diff --git a/CMakeLists.txt b/CMakeLists.txt index c5d5b15b1..fa5842560 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,6 +237,11 @@ ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 ${CMAKE_CXX_FLAGS}" ) SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}") ELSEIF( CMAKE_COMPILER_IS_MINGW ) + IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0) + message(FATAL_ERROR "MinGW is too old to be supported. Please update MinGW and try again.") + ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3) + message(WARNING "MinGW is old, if you experience errors, update MinGW.") + ENDIF() SET( CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}" ) SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS} ") ADD_DEFINITIONS( -U__STRICT_ANSI__ ) diff --git a/Readme.md b/Readme.md index 8cd3c7cb3..19e43a3cb 100644 --- a/Readme.md +++ b/Readme.md @@ -17,6 +17,8 @@ A library to import and export various 3d-model-formats including scene-post-pro APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. +[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/). + Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more. This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). diff --git a/appveyor.yml b/appveyor.yml index 78ef4da75..851d9c096 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,8 +15,8 @@ matrix: image: - Visual Studio 2013 - - Previous Visual Studio 2015 - - Previous Visual Studio 2017 + - Visual Studio 2015 + - Visual Studio 2017 platform: - Win32 @@ -28,10 +28,10 @@ install: - set PATH=C:\Ruby24-x64\bin;%PATH% - set CMAKE_DEFINES -DASSIMP_WERROR=ON - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" set CMAKE_GENERATOR_NAME=Visual Studio 12 2013 - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Previous Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Previous Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017 + - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 + - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017 - if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% Win64 - - cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" + - cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" . - set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5" - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/5/7/b/57b2947c-7221-4f33-b35e-2fc78cb10df4/vc_redist.x64.exe -OutFile .\packaging\windows-innosetup\vc_redist.x64.exe - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/1/d/8/1d8137db-b5bb-4925-8c5d-927424a2e4de/vc_redist.x86.exe -OutFile .\packaging\windows-innosetup\vc_redist.x86.exe @@ -53,7 +53,13 @@ build: project: Assimp.sln after_build: - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" iscc packaging\windows-innosetup\script.iss + - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( + if "%platform%"=="x64" ( + iscc packaging\windows-innosetup\script_x64.iss + ) else ( + iscc packaging\windows-innosetup\script_x86.iss + ) + ) - 7z a assimp.7z bin\%CONFIGURATION%\* lib\%CONFIGURATION%\* test_script: diff --git a/code/ASELoader.cpp b/code/ASELoader.cpp index 321e8548a..556e8ce66 100644 --- a/code/ASELoader.cpp +++ b/code/ASELoader.cpp @@ -1299,7 +1299,7 @@ void ASEImporter::BuildMaterialIndices() } } - // Dekete our temporary array + // Delete our temporary array delete[] pcIntMaterials; } diff --git a/code/ASEParser.cpp b/code/ASEParser.cpp index e8d6febc2..14b962320 100644 --- a/code/ASEParser.cpp +++ b/code/ASEParser.cpp @@ -45,7 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the ASE parser class */ - #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER diff --git a/code/ASEParser.h b/code/ASEParser.h index b8c820632..0cfd5313c 100644 --- a/code/ASEParser.h +++ b/code/ASEParser.h @@ -188,10 +188,11 @@ struct Animation { } mRotationType, mScalingType, mPositionType; Animation() AI_NO_EXCEPT - : mRotationType (TRACK) - , mScalingType (TRACK) - , mPositionType (TRACK) - {} + : mRotationType (TRACK) + , mScalingType (TRACK) + , mPositionType (TRACK) { + // empty + } //! List of track rotation keyframes std::vector< aiQuatKey > akeyRotations; @@ -243,7 +244,6 @@ struct BaseNode { mTargetPosition.x = qnan; } - //! Name of the mesh std::string mName; diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 05f916abd..5a7838515 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -804,6 +804,18 @@ ADD_ASSIMP_IMPORTER( MMD MMDVmdParser.h ) +# Workaround for issue #2406 - force problematic large file to be optimized to prevent string table overflow error +# Used -Os instead of -O2 as previous issues had mentioned, since -Os is roughly speaking -O2, excluding any +# optimizations that take up extra space. Given that the issue is a string table overflowing, -Os seemed appropriate +# Also, I'm not positive if both link & compile flags are needed, but this hopefully ensures that the issue should not +# recur for edge cases such as static builds. +if ((CMAKE_COMPILER_IS_MINGW) AND (CMAKE_BUILD_TYPE MATCHES Debug)) + message("-- Applying MinGW StepFileGen1.cpp Debug Workaround") + SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES COMPILE_FLAGS -Os ) + SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES LINK_FLAGS -Os ) + SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES STATIC_LIBRARY_FLAGS -Os ) +endif() + ADD_ASSIMP_IMPORTER( STEP STEPFile.h Importer/StepFile/StepFileImporter.h diff --git a/code/FBXCommon.h b/code/FBXCommon.h index fcb20a5ca..e51644913 100644 --- a/code/FBXCommon.h +++ b/code/FBXCommon.h @@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - +namespace Assimp { namespace FBX { const std::string NULL_RECORD = { // 13 null bytes @@ -80,7 +80,7 @@ namespace FBX TransformInheritance_MAX // end-of-enum sentinel }; } - +} #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // AI_FBXCOMMON_H_INC diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 0abfdafdc..1701b2966 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -67,6 +67,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include + namespace Assimp { namespace FBX { @@ -76,7 +77,7 @@ namespace Assimp { #define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000L - FBXConverter::FBXConverter(aiScene* out, const Document& doc) + FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit ) : defaultMaterialIndex() , lights() , cameras() @@ -89,7 +90,9 @@ namespace Assimp { , mNodeNames() , anim_fps() , out(out) - , doc(doc) { + , doc(doc) + , mRemoveEmptyBones( removeEmptyBones ) + , mCurrentUnit(FbxUnit::cm) { // animations need to be converted first since this will // populate the node_anim_chain_bits map, which is needed // to determine which nodes need to be generated. @@ -117,6 +120,7 @@ namespace Assimp { ConvertGlobalSettings(); TransferDataToScene(); + ConvertToUnitScale(unit); // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE // to make sure the scene passes assimp's validation. FBX files @@ -387,6 +391,7 @@ namespace Assimp { break; default: ai_assert(false); + break; } } @@ -977,7 +982,9 @@ namespace Assimp { unsigned int epcount = 0; for (unsigned i = 0; i < indices.size(); i++) { - if (indices[i] < 0) epcount++; + if (indices[i] < 0) { + epcount++; + } } unsigned int pcount = static_cast( indices.size() ); unsigned int scount = out_mesh->mNumFaces = pcount - epcount; @@ -1407,7 +1414,7 @@ namespace Assimp { const WeightIndexArray& indices = cluster->GetIndices(); - if (indices.empty()) { + if (indices.empty() && mRemoveEmptyBones ) { continue; } @@ -1439,13 +1446,11 @@ namespace Assimp { if (index_out_indices.back() == no_index_sentinel) { index_out_indices.back() = out_indices.size(); - } if (no_mat_check) { out_indices.push_back(out_idx[i]); - } - else { + } else { // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn) const std::vector::iterator it = std::lower_bound( outputVertStartIndices->begin(), @@ -1461,11 +1466,11 @@ namespace Assimp { } } } - + // if we found at least one, generate the output bones // XXX this could be heavily simplified by collecting the bone // data in a single step. - if (ok) { + if (ok && mRemoveEmptyBones) { ConvertCluster(bones, model, *cluster, out_indices, index_out_indices, count_out_indices, node_global_transform); } @@ -1596,6 +1601,13 @@ namespace Assimp { out_mat->AddProperty(&str, AI_MATKEY_NAME); } + // Set the shading mode as best we can: The FBX specification only mentions Lambert and Phong, and only Phong is mentioned in Assimp's aiShadingMode enum. + if (material.GetShadingModel() == "phong") + { + aiShadingMode shadingMode = aiShadingMode_Phong; + out_mat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL); + } + // shading stuff and colors SetShadingPropertiesCommon(out_mat, props); SetShadingPropertiesRaw( out_mat, props, material.Textures(), mesh ); @@ -3407,8 +3419,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa na->mNumScalingKeys = static_cast(keys.size()); na->mScalingKeys = new aiVectorKey[keys.size()]; - if (keys.size() > 0) + if (keys.size() > 0) { InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime); + } } void FBXConverter::ConvertTranslationKeys(aiNodeAnim* na, const std::vector& nodes, @@ -3472,6 +3485,46 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate()); } + void FBXConverter::ConvertToUnitScale( FbxUnit unit ) { + if (mCurrentUnit == unit) { + return; + } + + ai_real scale = 1.0; + if (mCurrentUnit == FbxUnit::cm) { + if (unit == FbxUnit::m) { + scale = (ai_real)0.01; + } else if (unit == FbxUnit::km) { + scale = (ai_real)0.00001; + } + } else if (mCurrentUnit == FbxUnit::m) { + if (unit == FbxUnit::cm) { + scale = (ai_real)100.0; + } else if (unit == FbxUnit::km) { + scale = (ai_real)0.001; + } + } else if (mCurrentUnit == FbxUnit::km) { + if (unit == FbxUnit::cm) { + scale = (ai_real)100000.0; + } else if (unit == FbxUnit::m) { + scale = (ai_real)1000.0; + } + } + + for (auto mesh : meshes) { + if (nullptr == mesh) { + continue; + } + + if (mesh->HasPositions()) { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + aiVector3D &pos = mesh->mVertices[i]; + pos *= scale; + } + } + } + } + void FBXConverter::TransferDataToScene() { ai_assert(!out->mMeshes); @@ -3525,9 +3578,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa } // ------------------------------------------------------------------------------------------------ - void ConvertToAssimpScene(aiScene* out, const Document& doc) + void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit) { - FBXConverter converter(out, doc); + FBXConverter converter(out, doc, removeEmptyBones, unit); } } // !FBX diff --git a/code/FBXConverter.h b/code/FBXConverter.h index 50637468b..f75222d5b 100644 --- a/code/FBXConverter.h +++ b/code/FBXConverter.h @@ -76,12 +76,22 @@ namespace FBX { class Document; +enum class FbxUnit { + cm = 0, + m, + km, + NumUnits, + + Undefined +}; + /** * Convert a FBX #Document to #aiScene * @param out Empty scene to be populated - * @param doc Parsed FBX document + * @param doc Parsed FBX document + * @param removeEmptyBones Will remove bones, which do not have any references to vertices. */ -void ConvertToAssimpScene(aiScene* out, const Document& doc); +void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit); /** Dummy class to encapsulate the conversion process */ class FBXConverter { @@ -112,7 +122,7 @@ public: }; public: - FBXConverter(aiScene* out, const Document& doc); + FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit); ~FBXConverter(); private: @@ -414,6 +424,10 @@ private: void ConvertGlobalSettings(); + // ------------------------------------------------------------------------------------------------ + // Will perform the conversion from a given unit to the requested unit. + void ConvertToUnitScale(FbxUnit unit); + // ------------------------------------------------------------------------------------------------ // copy generated meshes, animations, lights, cameras and textures to the output scene void TransferDataToScene(); @@ -453,6 +467,10 @@ private: aiScene* const out; const FBX::Document& doc; + + bool mRemoveEmptyBones; + + FbxUnit mCurrentUnit; }; } diff --git a/code/FBXExportNode.cpp b/code/FBXExportNode.cpp index e5215466a..06c89cee4 100644 --- a/code/FBXExportNode.cpp +++ b/code/FBXExportNode.cpp @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // ostringstream #include // shared_ptr +namespace Assimp { // AddP70 helpers... there's no usable pattern here, // so all are defined as separate functions. // Even "animatable" properties are often completely different @@ -252,7 +253,8 @@ void FBX::Node::DumpChildren( } else { std::ostringstream ss; DumpChildrenAscii(ss, indent); - s.PutString(ss.str()); + if (ss.tellp() > 0) + s.PutString(ss.str()); } } @@ -266,7 +268,8 @@ void FBX::Node::End( } else { std::ostringstream ss; EndAscii(ss, indent, has_children); - s.PutString(ss.str()); + if (ss.tellp() > 0) + s.PutString(ss.str()); } } @@ -367,7 +370,7 @@ void FBX::Node::EndBinary( bool has_children ) { // if there were children, add a null record - if (has_children) { s.PutString(FBX::NULL_RECORD); } + if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD); } // now go back and write initial pos this->end_pos = s.Tell(); @@ -563,6 +566,6 @@ void FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNodeAscii(name, v, s, indent); } } - +} #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/FBXExportNode.h b/code/FBXExportNode.h index e1ebc3696..b388a4f86 100644 --- a/code/FBXExportNode.h +++ b/code/FBXExportNode.h @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +namespace Assimp { namespace FBX { class Node; } @@ -264,7 +265,7 @@ private: // static helper functions ); }; - +} #endif // ASSIMP_BUILD_NO_FBX_EXPORTER diff --git a/code/FBXExportProperty.cpp b/code/FBXExportProperty.cpp index 9981d6b1c..ac464c806 100644 --- a/code/FBXExportProperty.cpp +++ b/code/FBXExportProperty.cpp @@ -52,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // ostringstream - +namespace Assimp { // constructors for single element properties FBX::Property::Property(bool v) @@ -359,6 +359,6 @@ void FBX::Property::DumpAscii(std::ostream& s, int indent) throw runtime_error(err.str()); } } - +} #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/FBXExportProperty.h b/code/FBXExportProperty.h index 9c9d37c36..424bf8b32 100644 --- a/code/FBXExportProperty.h +++ b/code/FBXExportProperty.h @@ -56,6 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // is_void +namespace Assimp { namespace FBX { class Property; } @@ -123,7 +124,7 @@ private: char type; std::vector data; }; - +} #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // AI_FBXEXPORTPROPERTY_H_INC diff --git a/code/FBXExporter.cpp b/code/FBXExporter.cpp index acb122714..ddfac6d34 100644 --- a/code/FBXExporter.cpp +++ b/code/FBXExporter.cpp @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXExportNode.h" #include "FBXExportProperty.h" #include "FBXCommon.h" +#include "FBXUtil.h" #include // aiGetVersion #include @@ -73,7 +74,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. const ai_real DEG = ai_real( 57.29577951308232087679815481 ); // degrees per radian +using namespace Assimp; +using namespace Assimp::FBX; + // some constants that we'll use for writing metadata +namespace Assimp { namespace FBX { const std::string EXPORT_VERSION_STR = "7.4.0"; const uint32_t EXPORT_VERSION_INT = 7400; // 7.4 == 2014/2015 @@ -92,11 +97,6 @@ namespace FBX { ";------------------------------------------------------------------"; } -using namespace Assimp; -using namespace FBX; - -namespace Assimp { - // --------------------------------------------------------------------- // Worker function for exporting a scene to binary FBX. // Prototyped and registered in Exporter.cpp @@ -121,6 +121,7 @@ namespace Assimp { IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties + ){ // initialize the exporter FBXExporter exporter(pScene, pProperties); @@ -1393,10 +1394,6 @@ void FBXExporter::WriteObjects () // FbxVideo - stores images used by textures. for (const auto &it : uid_by_image) { - if (it.first.compare(0, 1, "*") == 0) { - // TODO: embedded textures - continue; - } FBX::Node n("Video"); const int64_t& uid = it.second; const std::string name = ""; // TODO: ... name??? @@ -1406,7 +1403,33 @@ void FBXExporter::WriteObjects () // TODO: get full path... relative path... etc... ugh... // for now just use the same path for everything, // and hopefully one of them will work out. - const std::string& path = it.first; + std::string path = it.first; + // try get embedded texture + const aiTexture* embedded_texture = mScene->GetEmbeddedTexture(it.first.c_str()); + if (embedded_texture != nullptr) { + // change the path (use original filename, if available. If name is empty, concatenate texture index with file extension) + std::stringstream newPath; + if (embedded_texture->mFilename.length > 0) { + newPath << embedded_texture->mFilename.C_Str(); + } else if (embedded_texture->achFormatHint[0]) { + int texture_index = std::stoi(path.substr(1, path.size() - 1)); + newPath << texture_index << "." << embedded_texture->achFormatHint; + } + path = newPath.str(); + // embed the texture + size_t texture_size = static_cast(embedded_texture->mWidth * std::max(embedded_texture->mHeight, 1u)); + if (binary) { + // embed texture as binary data + std::vector tex_data; + tex_data.resize(texture_size); + memcpy(&tex_data[0], (char*)embedded_texture->pcData, texture_size); + n.AddChild("Content", tex_data); + } else { + // embed texture in base64 encoding + std::string encoded_texture = FBX::Util::EncodeBase64((char*)embedded_texture->pcData, texture_size); + n.AddChild("Content", encoded_texture); + } + } p.AddP70("Path", "KString", "XRefUrl", "", path); n.AddChild(p); n.AddChild("UseMipMap", int32_t(0)); @@ -1419,17 +1442,17 @@ void FBXExporter::WriteObjects () // referenced by material_index/texture_type pairs. std::map,int64_t> texture_uids; const std::map prop_name_by_tt = { - {aiTextureType_DIFFUSE, "DiffuseColor"}, - {aiTextureType_SPECULAR, "SpecularColor"}, - {aiTextureType_AMBIENT, "AmbientColor"}, - {aiTextureType_EMISSIVE, "EmissiveColor"}, - {aiTextureType_HEIGHT, "Bump"}, - {aiTextureType_NORMALS, "NormalMap"}, - {aiTextureType_SHININESS, "ShininessExponent"}, - {aiTextureType_OPACITY, "TransparentColor"}, + {aiTextureType_DIFFUSE, "DiffuseColor"}, + {aiTextureType_SPECULAR, "SpecularColor"}, + {aiTextureType_AMBIENT, "AmbientColor"}, + {aiTextureType_EMISSIVE, "EmissiveColor"}, + {aiTextureType_HEIGHT, "Bump"}, + {aiTextureType_NORMALS, "NormalMap"}, + {aiTextureType_SHININESS, "ShininessExponent"}, + {aiTextureType_OPACITY, "TransparentColor"}, {aiTextureType_DISPLACEMENT, "DisplacementColor"}, //{aiTextureType_LIGHTMAP, "???"}, - {aiTextureType_REFLECTION, "ReflectionColor"} + {aiTextureType_REFLECTION, "ReflectionColor"} //{aiTextureType_UNKNOWN, ""} }; for (size_t i = 0; i < mScene->mNumMaterials; ++i) { @@ -1575,11 +1598,22 @@ void FBXExporter::WriteObjects () // one sticky point is that the number of vertices may not match, // because assimp splits vertices by normal, uv, etc. + // functor for aiNode sorting + struct SortNodeByName + { + bool operator()(const aiNode *lhs, const aiNode *rhs) const + { + return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0; + } + }; + // first we should mark the skeleton for each mesh. // the skeleton must include not only the aiBones, // but also all their parent nodes. // anything that affects the position of any bone node must be included. - std::vector> skeleton_by_mesh(mScene->mNumMeshes); + // Use SorNodeByName to make sure the exported result will be the same across all systems + // Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent + std::vector> skeleton_by_mesh(mScene->mNumMeshes); // at the same time we can build a list of all the skeleton nodes, // which will be used later to mark them as type "limbNode". std::unordered_set limbnodes; @@ -1587,7 +1621,7 @@ void FBXExporter::WriteObjects () std::map node_by_bone; for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { const aiMesh* m = mScene->mMeshes[mi]; - std::set skeleton; + std::set skeleton; for (size_t bi =0; bi < m->mNumBones; ++bi) { const aiBone* b = m->mBones[bi]; const std::string name(b->mName.C_Str()); @@ -1728,7 +1762,7 @@ void FBXExporter::WriteObjects () aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene); // now make a subdeformer for each bone in the skeleton - const std::set &skeleton = skeleton_by_mesh[mi]; + const std::set skeleton= skeleton_by_mesh[mi]; for (const aiNode* bone_node : skeleton) { // if there's a bone for this node, find it const aiBone* b = nullptr; diff --git a/code/FBXImportSettings.h b/code/FBXImportSettings.h index d5e1c2060..1a4c80f8b 100644 --- a/code/FBXImportSettings.h +++ b/code/FBXImportSettings.h @@ -53,19 +53,22 @@ namespace FBX { struct ImportSettings { ImportSettings() - : strictMode(true) - , readAllLayers(true) - , readAllMaterials(false) - , readMaterials(true) - , readTextures(true) - , readCameras(true) - , readLights(true) - , readAnimations(true) - , readWeights(true) - , preservePivots(true) - , optimizeEmptyAnimationCurves(true) - , useLegacyEmbeddedTextureNaming(false) - {} + : strictMode(true) + , readAllLayers(true) + , readAllMaterials(false) + , readMaterials(true) + , readTextures(true) + , readCameras(true) + , readLights(true) + , readAnimations(true) + , readWeights(true) + , preservePivots(true) + , optimizeEmptyAnimationCurves(true) + , useLegacyEmbeddedTextureNaming(false) + , removeEmptyBones( true ) + , convertToMeters( false ) { + // empty + } /** enable strict mode: @@ -141,8 +144,16 @@ struct ImportSettings bool optimizeEmptyAnimationCurves; /** use legacy naming for embedded textures eg: (*0, *1, *2) - **/ + */ bool useLegacyEmbeddedTextureNaming; + + /** Empty bones shall be removed + */ + bool removeEmptyBones; + + /** Set to true to perform a conversion from cm to meter after the import + */ + bool convertToMeters; }; diff --git a/code/FBXImporter.cpp b/code/FBXImporter.cpp index 2cc8bffc2..988735a77 100644 --- a/code/FBXImporter.cpp +++ b/code/FBXImporter.cpp @@ -140,6 +140,8 @@ void FBXImporter::SetupProperties(const Importer* pImp) 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.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false); + settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true); + settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false); } // ------------------------------------------------------------------------------------------------ @@ -183,8 +185,12 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS // take the raw parse-tree and convert it to a FBX DOM Document doc(parser,settings); + FbxUnit unit(FbxUnit::cm); + if (settings.convertToMeters) { + unit = FbxUnit::m; + } // convert the FBX DOM to aiScene - ConvertToAssimpScene(pScene,doc); + ConvertToAssimpScene(pScene,doc, settings.removeEmptyBones, unit); std::for_each(tokens.begin(),tokens.end(),Util::delete_fun()); } diff --git a/code/FBXMeshGeometry.cpp b/code/FBXMeshGeometry.cpp index 2debfa651..44a0264ca 100644 --- a/code/FBXMeshGeometry.cpp +++ b/code/FBXMeshGeometry.cpp @@ -568,15 +568,15 @@ void MeshGeometry::ReadVertexDataColors(std::vector& colors_out, cons } // ------------------------------------------------------------------------------------------------ -static const std::string TangentIndexToken = "TangentIndex"; -static const std::string TangentsIndexToken = "TangentsIndex"; +static const char *TangentIndexToken = "TangentIndex"; +static const char *TangentsIndexToken = "TangentsIndex"; void MeshGeometry::ReadVertexDataTangents(std::vector& tangents_out, const Scope& source, const std::string& MappingInformationType, const std::string& ReferenceInformationType) { const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent"; - const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken.c_str() : TangentIndexToken.c_str(); + const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken; ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType, str, strIdx, diff --git a/code/FBXParser.cpp b/code/FBXParser.cpp index b255c4734..fe63866a0 100644 --- a/code/FBXParser.cpp +++ b/code/FBXParser.cpp @@ -117,7 +117,7 @@ namespace FBX { Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) { - TokenPtr n = NULL; + TokenPtr n = nullptr; do { n = parser.AdvanceToNextToken(); if(!n) { diff --git a/code/FBXUtil.cpp b/code/FBXUtil.cpp index fb483161b..557d0d843 100644 --- a/code/FBXUtil.cpp +++ b/code/FBXUtil.cpp @@ -157,6 +157,66 @@ size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) return outLength; } +static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +char EncodeBase64(char byte) +{ + return to_base64_string[(size_t)byte]; +} + +/** Encodes a block of 4 bytes to base64 encoding +* +* @param bytes Bytes to encode. +* @param out_string String to write encoded values to. +* @param string_pos Position in out_string.*/ +void EncodeByteBlock(const char* bytes, std::string& out_string, size_t string_pos) +{ + char b0 = (bytes[0] & 0xFC) >> 2; + char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4); + char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6); + char b3 = (bytes[2] & 0x3F); + + out_string[string_pos + 0] = EncodeBase64(b0); + out_string[string_pos + 1] = EncodeBase64(b1); + out_string[string_pos + 2] = EncodeBase64(b2); + out_string[string_pos + 3] = EncodeBase64(b3); +} + +std::string EncodeBase64(const char* data, size_t length) +{ + // calculate extra bytes needed to get a multiple of 3 + size_t extraBytes = 3 - length % 3; + + // number of base64 bytes + size_t encodedBytes = 4 * (length + extraBytes) / 3; + + std::string encoded_string(encodedBytes, '='); + + // read blocks of 3 bytes + for (size_t ib3 = 0; ib3 < length / 3; ib3++) + { + const size_t iByte = ib3 * 3; + const size_t iEncodedByte = ib3 * 4; + const char* currData = &data[iByte]; + + EncodeByteBlock(currData, encoded_string, iEncodedByte); + } + + // if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed) + if (extraBytes > 0) + { + char finalBytes[4] = { 0,0,0,0 }; + memcpy(&finalBytes[0], &data[length - length % 3], length % 3); + + const size_t iEncodedByte = encodedBytes - 4; + EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte); + + // add '=' at the end + for (size_t i = 0; i < 4 * extraBytes / 3; i++) + encoded_string[encodedBytes - i - 1] = '='; + } + return encoded_string; +} + } // !Util } // !FBX } // !Assimp diff --git a/code/FBXUtil.h b/code/FBXUtil.h index 6890e015b..b26eba5d5 100644 --- a/code/FBXUtil.h +++ b/code/FBXUtil.h @@ -113,6 +113,15 @@ uint8_t DecodeBase64(char ch); * @return size of the decoded data (number of bytes)*/ size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); +char EncodeBase64(char byte); + +/** Encode bytes in base64-encoding +* +* @param data Binary data to encode. +* @param inLength Number of bytes to encode. +* @return base64-encoded string*/ +std::string EncodeBase64(const char* data, size_t length); + } } } diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index a8509b583..d1603c6f0 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -151,7 +151,7 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { } else if (*m_DataIt == 't') { // read in texture coordinate ( 2D or 3D ) ++m_DataIt; - size_t dim = getVector(m_pModel->m_TextureCoord); + size_t dim = getTexCoordVector(m_pModel->m_TextureCoord); m_pModel->m_TextureCoordDim = std::max(m_pModel->m_TextureCoordDim, (unsigned int)dim); } else if (*m_DataIt == 'n') { // Read in normal vector definition @@ -272,6 +272,17 @@ static bool isDataDefinitionEnd( const char *tmp ) { return false; } +static bool isNanOrInf(const char * in) { + // Look for "nan" or "inf", case insensitive + if ((in[0] == 'N' || in[0] == 'n') && ASSIMP_strincmp(in, "nan", 3) == 0) { + return true; + } + else if ((in[0] == 'I' || in[0] == 'i') && ASSIMP_strincmp(in, "inf", 3) == 0) { + return true; + } + return false; +} + size_t ObjFileParser::getNumComponentsInDataDefinition() { size_t numComponents( 0 ); const char* tmp( &m_DataIt[0] ); @@ -285,7 +296,7 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() { if ( !SkipSpaces( &tmp ) ) { break; } - const bool isNum( IsNumeric( *tmp ) ); + const bool isNum( IsNumeric( *tmp ) || isNanOrInf(tmp)); SkipToken( tmp ); if ( isNum ) { ++numComponents; @@ -297,7 +308,7 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() { return numComponents; } -size_t ObjFileParser::getVector( std::vector &point3d_array ) { +size_t ObjFileParser::getTexCoordVector( std::vector &point3d_array ) { size_t numComponents = getNumComponentsInDataDefinition(); ai_real x, y, z; if( 2 == numComponents ) { @@ -319,6 +330,17 @@ size_t ObjFileParser::getVector( std::vector &point3d_array ) { } else { throw DeadlyImportError( "OBJ: Invalid number of components" ); } + + // Coerce nan and inf to 0 as is the OBJ default value + if (!std::isfinite(x)) + x = 0; + + if (!std::isfinite(y)) + y = 0; + + if (!std::isfinite(z)) + z = 0; + point3d_array.push_back( aiVector3D( x, y, z ) ); m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); return numComponents; @@ -429,13 +451,6 @@ void ObjFileParser::getFace( aiPrimitiveType type ) { if (type == aiPrimitiveType_POINT) { ASSIMP_LOG_ERROR("Obj: Separator unexpected in point statement"); } - if (iPos == 0) { - //if there are no texture coordinates in the file, but normals - if (!vt && vn) { - iPos = 1; - iStep++; - } - } iPos++; } else if( IsSpaceOrNewLine( *m_DataIt ) ) { iPos = 0; @@ -452,6 +467,9 @@ void ObjFileParser::getFace( aiPrimitiveType type ) { ++iStep; } + if (iPos == 1 && !vt && vn) + iPos = 2; // skip texture coords for normals if there are no tex coords + if ( iVal > 0 ) { // Store parsed index if ( 0 == iPos ) { diff --git a/code/ObjFileParser.h b/code/ObjFileParser.h index a8961452d..7d1b806ce 100644 --- a/code/ObjFileParser.h +++ b/code/ObjFileParser.h @@ -96,7 +96,7 @@ protected: /// Get the number of components in a line. size_t getNumComponentsInDataDefinition(); /// Stores the vector - size_t getVector( std::vector &point3d_array ); + size_t getTexCoordVector( std::vector &point3d_array ); /// Stores the following 3d vector. void getVector3( std::vector &point3d_array ); /// Stores the following homogeneous vector as a 3D vector diff --git a/code/ValidateDataStructure.cpp b/code/ValidateDataStructure.cpp index 657b0361b..712fd6943 100644 --- a/code/ValidateDataStructure.cpp +++ b/code/ValidateDataStructure.cpp @@ -46,8 +46,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * the data structure returned by Assimp. */ - - // internal headers #include "ValidateDataStructure.h" #include @@ -110,8 +108,8 @@ void ValidateDSProcess::ReportWarning(const char* msg,...) } // ------------------------------------------------------------------------------------------------ -inline int HasNameMatch(const aiString& in, aiNode* node) -{ +inline +int HasNameMatch(const aiString& in, aiNode* node) { int result = (node->mName == in ? 1 : 0 ); for (unsigned int i = 0; i < node->mNumChildren;++i) { result += HasNameMatch(in,node->mChildren[i]); @@ -121,9 +119,8 @@ inline int HasNameMatch(const aiString& in, aiNode* node) // ------------------------------------------------------------------------------------------------ template -inline void ValidateDSProcess::DoValidation(T** parray, unsigned int size, - const char* firstName, const char* secondName) -{ +inline +void ValidateDSProcess::DoValidation(T** parray, unsigned int size, const char* firstName, const char* secondName) { // validate all entries if (size) { @@ -181,7 +178,8 @@ inline void ValidateDSProcess::DoValidationEx(T** parray, unsigned int size, // ------------------------------------------------------------------------------------------------ template inline -void ValidateDSProcess::DoValidationWithNameCheck(T** array, unsigned int size, const char* firstName, const char* secondName) { +void ValidateDSProcess::DoValidationWithNameCheck(T** array, unsigned int size, const char* firstName, + const char* secondName) { // validate all entries DoValidationEx(array,size,firstName,secondName); @@ -201,9 +199,8 @@ void ValidateDSProcess::DoValidationWithNameCheck(T** array, unsigned int size, // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void ValidateDSProcess::Execute( aiScene* pScene) -{ - this->mScene = pScene; +void ValidateDSProcess::Execute( aiScene* pScene) { + mScene = pScene; ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin"); // validate the node graph of the scene @@ -516,13 +513,11 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) } // ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiMesh* pMesh, - const aiBone* pBone,float* afSum) -{ +void ValidateDSProcess::Validate( const aiMesh* pMesh, const aiBone* pBone,float* afSum) { this->Validate(&pBone->mName); if (!pBone->mNumWeights) { - ReportError("aiBone::mNumWeights is zero"); + //ReportError("aiBone::mNumWeights is zero"); } // check whether all vertices affected by this bone are valid @@ -563,9 +558,6 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation) else { ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); } - - // Animation duration is allowed to be zero in cases where the anim contains only a single key frame. - // if (!pAnimation->mDuration)this->ReportError("aiAnimation::mDuration is zero"); } // ------------------------------------------------------------------------------------------------ @@ -746,8 +738,9 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial) "AI_MATKEY_SHININESS_STRENGTH key is 0.0"); } break; - default: ; - }; + default: + break; + } } if (AI_SUCCESS == aiGetMaterialFloat( pMaterial,AI_MATKEY_OPACITY,&fTemp) && (!fTemp || fTemp > 1.01)) { diff --git a/code/glTF2Importer.cpp b/code/glTF2Importer.cpp index 4228db23f..bb0f7ad8d 100755 --- a/code/glTF2Importer.cpp +++ b/code/glTF2Importer.cpp @@ -789,13 +789,16 @@ static void BuildVertexWeightMapping(Mesh::Primitive& primitive, std::vector& meshOffsets, glTF2::Ref& ptr) { Node& node = *ptr; - std::string nameOrId = node.name.empty() ? node.id : node.name; - - aiNode* ainode = new aiNode(nameOrId); + aiNode* ainode = new aiNode(GetNodeName(node)); if (!node.children.empty()) { ainode->mNumChildren = unsigned(node.children.size()); @@ -921,7 +924,7 @@ struct AnimationSamplers { aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers) { aiNodeAnim* anim = new aiNodeAnim(); - anim->mNodeName = node.name; + anim->mNodeName = GetNodeName(node); static const float kMillisecondsFromSeconds = 1000.f; diff --git a/code/makefile.mingw b/code/makefile.mingw deleted file mode 100644 index 711d57f57..000000000 --- a/code/makefile.mingw +++ /dev/null @@ -1,105 +0,0 @@ -### USE OF THIS MAKEFILE IS NOT RECOMMENDED. -### It is no longer maintained. Use CMAKE instead. - -# --------------------------------------------------------------------------- -# Makefile for Open Asset Import Library (MinGW32-make) -# aramis_acg@users.sourceforge.net -# - just a quick'n'dirty one, could be buggy ... -# -# Usage: mingw32-make -f makefile.mingw - -# TARGETS: -# all Build a shared so from the whole library -# clean Cleanup object files, prepare for rebuild -# static Build a static library (*.a) - -# MACROS: (make clean before you change one) -# NOBOOST=1 Build against boost workaround -# SINGLETHREADED=1 Build single-threaded library -# DEBUG=1 Build debug build of library -# -# --------------------------------------------------------------------------- - -# C++ object files -OBJECTS := $(patsubst %.cpp,%.o, $(wildcard *.cpp)) -OBJECTS += $(patsubst %.cpp,%.o, $(wildcard extra/*.cpp)) -OBJECTS += $(patsubst %.cpp,%.o, $(wildcard ./../contrib/irrXML/*.cpp)) - -# C object files -OBJECTSC := $(patsubst %.c,%.oc, $(wildcard ./../contrib/zlib/*.c)) -OBJECTSC += $(patsubst %.c,%.oc, $(wildcard ./../contrib/ConvertUTF/*.c)) -OBJECTSC += $(patsubst %.c,%.oc, $(wildcard ./../contrib/unzip/*.c)) - -# Include flags for gcc -INCLUDEFLAGS = - -# Preprocessor defines for gcc -DEFINEFLAGS = - -# Suffix for the output binary, represents build type -NAMESUFFIX = - -# Output path for binaries -BINPATH = ../bin/mingw/ - -# GCC compiler flags -CPPFLAGS=-Wall - -# Setup environment for noboost build -ifeq ($(NOBOOST),1) - SINGLETHREADED = 1 - INCLUDEFLAGS += -I./BoostWorkaround/ - DEFINEFLAGS += -DASSIMP_BUILD_BOOST_WORKAROUND -# NAMESUFFIX += -noboost -else - # adjust this manually if your boost is stored elsewhere - INCLUDEFLAGS += -I"C:/Program Files/boost/boost_1_38" - #INCLUDEFLAGS += -I"$(BOOST_DIR)" - -endif - -# Setup environment for st build -ifeq ($(SINGLETHREADED),1) - DEFINEFLAGS += -DASSIMP_BUILD_SINGLETHREADED -# NAMESUFFIX += -st -endif - -# Setup environment for debug build -ifeq ($(DEBUG),1) - DEFINEFLAGS += -D_DEBUG -DDEBUG - CPPFLAGS += -g -# NAMESUFFIX += -debug -else - CPPFLAGS += -O2 -s - DEFINEFLAGS += -DNDEBUG -D_NDEBUG -endif - -# Output name of shared library -SHARED_TARGET = $(BINPATH)/libassimp$(NAMESUFFIX).so - -# Output name of static library -STATIC = $(BINPATH)/libassimp$(NAMESUFFIX).a - -# target: all -# usage : build a shared library (*.so) -all: $(SHARED_TARGET) - -$(SHARED_TARGET): $(OBJECTS) $(OBJECTSC) - gcc -o $@ $(OBJECTS) $(OBJECTSC) -shared -lstdc++ -%.o:%.cpp - $(CXX) -c $(CPPFLAGS) $? -o $@ $(INCLUDEFLAGS) $(DEFINEFLAGS) -%.oc:%.c - $(CXX) -x c -c -ansi $(CPPFLAGS) $? -o $@ - -# target: clean -# usage : cleanup all object files, prepare for a rebuild -.PHONY: clean -clean: - -del *.o .\..\contrib\irrXML\*.o .\..\contrib\zlib\*.oc .\..\contrib\unzip\*.oc .\..\contrib\ConvertUTF\*.oc - -# target: static -# usage : build a static library (*.a) -static: $(STATIC) -$(STATIC): $(OBJECTS) $(OBJECTSC) - ar rcs $@ $(OBJECTS) $(OBJECTSC) - diff --git a/include/assimp/color4.inl b/include/assimp/color4.inl index 3192d55f3..afa53dcb5 100644 --- a/include/assimp/color4.inl +++ b/include/assimp/color4.inl @@ -85,6 +85,8 @@ AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { return g; case 2: return b; + case 3: + return a; default: break; } @@ -100,6 +102,8 @@ AI_FORCE_INLINE TReal& aiColor4t::operator[](unsigned int i) { return g; case 2: return b; + case 3: + return a; default: break; } diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index a37ff0b8c..c42aa63da 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -651,13 +651,28 @@ enum aiComponent // --------------------------------------------------------------------------- /** @brief Set whether the fbx importer will use the legacy embedded texture naming. -* -* The default value is false (0) -* Property type: bool -*/ + * + * The default value is false (0) + * Property type: bool + */ #define AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING \ "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" - + +// --------------------------------------------------------------------------- +/** @brief Set wether the importer shall not remove empty bones. + * + * Empty bone are often used to define connections for other models. + */ +#define AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES \ + "AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES" + + +// --------------------------------------------------------------------------- +/** @brief Set wether the FBX importer shall convert the unit from cm to m. + */ +#define AI_CONFIG_FBX_CONVERT_TO_M \ + "AI_CONFIG_FBX_CONVERT_TO_M" + // --------------------------------------------------------------------------- /** @brief Set the vertex animation keyframe to be imported * diff --git a/include/assimp/scene.h b/include/assimp/scene.h index de0239702..e973f6c5b 100644 --- a/include/assimp/scene.h +++ b/include/assimp/scene.h @@ -389,6 +389,14 @@ struct aiScene //! Returns an embedded texture const aiTexture* GetEmbeddedTexture(const char* filename) const { + // lookup using texture ID (if referenced like: "*1", "*2", etc.) + if ('*' == *filename) { + int index = std::atoi(filename + 1); + if (0 > index || mNumTextures <= static_cast(index)) + return nullptr; + return mTextures[index]; + } + // lookup using filename const char* shortFilename = GetShortFilename(filename); for (unsigned int i = 0; i < mNumTextures; i++) { const char* shortTextureFilename = GetShortFilename(mTextures[i]->mFilename.C_Str()); diff --git a/packaging/windows-innosetup/script.iss b/packaging/windows-innosetup/script.iss deleted file mode 100644 index 695740679..000000000 --- a/packaging/windows-innosetup/script.iss +++ /dev/null @@ -1,103 +0,0 @@ -; Setup script for use with Inno Setup. - -[Setup] -AppName=Open Asset Import Library - SDK -AppVerName=Open Asset Import Library - SDK (v4.1.0) -DefaultDirName={pf}\Assimp -DefaultGroupName=Assimp -UninstallDisplayIcon={app}\bin\x86\assimp.exe -OutputDir=out -AppCopyright=Assimp Development Team -SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico -WizardImageFile=compiler:WizModernImage-IS.BMP -WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP -LicenseFile=License.rtf -OutputBaseFileName=assimp-sdk-4.1.0-setup -VersionInfoVersion=4.1.0.0 -VersionInfoTextVersion=4.1.0 -VersionInfoCompany=Assimp Development Team -ArchitecturesInstallIn64BitMode=x64 - -[Types] -Name: "full"; Description: "Full installation" -Name: "compact"; Description: "Compact installation, no test models or language bindings" -Name: "custom"; Description: "Custom installation"; Flags: iscustom - -[Components] -Name: "main"; Description: "Main Files (32 and 64 Bit)"; Types: full compact custom; Flags: fixed -Name: "tools"; Description: "Asset Viewer & Command Line Tools (32 and 64 Bit)"; Types: full compact -Name: "help"; Description: "Help Files"; Types: full compact -Name: "samples"; Description: "Samples"; Types: full -Name: "test"; Description: "Test Models (BSD-licensed)"; Types: full -Name: "test_nonbsd"; Description: "Test Models (other (free) licenses)"; Types: full -;Name: "pyassimp"; Description: "Python Bindings"; Types: full -;Name: "dassimp"; Description: "D Bindings"; Types: full -;Name: "assimp_net"; Description: "C#/.NET Bindings"; Types: full - -[Run] -;Filename: "{app}\stub\vc_redist.x86.exe"; Parameters: "/qb"; StatusMsg: "Installing VS2017 redistributable package (32 Bit)"; Check: not IsWin64 -Filename: "{app}\stub\vc_redist.x64.exe"; Parameters: "/qb"; StatusMsg: "Installing VS2017 redistributable package (64 Bit)"; Check: IsWin64 - -[Files] -Source: "readme_installer.txt"; DestDir: "{app}"; Flags: isreadme - -; Installer stub -;Source: "vc_redist.x86.exe"; DestDir: "{app}\stub\"; Check: not IsWin64 -Source: "vc_redist.x64.exe"; DestDir: "{app}\stub\"; Check: IsWin64 - -; Common stuff -Source: "..\..\CREDITS"; DestDir: "{app}" -Source: "..\..\LICENSE"; DestDir: "{app}" -Source: "..\..\README"; DestDir: "{app}" -Source: "WEB"; DestDir: "{app}" - -Source: "..\..\scripts\*"; DestDir: "{app}\scripts"; Flags: recursesubdirs - -; x86 binaries -;Source: "..\..\bin\release\x86\assimp-vc140-mt.dll"; DestDir: "{app}\bin\x86" -;Source: "..\..\bin\release\x86\assimp_viewer.exe"; DestDir: "{app}\bin\x86"; Components: tools -;Source: "C:\Windows\SysWOW64\D3DCompiler_42.dll"; DestDir: "{app}\bin\x86"; Components: tools -;Source: "C:\Windows\SysWOW64\D3DX9_42.dll"; DestDir: "{app}\bin\x86"; Components: tools -;Source: "..\..\bin\release\x86\assimp.exe"; DestDir: "{app}\bin\x86"; Components: tools - -; x64 binaries -Source: "..\..\bin\release\assimp-vc140-mt.dll"; DestDir: "{app}\bin\x64" -Source: "..\..\bin\release\assimp_viewer.exe"; DestDir: "{app}\bin\x64"; Components: tools -Source: "C:\Windows\SysWOW64\D3DCompiler_42.dll"; DestDir: "{app}\bin\x64"; DestName: "D3DCompiler_42.dll"; Components: tools -Source: "C:\Windows\SysWOW64\D3DX9_42.dll"; DestDir: "{app}\bin\x64"; DestName: "D3DX9_42.dll"; Components: tools -Source: "..\..\bin\release\assimp.exe"; DestDir: "{app}\bin\x64"; Components: tools - -; Documentation -;Source: "..\..\doc\AssimpDoc_Html\AssimpDoc.chm"; DestDir: "{app}\doc"; Components: help -;Source: "..\..\doc\AssimpCmdDoc_Html\AssimpCmdDoc.chm"; DestDir: "{app}\doc"; Components: help -;Source: "..\..\doc\datastructure.xml"; DestDir: "{app}\doc"; Components: help - -; Import libraries -;Source: "..\..\lib\release\x86\assimp.lib"; DestDir: "{app}\lib\x86" -Source: "..\..\lib\release\assimp-vc140-mt.lib"; DestDir: "{app}\lib\x64" - -; Samples -Source: "..\..\samples\*"; DestDir: "{app}\samples"; Flags: recursesubdirs; Components: samples - -; Include files -Source: "..\..\include\*"; DestDir: "{app}\include"; Flags: recursesubdirs - -; dAssimp -;Source: "..\..\port\dAssimp\*"; DestDir: "{app}\port\D"; Flags: recursesubdirs; Components: dassimp - -; Assimp.NET -;Source: "..\..\port\Assimp.NET\*"; DestDir: "{app}\port\C#"; Flags: recursesubdirs; Components: assimp_net - -; PyAssimp -;Source: "..\..\port\PyAssimp\*"; DestDir: "{app}\port\Python"; Excludes: "*.pyc,*.dll"; Flags: recursesubdirs; Components: pyassimp - -; Test repository -;Source: "..\..\test\models\*"; DestDir: "{app}\test\models"; Flags: recursesubdirs; Components: test -;Source: "..\..\test\regression\*"; DestDir: "{app}\test\regression"; Flags: recursesubdirs; Components: test -;Source: "..\..\test\models-nonbsd\*"; DestDir: "{app}\test\models-nonbsd"; Flags: recursesubdirs; Components: test_nonbsd - -[Icons] -Name: "{group}\Assimp Manual"; Filename: "{app}\doc\AssimpDoc.chm" ; Components: help -Name: "{group}\Assimp Command Line Manual"; Filename: "{app}\doc\AssimpCmdDoc.chm"; Components: help -Name: "{group}\AssimpView"; Filename: "{app}\bin\x64\assimp_view.exe"; Components: tools; Check: IsWin64 -Name: "{group}\AssimpView"; Filename: "{app}\bin\x86\assimp_view.exe"; Components: tools; Check: not IsWin64 diff --git a/packaging/windows-innosetup/script_x64.iss b/packaging/windows-innosetup/script_x64.iss new file mode 100644 index 000000000..cd4837f0a --- /dev/null +++ b/packaging/windows-innosetup/script_x64.iss @@ -0,0 +1,71 @@ +; Setup script for use with Inno Setup. + +[Setup] +AppName=Open Asset Import Library - SDK +AppVerName=Open Asset Import Library - SDK (v4.1.0) +DefaultDirName={pf}\Assimp +DefaultGroupName=Assimp +UninstallDisplayIcon={app}\bin\x86\assimp.exe +OutputDir=out +AppCopyright=Assimp Development Team +SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico +WizardImageFile=compiler:WizModernImage-IS.BMP +WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP +LicenseFile=License.rtf +OutputBaseFileName=assimp-sdk-4.1.0-setup +VersionInfoVersion=4.1.0.0 +VersionInfoTextVersion=4.1.0 +VersionInfoCompany=Assimp Development Team +ArchitecturesInstallIn64BitMode=x64 + +[Types] +Name: "full"; Description: "Full installation" +Name: "compact"; Description: "Compact installation, no test models or language bindings" +Name: "custom"; Description: "Custom installation"; Flags: iscustom + +[Components] +Name: "main"; Description: "Main Files ( 64 Bit )"; Types: full compact custom; Flags: fixed +Name: "tools"; Description: "Asset Viewer & Command Line Tools (32 and 64 Bit)"; Types: full compact +Name: "help"; Description: "Help Files"; Types: full compact +Name: "samples"; Description: "Samples"; Types: full +Name: "test"; Description: "Test Models (BSD-licensed)"; Types: full +Name: "test_nonbsd"; Description: "Test Models (other (free) licenses)"; Types: full + +[Run] +Filename: "{app}\stub\vc_redist.x64.exe"; Parameters: "/qb"; StatusMsg: "Installing VS2017 redistributable package (64 Bit)"; Check: IsWin64 + +[Files] +Source: "readme_installer.txt"; DestDir: "{app}"; Flags: isreadme + +; Installer stub +Source: "vc_redist.x64.exe"; DestDir: "{app}\stub\"; Check: IsWin64 + +; Common stuff +Source: "..\..\CREDITS"; DestDir: "{app}" +Source: "..\..\LICENSE"; DestDir: "{app}" +Source: "..\..\README"; DestDir: "{app}" +Source: "WEB"; DestDir: "{app}" + +Source: "..\..\scripts\*"; DestDir: "{app}\scripts"; Flags: recursesubdirs + +; x64 binaries +Source: "..\..\bin\release\assimp-vc141-mt.dll"; DestDir: "{app}\bin\x64" +Source: "..\..\bin\release\assimp_viewer.exe"; DestDir: "{app}\bin\x64"; Components: tools +Source: "C:\Windows\SysWOW64\D3DCompiler_42.dll"; DestDir: "{app}\bin\x64"; DestName: "D3DCompiler_42.dll"; Components: tools +Source: "C:\Windows\SysWOW64\D3DX9_42.dll"; DestDir: "{app}\bin\x64"; DestName: "D3DX9_42.dll"; Components: tools +Source: "..\..\bin\release\assimp.exe"; DestDir: "{app}\bin\x64"; Components: tools + +; Import libraries +Source: "..\..\lib\release\assimp-vc141-mt.lib"; DestDir: "{app}\lib\x64" + +; Samples +Source: "..\..\samples\*"; DestDir: "{app}\samples"; Flags: recursesubdirs; Components: samples + +; Include files +Source: "..\..\include\*"; DestDir: "{app}\include"; Flags: recursesubdirs + +[Icons] +; Name: "{group}\Assimp Manual"; Filename: "{app}\doc\AssimpDoc.chm" ; Components: help +; Name: "{group}\Assimp Command Line Manual"; Filename: "{app}\doc\AssimpCmdDoc.chm"; Components: help +; Name: "{group}\AssimpView"; Filename: "{app}\bin\x64\assimp_view.exe"; Components: tools; Check: IsWin64 +; Name: "{group}\AssimpView"; Filename: "{app}\bin\x86\assimp_view.exe"; Components: tools; Check: not IsWin64 diff --git a/packaging/windows-innosetup/script_x86.iss b/packaging/windows-innosetup/script_x86.iss new file mode 100644 index 000000000..9aca78550 --- /dev/null +++ b/packaging/windows-innosetup/script_x86.iss @@ -0,0 +1,72 @@ +; Setup script for use with Inno Setup. + +[Setup] +AppName=Open Asset Import Library - SDK +AppVerName=Open Asset Import Library - SDK (v4.1.0) +DefaultDirName={pf}\Assimp +DefaultGroupName=Assimp +UninstallDisplayIcon={app}\bin\x86\assimp.exe +OutputDir=out +AppCopyright=Assimp Development Team +SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico +WizardImageFile=compiler:WizModernImage-IS.BMP +WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP +LicenseFile=License.rtf +OutputBaseFileName=assimp-sdk-4.1.0-setup +VersionInfoVersion=4.1.0.0 +VersionInfoTextVersion=4.1.0 +VersionInfoCompany=Assimp Development Team +ArchitecturesInstallIn64BitMode=x64 + +[Types] +Name: "full"; Description: "Full installation" +Name: "compact"; Description: "Compact installation, no test models or language bindings" +Name: "custom"; Description: "Custom installation"; Flags: iscustom + +[Components] +Name: "main"; Description: "Main Files (32 and 64 Bit)"; Types: full compact custom; Flags: fixed +Name: "tools"; Description: "Asset Viewer & Command Line Tools (32 and 64 Bit)"; Types: full compact +Name: "help"; Description: "Help Files"; Types: full compact +Name: "samples"; Description: "Samples"; Types: full +Name: "test"; Description: "Test Models (BSD-licensed)"; Types: full +Name: "test_nonbsd"; Description: "Test Models (other (free) licenses)"; Types: full + +[Run] +Filename: "{app}\stub\vc_redist.x86.exe"; Parameters: "/qb"; StatusMsg: "Installing VS2017 redistributable package (32 Bit)"; Check: not IsWin64 + +[Files] +Source: "readme_installer.txt"; DestDir: "{app}"; Flags: isreadme + +; Installer stub +Source: "vc_redist.x86.exe"; DestDir: "{app}\stub\"; Check: not IsWin64 + +; Common stuff +Source: "..\..\CREDITS"; DestDir: "{app}" +Source: "..\..\LICENSE"; DestDir: "{app}" +Source: "..\..\README"; DestDir: "{app}" +Source: "WEB"; DestDir: "{app}" + +Source: "..\..\scripts\*"; DestDir: "{app}\scripts"; Flags: recursesubdirs + +; x86 binaries +Source: "..\..\bin\release\assimp-vc141-mt.dll"; DestDir: "{app}\bin\x86" +Source: "..\..\bin\release\assimp_viewer.exe"; DestDir: "{app}\bin\x86"; Components: tools +Source: "C:\Windows\SysWOW64\D3DCompiler_42.dll"; DestDir: "{app}\bin\x86"; Components: tools +Source: "C:\Windows\SysWOW64\D3DX9_42.dll"; DestDir: "{app}\bin\x86"; Components: tools +Source: "..\..\bin\release\assimp.exe"; DestDir: "{app}\bin\x86"; Components: tools + + +; Import libraries +Source: "..\..\lib\release\assimp-vc141-mt.lib"; DestDir: "{app}\lib\x86" + +; Samples +Source: "..\..\samples\*"; DestDir: "{app}\samples"; Flags: recursesubdirs; Components: samples + +; Include files +Source: "..\..\include\*"; DestDir: "{app}\include"; Flags: recursesubdirs + +[Icons] +; Name: "{group}\Assimp Manual"; Filename: "{app}\doc\AssimpDoc.chm" ; Components: help +; Name: "{group}\Assimp Command Line Manual"; Filename: "{app}\doc\AssimpCmdDoc.chm"; Components: help +; Name: "{group}\AssimpView"; Filename: "{app}\bin\x64\assimp_view.exe"; Components: tools; Check: IsWin64 +; Name: "{group}\AssimpView"; Filename: "{app}\bin\x86\assimp_view.exe"; Components: tools; Check: not IsWin64 diff --git a/port/AndroidJNI/README.md b/port/AndroidJNI/README.md index 7998fa3ef..0b95efd04 100644 --- a/port/AndroidJNI/README.md +++ b/port/AndroidJNI/README.md @@ -1,6 +1,6 @@ Build Asset Importer Lib for Android ==================================== -This module provides a fascade for the io-stream-access to files behind the android-asset-management within +This module provides a facade for the io-stream-access to files behind the android-asset-management within an Android-native application. - It is built as a static library - It requires Android NDK with android API > 9 support. diff --git a/port/PyAssimp/pyassimp/core.py b/port/PyAssimp/pyassimp/core.py index ca6d8629a..44163a434 100644 --- a/port/PyAssimp/pyassimp/core.py +++ b/port/PyAssimp/pyassimp/core.py @@ -93,7 +93,7 @@ def _is_init_type(obj): return False tname = obj.__class__.__name__ return not (tname[:2] == 'c_' or tname == 'Structure' \ - or tname == 'POINTER') and not isinstance(obj,int) + or tname == 'POINTER') and not isinstance(obj, (int, str, bytes)) def _init(self, target = None, parent = None): """ diff --git a/test/unit/utObjImportExport.cpp b/test/unit/utObjImportExport.cpp index 2d1933094..bb0d36b13 100644 --- a/test/unit/utObjImportExport.cpp +++ b/test/unit/utObjImportExport.cpp @@ -391,6 +391,39 @@ TEST_F(utObjImportExport, invalid_normals_uvs) { EXPECT_NE(nullptr, scene); } +TEST_F(utObjImportExport, no_vt_just_vns) { + static const char *ObjModel = + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 10 0 0\n" + "v 0 10 0\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "f 10/10 11/11 12/12\n"; + + Assimp::Importer myImporter; + const aiScene *scene = myImporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), 0); + EXPECT_NE(nullptr, scene); +} + TEST_F( utObjImportExport, mtllib_after_g ) { ::Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/cube_mtllib_after_g.obj", aiProcess_ValidateDataStructure );