diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index b23f4520f..483ee8fc1 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -46,7 +46,7 @@ jobs: CC: clang - name: configure and build - uses: lukka/run-cmake@v2 + uses: lukka/run-cmake@v3 with: cmakeListsOrSettingsJson: CMakeListsTxtAdvanced cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' diff --git a/CMakeLists.txt b/CMakeLists.txt index 224f6e48f..dfaa2b791 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -286,9 +286,9 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW) ELSEIF(MSVC) # enable multi-core compilation with MSVC IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl - ADD_COMPILE_OPTIONS(/bigobj /W4 /WX ) + ADD_COMPILE_OPTIONS(/bigobj) ELSE() # msvc - ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX) + ADD_COMPILE_OPTIONS(/MP /bigobj) ENDIF() # disable "elements of array '' will be default initialized" warning on MSVC2013 diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index 51ec79583..032089906 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -93,6 +93,8 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo mSceneOut(out), doc(doc), mRemoveEmptyBones(removeEmptyBones) { + + // 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. @@ -427,12 +429,26 @@ void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f); out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f); - out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); + // NOTE: Some software (maya) does not put FieldOfView in FBX, so we compute + // mHorizontalFOV from FocalLength and FilmWidth with unit conversion. - out_camera->mClipPlaneNear = cam.NearPlane(); - out_camera->mClipPlaneFar = cam.FarPlane(); + // TODO: This is not a complete solution for how FBX cameras can be stored. + // TODO: Incorporate non-square pixel aspect ratio. + // TODO: FBX aperture mode might be storing vertical FOV in need of conversion with aspect ratio. + + float fov_deg = cam.FieldOfView(); + // If FOV not specified in file, compute using FilmWidth and FocalLength. + if (fov_deg == kFovUnknown) { + float film_width_inches = cam.FilmWidth(); + float focal_length_mm = cam.FocalLength(); + ASSIMP_LOG_VERBOSE_DEBUG("FBX FOV unspecified. Computing from FilmWidth (", film_width_inches, "inches) and FocalLength (", focal_length_mm, "mm)."); + double half_fov_rad = std::atan2(film_width_inches * 25.4 * 0.5, focal_length_mm); + out_camera->mHorizontalFOV = half_fov_rad; + } else { + // FBX fov is full-view degrees. We want half-view radians. + out_camera->mHorizontalFOV = AI_DEG_TO_RAD(fov_deg) * 0.5; + } - out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); out_camera->mClipPlaneNear = cam.NearPlane(); out_camera->mClipPlaneFar = cam.FarPlane(); } diff --git a/code/AssetLib/FBX/FBXDocument.h b/code/AssetLib/FBX/FBXDocument.h index e229eef52..3af757a19 100644 --- a/code/AssetLib/FBX/FBXDocument.h +++ b/code/AssetLib/FBX/FBXDocument.h @@ -55,9 +55,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _AI_CONCAT(a,b) a ## b #define AI_CONCAT(a,b) _AI_CONCAT(a,b) + namespace Assimp { namespace FBX { +// Use an 'illegal' default FOV value to detect if the FBX camera has set the FOV. +static const float kFovUnknown = -1.0f; + + class Parser; class Object; struct ImportSettings; @@ -247,7 +252,7 @@ public: fbx_simple_property(FilmAspectRatio, float, 1.0f) fbx_simple_property(ApertureMode, int, 0) - fbx_simple_property(FieldOfView, float, 1.0f) + fbx_simple_property(FieldOfView, float, kFovUnknown) fbx_simple_property(FocalLength, float, 1.0f) }; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 227f3878c..53ffdaf31 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -45,6 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include +#include // clang-format off #ifdef ASSIMP_ENABLE_DRACO diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index f7fa9cd42..d4568fa31 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -730,7 +730,7 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) { // Specular requires either/or, default factors of zero disables specular, so do not export - if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS || mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) { + if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS && mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) { return false; } // The spec states that the default is 1.0 and [1.0, 1.0, 1.0]. We if both are 0, which should disable specular. Otherwise, if one is 0, set to 1.0 diff --git a/code/Common/BaseImporter.cpp b/code/Common/BaseImporter.cpp index 87b385268..d2ff4a9dd 100644 --- a/code/Common/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -59,6 +59,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +namespace { +// Checks whether the passed string is a gcs version. +bool IsGcsVersion(const std::string &s) { + if (s.empty()) return false; + return std::all_of(s.cbegin(), s.cend(), [](const char c) { + // gcs only permits numeric characters. + return std::isdigit(static_cast(c)); + }); +} + +// Removes a possible version hash from a filename, as found for example in +// gcs uris (e.g. `gs://bucket/model.glb#1234`), see also +// https://github.com/GoogleCloudPlatform/gsutil/blob/c80f329bc3c4011236c78ce8910988773b2606cb/gslib/storage_url.py#L39. +std::string StripVersionHash(const std::string &filename) { + const std::string::size_type pos = filename.find_last_of('#'); + // Only strip if the hash is behind a possible file extension and the part + // behind the hash is a version string. + if (pos != std::string::npos && pos > filename.find_last_of('.') && + IsGcsVersion(filename.substr(pos + 1))) { + return filename.substr(0, pos); + } + return filename; +} +} // namespace + using namespace Assimp; // ------------------------------------------------------------------------------------------------ @@ -158,7 +183,7 @@ void BaseImporter::GetExtensionList(std::set &extensions) { std::size_t numTokens, unsigned int searchBytes /* = 200 */, bool tokensSol /* false */, - bool noAlphaBeforeTokens /* false */) { + bool noGraphBeforeTokens /* false */) { ai_assert(nullptr != tokens); ai_assert(0 != numTokens); ai_assert(0 != searchBytes); @@ -207,8 +232,9 @@ void BaseImporter::GetExtensionList(std::set &extensions) { continue; } // We need to make sure that we didn't accidentally identify the end of another token as our token, - // e.g. in a previous version the "gltf " present in some gltf files was detected as "f " - if (noAlphaBeforeTokens && (r != buffer && isalpha(static_cast(r[-1])))) { + // e.g. in a previous version the "gltf " present in some gltf files was detected as "f ", or a + // Blender-exported glb file containing "Khronos glTF Blender I/O " was detected as "o " + if (noGraphBeforeTokens && (r != buffer && isgraph(static_cast(r[-1])))) { continue; } // We got a match, either we don't care where it is, or it happens to @@ -229,33 +255,38 @@ void BaseImporter::GetExtensionList(std::set &extensions) { const char *ext0, const char *ext1, const char *ext2) { - std::string::size_type pos = pFile.find_last_of('.'); - - // no file extension - can't read - if (pos == std::string::npos) { - return false; + std::set extensions; + for (const char* ext : {ext0, ext1, ext2}) { + if (ext == nullptr) continue; + extensions.emplace(ext); } + return HasExtension(pFile, extensions); +} - const char *ext_real = &pFile[pos + 1]; - if (!ASSIMP_stricmp(ext_real, ext0)) { - return true; +// ------------------------------------------------------------------------------------------------ +// Check for file extension +/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set &extensions) { + const std::string file = StripVersionHash(pFile); + // CAUTION: Do not just search for the extension! + // GetExtension() returns the part after the *last* dot, but some extensions + // have dots inside them, e.g. ogre.mesh.xml. Compare the entire end of the + // string. + for (const std::string& ext : extensions) { + // Yay for C++<20 not having std::string::ends_with() + const std::string dotExt = "." + ext; + if (dotExt.length() > file.length()) continue; + // Possible optimization: Fetch the lowercase filename! + if (0 == ASSIMP_stricmp(file.c_str() + file.length() - dotExt.length(), dotExt.c_str())) { + return true; + } } - - // check for other, optional, file extensions - if (ext1 && !ASSIMP_stricmp(ext_real, ext1)) { - return true; - } - - if (ext2 && !ASSIMP_stricmp(ext_real, ext2)) { - return true; - } - return false; } // ------------------------------------------------------------------------------------------------ // Get file extension from path -std::string BaseImporter::GetExtension(const std::string &file) { +std::string BaseImporter::GetExtension(const std::string &pFile) { + const std::string file = StripVersionHash(pFile); std::string::size_type pos = file.find_last_of('.'); // no file extension at all diff --git a/code/Common/Importer.cpp b/code/Common/Importer.cpp index b66059397..bdf64ac8f 100644 --- a/code/Common/Importer.cpp +++ b/code/Common/Importer.cpp @@ -637,24 +637,10 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) { std::set extensions; pimpl->mImporter[a]->GetExtensionList(extensions); - // CAUTION: Do not just search for the extension! - // GetExtension() returns the part after the *last* dot, but some extensions have dots - // inside them, e.g. ogre.mesh.xml. Compare the entire end of the string. - for (std::set::const_iterator it = extensions.cbegin(); it != extensions.cend(); ++it) { - - // Yay for C++<20 not having std::string::ends_with() - std::string extension = "." + *it; - if (extension.length() <= pFile.length()) { - // Possible optimization: Fetch the lowercase filename! - if (0 == ASSIMP_stricmp(pFile.c_str() + pFile.length() - extension.length(), extension.c_str())) { - ImporterAndIndex candidate = { pimpl->mImporter[a], a }; - possibleImporters.push_back(candidate); - break; - } - } - + if (BaseImporter::HasExtension(pFile, extensions)) { + ImporterAndIndex candidate = { pimpl->mImporter[a], a }; + possibleImporters.push_back(candidate); } - } // If just one importer supports this extension, pick it and close the case. diff --git a/include/assimp/BaseImporter.h b/include/assimp/BaseImporter.h index 5a3c764d4..d0b173171 100644 --- a/include/assimp/BaseImporter.h +++ b/include/assimp/BaseImporter.h @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -258,7 +259,7 @@ public: // static utilities std::size_t numTokens, unsigned int searchBytes = 200, bool tokensSol = false, - bool noAlphaBeforeTokens = false); + bool noGraphBeforeTokens = false); // ------------------------------------------------------------------- /** @brief Check whether a file has a specific file extension @@ -274,6 +275,16 @@ public: // static utilities const char *ext1 = nullptr, const char *ext2 = nullptr); + // ------------------------------------------------------------------- + /** @brief Check whether a file has one of the passed file extensions + * @param pFile Input file + * @param extensions Extensions to check for. Lowercase characters only, no dot! + * @note Case-insensitive + */ + static bool HasExtension( + const std::string &pFile, + const std::set &extensions); + // ------------------------------------------------------------------- /** @brief Extract file extension from a string * @param pFile Input file diff --git a/port/swig/DONOTUSEYET b/port/swig/DONOTUSEYET deleted file mode 100644 index 87c6e0699..000000000 --- a/port/swig/DONOTUSEYET +++ /dev/null @@ -1 +0,0 @@ -The interface files are by no means complete yet and only work with the not-yet-released D SWIG backend, although adding support for other languages should not be too much of problem via #ifdefs. diff --git a/port/swig/assimp.i b/port/swig/assimp.i deleted file mode 100644 index 58e1546e7..000000000 --- a/port/swig/assimp.i +++ /dev/null @@ -1,140 +0,0 @@ -%module assimp - -// SWIG helpers for std::string and std::vector wrapping. -%include -%include - -// Globally enable enum prefix stripping. -%dstripprefix; - - -// PACK_STRUCT is a no-op for SWIG – it does not matter for the generated -// bindings how the underlying C++ code manages its memory. -#define PACK_STRUCT - - -// Helper macros for wrapping the pointer-and-length arrays used in the -// Assimp API. - -%define ASSIMP_ARRAY(CLASS, TYPE, NAME, LENGTH) -%newobject CLASS::NAME; -%extend CLASS { - std::vector *NAME() const { - std::vector *result = new std::vector; - result->reserve(LENGTH); - - for (unsigned int i = 0; i < LENGTH; ++i) { - result->push_back($self->NAME[i]); - } - - return result; - } -} -%ignore CLASS::NAME; -%enddef - -%define ASSIMP_POINTER_ARRAY(CLASS, TYPE, NAME, LENGTH) -%newobject CLASS::NAME; -%extend CLASS { - std::vector *NAME() const { - std::vector *result = new std::vector; - result->reserve(LENGTH); - - TYPE *currentValue = $self->NAME; - TYPE *valueLimit = $self->NAME + LENGTH; - while (currentValue < valueLimit) { - result->push_back(currentValue); - ++currentValue; - } - - return result; - } -} -%ignore CLASS::NAME; -%enddef - -%define ASSIMP_POINTER_ARRAY_ARRAY(CLASS, TYPE, NAME, OUTER_LENGTH, INNER_LENGTH) -%newobject CLASS::NAME; -%extend CLASS { - std::vector > *NAME() const { - std::vector > *result = new std::vector >; - result->reserve(OUTER_LENGTH); - - for (unsigned int i = 0; i < OUTER_LENGTH; ++i) { - std::vector currentElements; - - if ($self->NAME[i] != 0) { - currentElements.reserve(INNER_LENGTH); - - TYPE *currentValue = $self->NAME[i]; - TYPE *valueLimit = $self->NAME[i] + INNER_LENGTH; - while (currentValue < valueLimit) { - currentElements.push_back(currentValue); - ++currentValue; - } - } - - result->push_back(currentElements); - } - - return result; - } -} -%ignore CLASS::NAME; -%enddef - - -%include "interface/aiDefines.i" -%include "interface/aiTypes.i" -%include "interface/assimp.i" -%include "interface/aiTexture.i" -%include "interface/aiMatrix4x4.i" -%include "interface/aiMatrix3x3.i" -%include "interface/aiVector3D.i" -%include "interface/aiVector2D.i" -%include "interface/aiColor4D.i" -%include "interface/aiLight.i" -%include "interface/aiCamera.i" -%include "interface/aiFileIO.i" -%include "interface/aiAssert.i" -%include "interface/aiVersion.i" -%include "interface/aiAnim.i" -%include "interface/aiMaterial.i" -%include "interface/aiMesh.i" -%include "interface/aiPostProcess.i" -%include "interface/aiConfig.i" -%include "interface/assimp.i" -%include "interface/aiQuaternion.i" -%include "interface/aiScene.i" -%include "interface/Logger.i" -%include "interface/DefaultLogger.i" -%include "interface/NullLogger.i" -%include "interface/LogStream.i" -%include "interface/IOStream.i" -%include "interface/IOSystem.i" - - -// We have to "instantiate" the templates used by the ASSSIMP_*_ARRAY macros -// here at the end to avoid running into forward reference issues (SWIG would -// spit out the helper functions before the header includes for the element -// types otherwise). - -%template(UintVector) std::vector; -%template(aiAnimationVector) std::vector; -%template(aiAnimMeshVector) std::vector; -%template(aiBonesVector) std::vector; -%template(aiCameraVector) std::vector; -%template(aiColor4DVector) std::vector; -%template(aiColor4DVectorVector) std::vector >; -%template(aiFaceVector) std::vector; -%template(aiLightVector) std::vector; -%template(aiMaterialVector) std::vector; -%template(aiMaterialPropertyVector) std::vector; -%template(aiMeshAnimVector) std::vector; -%template(aiMeshVector) std::vector; -%template(aiNodeVector) std::vector; -%template(aiNodeAnimVector) std::vector; -%template(aiTextureVector) std::vector; -%template(aiVector3DVector) std::vector; -%template(aiVector3DVectorVector) std::vector >; -%template(aiVertexWeightVector) std::vector; diff --git a/port/swig/d/build.sh b/port/swig/d/build.sh deleted file mode 100755 index 0bf6bff6a..000000000 --- a/port/swig/d/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -gcc -shared -fPIC -g3 -I../../../include/ -lassimp -olibassimp_wrap.so assimp_wrap.cxx diff --git a/port/swig/d/generate.sh b/port/swig/d/generate.sh deleted file mode 100755 index 7de66b1ff..000000000 --- a/port/swig/d/generate.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -rm -rf assimp/ -mkdir assimp -swig -c++ -d -outcurrentdir -I../../../include -splitproxy -package assimp $@ ../assimp.i diff --git a/port/swig/interface/DefaultLogger.i b/port/swig/interface/DefaultLogger.i deleted file mode 100644 index 600d28e84..000000000 --- a/port/swig/interface/DefaultLogger.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "DefaultLogger.h" -%} - -%include "DefaultLogger.h" diff --git a/port/swig/interface/IOStream.i b/port/swig/interface/IOStream.i deleted file mode 100644 index baca5ef45..000000000 --- a/port/swig/interface/IOStream.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "IOStream.h" -%} - -%include "IOStream.h" diff --git a/port/swig/interface/IOSystem.i b/port/swig/interface/IOSystem.i deleted file mode 100644 index 3e3e04a67..000000000 --- a/port/swig/interface/IOSystem.i +++ /dev/null @@ -1,11 +0,0 @@ -%{ -#include "IOSystem.h" -%} - -// The const char* overload is used instead. -%ignore Assimp::IOSystem::Exists(const std::string&) const; -%ignore Assimp::IOSystem::Open(const std::string& pFile); -%ignore Assimp::IOSystem::Open(const std::string& pFile, const std::string& pMode); -%ignore Assimp::IOSystem::ComparePaths(const std::string& one, const std::string& second) const; - -%include "IOSystem.h" diff --git a/port/swig/interface/LogStream.i b/port/swig/interface/LogStream.i deleted file mode 100644 index 022f8e586..000000000 --- a/port/swig/interface/LogStream.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "LogStream.h" -%} - -%include "LogStream.h" diff --git a/port/swig/interface/Logger.i b/port/swig/interface/Logger.i deleted file mode 100644 index cadc50b8e..000000000 --- a/port/swig/interface/Logger.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "Logger.h" -%} - -%include "Logger.h" diff --git a/port/swig/interface/NullLogger.i b/port/swig/interface/NullLogger.i deleted file mode 100644 index 5cf42edf5..000000000 --- a/port/swig/interface/NullLogger.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "NullLogger.h" -%} - -%include "NullLogger.h" diff --git a/port/swig/interface/aiAnim.i b/port/swig/interface/aiAnim.i deleted file mode 100644 index de497008f..000000000 --- a/port/swig/interface/aiAnim.i +++ /dev/null @@ -1,8 +0,0 @@ -%{ -#include "aiAnim.h" -%} - -ASSIMP_ARRAY(aiAnimation, aiNodeAnim*, mChannels, $self->mNumChannels); -ASSIMP_ARRAY(aiAnimation, aiMeshAnim*, mMeshChannels, $self->mNumMeshChannels); - -%include "aiAnim.h" diff --git a/port/swig/interface/aiAssert.i b/port/swig/interface/aiAssert.i deleted file mode 100644 index bc8a9b88c..000000000 --- a/port/swig/interface/aiAssert.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiAssert.h" -%} - -%include "aiAssert.h" diff --git a/port/swig/interface/aiCamera.i b/port/swig/interface/aiCamera.i deleted file mode 100644 index 5c2124501..000000000 --- a/port/swig/interface/aiCamera.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiCamera.h" -%} - -%include "aiCamera.h" diff --git a/port/swig/interface/aiColor4D.i b/port/swig/interface/aiColor4D.i deleted file mode 100644 index 3c009168b..000000000 --- a/port/swig/interface/aiColor4D.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiColor4D.h" -%} - -%include "aiColor4D.h" diff --git a/port/swig/interface/aiConfig.i b/port/swig/interface/aiConfig.i deleted file mode 100644 index 110abb3d6..000000000 --- a/port/swig/interface/aiConfig.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiConfig.h" -%} - -%include "aiConfig.h" diff --git a/port/swig/interface/aiDefines.i b/port/swig/interface/aiDefines.i deleted file mode 100644 index 3a61ea62f..000000000 --- a/port/swig/interface/aiDefines.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiDefines.h" -%} - -%include "aiDefines.h" diff --git a/port/swig/interface/aiFileIO.i b/port/swig/interface/aiFileIO.i deleted file mode 100644 index 5a1e0923e..000000000 --- a/port/swig/interface/aiFileIO.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiFileIO.h" -%} - -%include "aiFileIO.h" diff --git a/port/swig/interface/aiLight.i b/port/swig/interface/aiLight.i deleted file mode 100644 index fbefde7c0..000000000 --- a/port/swig/interface/aiLight.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiLight.h" -%} - -%include "aiLight.h" diff --git a/port/swig/interface/aiMaterial.i b/port/swig/interface/aiMaterial.i deleted file mode 100644 index 630e6b711..000000000 --- a/port/swig/interface/aiMaterial.i +++ /dev/null @@ -1,33 +0,0 @@ -%{ -#include "aiMaterial.h" -%} - -ASSIMP_ARRAY(aiMaterial, aiMaterialProperty*, mProperties, $self->mNumProperties) - -%include -%apply enum SWIGTYPE *OUTPUT { aiTextureMapping* mapping }; -%apply unsigned int *OUTPUT { unsigned int* uvindex }; -%apply float *OUTPUT { float* blend }; -%apply enum SWIGTYPE *OUTPUT { aiTextureOp* op }; -%apply unsigned int *OUTPUT { unsigned int* flags }; - -%include "aiMaterial.h" - -%clear unsigned int* flags; -%clear aiTextureOp* op; -%clear float *blend; -%clear unsigned int* uvindex; -%clear aiTextureMapping* mapping; - - -%apply int &OUTPUT { int &pOut }; -%apply float &OUTPUT { float &pOut }; - -%template(GetInteger) aiMaterial::Get; -%template(GetFloat) aiMaterial::Get; -%template(GetColor4D) aiMaterial::Get; -%template(GetColor3D) aiMaterial::Get; -%template(GetString) aiMaterial::Get; - -%clear int &pOut; -%clear float &pOut; diff --git a/port/swig/interface/aiMatrix3x3.i b/port/swig/interface/aiMatrix3x3.i deleted file mode 100644 index 8336d447a..000000000 --- a/port/swig/interface/aiMatrix3x3.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiMatrix3x3.h" -%} - -%include "aiMatrix3x3.h" diff --git a/port/swig/interface/aiMatrix4x4.i b/port/swig/interface/aiMatrix4x4.i deleted file mode 100644 index 976c56b03..000000000 --- a/port/swig/interface/aiMatrix4x4.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiMatrix4x4.h" -%} - -%include "aiMatrix4x4.h" diff --git a/port/swig/interface/aiMesh.i b/port/swig/interface/aiMesh.i deleted file mode 100644 index 141366c2e..000000000 --- a/port/swig/interface/aiMesh.i +++ /dev/null @@ -1,29 +0,0 @@ -%{ -#include "aiMesh.h" -%} - - -ASSIMP_ARRAY(aiFace, unsigned int, mIndices, $self->mNumIndices); - -ASSIMP_POINTER_ARRAY(aiBone, aiVertexWeight, mWeights, $self->mNumWeights); - -ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mVertices, $self->mNumVertices); -ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mNormals, $self->mNumVertices); -ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mTangents, $self->mNumVertices); -ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mBitangents, $self->mNumVertices); -ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices); -ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices); - -ASSIMP_ARRAY(aiMesh, aiAnimMesh*, mAnimMeshes, $self->mNumAnimMeshes); -ASSIMP_ARRAY(aiMesh, aiBone*, mBones, $self->mNumBones); -ASSIMP_ARRAY(aiMesh, unsigned int, mNumUVComponents, AI_MAX_NUMBER_OF_TEXTURECOORDS); -ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mVertices, $self->mNumVertices); -ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mNormals, $self->mNumVertices); -ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mTangents, $self->mNumVertices); -ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mBitangents, $self->mNumVertices); -ASSIMP_POINTER_ARRAY(aiMesh, aiFace, mFaces, $self->mNumFaces); -ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices); -ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices); - - -%include "aiMesh.h" diff --git a/port/swig/interface/aiPostProcess.i b/port/swig/interface/aiPostProcess.i deleted file mode 100644 index 5f64ec53a..000000000 --- a/port/swig/interface/aiPostProcess.i +++ /dev/null @@ -1,7 +0,0 @@ -%{ -#include "aiPostProcess.h" -%} - -%feature("d:stripprefix", "aiProcess_") aiPostProcessSteps; - -%include "aiPostProcess.h" diff --git a/port/swig/interface/aiQuaternion.i b/port/swig/interface/aiQuaternion.i deleted file mode 100644 index 256057a22..000000000 --- a/port/swig/interface/aiQuaternion.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiQuaternion.h" -%} - -%include "aiQuaternion.h" diff --git a/port/swig/interface/aiScene.i b/port/swig/interface/aiScene.i deleted file mode 100644 index 7278f3368..000000000 --- a/port/swig/interface/aiScene.i +++ /dev/null @@ -1,17 +0,0 @@ -%{ -#include "aiScene.h" -%} - - -ASSIMP_ARRAY(aiScene, aiAnimation*, mAnimations, $self->mNumAnimations); -ASSIMP_ARRAY(aiScene, aiCamera*, mCameras, $self->mNumCameras); -ASSIMP_ARRAY(aiScene, aiLight*, mLights, $self->mNumLights); -ASSIMP_ARRAY(aiScene, aiMaterial*, mMaterials, $self->mNumMaterials); -ASSIMP_ARRAY(aiScene, aiMesh*, mMeshes, $self->mNumMeshes); -ASSIMP_ARRAY(aiScene, aiTexture*, mTextures, $self->mNumTextures); - -ASSIMP_ARRAY(aiNode, aiNode*, mChildren, $self->mNumChildren); -ASSIMP_ARRAY(aiNode, unsigned int, mMeshes, $self->mNumMeshes); - - -%include "aiScene.h" diff --git a/port/swig/interface/aiTexture.i b/port/swig/interface/aiTexture.i deleted file mode 100644 index d07d00190..000000000 --- a/port/swig/interface/aiTexture.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiTexture.h" -%} - -%include "aiTexture.h" diff --git a/port/swig/interface/aiTypes.i b/port/swig/interface/aiTypes.i deleted file mode 100644 index a086dfd30..000000000 --- a/port/swig/interface/aiTypes.i +++ /dev/null @@ -1,8 +0,0 @@ -%{ -#include "aiTypes.h" -%} - -// The const char* overload is used instead. -%ignore aiString::Set(const std::string& pString); - -%include "aiTypes.h" diff --git a/port/swig/interface/aiVector2D.i b/port/swig/interface/aiVector2D.i deleted file mode 100644 index 5db15c0e6..000000000 --- a/port/swig/interface/aiVector2D.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiVector2D.h" -%} - -%include "aiVector2D.h" diff --git a/port/swig/interface/aiVector3D.i b/port/swig/interface/aiVector3D.i deleted file mode 100644 index 2c83f605f..000000000 --- a/port/swig/interface/aiVector3D.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiVector3D.h" -%} - -%include "aiVector3D.h" diff --git a/port/swig/interface/aiVersion.i b/port/swig/interface/aiVersion.i deleted file mode 100644 index 9ddd532ef..000000000 --- a/port/swig/interface/aiVersion.i +++ /dev/null @@ -1,5 +0,0 @@ -%{ -#include "aiVersion.h" -%} - -%include "aiVersion.h" diff --git a/port/swig/interface/assimp.i b/port/swig/interface/assimp.i deleted file mode 100644 index a1b1404a0..000000000 --- a/port/swig/interface/assimp.i +++ /dev/null @@ -1,45 +0,0 @@ -%{ -#include "assimp.hpp" -%} - - -namespace Assimp { - -// See docs in assimp.hpp. -%ignore Importer::ReadFile(const std::string& pFile, unsigned int pFlags); -%ignore Importer::GetExtensionList(std::string& szOut); -%ignore Importer::IsExtensionSupported(const std::string& szExtension); - -// These are only necessary for extending Assimp with custom importers or post -// processing steps, which would require wrapping the internal BaseImporter and -// BaseProcess classes. -%ignore Importer::RegisterLoader(BaseImporter* pImp); -%ignore Importer::UnregisterLoader(BaseImporter* pImp); -%ignore Importer::RegisterPPStep(BaseProcess* pImp); -%ignore Importer::UnregisterPPStep(BaseProcess* pImp); -%ignore Importer::FindLoader(const char* szExtension); - -} - - -// Each aiScene has to keep a reference to the Importer to prevent it from -// being garbage collected, whose destructor would release the underlying -// C++ memory the scene is stored in. -%typemap(dcode) aiScene "package Object m_importer;" -%typemap(dout) - aiScene* GetScene, - aiScene* ReadFile, - aiScene* ApplyPostProcessing, - aiScene* ReadFileFromMemory { - void* cPtr = $wcall; - $dclassname ret = (cPtr is null) ? null : new $dclassname(cPtr, $owner);$excode - ret.m_importer = this; - return ret; -} - -%include -%apply bool *OUTPUT { bool *bWasExisting }; - -%include "assimp.hpp" - -%clear bool *bWasExisting; diff --git a/test/models/IRR/scenegraphAnimMod.irr b/test/models/IRR/scenegraphAnimMod.irr new file mode 100644 index 000000000..21408b245 --- /dev/null +++ b/test/models/IRR/scenegraphAnimMod.irr @@ -0,0 +1,554 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/models/IRR/scenegraphAnimMod_UTF16LE.irr b/test/models/IRR/scenegraphAnimMod_UTF16LE.irr new file mode 100644 index 000000000..7384ae29a Binary files /dev/null and b/test/models/IRR/scenegraphAnimMod_UTF16LE.irr differ diff --git a/test/models/IRR/scenegraphAnim_UTF16LE.irr b/test/models/IRR/scenegraphAnim_UTF16LE.irr index b22aaf4b7..f6794351f 100644 Binary files a/test/models/IRR/scenegraphAnim_UTF16LE.irr and b/test/models/IRR/scenegraphAnim_UTF16LE.irr differ diff --git a/test/unit/utImporter.cpp b/test/unit/utImporter.cpp index 98080c526..5ecc45e34 100644 --- a/test/unit/utImporter.cpp +++ b/test/unit/utImporter.cpp @@ -361,3 +361,37 @@ TEST_F(ImporterTest, unexpectedException) { EXPECT_TRUE(false); } } + +// ------------------------------------------------------------------------------------------------ + +struct ExtensionTestCase { + std::string testName; + std::string filename; + std::string getExtensionResult; + std::string hasExtension; + bool hasExtensionResult; +}; + +using ExtensionTest = ::testing::TestWithParam; + +TEST_P(ExtensionTest, testGetAndHasExtension) { + const ExtensionTestCase& testCase = GetParam(); + EXPECT_EQ(testCase.getExtensionResult, BaseImporter::GetExtension(testCase.filename)); + EXPECT_EQ(testCase.hasExtensionResult, BaseImporter::HasExtension(testCase.filename, {testCase.hasExtension})); +} + +INSTANTIATE_TEST_SUITE_P( + ExtensionTests, ExtensionTest, + ::testing::ValuesIn({ + {"NoExtension", "name", "", "glb", false}, + {"NoExtensionAndEmptyVersion", "name#", "", "glb", false}, + {"WithExtensionAndEmptyVersion", "name.glb#", "glb#", "glb", false}, + {"WithExtensionAndVersion", "name.glb#1234", "glb", "glb", true}, + {"WithExtensionAndHashInStem", "name#1234.glb", "glb", "glb", true}, + {"WithExtensionAndInvalidVersion", "name.glb#_", "glb#_", "glb", false}, + {"WithExtensionAndDotAndHashInStem", "name.glb#.abc", "abc", "glb", false}, + {"WithTwoExtensions", "name.abc.def", "def", "abc.def", true}, + }), + [](const ::testing::TestParamInfo& info) { + return info.param.testName; + }); diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 91ac87ee5..ba1c859ad 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -60,7 +60,7 @@ using namespace Assimp; class utglTF2ImportExport : public AbstractImportExportBase { public: - virtual bool importerMatTest(const char *file, bool spec_gloss, std::array exp_modes = { aiTextureMapMode_Wrap, aiTextureMapMode_Wrap }) { + virtual bool importerMatTest(const char *file, bool spec, bool gloss, std::array exp_modes = { aiTextureMapMode_Wrap, aiTextureMapMode_Wrap }) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure); EXPECT_NE(scene, nullptr); @@ -105,16 +105,19 @@ public: aiColor3D spec_color = { 0, 0, 0 }; ai_real glossiness = ai_real(0.5); - if (spec_gloss) { + if (spec) { EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color)); constexpr ai_real spec_val(0.20000000298023225); // From the file EXPECT_EQ(spec_val, spec_color.r); EXPECT_EQ(spec_val, spec_color.g); EXPECT_EQ(spec_val, spec_color.b); + } else { + EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color)); + } + if (gloss) { EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness)); EXPECT_EQ(ai_real(1.0), glossiness); } else { - EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color)); EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness)); } @@ -143,7 +146,7 @@ public: }; TEST_F(utglTF2ImportExport, importglTF2FromFileTest) { - EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", false, {aiTextureMapMode_Mirror, aiTextureMapMode_Clamp})); + EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", false, false, {aiTextureMapMode_Mirror, aiTextureMapMode_Clamp})); } TEST_F(utglTF2ImportExport, importBinaryglTF2FromFileTest) { @@ -151,7 +154,7 @@ TEST_F(utglTF2ImportExport, importBinaryglTF2FromFileTest) { } TEST_F(utglTF2ImportExport, importglTF2_KHR_materials_pbrSpecularGlossiness) { - EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf", true)); + EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf", true, true)); } void VerifyClearCoatScene(const aiScene *scene) { @@ -223,13 +226,16 @@ TEST_F(utglTF2ImportExport, importglTF2AndExport_KHR_materials_pbrSpecularGlossi // Export with specular glossiness disabled EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb")); + // And re-import + EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true, false)); + // Export with specular glossiness enabled ExportProperties props; props.SetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS, true); EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", 0, &props)); // And re-import - EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true)); + EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true, true)); } TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) {