diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 15f7643ce..60bfba170 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: configure run: cmake CMakeLists.txt - name: build @@ -23,7 +23,7 @@ jobs: runs-on: macos-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: configure run: cmake CMakeLists.txt - name: build @@ -35,7 +35,7 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: configure run: cmake CMakeLists.txt - name: build diff --git a/assimpTargets-debug.cmake.in b/assimpTargets-debug.cmake.in index 2488c1f57..de6459eaf 100644 --- a/assimpTargets-debug.cmake.in +++ b/assimpTargets-debug.cmake.in @@ -7,6 +7,8 @@ set(CMAKE_IMPORT_FILE_VERSION 1) set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) +get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) + if(MSVC) if(MSVC_TOOLSET_VERSION) set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") @@ -35,8 +37,6 @@ if(MSVC) endif() set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" ) - file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX) - if(ASSIMP_BUILD_SHARED_LIBS) set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@") set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@") @@ -89,9 +89,6 @@ else() endif() endif() - - - # Commands beyond this point should not need to know the version. set(CMAKE_IMPORT_FILE_VERSION) diff --git a/assimpTargets-release.cmake.in b/assimpTargets-release.cmake.in index a4555e326..6a5bafcf7 100644 --- a/assimpTargets-release.cmake.in +++ b/assimpTargets-release.cmake.in @@ -7,6 +7,8 @@ set(CMAKE_IMPORT_FILE_VERSION 1) set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) +get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) + if(MSVC) if(MSVC_TOOLSET_VERSION) set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") @@ -34,8 +36,6 @@ if(MSVC) endif() endif() set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" ) - - file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX) if(ASSIMP_BUILD_SHARED_LIBS) set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@") @@ -56,7 +56,7 @@ if(MSVC) # Import target "assimp::assimp" for configuration "Release" set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(assimp::assimp PROPERTIES - IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}" + IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" ) list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}") diff --git a/code/3MF/D3MFExporter.cpp b/code/3MF/D3MFExporter.cpp index 092b947e9..83036b236 100644 --- a/code/3MF/D3MFExporter.cpp +++ b/code/3MF/D3MFExporter.cpp @@ -181,7 +181,7 @@ bool D3MFExporter::export3DModel() { writeHeader(); mModelOutput << "<" << XmlTag::model << " " << XmlTag::model_unit << "=\"millimeter\"" - << "xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">" + << " xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">" << std::endl; mModelOutput << "<" << XmlTag::resources << ">"; mModelOutput << std::endl; @@ -212,7 +212,7 @@ bool D3MFExporter::export3DModel() { } void D3MFExporter::writeHeader() { - mModelOutput << ""; + mModelOutput << ""; mModelOutput << std::endl; } @@ -254,16 +254,28 @@ void D3MFExporter::writeBaseMaterials() { if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) { hexDiffuseColor.clear(); tmp.clear(); - hexDiffuseColor = "#"; - - tmp = DecimalToHexa( (ai_real) color.r ); - hexDiffuseColor += tmp; - tmp = DecimalToHexa((ai_real)color.g); - hexDiffuseColor += tmp; - tmp = DecimalToHexa((ai_real)color.b); - hexDiffuseColor += tmp; - tmp = DecimalToHexa((ai_real)color.a); - hexDiffuseColor += tmp; + // rgbs % + if(color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1){ + + hexDiffuseColor = Rgba2Hex( + (int)((ai_real)color.r)*255, + (int)((ai_real)color.g)*255, + (int)((ai_real)color.b)*255, + (int)((ai_real)color.a)*255, + true + ); + + }else{ + hexDiffuseColor = "#"; + tmp = DecimalToHexa( (ai_real) color.r ); + hexDiffuseColor += tmp; + tmp = DecimalToHexa((ai_real)color.g); + hexDiffuseColor += tmp; + tmp = DecimalToHexa((ai_real)color.b); + hexDiffuseColor += tmp; + tmp = DecimalToHexa((ai_real)color.a); + hexDiffuseColor += tmp; + } } else { hexDiffuseColor = "#FFFFFFFF"; } @@ -284,7 +296,7 @@ void D3MFExporter::writeObjects() { if ( nullptr == currentNode ) { continue; } - mModelOutput << "<" << XmlTag::object << " id=\"" << currentNode->mName.C_Str() << "\" type=\"model\">"; + mModelOutput << "<" << XmlTag::object << " id=\"" << i + 2 << "\" type=\"model\">"; mModelOutput << std::endl; for ( unsigned int j = 0; j < currentNode->mNumMeshes; ++j ) { aiMesh *currentMesh = mScene->mMeshes[ currentNode->mMeshes[ j ] ]; @@ -348,7 +360,7 @@ void D3MFExporter::writeBuild() { mModelOutput << "<" << XmlTag::build << ">" << std::endl; for ( size_t i = 0; i < mBuildItems.size(); ++i ) { - mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 1 << "\"/>"; + mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>"; mModelOutput << std::endl; } mModelOutput << ""; diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index c872e7b20..49583c0c8 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -121,6 +121,7 @@ SET( PUBLIC_HEADERS ${HEADER_PATH}/GenericProperty.h ${HEADER_PATH}/SpatialSort.h ${HEADER_PATH}/SkeletonMeshBuilder.h + ${HEADER_PATH}/SmallVector.h ${HEADER_PATH}/SmoothingGroups.h ${HEADER_PATH}/SmoothingGroups.inl ${HEADER_PATH}/StandardShapes.h diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index 66bb921d7..c34457be5 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -83,32 +83,61 @@ namespace Assimp { void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out); // ------------------------------------------------------------------------------------------------ -// Exporter worker function prototypes. Should not be necessary to #ifndef them, it's just a prototype -// do not use const, because some exporter need to convert the scene temporary +// Exporter worker function prototypes. Do not use const, because some exporter need to convert +// the scene temporary +#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER void ExportSceneCollada(const char*,IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_X_EXPORTER void ExportSceneXFile(const char*,IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER void ExportSceneStep(const char*,IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER void ExportSceneObj(const char*,IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneObjNoMtl(const char*,IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_STL_EXPORTER void ExportSceneSTL(const char*,IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*); void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneGLTF2(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneGLB2(const char*, IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); +#endif +#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneM3DA(const char*, IOSystem*, const aiScene*, const ExportProperties*); +#endif +#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); - +#endif static void setupExporterArray(std::vector &exporters) { #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER diff --git a/code/PostProcessing/LimitBoneWeightsProcess.cpp b/code/PostProcessing/LimitBoneWeightsProcess.cpp index 1f1abfabb..5b8934159 100644 --- a/code/PostProcessing/LimitBoneWeightsProcess.cpp +++ b/code/PostProcessing/LimitBoneWeightsProcess.cpp @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "LimitBoneWeightsProcess.h" +#include #include #include #include @@ -52,7 +53,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; - // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer LimitBoneWeightsProcess::LimitBoneWeightsProcess() @@ -76,10 +76,12 @@ bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void LimitBoneWeightsProcess::Execute( aiScene* pScene) { +void LimitBoneWeightsProcess::Execute( aiScene* pScene) +{ ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin"); - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a ) { - ProcessMesh(pScene->mMeshes[a]); + + for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) { + ProcessMesh(pScene->mMeshes[m]); } ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end"); @@ -95,107 +97,96 @@ void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) // ------------------------------------------------------------------------------------------------ // Unites identical vertices in the given mesh -void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh) +void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) { - if( !pMesh->HasBones()) + if (!pMesh->HasBones()) return; // collect all bone weights per vertex - typedef std::vector< std::vector< Weight > > WeightsPerVertex; - WeightsPerVertex vertexWeights( pMesh->mNumVertices); + typedef SmallVector VertexWeightArray; + typedef std::vector WeightsPerVertex; + WeightsPerVertex vertexWeights(pMesh->mNumVertices); + size_t maxVertexWeights = 0; - // collect all weights per vertex - for( unsigned int a = 0; a < pMesh->mNumBones; a++) + for (unsigned int b = 0; b < pMesh->mNumBones; ++b) { - const aiBone* bone = pMesh->mBones[a]; - for( unsigned int b = 0; b < bone->mNumWeights; b++) + const aiBone* bone = pMesh->mBones[b]; + for (unsigned int w = 0; w < bone->mNumWeights; ++w) { - const aiVertexWeight& w = bone->mWeights[b]; - vertexWeights[w.mVertexId].push_back( Weight( a, w.mWeight)); + const aiVertexWeight& vw = bone->mWeights[w]; + vertexWeights[vw.mVertexId].push_back(Weight(b, vw.mWeight)); + maxVertexWeights = std::max(maxVertexWeights, vertexWeights[vw.mVertexId].size()); } } + if (maxVertexWeights <= mMaxWeights) + return; + unsigned int removed = 0, old_bones = pMesh->mNumBones; // now cut the weight count if it exceeds the maximum - bool bChanged = false; - for( WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) + for (WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) { - if( vit->size() <= mMaxWeights) + if (vit->size() <= mMaxWeights) continue; - bChanged = true; - // more than the defined maximum -> first sort by weight in descending order. That's // why we defined the < operator in such a weird way. - std::sort( vit->begin(), vit->end()); + std::sort(vit->begin(), vit->end()); // now kill everything beyond the maximum count unsigned int m = static_cast(vit->size()); - vit->erase( vit->begin() + mMaxWeights, vit->end()); - removed += static_cast(m-vit->size()); + vit->resize(mMaxWeights); + removed += static_cast(m - vit->size()); // and renormalize the weights float sum = 0.0f; - for( std::vector::const_iterator it = vit->begin(); it != vit->end(); ++it ) { + for(const Weight* it = vit->begin(); it != vit->end(); ++it) { sum += it->mWeight; } - if( 0.0f != sum ) { + if (0.0f != sum) { const float invSum = 1.0f / sum; - for( std::vector::iterator it = vit->begin(); it != vit->end(); ++it ) { + for(Weight* it = vit->begin(); it != vit->end(); ++it) { it->mWeight *= invSum; } } } - if (bChanged) { - // rebuild the vertex weight array for all bones - typedef std::vector< std::vector< aiVertexWeight > > WeightsPerBone; - WeightsPerBone boneWeights( pMesh->mNumBones); - for( unsigned int a = 0; a < vertexWeights.size(); a++) + // clear weight count for all bone + for (unsigned int a = 0; a < pMesh->mNumBones; ++a) + { + pMesh->mBones[a]->mNumWeights = 0; + } + + // rebuild the vertex weight array for all bones + for (unsigned int a = 0; a < vertexWeights.size(); ++a) + { + const VertexWeightArray& vw = vertexWeights[a]; + for (const Weight* it = vw.begin(); it != vw.end(); ++it) { - const std::vector& vw = vertexWeights[a]; - for( std::vector::const_iterator it = vw.begin(); it != vw.end(); ++it) - boneWeights[it->mBone].push_back( aiVertexWeight( a, it->mWeight)); - } - - // and finally copy the vertex weight list over to the mesh's bones - std::vector abNoNeed(pMesh->mNumBones,false); - bChanged = false; - - for( unsigned int a = 0; a < pMesh->mNumBones; a++) - { - const std::vector& bw = boneWeights[a]; - aiBone* bone = pMesh->mBones[a]; - - if ( bw.empty() ) - { - abNoNeed[a] = bChanged = true; - continue; - } - - // copy the weight list. should always be less weights than before, so we don't need a new allocation - ai_assert( bw.size() <= bone->mNumWeights); - bone->mNumWeights = static_cast( bw.size() ); - ::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight)); - } - - if (bChanged) { - // the number of new bones is smaller than before, so we can reuse the old array - aiBone** ppcCur = pMesh->mBones;aiBone** ppcSrc = ppcCur; - - for (std::vector::const_iterator iter = abNoNeed.begin();iter != abNoNeed.end() ;++iter) { - if (*iter) { - delete *ppcSrc; - --pMesh->mNumBones; - } - else *ppcCur++ = *ppcSrc; - ++ppcSrc; - } - } - - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones ); + aiBone* bone = pMesh->mBones[it->mBone]; + bone->mWeights[bone->mNumWeights++] = aiVertexWeight(a, it->mWeight); } } + + // remove empty bones + unsigned int writeBone = 0; + + for (unsigned int readBone = 0; readBone< pMesh->mNumBones; ++readBone) + { + aiBone* bone = pMesh->mBones[readBone]; + if (bone->mNumWeights > 0) + { + pMesh->mBones[writeBone++] = bone; + } + else + { + delete bone; + } + } + pMesh->mNumBones = writeBone; + + if (!DefaultLogger::isNullLogger()) { + ASSIMP_LOG_INFO_F("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones); + } } diff --git a/code/glTF2/glTF2Asset.h b/code/glTF2/glTF2Asset.h index c27522df3..a78d6b53a 100644 --- a/code/glTF2/glTF2Asset.h +++ b/code/glTF2/glTF2Asset.h @@ -58,6 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include @@ -81,14 +82,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP #else #define gltf_unordered_map map +#define gltf_unordered_set set #endif #ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP #include +#include #if _MSC_VER > 1600 #define gltf_unordered_map unordered_map +#define gltf_unordered_set unordered_set #else #define gltf_unordered_map tr1::unordered_map +#define gltf_unordered_set tr1::unordered_set #endif #endif @@ -375,8 +380,8 @@ struct Accessor : public Object { inline uint8_t *GetPointer(); - template - bool ExtractData(T *&outData); + template + void ExtractData(T *&outData); void WriteData(size_t count, const void *src_buffer, size_t src_stride); @@ -720,6 +725,7 @@ struct Mesh : public Object { std::vector primitives; std::vector weights; + std::vector targetNames; Mesh() {} @@ -874,6 +880,8 @@ class LazyDict : public LazyDictBase { Value *mDict; //! JSON dictionary object Asset &mAsset; //! The asset instance + std::gltf_unordered_set mRecursiveReferenceCheck; //! Used by Retrieve to prevent recursive lookups + void AttachToDocument(Document &doc); void DetachFromDocument(); diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index a41e62e5c..ed23b388a 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -280,6 +280,11 @@ Ref LazyDict::Retrieve(unsigned int i) { throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object"); } + if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) { + throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" has recursive reference to itself"); + } + mRecursiveReferenceCheck.insert(i); + // Unique ptr prevents memory leak in case of Read throws an exception auto inst = std::unique_ptr(new T()); inst->id = std::string(mDictId) + "_" + to_string(i); @@ -287,7 +292,9 @@ Ref LazyDict::Retrieve(unsigned int i) { ReadMember(obj, "name", inst->name); inst->Read(obj, mAsset); - return Add(inst.release()); + Ref result = Add(inst.release()); + mRecursiveReferenceCheck.erase(i); + return result; } template @@ -613,10 +620,13 @@ inline void CopyData(size_t count, } } // namespace -template -bool Accessor::ExtractData(T *&outData) { - uint8_t *data = GetPointer(); - if (!data) return false; +template +void Accessor::ExtractData(T *&outData) +{ + uint8_t* data = GetPointer(); + if (!data) { + throw DeadlyImportError("GLTF: data is NULL"); + } const size_t elemSize = GetElementSize(); const size_t totalSize = elemSize * count; @@ -636,8 +646,6 @@ bool Accessor::ExtractData(T *&outData) { memcpy(outData + i, data + i * stride, elemSize); } } - - return true; } inline void Accessor::WriteData(size_t _count, const void *src_buffer, size_t src_stride) { @@ -1026,6 +1034,19 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) { } } } + + Value *extras = FindObject(pJSON_Object, "extras"); + if (nullptr != extras ) { + if (Value* curTargetNames = FindArray(*extras, "targetNames")) { + this->targetNames.resize(curTargetNames->Size()); + for (unsigned int i = 0; i < curTargetNames->Size(); ++i) { + Value& targetNameValue = (*curTargetNames)[i]; + if (targetNameValue.IsString()) { + this->targetNames[i] = targetNameValue.GetString(); + } + } + } + } } inline void Camera::Read(Value &obj, Asset & /*r*/) { diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index caff630dc..87f170e31 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -472,6 +472,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { if (mesh.weights.size() > i) { aiAnimMesh.mWeight = mesh.weights[i]; } + if (mesh.targetNames.size() > i) { + aiAnimMesh.mName = mesh.targetNames[i]; + } } } diff --git a/include/assimp/MathFunctions.h b/include/assimp/MathFunctions.h index 1880ce0a9..d4bc54451 100644 --- a/include/assimp/MathFunctions.h +++ b/include/assimp/MathFunctions.h @@ -55,36 +55,51 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace Math { -// TODO: use binary GCD for unsigned integers .... -template < typename IntegerType > -inline -IntegerType gcd( IntegerType a, IntegerType b ) { +/// @brief Will return the greatest common divisor. +/// @param a [in] Value a. +/// @param b [in] Value b. +/// @return The greatest common divisor. +template +inline IntegerType gcd( IntegerType a, IntegerType b ) { const IntegerType zero = (IntegerType)0; while ( true ) { - if ( a == zero ) + if ( a == zero ) { return b; + } b %= a; - if ( b == zero ) + if ( b == zero ) { return a; + } a %= b; } } +/// @brief Will return the greatest common divisor. +/// @param a [in] Value a. +/// @param b [in] Value b. +/// @return The greatest common divisor. template < typename IntegerType > -inline -IntegerType lcm( IntegerType a, IntegerType b ) { +inline IntegerType lcm( IntegerType a, IntegerType b ) { const IntegerType t = gcd (a,b); - if (!t) + if (!t) { return t; + } return a / t * b; } - +/// @brief Will return the smallest epsilon-value for the requested type. +/// @return The numercical limit epsilon depending on its type. template -inline -T getEpsilon() { +inline T getEpsilon() { return std::numeric_limits::epsilon(); } +/// @brief Will return the constant PI for the requested type. +/// @return Pi +template +inline T PI() { + return static_cast(3.14159265358979323846); } -} + +} // namespace Math +} // namespace Assimp diff --git a/include/assimp/SmallVector.h b/include/assimp/SmallVector.h new file mode 100644 index 000000000..4e0c200e2 --- /dev/null +++ b/include/assimp/SmallVector.h @@ -0,0 +1,164 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file Defines small vector with inplace storage. +Based on CppCon 2016: Chandler Carruth "High Performance Code 201: Hybrid Data Structures" */ + +#pragma once +#ifndef AI_SMALLVECTOR_H_INC +#define AI_SMALLVECTOR_H_INC + +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +namespace Assimp { + +// -------------------------------------------------------------------------------------------- +/// @brief Small vector with inplace storage. +/// +/// Reduces heap allocations when list is shorter. It uses a small array for a dedicated size. +/// When the growing gets bigger than this small cache a dynamic growing algorithm will be +/// used. +// -------------------------------------------------------------------------------------------- +template +class SmallVector { +public: + /// @brief The default class constructor. + SmallVector() : + mStorage(mInplaceStorage), + mSize(0), + mCapacity(Capacity) { + // empty + } + + /// @brief The class destructor. + ~SmallVector() { + if (mStorage != mInplaceStorage) { + delete [] mStorage; + } + } + + /// @brief Will push a new item. The capacity will grow in case of a too small capacity. + /// @param item [in] The item to push at the end of the vector. + void push_back(const T& item) { + if (mSize < mCapacity) { + mStorage[mSize++] = item; + return; + } + + push_back_and_grow(item); + } + + /// @brief Will resize the vector. + /// @param newSize [in] The new size. + void resize(size_t newSize) { + if (newSize > mCapacity) { + grow(newSize); + } + mSize = newSize; + } + + /// @brief Returns the current size of the vector. + /// @return The current size. + size_t size() const { + return mSize; + } + + /// @brief Returns a pointer to the first item. + /// @return The first item as a pointer. + T* begin() { + return mStorage; + } + + /// @brief Returns a pointer to the end. + /// @return The end as a pointer. + T* end() { + return &mStorage[mSize]; + } + + /// @brief Returns a const pointer to the first item. + /// @return The first item as a const pointer. + T* begin() const { + return mStorage; + } + + /// @brief Returns a const pointer to the end. + /// @return The end as a const pointer. + T* end() const { + return &mStorage[mSize]; + } + + SmallVector(const SmallVector &) = delete; + SmallVector(SmallVector &&) = delete; + SmallVector &operator = (const SmallVector &) = delete; + SmallVector &operator = (SmallVector &&) = delete; + +private: + void grow( size_t newCapacity) { + T* oldStorage = mStorage; + T* newStorage = new T[newCapacity]; + + std::memcpy(newStorage, oldStorage, mSize * sizeof(T)); + + mStorage = newStorage; + mCapacity = newCapacity; + + if (oldStorage != mInplaceStorage) { + delete [] oldStorage; + } + } + + void push_back_and_grow(const T& item) { + grow(mCapacity + Capacity); + + mStorage[mSize++] = item; + } + + T* mStorage; + size_t mSize; + size_t mCapacity; + T mInplaceStorage[Capacity]; +}; + +} // end namespace Assimp + +#endif // !! AI_SMALLVECTOR_H_INC diff --git a/include/assimp/StringUtils.h b/include/assimp/StringUtils.h index 894eada60..7e1cb4ce0 100644 --- a/include/assimp/StringUtils.h +++ b/include/assimp/StringUtils.h @@ -145,4 +145,21 @@ std::string DecimalToHexa( T toConvert ) { return result; } +/// @brief translate RGBA to String +/// @param r aiColor.r +/// @param g aiColor.g +/// @param b aiColor.b +/// @param a aiColor.a +/// @param with_head # +/// @return The hexadecimal string, is empty in case of an error. +AI_FORCE_INLINE std::string Rgba2Hex(int r, int g, int b, int a, bool with_head) { + std::stringstream ss; + if (with_head) { + ss << "#"; + } + ss << std::hex << (r << 24 | g << 16 | b << 8 | a); + + return ss.str(); +} + #endif // INCLUDED_AI_STRINGUTILS_H diff --git a/packaging/windows-innosetup/script_x64.iss b/packaging/windows-innosetup/script_x64.iss index 4d1b67cd0..7b49eba63 100644 --- a/packaging/windows-innosetup/script_x64.iss +++ b/packaging/windows-innosetup/script_x64.iss @@ -2,7 +2,7 @@ [Setup] AppName=Open Asset Import Library - SDK -AppVerName=Open Asset Import Library - SDK (v5.0.0) +AppVerName=Open Asset Import Library - SDK (v5.0.1) DefaultDirName={pf}\Assimp DefaultGroupName=Assimp UninstallDisplayIcon={app}\bin\x64\assimp.exe @@ -12,9 +12,9 @@ SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico WizardImageFile=compiler:WizModernImage-IS.BMP WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP LicenseFile=License.rtf -OutputBaseFileName=assimp-sdk-5.0.0-setup -VersionInfoVersion=5.0.0.0 -VersionInfoTextVersion=5.0.0 +OutputBaseFileName=assimp-sdk-5.0.1-setup +VersionInfoVersion=5.0.1.0 +VersionInfoTextVersion=5.0.1 VersionInfoCompany=Assimp Development Team ArchitecturesInstallIn64BitMode=x64 diff --git a/packaging/windows-innosetup/script_x86.iss b/packaging/windows-innosetup/script_x86.iss index d22d23b64..e8f591bbe 100644 --- a/packaging/windows-innosetup/script_x86.iss +++ b/packaging/windows-innosetup/script_x86.iss @@ -2,7 +2,7 @@ [Setup] AppName=Open Asset Import Library - SDK -AppVerName=Open Asset Import Library - SDK (v5.0.0) +AppVerName=Open Asset Import Library - SDK (v5.0.1) DefaultDirName={pf}\Assimp DefaultGroupName=Assimp UninstallDisplayIcon={app}\bin\x86\assimp.exe @@ -12,9 +12,9 @@ SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico WizardImageFile=compiler:WizModernImage-IS.BMP WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP LicenseFile=License.rtf -OutputBaseFileName=assimp-sdk-5.0.0-setup -VersionInfoVersion=4.1.0.0 -VersionInfoTextVersion=4.1.0 +OutputBaseFileName=assimp-sdk-5.0.1-setup +VersionInfoVersion=5.0.1.0 +VersionInfoTextVersion=5.0.1 VersionInfoCompany=Assimp Development Team ;ArchitecturesInstallIn64BitMode=x64 diff --git a/samples/SimpleOpenGL/CMakeLists.txt b/samples/SimpleOpenGL/CMakeLists.txt index 39593fdb9..6bc8e37e6 100644 --- a/samples/SimpleOpenGL/CMakeLists.txt +++ b/samples/SimpleOpenGL/CMakeLists.txt @@ -1,3 +1,5 @@ +SET(SAMPLE_PROJECT_NAME assimp_simpleogl) + FIND_PACKAGE(OpenGL) FIND_PACKAGE(GLUT) IF ( MSVC ) @@ -16,6 +18,10 @@ IF ( NOT GLUT_FOUND ) ENDIF () ENDIF () +# Used for usage and error messages in the program. +ADD_COMPILE_DEFINITIONS(ASSIMP_VERSION="${ASSIMP_VERSION}") +ADD_COMPILE_DEFINITIONS(PROJECT_NAME="${SAMPLE_PROJECT_NAME}") + if ( MSVC ) ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) @@ -34,17 +40,17 @@ LINK_DIRECTORIES( ${Assimp_BINARY_DIR}/lib ) -ADD_EXECUTABLE( assimp_simpleogl +ADD_EXECUTABLE( ${SAMPLE_PROJECT_NAME} Sample_SimpleOpenGL.c ) -SET_PROPERTY(TARGET assimp_simpleogl PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) +SET_PROPERTY(TARGET ${SAMPLE_PROJECT_NAME} PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) -TARGET_LINK_LIBRARIES( assimp_simpleogl assimp ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${M_LIB} ) -SET_TARGET_PROPERTIES( assimp_simpleogl PROPERTIES - OUTPUT_NAME assimp_simpleogl +TARGET_LINK_LIBRARIES( ${SAMPLE_PROJECT_NAME} assimp ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${M_LIB} ) +SET_TARGET_PROPERTIES( ${SAMPLE_PROJECT_NAME} PROPERTIES + OUTPUT_NAME ${SAMPLE_PROJECT_NAME} ) -INSTALL( TARGETS assimp_simpleogl +INSTALL( TARGETS ${SAMPLE_PROJECT_NAME} DESTINATION "${ASSIMP_BIN_INSTALL_DIR}" COMPONENT assimp-dev ) diff --git a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c index e1a9be0d9..bcc964efe 100644 --- a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c +++ b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c @@ -15,9 +15,9 @@ #include #ifdef __APPLE__ -#include +#include #else -#include +#include #endif /* assimp include files. These three are usually needed. */ @@ -25,6 +25,39 @@ #include #include +#define COMMAND_USAGE "--usage" + +/* ---------------------------------------------------------------------------- */ +inline static void print_run_command(const char* command_name) { + printf("Run '%s %s' for more information.\n", + PROJECT_NAME, command_name); +} + +/* ---------------------------------------------------------------------------- */ +inline static void print_error(const char* msg) { + printf("ERROR: %s\n", msg); +} + +#define NEW_LINE "\n" +#define DOUBLE_NEW_LINE NEW_LINE NEW_LINE + +/* ---------------------------------------------------------------------------- */ +inline static void print_usage() { + static const char* usage_format = + "Usage: " + PROJECT_NAME + " " DOUBLE_NEW_LINE + "where:" DOUBLE_NEW_LINE + " %-10s %s" DOUBLE_NEW_LINE + "options:" DOUBLE_NEW_LINE + " %-10s %s" DOUBLE_NEW_LINE; + printf(usage_format, + // where + "file", "The input model file to load.", + // options + COMMAND_USAGE, "Display usage."); +} + /* the global Assimp scene object */ const C_STRUCT aiScene* scene = NULL; GLuint scene_list = 0; @@ -245,7 +278,7 @@ void do_motion (void) static int frames = 0; int time = glutGet(GLUT_ELAPSED_TIME); - angle += (time-prev_time)*0.01f; + angle += static_cast((time-prev_time)*0.01); prev_time = time; frames += 1; @@ -324,12 +357,42 @@ int loadasset (const char* path) /* ---------------------------------------------------------------------------- */ int main(int argc, char **argv) { + const char* model_file = NULL; C_STRUCT aiLogStream stream; + if (argc < 2) { + print_error("No input model file specifed."); + print_run_command(COMMAND_USAGE); + return EXIT_FAILURE; + } + + // Find and execute available commands entered by the user. + for (int i = 1; i < argc; ++i) { + if (!strncmp(argv[i], COMMAND_USAGE, strlen(COMMAND_USAGE))) { + print_usage(); + return EXIT_SUCCESS; + } + } + + // Check and validate the specified model file extension. + model_file = argv[1]; + const char* extension = strchr(model_file, '.'); + if (!extension) { + print_error("Please provide a file with a valid extension."); + return EXIT_FAILURE; + } + + if (AI_FALSE == aiIsExtensionSupported(extension)) { + print_error("The specified model file extension is currently " + "unsupported in Assimp " ASSIMP_VERSION "."); + return EXIT_FAILURE; + } + glutInitWindowSize(900,600); glutInitWindowPosition(100,100); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInit(&argc, argv); + glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); glutCreateWindow("Assimp - Very simple OpenGL sample"); glutDisplayFunc(display); @@ -346,14 +409,11 @@ int main(int argc, char **argv) stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,"assimp_log.txt"); aiAttachLogStream(&stream); - /* the model name can be specified on the command line. If none - is specified, we try to locate one of the more expressive test - models from the repository (/models-nonbsd may be missing in - some distributions so we need a fallback from /models!). */ - if( 0 != loadasset( argc >= 2 ? argv[1] : "../../test/models-nonbsd/X/dwarf.x")) { - if( argc != 1 || (0 != loadasset( "../../../../test/models-nonbsd/X/dwarf.x") && 0 != loadasset( "../../test/models/X/Testwuson.X"))) { - return -1; - } + // Load the model file. + if(0 != loadasset(model_file)) { + print_error("Failed to load model. Please ensure that the specified file exists."); + aiDetachAllLogStreams(); + return EXIT_FAILURE; } glClearColor(0.1f,0.1f,0.1f,1.f); @@ -384,5 +444,5 @@ int main(int argc, char **argv) again. This will definitely release the last resources allocated by Assimp.*/ aiDetachAllLogStreams(); - return 0; + return EXIT_SUCCESS; } diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp index c8f86bbec..733d3d620 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp @@ -22,7 +22,7 @@ bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devc aiProcess_Triangulate | aiProcess_ConvertToLeftHanded); - if (pScene == NULL) + if (pScene == nullptr) return false; this->directory_ = filename.substr(0, filename.find_last_of("/\\")); diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp index 1ef4a401f..90338105e 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp @@ -126,7 +126,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, int argc; LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (!argv) { - MessageBox(NULL, + MessageBox(nullptr, TEXT("An error occured while reading command line arguments."), TEXT("Error!"), MB_ICONERROR | MB_OK); @@ -143,7 +143,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, // Ensure that a model file has been specified. if (argc < 2) { - MessageBox(NULL, + MessageBox(nullptr, TEXT("No model file specified. The program will now close."), TEXT("Error!"), MB_ICONERROR | MB_OK); @@ -165,16 +165,16 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; + wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION); + wc.hCursor = LoadCursor(nullptr, IDC_ARROW); + wc.hbrBackground = nullptr; + wc.lpszMenuName = nullptr; wc.lpszClassName = g_szClassName; - wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { - MessageBox(NULL, "Window Registration Failed!", "Error!", + MessageBox(nullptr, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } @@ -188,12 +188,12 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, " Simple Textured Directx11 Sample ", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top, - NULL, NULL, hInstance, NULL + nullptr, nullptr, hInstance, nullptr ); - if (g_hwnd == NULL) + if (g_hwnd == nullptr) { - MessageBox(NULL, "Window Creation Failed!", "Error!", + MessageBox(nullptr, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } @@ -210,7 +210,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, while (true) { - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); @@ -372,7 +372,7 @@ void InitD3D(HINSTANCE /*hinstance*/, HWND hWnd) ID3D11Texture2D *pBackBuffer; swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); - dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer); + dev->CreateRenderTargetView(pBackBuffer, nullptr, &backbuffer); pBackBuffer->Release(); D3D11_TEXTURE2D_DESC descDepth; @@ -440,7 +440,7 @@ void InitD3D(HINSTANCE /*hinstance*/, HWND hWnd) void CleanD3D(void) { if (swapchain) - swapchain->SetFullscreenState(FALSE, NULL); + swapchain->SetFullscreenState(FALSE, nullptr); if (ourModel) { ourModel->Close(); @@ -513,8 +513,8 @@ void InitPipeline() if(FAILED(CompileShaderFromFile(SHADER_PATH PIXEL_SHADER_FILE, 0, "main", "ps_4_0", &PS))) Throwanerror(UTFConverter(L"Failed to compile shader from file " PIXEL_SHADER_FILE).c_str()); - dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS); - dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS); + dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), nullptr, &pVS); + dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), nullptr, &pPS); D3D11_INPUT_ELEMENT_DESC ied[] = { @@ -576,16 +576,16 @@ HRESULT CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefine compileFlags |= D3DCOMPILE_DEBUG; #endif - ID3DBlob* pErrorBlob = NULL; + ID3DBlob* pErrorBlob = nullptr; HRESULT result = D3DCompileFromFile(pFileName, pDefines, D3D_COMPILE_STANDARD_FILE_INCLUDE, pEntryPoint, pShaderModel, compileFlags, 0, ppBytecodeBlob, &pErrorBlob); if (FAILED(result)) { - if (pErrorBlob != NULL) + if (pErrorBlob != nullptr) OutputDebugStringA((LPCSTR)pErrorBlob->GetBufferPointer()); } - if (pErrorBlob != NULL) + if (pErrorBlob != nullptr) pErrorBlob->Release(); return result; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 71316c09b..fac246d68 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -61,6 +61,14 @@ SET( COMMON unit/utIssues.cpp unit/utAnim.cpp unit/AssimpAPITest.cpp + unit/AssimpAPITest_aiMatrix3x3.cpp + unit/AssimpAPITest_aiMatrix4x4.cpp + unit/AssimpAPITest_aiQuaternion.cpp + unit/AssimpAPITest_aiVector2D.cpp + unit/AssimpAPITest_aiVector3D.cpp + unit/MathTest.cpp + unit/MathTest.h + unit/RandomNumberGeneration.h unit/utBatchLoader.cpp unit/utDefaultIOStream.cpp unit/utFastAtof.cpp diff --git a/test/models/glTF2/RecursiveNodes/RecursiveNodes.gltf b/test/models/glTF2/RecursiveNodes/RecursiveNodes.gltf new file mode 100644 index 000000000..11cf04166 --- /dev/null +++ b/test/models/glTF2/RecursiveNodes/RecursiveNodes.gltf @@ -0,0 +1,25 @@ +{ + "asset": { + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ] + }, + { + "children": [ + 0 + ] + } + ] +} diff --git a/test/unit/AssimpAPITest_aiMatrix3x3.cpp b/test/unit/AssimpAPITest_aiMatrix3x3.cpp new file mode 100644 index 000000000..5c0282a63 --- /dev/null +++ b/test/unit/AssimpAPITest_aiMatrix3x3.cpp @@ -0,0 +1,151 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ +#include "UnitTestPCH.h" +#include "MathTest.h" + +using namespace Assimp; + +class AssimpAPITest_aiMatrix3x3 : public AssimpMathTest { +protected: + virtual void SetUp() { + result_c = result_cpp = aiMatrix3x3(); + } + + aiMatrix3x3 result_c, result_cpp; +}; + +TEST_F(AssimpAPITest_aiMatrix3x3, aiIdentityMatrix3Test) { + // Force a non-identity matrix. + result_c = aiMatrix3x3(0,0,0,0,0,0,0,0,0); + aiIdentityMatrix3(&result_c); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3FromMatrix4Test) { + const auto m = random_mat4(); + result_cpp = aiMatrix3x3(m); + aiMatrix3FromMatrix4(&result_c, &m); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3FromQuaternionTest) { + const auto q = random_quat(); + result_cpp = q.GetMatrix(); + aiMatrix3FromQuaternion(&result_c, &q); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3AreEqualTest) { + result_c = result_cpp = random_mat3(); + EXPECT_EQ(result_cpp == result_c, + (bool)aiMatrix3AreEqual(&result_cpp, &result_c)); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3AreEqualEpsilonTest) { + result_c = result_cpp = random_mat3(); + EXPECT_EQ(result_cpp.Equal(result_c, Epsilon), + (bool)aiMatrix3AreEqualEpsilon(&result_cpp, &result_c, Epsilon)); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMultiplyMatrix3Test) { + const auto m = random_mat3(); + result_c = result_cpp = random_mat3(); + result_cpp *= m; + aiMultiplyMatrix3(&result_c, &m); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiTransposeMatrix3Test) { + result_c = result_cpp = random_mat3(); + result_cpp.Transpose(); + aiTransposeMatrix3(&result_c); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3InverseTest) { + // Use a predetermined matrix to prevent arbitrary + // cases where it could have a null determinant. + result_c = result_cpp = aiMatrix3x3( + 5, 2, 7, + 4, 6, 9, + 1, 8, 3); + result_cpp.Inverse(); + aiMatrix3Inverse(&result_c); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3DeterminantTest) { + result_c = result_cpp = random_mat3(); + EXPECT_EQ(result_cpp.Determinant(), + aiMatrix3Determinant(&result_c)); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3RotationZTest) { + const float angle(RandPI.next()); + aiMatrix3x3::RotationZ(angle, result_cpp); + aiMatrix3RotationZ(&result_c, angle); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3FromRotationAroundAxisTest) { + const float angle(RandPI.next()); + const auto axis = random_unit_vec3(); + aiMatrix3x3::Rotation(angle, axis, result_cpp); + aiMatrix3FromRotationAroundAxis(&result_c, &axis, angle); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3TranslationTest) { + const auto axis = random_vec2(); + aiMatrix3x3::Translation(axis, result_cpp); + aiMatrix3Translation(&result_c, &axis); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3FromToTest) { + // Use predetermined vectors to prevent running into division by zero. + const auto from = aiVector3D(1,2,1).Normalize(), to = aiVector3D(-1,1,1).Normalize(); + aiMatrix3x3::FromToMatrix(from, to, result_cpp); + aiMatrix3FromTo(&result_c, &from, &to); + EXPECT_EQ(result_cpp, result_c); +} diff --git a/test/unit/AssimpAPITest_aiMatrix4x4.cpp b/test/unit/AssimpAPITest_aiMatrix4x4.cpp new file mode 100644 index 000000000..2c89726e0 --- /dev/null +++ b/test/unit/AssimpAPITest_aiMatrix4x4.cpp @@ -0,0 +1,259 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ +#include "UnitTestPCH.h" +#include "MathTest.h" + +using namespace Assimp; + +class AssimpAPITest_aiMatrix4x4 : public AssimpMathTest { +protected: + virtual void SetUp() { + result_c = result_cpp = aiMatrix4x4(); + } + + /* Generates a predetermined transformation matrix to use + for the aiDecompose functions to prevent running into + division by zero. */ + aiMatrix4x4 get_predetermined_transformation_matrix_for_decomposition() const { + aiMatrix4x4 t, r; + aiMatrix4x4::Translation(aiVector3D(14,-25,-8), t); + aiMatrix4x4::Rotation(Math::PI() / 4.0f, aiVector3D(1).Normalize(), r); + return t * r; + } + + aiMatrix4x4 result_c, result_cpp; +}; + +TEST_F(AssimpAPITest_aiMatrix4x4, aiIdentityMatrix4Test) { + // Force a non-identity matrix. + result_c = aiMatrix4x4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + aiIdentityMatrix4(&result_c); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromMatrix3Test) { + aiMatrix3x3 m = random_mat3(); + result_cpp = aiMatrix4x4(m); + aiMatrix4FromMatrix3(&result_c, &m); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromScalingQuaternionPositionTest) { + const aiVector3D s = random_vec3(); + const aiQuaternion q = random_quat(); + const aiVector3D t = random_vec3(); + result_cpp = aiMatrix4x4(s, q, t); + aiMatrix4FromScalingQuaternionPosition(&result_c, &s, &q, &t); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4AddTest) { + const aiMatrix4x4 temp = random_mat4(); + result_c = result_cpp = random_mat4(); + result_cpp = result_cpp + temp; + aiMatrix4Add(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4AreEqualTest) { + result_c = result_cpp = random_mat4(); + EXPECT_EQ(result_cpp == result_c, + (bool)aiMatrix4AreEqual(&result_cpp, &result_c)); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4AreEqualEpsilonTest) { + result_c = result_cpp = random_mat4(); + EXPECT_EQ(result_cpp.Equal(result_c, Epsilon), + (bool)aiMatrix4AreEqualEpsilon(&result_cpp, &result_c, Epsilon)); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMultiplyMatrix4Test) { + const auto m = random_mat4(); + result_c = result_cpp = random_mat4(); + result_cpp *= m; + aiMultiplyMatrix4(&result_c, &m); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiTransposeMatrix4Test) { + result_c = result_cpp = random_mat4(); + result_cpp.Transpose(); + aiTransposeMatrix4(&result_c); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4InverseTest) { + // Use a predetermined matrix to prevent arbitrary + // cases where it could have a null determinant. + result_c = result_cpp = aiMatrix4x4( + 6, 10, 15, 3, + 14, 2, 12, 8, + 9, 13, 5, 16, + 4, 7, 11, 1); + result_cpp.Inverse(); + aiMatrix4Inverse(&result_c); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4DeterminantTest) { + result_c = result_cpp = random_mat4(); + EXPECT_EQ(result_cpp.Determinant(), + aiMatrix4Determinant(&result_c)); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4IsIdentityTest) { + EXPECT_EQ(result_cpp.IsIdentity(), + (bool)aiMatrix4IsIdentity(&result_c)); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiDecomposeMatrixTest) { + aiVector3D scaling_c, scaling_cpp, + position_c, position_cpp; + aiQuaternion rotation_c, rotation_cpp; + + result_c = result_cpp = get_predetermined_transformation_matrix_for_decomposition(); + result_cpp.Decompose(scaling_cpp, rotation_cpp, position_cpp); + aiDecomposeMatrix(&result_c, &scaling_c, &rotation_c, &position_c); + EXPECT_EQ(scaling_cpp, scaling_c); + EXPECT_EQ(position_cpp, position_c); + EXPECT_EQ(rotation_cpp, rotation_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4DecomposeIntoScalingEulerAnglesPositionTest) { + aiVector3D scaling_c, scaling_cpp, + rotation_c, rotation_cpp, + position_c, position_cpp; + + result_c = result_cpp = get_predetermined_transformation_matrix_for_decomposition(); + result_cpp.Decompose(scaling_cpp, rotation_cpp, position_cpp); + aiMatrix4DecomposeIntoScalingEulerAnglesPosition(&result_c, &scaling_c, &rotation_c, &position_c); + EXPECT_EQ(scaling_cpp, scaling_c); + EXPECT_EQ(position_cpp, position_c); + EXPECT_EQ(rotation_cpp, rotation_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4DecomposeIntoScalingAxisAnglePositionTest) { + aiVector3D scaling_c, scaling_cpp, + axis_c, axis_cpp, + position_c, position_cpp; + float angle_c, angle_cpp; + + result_c = result_cpp = get_predetermined_transformation_matrix_for_decomposition(); + result_cpp.Decompose(scaling_cpp, axis_cpp, angle_cpp, position_cpp); + aiMatrix4DecomposeIntoScalingAxisAnglePosition(&result_c, &scaling_c, &axis_c, &angle_c, &position_c); + EXPECT_EQ(scaling_cpp, scaling_c); + EXPECT_EQ(axis_cpp, axis_c); + EXPECT_EQ(angle_cpp, angle_c); + EXPECT_EQ(position_cpp, position_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4DecomposeNoScalingTest) { + aiVector3D position_c, position_cpp; + aiQuaternion rotation_c, rotation_cpp; + + result_c = result_cpp = get_predetermined_transformation_matrix_for_decomposition(); + result_cpp.DecomposeNoScaling(rotation_cpp, position_cpp); + aiMatrix4DecomposeNoScaling(&result_c, &rotation_c, &position_c); + EXPECT_EQ(position_cpp, position_c); + EXPECT_EQ(rotation_cpp, rotation_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromEulerAnglesTest) { + const float x(RandPI.next()), + y(RandPI.next()), + z(RandPI.next()); + result_cpp.FromEulerAnglesXYZ(x, y, z); + aiMatrix4FromEulerAngles(&result_c, x, y, z); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4RotationXTest) { + const float angle(RandPI.next()); + aiMatrix4x4::RotationX(angle, result_cpp); + aiMatrix4RotationX(&result_c, angle); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4RotationYTest) { + const float angle(RandPI.next()); + aiMatrix4x4::RotationY(angle, result_cpp); + aiMatrix4RotationY(&result_c, angle); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4RotationZTest) { + const float angle(RandPI.next()); + aiMatrix4x4::RotationZ(angle, result_cpp); + aiMatrix4RotationZ(&result_c, angle); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromRotationAroundAxisTest) { + const float angle(RandPI.next()); + const auto axis = random_unit_vec3(); + aiMatrix4x4::Rotation(angle, axis, result_cpp); + aiMatrix4FromRotationAroundAxis(&result_c, &axis, angle); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4TranslationTest) { + const auto axis = random_vec3(); + aiMatrix4x4::Translation(axis, result_cpp); + aiMatrix4Translation(&result_c, &axis); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4ScalingTest) { + const auto scaling = random_vec3(); + aiMatrix4x4::Scaling(scaling, result_cpp); + aiMatrix4Scaling(&result_c, &scaling); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromToTest) { + // Use predetermined vectors to prevent running into division by zero. + const auto from = aiVector3D(1,2,1).Normalize(), to = aiVector3D(-1,1,1).Normalize(); + aiMatrix4x4::FromToMatrix(from, to, result_cpp); + aiMatrix4FromTo(&result_c, &from, &to); + EXPECT_EQ(result_cpp, result_c); +} diff --git a/test/unit/AssimpAPITest_aiQuaternion.cpp b/test/unit/AssimpAPITest_aiQuaternion.cpp new file mode 100644 index 000000000..6bdef5a15 --- /dev/null +++ b/test/unit/AssimpAPITest_aiQuaternion.cpp @@ -0,0 +1,135 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ +#include "UnitTestPCH.h" +#include "MathTest.h" + +using namespace Assimp; + +class AssimpAPITest_aiQuaternion : public AssimpMathTest { +protected: + virtual void SetUp() { + result_c = result_cpp = aiQuaternion(); + } + + aiQuaternion result_c, result_cpp; +}; + +TEST_F(AssimpAPITest_aiQuaternion, aiCreateQuaternionFromMatrixTest) { + // Use a predetermined transformation matrix + // to prevent running into division by zero. + aiMatrix3x3 m, r; + aiMatrix3x3::Translation(aiVector2D(14,-25), m); + aiMatrix3x3::RotationZ(Math::PI() / 4.0f, r); + m = m * r; + + result_cpp = aiQuaternion(m); + aiCreateQuaternionFromMatrix(&result_c, &m); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionFromEulerAnglesTest) { + const float x(RandPI.next()), + y(RandPI.next()), + z(RandPI.next()); + result_cpp = aiQuaternion(x, y, z); + aiQuaternionFromEulerAngles(&result_c, x, y, z); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionFromAxisAngleTest) { + const float angle(RandPI.next()); + const aiVector3D axis(random_unit_vec3()); + result_cpp = aiQuaternion(axis, angle); + aiQuaternionFromAxisAngle(&result_c, &axis, angle); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionFromNormalizedQuaternionTest) { + const auto qvec3 = random_unit_vec3(); + result_cpp = aiQuaternion(qvec3); + aiQuaternionFromNormalizedQuaternion(&result_c, &qvec3); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionAreEqualTest) { + result_c = result_cpp = random_quat(); + EXPECT_EQ(result_cpp == result_c, + (bool)aiQuaternionAreEqual(&result_cpp, &result_c)); +} + +TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionAreEqualEpsilonTest) { + result_c = result_cpp = random_quat(); + EXPECT_EQ(result_cpp.Equal(result_c, Epsilon), + (bool)aiQuaternionAreEqualEpsilon(&result_cpp, &result_c, Epsilon)); +} + +TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionNormalizeTest) { + result_c = result_cpp = random_quat(); + aiQuaternionNormalize(&result_c); + EXPECT_EQ(result_cpp.Normalize(), result_c); +} + +TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionConjugateTest) { + result_c = result_cpp = random_quat(); + aiQuaternionConjugate(&result_c); + EXPECT_EQ(result_cpp.Conjugate(), result_c); +} + +TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionMultiplyTest) { + const aiQuaternion temp = random_quat(); + result_c = result_cpp = random_quat(); + result_cpp = result_cpp * temp; + aiQuaternionMultiply(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionInterpolateTest) { + // Use predetermined quaternions to prevent division by zero + // during slerp calculations. + const float INTERPOLATION(0.5f); + const auto q1 = aiQuaternion(aiVector3D(-1,1,1).Normalize(), Math::PI() / 4.0f); + const auto q2 = aiQuaternion(aiVector3D(1,2,1).Normalize(), Math::PI() / 2.0f); + aiQuaternion::Interpolate(result_cpp, q1, q2, INTERPOLATION); + aiQuaternionInterpolate(&result_c, &q1, &q2, INTERPOLATION); + EXPECT_EQ(result_cpp, result_c); +} diff --git a/test/unit/AssimpAPITest_aiVector2D.cpp b/test/unit/AssimpAPITest_aiVector2D.cpp new file mode 100644 index 000000000..55df06025 --- /dev/null +++ b/test/unit/AssimpAPITest_aiVector2D.cpp @@ -0,0 +1,140 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ +#include "UnitTestPCH.h" +#include "MathTest.h" + +using namespace Assimp; + +class AssimpAPITest_aiVector2D : public AssimpMathTest { +protected: + virtual void SetUp() { + result_c = result_cpp = aiVector2D(); + temp = random_vec2(); // Generates a random 2D vector != null vector. + } + + aiVector2D result_c, result_cpp, temp; +}; + +TEST_F(AssimpAPITest_aiVector2D, aiVector2AreEqualTest) { + result_c = result_cpp = random_vec2(); + EXPECT_EQ(result_cpp == result_c, + (bool)aiVector2AreEqual(&result_cpp, &result_c)); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2AreEqualEpsilonTest) { + result_c = result_cpp = random_vec2(); + EXPECT_EQ(result_cpp.Equal(result_c, Epsilon), + (bool)aiVector2AreEqualEpsilon(&result_cpp, &result_c, Epsilon)); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2AddTest) { + result_c = result_cpp = random_vec2(); + result_cpp += temp; + aiVector2Add(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2SubtractTest) { + result_c = result_cpp = random_vec2(); + result_cpp -= temp; + aiVector2Subtract(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2ScaleTest) { + const float FACTOR = RandNonZero.next(); + result_c = result_cpp = random_vec2(); + result_cpp *= FACTOR; + aiVector2Scale(&result_c, FACTOR); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2SymMulTest) { + result_c = result_cpp = random_vec2(); + result_cpp = result_cpp.SymMul(temp); + aiVector2SymMul(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2DivideByScalarTest) { + const float DIVISOR = RandNonZero.next(); + result_c = result_cpp = random_vec2(); + result_cpp /= DIVISOR; + aiVector2DivideByScalar(&result_c, DIVISOR); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2DivideByVectorTest) { + result_c = result_cpp = random_vec2(); + result_cpp = result_cpp / temp; + aiVector2DivideByVector(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2LengthTest) { + result_c = result_cpp = random_vec2(); + EXPECT_EQ(result_cpp.Length(), aiVector2Length(&result_c)); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2SquareLengthTest) { + result_c = result_cpp = random_vec2(); + EXPECT_EQ(result_cpp.SquareLength(), aiVector2SquareLength(&result_c)); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2NegateTest) { + result_c = result_cpp = random_vec2(); + aiVector2Negate(&result_c); + EXPECT_EQ(-result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2DotProductTest) { + result_c = result_cpp = random_vec2(); + EXPECT_EQ(result_cpp * result_c, + aiVector2DotProduct(&result_cpp, &result_c)); +} + +TEST_F(AssimpAPITest_aiVector2D, aiVector2NormalizeTest) { + result_c = result_cpp = random_vec2(); + aiVector2Normalize(&result_c); + EXPECT_EQ(result_cpp.Normalize(), result_c); +} diff --git a/test/unit/AssimpAPITest_aiVector3D.cpp b/test/unit/AssimpAPITest_aiVector3D.cpp new file mode 100644 index 000000000..a59867f10 --- /dev/null +++ b/test/unit/AssimpAPITest_aiVector3D.cpp @@ -0,0 +1,185 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ +#include "UnitTestPCH.h" +#include "MathTest.h" + +using namespace Assimp; + +class AssimpAPITest_aiVector3D : public AssimpMathTest { +protected: + virtual void SetUp() { + result_c = result_cpp = aiVector3D(); + temp = random_vec3(); // Generates a random 3D vector != null vector. + } + + aiVector3D result_c, result_cpp, temp; +}; + +TEST_F(AssimpAPITest_aiVector3D, aiVector3AreEqualTest) { + result_c = result_cpp = random_vec3(); + EXPECT_EQ(result_cpp == result_c, + (bool)aiVector3AreEqual(&result_cpp, &result_c)); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3AreEqualEpsilonTest) { + result_c = result_cpp = random_vec3(); + EXPECT_EQ(result_cpp.Equal(result_c, Epsilon), + (bool)aiVector3AreEqualEpsilon(&result_cpp, &result_c, Epsilon)); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3LessThanTest) { + result_c = result_cpp = random_vec3(); + EXPECT_EQ(result_cpp < temp, + (bool)aiVector3LessThan(&result_c, &temp)); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3AddTest) { + result_c = result_cpp = random_vec3(); + result_cpp += temp; + aiVector3Add(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3SubtractTest) { + result_c = result_cpp = random_vec3(); + result_cpp -= temp; + aiVector3Subtract(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3ScaleTest) { + const float FACTOR = RandNonZero.next(); + result_c = result_cpp = random_vec3(); + result_cpp *= FACTOR; + aiVector3Scale(&result_c, FACTOR); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3SymMulTest) { + result_c = result_cpp = random_vec3(); + result_cpp = result_cpp.SymMul(temp); + aiVector3SymMul(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3DivideByScalarTest) { + const float DIVISOR = RandNonZero.next(); + result_c = result_cpp = random_vec3(); + result_cpp /= DIVISOR; + aiVector3DivideByScalar(&result_c, DIVISOR); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3DivideByVectorTest) { + result_c = result_cpp = random_vec3(); + result_cpp = result_cpp / temp; + aiVector3DivideByVector(&result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3LengthTest) { + result_c = result_cpp = random_vec3(); + EXPECT_EQ(result_cpp.Length(), aiVector3Length(&result_c)); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3SquareLengthTest) { + result_c = result_cpp = random_vec3(); + EXPECT_EQ(result_cpp.SquareLength(), aiVector3SquareLength(&result_c)); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3NegateTest) { + result_c = result_cpp = random_vec3(); + aiVector3Negate(&result_c); + EXPECT_EQ(-result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3DotProductTest) { + result_c = result_cpp = random_vec3(); + EXPECT_EQ(result_cpp * result_c, + aiVector3DotProduct(&result_cpp, &result_c)); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3CrossProductTest) { + result_c = result_cpp = random_vec3(); + result_cpp = result_cpp ^ temp; + aiVector3CrossProduct(&result_c, &result_c, &temp); + EXPECT_EQ(result_cpp, result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3NormalizeTest) { + result_c = result_cpp = random_vec3(); + aiVector3Normalize(&result_c); + EXPECT_EQ(result_cpp.Normalize(), result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3NormalizeSafeTest) { + result_c = result_cpp = random_vec3(); + aiVector3NormalizeSafe(&result_c); + EXPECT_EQ(result_cpp.NormalizeSafe(), result_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiVector3RotateByQuaternionTest) { + aiVector3D v_c, v_cpp; + v_c = v_cpp = random_vec3(); + const auto q = random_quat(); + aiVector3RotateByQuaternion(&v_c, &q); + EXPECT_EQ(q.Rotate(v_cpp), v_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiTransformVecByMatrix3Test) { + const auto m = random_mat3(); + aiVector3D v_c, v_cpp; + v_c = v_cpp = random_vec3(); + v_cpp *= m; + aiTransformVecByMatrix3(&v_c, &m); + EXPECT_EQ(v_cpp, v_c); +} + +TEST_F(AssimpAPITest_aiVector3D, aiTransformVecByMatrix4Test) { + const auto m = random_mat4(); + aiVector3D v_c, v_cpp; + v_c = v_cpp = random_vec3(); + v_cpp *= m; + aiTransformVecByMatrix4(&v_c, &m); + EXPECT_EQ(v_cpp, v_c); +} diff --git a/test/unit/MathTest.cpp b/test/unit/MathTest.cpp new file mode 100644 index 000000000..69b23f625 --- /dev/null +++ b/test/unit/MathTest.cpp @@ -0,0 +1,56 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ +#include "MathTest.h" + +namespace Assimp { + +// Initialize epsilon value. +const float AssimpMathTest::Epsilon = Math::getEpsilon(); + +// Initialize with an interval of [1,100]. +RandomUniformFloatGenerator AssimpMathTest::RandNonZero(1.0f, 100.0f); + +// Initialize with an interval of [-PI,PI] inclusively. +RandomUniformFloatGenerator AssimpMathTest::RandPI(-Math::PI(), Math::PI()); + +} diff --git a/test/unit/MathTest.h b/test/unit/MathTest.h new file mode 100644 index 000000000..19401b29a --- /dev/null +++ b/test/unit/MathTest.h @@ -0,0 +1,103 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_MATH_TEST_H +#define ASSIMP_MATH_TEST_H + +#include "UnitTestPCH.h" +#include +#include "RandomNumberGeneration.h" + +namespace Assimp { + +/** Custom test class providing several math related utilities. */ +class AssimpMathTest : public ::testing::Test { +public: + /** Return a random non-null 2D vector. */ + inline static aiVector2D random_vec2() { + return aiVector2D(RandNonZero.next(), RandNonZero.next()); + } + + /** Return a random non-null 3D vector. */ + inline static aiVector3D random_vec3() { + return aiVector3D(RandNonZero.next(), RandNonZero.next(),RandNonZero.next()); + } + + /** Return a random unit 3D vector. */ + inline static aiVector3D random_unit_vec3() { + return random_vec3().NormalizeSafe(); + } + + /** Return a quaternion with random orientation and + * rotation angle around axis. */ + inline static aiQuaternion random_quat() { + return aiQuaternion(random_unit_vec3(), RandPI.next()); + } + + /** Return a random non-null 3x3 matrix. */ + inline static aiMatrix3x3 random_mat3() { + return aiMatrix3x3( + RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), + RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), + RandNonZero.next(), RandNonZero.next(),RandNonZero.next()); + } + + /** Return a random non-null 4x4 matrix. */ + inline static aiMatrix4x4 random_mat4() { + return aiMatrix4x4( + RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), RandNonZero.next(), + RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), RandNonZero.next(), + RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), RandNonZero.next(), + RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), RandNonZero.next()); + } + + /** Epsilon value to use in tests. */ + static const float Epsilon; + + /** Random number generators. */ + static RandomUniformFloatGenerator RandNonZero, RandPI; +}; + +} + +#endif // ASSIMP_MATH_TEST_H diff --git a/test/unit/RandomNumberGeneration.h b/test/unit/RandomNumberGeneration.h new file mode 100644 index 000000000..a313f34ae --- /dev/null +++ b/test/unit/RandomNumberGeneration.h @@ -0,0 +1,82 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_RANDOM_NUMBER_GENERATION_H +#define ASSIMP_RANDOM_NUMBER_GENERATION_H + +#include + +namespace Assimp { + +/** Helper class to use for generating pseudo-random + * real numbers, with a uniform distribution. */ +template +class RandomUniformRealGenerator { +public: + RandomUniformRealGenerator() : + dist_(), + rd_(), + re_(rd_()) { + // empty + } + + RandomUniformRealGenerator(T min, T max) : + dist_(min, max), + rd_(), + re_(rd_()) { + // empty + } + + inline T next() { + return dist_(re_); + } + +private: + std::uniform_real_distribution dist_; + std::random_device rd_; + std::default_random_engine re_; +}; + +using RandomUniformFloatGenerator = RandomUniformRealGenerator; + +} + +#endif // ASSIMP_RANDOM_NUMBER_GENERATION_H diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 23901b9b2..55cd2ef6a 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -491,6 +491,12 @@ TEST_F(utglTF2ImportExport, texcoords) { EXPECT_EQ(uvIndex, 1); } +TEST_F(utglTF2ImportExport, recursive_nodes) { + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/RecursiveNodes/RecursiveNodes.gltf", aiProcess_ValidateDataStructure); + EXPECT_EQ(nullptr, scene); +} + TEST_F(utglTF2ImportExport, norootnode_noscene) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/TestNoRootNode/NoScene.gltf", aiProcess_ValidateDataStructure);