소스 검색

Merge branch 'master' into deprecated_gltfpbr_macros

RichardTea 3 년 전
부모
커밋
d704824be3
54개의 변경된 파일965개의 추가작업 그리고 774개의 파일을 삭제
  1. 0 67
      .travis.sh
  2. 0 78
      .travis.yml
  3. 6 7
      BUILDBINARIES_EXAMPLE.bat
  4. 33 9
      CMakeLists.txt
  5. 7 4
      code/AssetLib/ASE/ASEParser.cpp
  6. 3 1
      code/AssetLib/Assbin/AssbinFileWriter.cpp
  7. 10 40
      code/AssetLib/Blender/BlenderLoader.cpp
  8. 3 3
      code/AssetLib/Collada/ColladaLoader.cpp
  9. 2 0
      code/AssetLib/FBX/FBXCommon.h
  10. 8 7
      code/AssetLib/FBX/FBXConverter.cpp
  11. 16 45
      code/AssetLib/FBX/FBXParser.cpp
  12. 48 35
      code/AssetLib/HMP/HMPLoader.cpp
  13. 9 9
      code/AssetLib/IFC/IFCBoolean.cpp
  14. 5 7
      code/AssetLib/IFC/IFCGeometry.cpp
  15. 3 3
      code/AssetLib/IFC/IFCOpenings.cpp
  16. 11 13
      code/AssetLib/IFC/IFCUtil.cpp
  17. 6 2
      code/AssetLib/LWO/LWOAnimation.cpp
  18. 5 1
      code/AssetLib/Obj/ObjFileData.h
  19. 10 0
      code/AssetLib/Obj/ObjFileImporter.cpp
  20. 5 1
      code/AssetLib/Obj/ObjFileMtlImporter.cpp
  21. 30 67
      code/AssetLib/X/XFileParser.cpp
  22. 31 61
      code/AssetLib/XGL/XGLLoader.cpp
  23. 1 1
      code/AssetLib/XGL/XGLLoader.h
  24. 56 107
      code/AssetLib/glTF/glTFAsset.h
  25. 0 2
      code/AssetLib/glTF/glTFCommon.h
  26. 47 29
      code/AssetLib/glTF2/glTF2Asset.h
  27. 99 91
      code/AssetLib/glTF2/glTF2Exporter.cpp
  28. 6 5
      code/CMakeLists.txt
  29. 14 16
      code/Common/Base64.cpp
  30. 214 0
      code/Common/Compression.cpp
  31. 121 0
      code/Common/Compression.h
  32. 1 1
      code/Common/IOSystem.cpp
  33. 1 2
      code/Common/Version.cpp
  34. 0 1
      code/Common/material.cpp
  35. 0 2
      code/Common/simd.cpp
  36. 4 4
      code/PostProcessing/CalcTangentsProcess.cpp
  37. 1 1
      code/PostProcessing/FindDegenerates.cpp
  38. 4 0
      include/assimp/Base64.hpp
  39. 14 14
      include/assimp/ByteSwapper.h
  40. 0 8
      include/assimp/Exceptional.h
  41. 7 3
      include/assimp/Hash.h
  42. 84 0
      include/assimp/ObjMaterial.h
  43. 19 7
      include/assimp/TinyFormatter.h
  44. 3 3
      include/assimp/defs.h
  45. 1 1
      include/assimp/matrix3x3.h
  46. 1 1
      include/assimp/matrix4x4.h
  47. 1 1
      include/assimp/quaternion.h
  48. 1 1
      include/assimp/vector2.h
  49. 1 1
      include/assimp/vector3.h
  50. 6 5
      test/unit/Common/utMesh.cpp
  51. 2 2
      test/unit/utColladaExport.cpp
  52. 1 1
      test/unit/utFBXImporterExporter.cpp
  53. 3 3
      test/unit/utVersion.cpp
  54. 1 1
      test/unit/utglTF2ImportExport.cpp

+ 0 - 67
.travis.sh

@@ -1,67 +0,0 @@
-#---------------------------------------------------------------------------
-#Open Asset Import Library (assimp)
-#---------------------------------------------------------------------------
-# Copyright (c) 2006-2020, assimp team
-#
-# License see LICENSE file
-#
-function generate() {
-    OPTIONS="-DASSIMP_WERROR=ON"
-    OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO"
-    
-    if [ "$DISABLE_EXPORTERS" = "YES" ] ; then
-        OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES"
-    else
-        OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO"
-    fi
-
-    if [ "$SHARED_BUILD" = "ON" ] ; then
-        OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=ON"
-    else
-        OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=OFF"
-    fi
-
-    if [ "$ENABLE_COVERALLS" = "ON" ] ; then
-        OPTIONS="$OPTIONS -DASSIMP_COVERALLS=ON"
-    else
-        OPTIONS="$OPTIONS -DASSIMP_COVERALLS=OFF"
-    fi
-
-    if [ "$ASAN" = "ON" ] ; then
-        OPTIONS="$OPTIONS -DASSIMP_ASAN=ON"
-    else
-        OPTIONS="$OPTIONS -DASSIMP_ASAN=OFF"
-    fi
-
-    if [ "$UBSAN" = "ON" ] ; then
-        OPTIONS="$OPTIONS -DASSIMP_UBSAN=ON"
-    fi
-
-    cmake -G "Unix Makefiles" $OPTIONS
-}
-# build and run unittests, if not android
-if [ $ANDROID ]; then
-    ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
-fi
-if [ "$TRAVIS_OS_NAME" = "linux" ]; then
-  if [ $ANALYZE = "ON" ] ; then
-    if [ "$CC" = "clang" ]; then
-        scan-build cmake -G "Unix Makefiles" -DBUILD_SHARED_LIBS=OFF -DASSIMP_BUILD_TESTS=OFF
-        scan-build --status-bugs make -j2
-    else
-        cppcheck --version
-        generate \
-        && cppcheck --error-exitcode=1 -j2 -Iinclude -Icode code 2> cppcheck.txt
-        if [ -s cppcheck.txt ]; then
-            cat cppcheck.txt
-            exit 1
-        fi
-    fi
-  else
-    generate \
-    && make -j4 \
-    && sudo make install \
-    && sudo ldconfig \
-    && (cd test/unit; ../../bin/unit)
-  fi
-fi

+ 0 - 78
.travis.yml

@@ -1,78 +0,0 @@
-sudo: required
-language: cpp
-
-cache: ccache
-
-before_install:
-  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake cppcheck && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi
-  - 'if [ "$TRAVIS_OS_NAME" = "osx" ];  then
-       if brew ls --versions cmake > /dev/null; then
-         echo cmake already installed.;
-       else
-         brew install cmake;
-       fi;
-       brew install python3;
-       brew install homebrew/x11/freeglut; 
-    fi'
-  - echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h
-  # install latest LCOV (1.9 was failing)
-  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz && tar xf lcov_1.11.orig.tar.gz && sudo make -C lcov-1.11/ install && gem install coveralls-lcov && lcov --version && g++ --version ; fi
-
-os:
-  - linux
-
-compiler:
-  - gcc
-  - clang
-
-env:
-  global:
-    - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
-    - PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
-
-git:
-  depth: 1
-
-matrix:
-  include:
-    - os: linux
-      compiler: clang
-      env: ASAN=ON
-    - os: linux
-      compiler: clang
-      env: UBSAN=ON
-    - os: linux
-      compiler: clang
-      env: SHARED_BUILD=ON
-    - os: linux
-      compiler: gcc
-      env: ANALYZE=ON
-    - os: linux
-      compiler: gcc
-      env: ENABLE_COVERALLS=ON
-    - os: linux
-      compiler: gcc
-      env: SHARED_BUILD=ON
-
-install:
-  - if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi
-
-before_script:
-  cmake . -DASSIMP_ENABLE_BOOST_WORKAROUND=YES
-
-script:
-  - export COVERALLS_SERVICE_NAME=travis-ci
-  - export COVERALLS_REPO_TOKEN=abc12345
-  - . ./.travis.sh
- 
-after_success:
-  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --capture --output-file coverage.info && lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info && lcov --list coverage.info && coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info ; fi
-
-addons:
-  coverity_scan:
-    project:
-      name: "assimp/assimp"
-    notification_email: [email protected]
-    build_command_prepend: "cmake ./"
-    build_command: "make -j4"
-    branch_pattern: coverity_scan

+ 6 - 7
BUILDBINARIES_EXAMPLE.bat

@@ -10,16 +10,15 @@
 :: Also see: https://github.com/assimp/assimp/pull/2646
 
 SET SOURCE_DIR=.
+SET GENERATOR=Visual Studio 16 2019
 
-:: For generators see "cmake --help"
-SET GENERATOR=Visual Studio 15 2017
-
-SET BINARIES_DIR="./BINARIES/Win32"
-cmake CMakeLists.txt -G "%GENERATOR%" -S %SOURCE_DIR% -B %BINARIES_DIR%
+SET BINARIES_DIR="./build/Win32"
+cmake . -G "%GENERATOR%" -A Win32 -S %SOURCE_DIR% -B %BINARIES_DIR%
+cmake --build %BINARIES_DIR% --config debug
 cmake --build %BINARIES_DIR% --config release
 
-SET BINARIES_DIR="./BINARIES/x64"
-cmake CMakeLists.txt -G "%GENERATOR% Win64" -S %SOURCE_DIR% -B %BINARIES_DIR%
+SET BINARIES_DIR="./build/x64"
+cmake . -G "%GENERATOR%" -A x64 -S %SOURCE_DIR% -B %BINARIES_DIR%
 cmake --build %BINARIES_DIR% --config debug
 cmake --build %BINARIES_DIR% --config release
 

+ 33 - 9
CMakeLists.txt

@@ -49,14 +49,14 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
 IF(ASSIMP_HUNTER_ENABLED)
   include("cmake-modules/HunterGate.cmake")
   HunterGate(
-    URL "https://github.com/cpp-pm/hunter/archive/v0.23.311.tar.gz"
-    SHA1 "1a82b9b73055879181cb1466b2ab5d48ee8ae410"
+    URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz"
+    SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd"
   )
 
   add_definitions(-DASSIMP_USE_HUNTER)
 ENDIF()
 
-PROJECT(Assimp VERSION 5.1.6)
+PROJECT(Assimp VERSION 5.2.0)
 
 # All supported options ###############################################
 
@@ -134,12 +134,12 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
    OFF
 )
 
-IF ( WIN32 )
+IF (WIN32)
   # Use subset of Windows.h
   ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
 
   IF(MSVC)
-    OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
+    OPTION (ASSIMP_BUILD_ASSIMP_VIEW
       "If the Assimp view tool is built. (requires DirectX)"
       OFF )
 
@@ -243,6 +243,13 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
 IF( UNIX )
   # Use GNUInstallDirs for Unix predefined directories
   INCLUDE(GNUInstallDirs)
+  # Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
+  IF( ${OPERATING_SYSTEM} MATCHES "Android")
+  ELSE()
+    IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
+      ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
+    ENDIF()
+  ENDIF()
 ENDIF()
 
 # Grouped compiler settings ########################################
@@ -341,9 +348,24 @@ INCLUDE (FindPkgMacros)
 INCLUDE (PrecompiledHeader)
 
 # Set Assimp project output directory variables.
-SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for runtime output files")
-SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for library output files")
-SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib" CACHE STRING "Path for archive output files")
+# Will respect top-level CMAKE_*_OUTPUT_DIRECTORY variables if any are set.
+IF(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+  SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for runtime output files")
+ELSE()
+  SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} CACHE STRING "Path for runtime output files")
+ENDIF()
+
+IF(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY)
+  SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for library output files")
+ELSE()
+  SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} CACHE STRING "Path for runtime output files")
+ENDIF()
+
+IF(NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
+  SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib" CACHE STRING "Path for library output files")
+ELSE()
+  SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} CACHE STRING "Path for runtime output files")
+ENDIF()
 
 # Macro used to set the output directories of a target to the
 # respective Assimp output directories.
@@ -672,11 +694,13 @@ ENDIF()
 ADD_SUBDIRECTORY( code/ )
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
   # The viewer for windows only
-  IF ( WIN32 )
+  IF (WIN32)
     OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF )
     IF ( ASSIMP_BUILD_ASSIMP_VIEW )
       ADD_SUBDIRECTORY( tools/assimp_view/ )
     ENDIF ()
+  ELSE()
+    MESSAGE("Building Assimp Viewer only supported on Windows.")
   ENDIF ()
   # The command line tool
   ADD_SUBDIRECTORY( tools/assimp_cmd/ )

+ 7 - 4
code/AssetLib/ASE/ASEParser.cpp

@@ -112,6 +112,7 @@ using namespace Assimp::ASE;
 // ------------------------------------------------------------------------------------------------
 Parser::Parser(const char *szFile, unsigned int fileFormatDefault) {
     ai_assert(nullptr != szFile);
+
     filePtr = szFile;
     iFileFormat = fileFormatDefault;
 
@@ -486,7 +487,7 @@ void Parser::ParseLV1MaterialListBlock() {
                 ParseLV4MeshLong(iIndex);
 
                 if (iIndex >= iMaterialCount) {
-                    LogError("Out of range: material index is too large");
+                    LogWarning("Out of range: material index is too large");
                     iIndex = iMaterialCount - 1;
                     return;
                 }
@@ -905,7 +906,6 @@ void Parser::ParseLV2LightSettingsBlock(ASE::Light &light) {
         }
         AI_ASE_HANDLE_SECTION("2", "LIGHT_SETTINGS");
     }
-    return;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -1782,7 +1782,9 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
 
     // *MESH_MTLID  is optional, too
     while (true) {
-        if ('*' == *filePtr) break;
+        if ('*' == *filePtr) {
+            break;
+        }
         if (IsLineEnd(*filePtr)) {
             return;
         }
@@ -1831,8 +1833,9 @@ void Parser::ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut) {
 void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) {
     ai_assert(nullptr != apOut);
 
-    for (unsigned int i = 0; i < 3; ++i)
+    for (unsigned int i = 0; i < 3; ++i) {
         ParseLV4MeshFloat(apOut[i]);
+    }
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshFloat(ai_real &fOut) {

+ 3 - 1
code/AssetLib/Assbin/AssbinFileWriter.cpp

@@ -182,6 +182,8 @@ inline size_t Write<aiVertexWeight>(IOStream *stream, const aiVertexWeight &v) {
     return t + Write<float>(stream, v.mWeight);
 }
 
+constexpr size_t MatrixSize = 64;
+
 // -----------------------------------------------------------------------------------
 // Serialize a mat4x4
 template <>
@@ -192,7 +194,7 @@ inline size_t Write<aiMatrix4x4>(IOStream *stream, const aiMatrix4x4 &m) {
         }
     }
 
-    return 64;
+    return MatrixSize;
 }
 
 // -----------------------------------------------------------------------------------

+ 10 - 40
code/AssetLib/Blender/BlenderLoader.cpp

@@ -66,11 +66,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // zlib is needed for compressed blend files
 #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
-#  ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#include "Common/Compression.h"
+/* #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
 #    include <zlib.h>
 #  else
 #    include "../contrib/zlib/zlib.h"
-#  endif
+#  endif*/
 #endif
 
 namespace Assimp {
@@ -141,7 +142,7 @@ void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
 void BlenderImporter::InternReadFile(const std::string &pFile,
         aiScene *pScene, IOSystem *pIOHandler) {
 #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
-    std::vector<Bytef> uncompressed;
+    std::vector<char> uncompressed;
 #endif
 
     FileDatabase file;
@@ -159,7 +160,6 @@ void BlenderImporter::InternReadFile(const std::string &pFile,
 #ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
         ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
 #else
-
         if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
             ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
         }
@@ -173,42 +173,12 @@ void BlenderImporter::InternReadFile(const std::string &pFile,
         stream->Seek(0L, aiOrigin_SET);
         std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
 
-        // build a zlib stream
-        z_stream zstream;
-        zstream.opaque = Z_NULL;
-        zstream.zalloc = Z_NULL;
-        zstream.zfree = Z_NULL;
-        zstream.data_type = Z_BINARY;
-
-        // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
-        inflateInit2(&zstream, 16 + MAX_WBITS);
-
-        zstream.next_in = reinterpret_cast<Bytef *>(reader->GetPtr());
-        zstream.avail_in = (uInt)reader->GetRemainingSize();
-
-        size_t total = 0l;
-
-        // TODO: be smarter about this, decompress directly into heap buffer
-        // and decompress the data .... do 1k chunks in the hope that we won't kill the stack
-#define MYBLOCK 1024
-        Bytef block[MYBLOCK];
-        int ret;
-        do {
-            zstream.avail_out = MYBLOCK;
-            zstream.next_out = block;
-            ret = inflate(&zstream, Z_NO_FLUSH);
-
-            if (ret != Z_STREAM_END && ret != Z_OK) {
-                ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .BLEND file");
-            }
-            const size_t have = MYBLOCK - zstream.avail_out;
-            total += have;
-            uncompressed.resize(total);
-            memcpy(uncompressed.data() + total - have, block, have);
-        } while (ret != Z_STREAM_END);
-
-        // terminate zlib
-        inflateEnd(&zstream);
+        size_t total = 0;
+        Compression compression;
+        if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
+            total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), uncompressed);
+            compression.close();
+        }
 
         // replace the input stream with a memory stream
         stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t *>(uncompressed.data()), total));

+ 3 - 3
code/AssetLib/Collada/ColladaLoader.cpp

@@ -357,9 +357,9 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Node
             out->mAngleInnerCone = AI_DEG_TO_RAD(srcLight->mFalloffAngle);
 
             // ... some extension magic.
-            if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) {
+            if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - ai_epsilon)) {
                 // ... some deprecation magic.
-                if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) {
+                if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - ai_epsilon)) {
                     // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
                     // epsilon chosen to be 0.1
                     float f = 1.0f;
@@ -1065,7 +1065,7 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
         return;
     }
     for (unsigned int i = 0; i < values.size(); i++) {
-        if (std::abs(time - values[i].mTime) < 1e-6f) {
+        if (std::abs(time - values[i].mTime) < ai_epsilon) {
             values[i].mKeys.push_back(k);
             return;
         } else if (time > values[i].mTime && time < values[i + 1].mTime) {

+ 2 - 0
code/AssetLib/FBX/FBXCommon.h

@@ -80,8 +80,10 @@ enum TransformInheritance {
 
     TransformInheritance_MAX // end-of-enum sentinel
 };
+
 } // namespace FBX
 } // namespace Assimp
+
 #endif // ASSIMP_BUILD_NO_FBX_EXPORTER
 
 #endif // AI_FBXCOMMON_H_INC

+ 8 - 7
code/AssetLib/FBX/FBXConverter.cpp

@@ -653,7 +653,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
     const PropertyTable &props = model.Props();
     bool ok;
 
-    const float zero_epsilon = 1e-6f;
+    const float zero_epsilon = ai_epsilon;
     const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
     for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
         const TransformationComp comp = static_cast<TransformationComp>(i);
@@ -1267,7 +1267,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
     const std::vector<aiVector3D> &normals = mesh.GetNormals();
     if (normals.size()) {
         ai_assert(normals.size() == vertices.size());
-        out_mesh->mNormals = new aiVector3D[vertices.size()];
+        out_mesh->mNormals = new aiVector3D[count_vertices];
     }
 
     // allocate tangents, binormals.
@@ -1295,8 +1295,8 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
             ai_assert(tangents.size() == vertices.size());
             ai_assert(binormals->size() == vertices.size());
 
-            out_mesh->mTangents = new aiVector3D[vertices.size()];
-            out_mesh->mBitangents = new aiVector3D[vertices.size()];
+            out_mesh->mTangents = new aiVector3D[count_vertices];
+            out_mesh->mBitangents = new aiVector3D[count_vertices];
         }
     }
 
@@ -1308,7 +1308,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
             break;
         }
 
-        out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()];
+        out_mesh->mTextureCoords[i] = new aiVector3D[count_vertices];
         out_mesh->mNumUVComponents[i] = 2;
     }
 
@@ -1320,7 +1320,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
             break;
         }
 
-        out_mesh->mColors[i] = new aiColor4D[vertices.size()];
+        out_mesh->mColors[i] = new aiColor4D[count_vertices];
     }
 
     unsigned int cursor = 0, in_cursor = 0;
@@ -3187,7 +3187,8 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
     }
 
     bool ok = false;
-    const float zero_epsilon = 1e-6f;
+    
+    const float zero_epsilon = ai_epsilon;
 
     const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
     if (ok && preRotation.SquareLength() > zero_epsilon) {

+ 16 - 45
code/AssetLib/FBX/FBXParser.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -46,11 +45,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
 
-#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#   include <zlib.h>
-#else
-#   include "../contrib/zlib/zlib.h"
-#endif
+//#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#include "Common/Compression.h"
+//#   include <zlib.h>
+//#else
+//#   include "../contrib/zlib/zlib.h"
+//#endif
 
 #include "FBXTokenizer.h"
 #include "FBXParser.h"
@@ -115,9 +115,7 @@ namespace Assimp {
 namespace FBX {
 
 // ------------------------------------------------------------------------------------------------
-Element::Element(const Token& key_token, Parser& parser)
-: key_token(key_token)
-{
+Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) {
     TokenPtr n = nullptr;
     do {
         n = parser.AdvanceToNextToken();
@@ -210,8 +208,7 @@ Scope::Scope(Parser& parser,bool topLevel)
 }
 
 // ------------------------------------------------------------------------------------------------
-Scope::~Scope()
-{
+Scope::~Scope() {
     for(ElementMap::value_type& v : elements) {
         delete v.second;
     }
@@ -527,9 +524,7 @@ void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uin
 // ------------------------------------------------------------------------------------------------
 // read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
 void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end,
-    std::vector<char>& buff,
-    const Element& /*el*/)
-{
+        std::vector<char>& buff, const Element& /*el*/) {
     BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end);
     AI_SWAP4(encmode);
     data += 4;
@@ -571,31 +566,11 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha
     else if(encmode == 1) {
         // zlib/deflate, next comes ZIP head (0x78 0x01)
         // see http://www.ietf.org/rfc/rfc1950.txt
-
-        z_stream zstream;
-        zstream.opaque = Z_NULL;
-        zstream.zalloc = Z_NULL;
-        zstream.zfree  = Z_NULL;
-        zstream.data_type = Z_BINARY;
-
-        // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
-        if(Z_OK != inflateInit(&zstream)) {
-            ParseError("failure initializing zlib");
+         Compression compress;
+        if (compress.open(Compression::Format::Binary, Compression::FlushMode::Finish, 0)) {
+            compress.decompress(data, comp_len, buff);
+            compress.close();
         }
-
-        zstream.next_in   = reinterpret_cast<Bytef*>( const_cast<char*>(data) );
-        zstream.avail_in  = comp_len;
-
-        zstream.avail_out = static_cast<uInt>(buff.size());
-        zstream.next_out = reinterpret_cast<Bytef*>(&*buff.begin());
-        const int ret = inflate(&zstream, Z_FINISH);
-
-        if (ret != Z_STREAM_END && ret != Z_OK) {
-            ParseError("failure decompressing compressed data section");
-        }
-
-        // terminate zlib
-        inflateEnd(&zstream);
     }
 #ifdef ASSIMP_BUILD_DEBUG
     else {
@@ -701,7 +676,6 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
     }
 }
 
-
 // ------------------------------------------------------------------------------------------------
 // read an array of color4 tuples
 void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
@@ -786,8 +760,7 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
 
 // ------------------------------------------------------------------------------------------------
 // read an array of float2 tuples
-void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
-{
+void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) {
     out.resize( 0 );
     const TokenList& tok = el.Tokens();
     if(tok.empty()) {
@@ -831,8 +804,7 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
                 out.push_back(aiVector2D(static_cast<float>(d[0]),
                     static_cast<float>(d[1])));
             }
-        }
-        else if (type == 'f') {
+        } else if (type == 'f') {
             const float* f = reinterpret_cast<const float*>(&buff[0]);
             for (unsigned int i = 0; i < count2; ++i, f += 2) {
                 out.push_back(aiVector2D(f[0],f[1]));
@@ -865,8 +837,7 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
 
 // ------------------------------------------------------------------------------------------------
 // read an array of ints
-void ParseVectorDataArray(std::vector<int>& out, const Element& el)
-{
+void ParseVectorDataArray(std::vector<int>& out, const Element& el) {
     out.resize( 0 );
     const TokenList& tok = el.Tokens();
     if(tok.empty()) {

+ 48 - 35
code/AssetLib/HMP/HMPLoader.cpp

@@ -275,7 +275,9 @@ void HMPImporter::InternReadFile_HMP7() {
 
     // now load all vertices from the file
     aiVector3D *pcVertOut = pcMesh->mVertices;
+    ai_assert(pcVertOut != nullptr);
     aiVector3D *pcNorOut = pcMesh->mNormals;
+    ai_assert(pcNorOut != nullptr);
     const HMP::Vertex_HMP7 *src = (const HMP::Vertex_HMP7 *)szCurrent;
     for (unsigned int y = 0; y < height; ++y) {
         for (unsigned int x = 0; x < width; ++x) {
@@ -327,29 +329,31 @@ void HMPImporter::CreateMaterial(const unsigned char *szCurrent,
 
         // now read the first skin and skip all others
         ReadFirstSkin(pcHeader->numskins, szCurrent, &szCurrent);
-    } else {
-        // generate a default material
-        const int iMode = (int)aiShadingMode_Gouraud;
-        aiMaterial *pcHelper = new aiMaterial();
-        pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
-
-        aiColor3D clr;
-        clr.b = clr.g = clr.r = 0.6f;
-        pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
-        pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
-
-        clr.b = clr.g = clr.r = 0.05f;
-        pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
-
-        aiString szName;
-        szName.Set(AI_DEFAULT_MATERIAL_NAME);
-        pcHelper->AddProperty(&szName, AI_MATKEY_NAME);
-
-        // add the material to the scene
-        pScene->mNumMaterials = 1;
-        pScene->mMaterials = new aiMaterial *[1];
-        pScene->mMaterials[0] = pcHelper;
-    }
+        *szCurrentOut = szCurrent;
+        return;
+    } 
+
+    // generate a default material
+    const int iMode = (int)aiShadingMode_Gouraud;
+    aiMaterial *pcHelper = new aiMaterial();
+    pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+
+    aiColor3D clr;
+    clr.b = clr.g = clr.r = 0.6f;
+    pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
+    pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
+
+    clr.b = clr.g = clr.r = 0.05f;
+    pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
+
+    aiString szName;
+    szName.Set(AI_DEFAULT_MATERIAL_NAME);
+    pcHelper->AddProperty(&szName, AI_MATKEY_NAME);
+
+    // add the material to the scene
+    pScene->mNumMaterials = 1;
+    pScene->mMaterials = new aiMaterial *[1];
+    pScene->mMaterials[0] = pcHelper;
     *szCurrentOut = szCurrent;
 }
 
@@ -373,27 +377,36 @@ void HMPImporter::CreateOutputFaceList(unsigned int width, unsigned int height)
     aiVector3D *pcUVOut(pcUVs);
 
     // Build the terrain square
+    const unsigned int upperBound = pcMesh->mNumVertices;
     unsigned int iCurrent = 0;
     for (unsigned int y = 0; y < height - 1; ++y) {
+        const size_t offset0 = y * width;
+        const size_t offset1 = (y + 1) * width;
         for (unsigned int x = 0; x < width - 1; ++x, ++pcFaceOut) {
             pcFaceOut->mNumIndices = 4;
             pcFaceOut->mIndices = new unsigned int[4];
+            if ((offset0 + x + 1) >= upperBound){
+                continue;
+            }
+            if ((offset1 + x + 1) >= upperBound){
+                continue;
+            }
 
-            *pcVertOut++ = pcMesh->mVertices[y * width + x];
-            *pcVertOut++ = pcMesh->mVertices[(y + 1) * width + x];
-            *pcVertOut++ = pcMesh->mVertices[(y + 1) * width + x + 1];
-            *pcVertOut++ = pcMesh->mVertices[y * width + x + 1];
+            *pcVertOut++ = pcMesh->mVertices[offset0 + x];
+            *pcVertOut++ = pcMesh->mVertices[offset1 + x];
+            *pcVertOut++ = pcMesh->mVertices[offset1 + x + 1];
+            *pcVertOut++ = pcMesh->mVertices[offset0 + x + 1];
 
-            *pcNorOut++ = pcMesh->mNormals[y * width + x];
-            *pcNorOut++ = pcMesh->mNormals[(y + 1) * width + x];
-            *pcNorOut++ = pcMesh->mNormals[(y + 1) * width + x + 1];
-            *pcNorOut++ = pcMesh->mNormals[y * width + x + 1];
+            *pcNorOut++ = pcMesh->mNormals[offset0 + x];
+            *pcNorOut++ = pcMesh->mNormals[offset1 + x];
+            *pcNorOut++ = pcMesh->mNormals[offset1 + x + 1];
+            *pcNorOut++ = pcMesh->mNormals[offset0 + x + 1];
 
             if (pcMesh->mTextureCoords[0]) {
-                *pcUVOut++ = pcMesh->mTextureCoords[0][y * width + x];
-                *pcUVOut++ = pcMesh->mTextureCoords[0][(y + 1) * width + x];
-                *pcUVOut++ = pcMesh->mTextureCoords[0][(y + 1) * width + x + 1];
-                *pcUVOut++ = pcMesh->mTextureCoords[0][y * width + x + 1];
+                *pcUVOut++ = pcMesh->mTextureCoords[0][offset0 + x];
+                *pcUVOut++ = pcMesh->mTextureCoords[0][offset1 + x];
+                *pcUVOut++ = pcMesh->mTextureCoords[0][offset1 + x + 1];
+                *pcUVOut++ = pcMesh->mTextureCoords[0][offset0 + x + 1];
             }
 
             for (unsigned int i = 0; i < 4; ++i)

+ 9 - 9
code/AssetLib/IFC/IFCBoolean.cpp

@@ -66,12 +66,12 @@ bool IntersectSegmentPlane(const IfcVector3 &p, const IfcVector3 &n, const IfcVe
 
     // if segment ends on plane, do not report a hit. We stay on that side until a following segment starting at this
     // point leaves the plane through the other side
-    if (std::abs(dotOne + dotTwo) < 1e-6)
+    if (std::abs(dotOne + dotTwo) < ai_epsilon)
         return false;
 
     // if segment starts on the plane, report a hit only if the end lies on the *other* side
-    if (std::abs(dotTwo) < 1e-6) {
-        if ((assumeStartOnWhiteSide && dotOne + dotTwo < 1e-6) || (!assumeStartOnWhiteSide && dotOne + dotTwo > -1e-6)) {
+    if (std::abs(dotTwo) < ai_epsilon) {
+        if ((assumeStartOnWhiteSide && dotOne + dotTwo < ai_epsilon) || (!assumeStartOnWhiteSide && dotOne + dotTwo > -ai_epsilon)) {
             out = e0;
             return true;
         } else {
@@ -81,7 +81,7 @@ bool IntersectSegmentPlane(const IfcVector3 &p, const IfcVector3 &n, const IfcVe
 
     // ignore if segment is parallel to plane and far away from it on either side
     // Warning: if there's a few thousand of such segments which slowly accumulate beyond the epsilon, no hit would be registered
-    if (std::abs(dotOne) < 1e-6)
+    if (std::abs(dotOne) < ai_epsilon)
         return false;
 
     // t must be in [0..1] if the intersection point is within the given segment
@@ -163,7 +163,7 @@ void ProcessBooleanHalfSpaceDifference(const Schema_2x3::IfcHalfSpaceSolid *hs,
     for (iit = begin; iit != end; vidx += *iit++) {
 
         unsigned int newcount = 0;
-        bool isAtWhiteSide = (in[vidx] - p) * n > -1e-6;
+        bool isAtWhiteSide = (in[vidx] - p) * n > -ai_epsilon;
         for (unsigned int i = 0; i < *iit; ++i) {
             const IfcVector3 &e0 = in[vidx + i], e1 = in[vidx + (i + 1) % *iit];
 
@@ -259,7 +259,7 @@ bool IntersectsBoundaryProfile(const IfcVector3 &e0, const IfcVector3 &e1, const
         // segment-segment intersection
         // solve b0 + b*s = e0 + e*t for (s,t)
         const IfcFloat det = (-b.x * e.y + e.x * b.y);
-        if (std::abs(det) < 1e-6) {
+        if (std::abs(det) < ai_epsilon) {
             // no solutions (parallel lines)
             continue;
         }
@@ -316,7 +316,7 @@ bool IntersectsBoundaryProfile(const IfcVector3 &e0, const IfcVector3 &e1, const
 
         // for a valid intersection, s and t should be in range [0,1]. Including a bit of epsilon on s, potential double
         // hits on two consecutive boundary segments are filtered
-        if (s >= -1e-6 * b_sqlen_inv && s <= 1.0 + 1e-6 * b_sqlen_inv && t >= 0.0 && (t <= 1.0 || halfOpen)) {
+        if (s >= -ai_epsilon * b_sqlen_inv && s <= 1.0 + ai_epsilon * b_sqlen_inv && t >= 0.0 && (t <= 1.0 || halfOpen)) {
             // only insert the point into the list if it is sufficiently far away from the previous intersection point.
             // This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments.
             if (!intersect_results.empty() && intersect_results.back().first == i - 1) {
@@ -431,14 +431,14 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const Schema_2x3::IfcPoly
 
             // if the poly is parallel to the plane, put it completely on the black or white side
             if (std::abs(polyNormal * n) > 0.9999) {
-                bool isOnWhiteSide = (srcVertices[0] - p) * n > -1e-6;
+                bool isOnWhiteSide = (srcVertices[0] - p) * n > -ai_epsilon;
                 std::vector<IfcVector3> &targetSide = isOnWhiteSide ? whiteside : blackside;
                 targetSide.insert(targetSide.end(), srcVertices, srcVertices + srcVtxCount);
             } else {
                 // otherwise start building one polygon for each side. Whenever the current line segment intersects the plane
                 // we put a point there as an end of the current segment. Then we switch to the other side, put a point there, too,
                 // as a beginning of the current segment, and simply continue accumulating vertices.
-                bool isCurrentlyOnWhiteSide = ((srcVertices[0]) - p) * n > -1e-6;
+                bool isCurrentlyOnWhiteSide = ((srcVertices[0]) - p) * n > -ai_epsilon;
                 for (size_t a = 0; a < srcVtxCount; ++a) {
                     IfcVector3 e0 = srcVertices[a];
                     IfcVector3 e1 = srcVertices[(a + 1) % srcVtxCount];

+ 5 - 7
code/AssetLib/IFC/IFCGeometry.cpp

@@ -380,21 +380,19 @@ void ProcessSweptDiskSolid(const Schema_2x3::IfcSweptDiskSolid &solid, TempMesh&
         bool take_any = false;
 
         for (unsigned int j = 0; j < 2; ++j, take_any = true) {
-            if ((last_dir == 0 || take_any) && std::abs(d.x) > 1e-6) {
+            if ((last_dir == 0 || take_any) && std::abs(d.x) > ai_epsilon) {
                 q.y = startvec.y;
                 q.z = startvec.z;
                 q.x = -(d.y * q.y + d.z * q.z) / d.x;
                 last_dir = 0;
                 break;
-            }
-            else if ((last_dir == 1 || take_any) && std::abs(d.y) > 1e-6) {
+            } else if ((last_dir == 1 || take_any) && std::abs(d.y) > ai_epsilon) {
                 q.x = startvec.x;
                 q.z = startvec.z;
                 q.y = -(d.x * q.x + d.z * q.z) / d.y;
                 last_dir = 1;
                 break;
-            }
-            else if ((last_dir == 2 && std::abs(d.z) > 1e-6) || take_any) {
+            } else if ((last_dir == 2 && std::abs(d.z) > ai_epsilon) || take_any) {
                 q.y = startvec.y;
                 q.x = startvec.x;
                 q.z = -(d.y * q.y + d.x * q.x) / d.z;
@@ -529,7 +527,7 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVect
     return m;
 }
 
-const auto closeDistance = 1e-6;
+const auto closeDistance = ai_epsilon;
 
 bool areClose(Schema_2x3::IfcCartesianPoint pt1,Schema_2x3::IfcCartesianPoint pt2) {
     if(pt1.Coordinates.size() != pt2.Coordinates.size())
@@ -561,7 +559,7 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
     // Outline: 'curve' is now a list of vertex points forming the underlying profile, extrude along the given axis,
     // forming new triangles.
     const bool has_area = solid.SweptArea->ProfileType == "AREA" && curve.mVerts.size() > 2;
-    if( solid.Depth < 1e-6 ) {
+    if (solid.Depth < ai_epsilon) {
         if( has_area ) {
             result.Append(curve);
         }

+ 3 - 3
code/AssetLib/IFC/IFCOpenings.cpp

@@ -1133,7 +1133,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
     }
 
     for(size_t i = 0; i < out_contour.size(); ++i) {
-        ai_assert((out_contour[i]-out_contour2[i]).SquareLength() < 1e-6);
+        ai_assert((out_contour[i] - out_contour2[i]).SquareLength() < ai_epsilon);
     }
 #endif
 
@@ -1435,7 +1435,7 @@ std::vector<IfcVector2> GetContourInPlane2D(std::shared_ptr<TempMesh> mesh,IfcMa
 
     const auto outernor = ((mesh->mVerts[2] - mesh->mVerts[0]) ^ (mesh->mVerts[1] - mesh->mVerts[0])).Normalize();
     const IfcFloat dot = planeNor * outernor;
-    if(std::fabs(dot) < 1.f - 1e-6f) {
+    if (std::fabs(dot) < 1.f - ai_epsilon) {
         std::stringstream msg;
         msg << "Skipping: Unaligned opening (" << planeNor.x << ", " << planeNor.y << ", " << planeNor.z << ")";
         msg << " . ( " << outernor.x << ", " << outernor.y << ", " << outernor.z << ") = " << dot;
@@ -1476,7 +1476,7 @@ std::vector<IfcVector2> GetContourInPlane2D(std::shared_ptr<TempMesh> mesh,IfcMa
     return contour;
 }
 
-const float close { 1e-6f };
+const float close{ ai_epsilon };
 
 static bool isClose(IfcVector2 first,IfcVector2 second) {
     auto diff = (second - first);

+ 11 - 13
code/AssetLib/IFC/IFCUtil.cpp

@@ -228,25 +228,24 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
 
 // ------------------------------------------------------------------------------------------------
 // Compute the normal of the last polygon in the given mesh
-IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const
-{
+IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
     return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize);
 }
 
-struct CompareVector
-{
-    bool operator () (const IfcVector3& a, const IfcVector3& b) const
-    {
+struct CompareVector {
+    bool operator () (const IfcVector3& a, const IfcVector3& b) const {
         IfcVector3 d = a - b;
-        IfcFloat eps = 1e-6;
+        IfcFloat eps = ai_epsilon;
         return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
     }
 };
-struct FindVector
-{
+
+struct FindVector {
     IfcVector3 v;
     FindVector(const IfcVector3& p) : v(p) { }
-    bool operator () (const IfcVector3& p) { return FuzzyVectorCompare(1e-6)(p, v); }
+    bool operator()(const IfcVector3 &p) {
+        return FuzzyVectorCompare(ai_epsilon)(p, v);
+    }
 };
 
 // ------------------------------------------------------------------------------------------------
@@ -357,8 +356,7 @@ void TempMesh::FixupFaceOrientation()
                 // to reverse the neighbour
                 nb_vidx = (nb_vidx + 1) % nbvc;
                 size_t oursideidx = (a + 1) % vc;
-                if( FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx]) )
-                {
+                if (FuzzyVectorCompare(ai_epsilon)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx])) {
                     std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
                     std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
                     for (size_t aa = 0; aa < nbvc - 1; ++aa) {
@@ -564,7 +562,7 @@ void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
         out[static_cast<unsigned int>(i)] = in.DirectionRatios[i];
     }
     const IfcFloat len = out.Length();
-    if (len<1e-6) {
+    if (len < ai_epsilon) {
         IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero");
         return;
     }

+ 6 - 2
code/AssetLib/LWO/LWOAnimation.cpp

@@ -83,9 +83,13 @@ AnimResolver::AnimResolver(std::list<Envelope> &_envelopes, double tick) :
         (*it).old_first = 0;
         (*it).old_last = (*it).keys.size() - 1;
 
-        if ((*it).keys.empty()) continue;
+        if ((*it).keys.empty()) {
+            continue;
+        }
+        if ((int)(*it).type < 1 || (int)(*it).type>EnvelopeType_Unknown) {
+            continue;
+        }
         switch ((*it).type) {
-
         // translation
         case LWO::EnvelopeType_Position_X:
             trans_x = &*it;

+ 5 - 1
code/AssetLib/Obj/ObjFileData.h

@@ -195,6 +195,9 @@ struct Material {
     //! PBR Anisotropy
     ai_real anisotropy;
 
+    //! bump map multipler (normal map scalar)(-bm)
+    ai_real bump_multiplier;
+
     //! Constructor
     Material() :
             diffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
@@ -208,7 +211,8 @@ struct Material {
             sheen(ai_real(1.0), ai_real(1.0), ai_real(1.0)),
             clearcoat_thickness(ai_real(0.0)),
             clearcoat_roughness(ai_real(0.0)),
-            anisotropy(ai_real(0.0)) {
+            anisotropy(ai_real(0.0)),
+            bump_multiplier(ai_real(1.0)) {
         std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false);
     }
 

+ 10 - 0
code/AssetLib/Obj/ObjFileImporter.cpp

@@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Importer.hpp>
+#include <assimp/ObjMaterial.h>
 #include <memory>
 
 static const aiImporterDesc desc = {
@@ -604,6 +605,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
 
         mat->AddProperty<int>(&sm, 1, AI_MATKEY_SHADING_MODEL);
 
+        // Preserve the original illum value
+        mat->AddProperty<int>(&pCurrentMaterial->illumination_model, 1, AI_MATKEY_OBJ_ILLUM);
+
         // Adding material colors
         mat->AddProperty(&pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT);
         mat->AddProperty(&pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
@@ -657,6 +661,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
         if (0 != pCurrentMaterial->textureBump.length) {
             mat->AddProperty(&pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
             mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_HEIGHT(0));
+            if (pCurrentMaterial->bump_multiplier != 1.0) {
+                mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_HEIGHT(0));
+            }
             if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) {
                 addTextureMappingModeProperty(mat, aiTextureType_HEIGHT);
             }
@@ -665,6 +672,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
         if (0 != pCurrentMaterial->textureNormal.length) {
             mat->AddProperty(&pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
             mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_NORMALS(0));
+            if (pCurrentMaterial->bump_multiplier != 1.0) {
+                mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_NORMALS(0));
+            }
             if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) {
                 addTextureMappingModeProperty(mat, aiTextureType_NORMALS);
             }

+ 5 - 1
code/AssetLib/Obj/ObjFileMtlImporter.cpp

@@ -472,7 +472,11 @@ void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString
             }
 
             skipToken = 2;
-        } else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size()))) {
+        } else if (!ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size()))) {
+            DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+            getFloat(it, m_DataItEnd, m_pModel->m_pCurrentMaterial->bump_multiplier);
+            skipToken = 2;
+        } else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size()))) {
             skipToken = 2;
         } else if (!ASSIMP_strincmp(pPtr, ModifyMapOption.c_str(), static_cast<unsigned int>(ModifyMapOption.size()))) {
             skipToken = 3;

+ 30 - 67
code/AssetLib/X/XFileParser.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -60,25 +58,11 @@ using namespace Assimp::Formatter;
 
 #ifndef ASSIMP_BUILD_NO_COMPRESSED_X
 
-#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#include <zlib.h>
-#else
-#include "../contrib/zlib/zlib.h"
-#endif
+#include "Common/Compression.h"
 
 // Magic identifier for MSZIP compressed data
-#define MSZIP_MAGIC 0x4B43
-#define MSZIP_BLOCK 32786
-
-// ------------------------------------------------------------------------------------------------
-// Dummy memory wrappers for use with zlib
-static void *dummy_alloc(void * /*opaque*/, unsigned int items, unsigned int size) {
-    return ::operator new(items *size);
-}
-
-static void dummy_free(void * /*opaque*/, void *address) {
-    return ::operator delete(address);
-}
+constexpr unsigned int MSZIP_MAGIC = 0x4B43;
+constexpr size_t MSZIP_BLOCK = 32786l;
 
 #endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
 
@@ -133,13 +117,13 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
         mIsBinaryFormat = true;
         compressed = true;
     } else
-        ThrowException("Unsupported xfile format '", mP[8], mP[9], mP[10], mP[11], "'");
+        ThrowException("Unsupported x-file format '", mP[8], mP[9], mP[10], mP[11], "'");
 
     // float size
     mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000 + (unsigned int)(mP[13] - 48) * 100 + (unsigned int)(mP[14] - 48) * 10 + (unsigned int)(mP[15] - 48);
 
     if (mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
-        ThrowException("Unknown float size ", mBinaryFloatSize, " specified in xfile header.");
+        ThrowException("Unknown float size ", mBinaryFloatSize, " specified in x-file header.");
 
     // The x format specifies size in bits, but we work in bytes
     mBinaryFloatSize /= 8;
@@ -171,16 +155,6 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
          * ///////////////////////////////////////////////////////////////////////
          */
 
-        // build a zlib stream
-        z_stream stream;
-        stream.opaque = nullptr;
-        stream.zalloc = &dummy_alloc;
-        stream.zfree = &dummy_free;
-        stream.data_type = (mIsBinaryFormat ? Z_BINARY : Z_ASCII);
-
-        // initialize the inflation algorithm
-        ::inflateInit2(&stream, -MAX_WBITS);
-
         // skip unknown data (checksum, flags?)
         mP += 6;
 
@@ -207,43 +181,29 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
 
             // and advance to the next offset
             P1 += ofs;
-            est_out += MSZIP_BLOCK; // one decompressed block is 32786 in size
+            est_out += MSZIP_BLOCK; // one decompressed block is 327861 in size
         }
-
+        
         // Allocate storage and terminating zero and do the actual uncompressing
+        Compression compression;
         uncompressed.resize(est_out + 1);
         char *out = &uncompressed.front();
-        while (mP + 3 < mEnd) {
-            uint16_t ofs = *((uint16_t *)mP);
-            AI_SWAP2(ofs);
-            mP += 4;
+        if (compression.open(mIsBinaryFormat ? Compression::Format::Binary : Compression::Format::ASCII,
+                Compression::FlushMode::SyncFlush, -Compression::MaxWBits)) {
+            while (mP + 3 < mEnd) {
+                uint16_t ofs = *((uint16_t *)mP);
+                AI_SWAP2(ofs);
+                mP += 4;
 
-            if (mP + ofs > mEnd + 2) {
-                throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
+                if (mP + ofs > mEnd + 2) {
+                    throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
+                }
+                out += compression.decompressBlock(mP, ofs, out, MSZIP_BLOCK);
+                mP += ofs;
             }
-
-            // push data to the stream
-            stream.next_in = (Bytef *)mP;
-            stream.avail_in = ofs;
-            stream.next_out = (Bytef *)out;
-            stream.avail_out = MSZIP_BLOCK;
-
-            // and decompress the data ....
-            int ret = ::inflate(&stream, Z_SYNC_FLUSH);
-            if (ret != Z_OK && ret != Z_STREAM_END)
-                throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
-
-            ::inflateReset(&stream);
-            ::inflateSetDictionary(&stream, (const Bytef *)out, MSZIP_BLOCK - stream.avail_out);
-
-            // and advance to the next offset
-            out += MSZIP_BLOCK - stream.avail_out;
-            mP += ofs;
+            compression.close();
         }
 
-        // terminate zlib
-        ::inflateEnd(&stream);
-
         // ok, update pointers to point to the uncompressed file data
         mP = &uncompressed[0];
         mEnd = out;
@@ -279,15 +239,16 @@ void XFileParser::ParseFile() {
     while (running) {
         // read name of next object
         std::string objectName = GetNextToken();
-        if (objectName.length() == 0)
+        if (objectName.length() == 0) {
             break;
+        }
 
         // parse specific object
-        if (objectName == "template")
+        if (objectName == "template") {
             ParseDataObjectTemplate();
-        else if (objectName == "Frame")
+        } else if (objectName == "Frame") {
             ParseDataObjectFrame(nullptr);
-        else if (objectName == "Mesh") {
+        } else if (objectName == "Mesh") {
             // some meshes have no frames at all
             Mesh *mesh = new Mesh;
             ParseDataObjectMesh(mesh);
@@ -326,11 +287,13 @@ void XFileParser::ParseDataObjectTemplate() {
     while (running) {
         std::string s = GetNextToken();
 
-        if (s == "}")
+        if (s == "}") {
             break;
+        }
 
-        if (s.length() == 0)
+        if (s.length() == 0) {
             ThrowException("Unexpected end of file reached while parsing template definition");
+        }
     }
 }
 
@@ -500,7 +463,7 @@ void XFileParser::ParseDataObjectSkinWeights(Mesh *pMesh) {
     bone.mWeights.reserve(numWeights);
 
     for (unsigned int a = 0; a < numWeights; a++) {
-        BoneWeight weight;
+        BoneWeight weight = {};
         weight.mVertex = ReadInt();
         bone.mWeights.push_back(weight);
     }

+ 31 - 61
code/AssetLib/XGL/XGLLoader.cpp

@@ -44,28 +44,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_XGL_IMPORTER
 
 #include "XGLLoader.h"
+#include "Common/Compression.h"
+
 #include <assimp/ParsingUtils.h>
 #include <assimp/fast_atof.h>
-
 #include <assimp/MemoryIOWrapper.h>
 #include <assimp/StreamReader.h>
 #include <assimp/importerdesc.h>
 #include <assimp/mesh.h>
 #include <assimp/scene.h>
-#include <cctype>
-#include <memory>
+//#include <cctype>
+//#include <memory>
 
 using namespace Assimp;
 
-// zlib is needed for compressed XGL files
-#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
-#  ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#    include <zlib.h>
-#  else
-#    include <contrib/zlib/zlib.h>
-#  endif
-#endif
-
 namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp
 
 template <>
@@ -73,6 +65,7 @@ const char *LogFunctions<XGLImporter>::Prefix() {
     static auto prefix = "XGL: ";
 	return prefix;
 }
+
 } // namespace Assimp
 
 static const aiImporterDesc desc = {
@@ -118,8 +111,8 @@ const aiImporterDesc *XGLImporter::GetInfo() const {
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
-#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
-	std::vector<Bytef> uncompressed;
+ #ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
+	std::vector<char> uncompressed;
 #endif
 
 	m_scene = pScene;
@@ -137,48 +130,16 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 #else
 		std::unique_ptr<StreamReaderLE> raw_reader(new StreamReaderLE(stream));
 
-		// build a zlib stream
-		z_stream zstream;
-		zstream.opaque = Z_NULL;
-		zstream.zalloc = Z_NULL;
-		zstream.zfree = Z_NULL;
-		zstream.data_type = Z_BINARY;
-
-		// raw decompression without a zlib or gzip header
-		inflateInit2(&zstream, -MAX_WBITS);
-
-		// skip two extra bytes, zgl files do carry a crc16 upfront (I think)
-		raw_reader->IncPtr(2);
-
-		zstream.next_in = reinterpret_cast<Bytef *>(raw_reader->GetPtr());
-		zstream.avail_in = (uInt) raw_reader->GetRemainingSize();
-
-		size_t total = 0l;
-
-		// TODO: be smarter about this, decompress directly into heap buffer
-		// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
-#define MYBLOCK 1024
-		Bytef block[MYBLOCK];
-		int ret;
-		do {
-			zstream.avail_out = MYBLOCK;
-			zstream.next_out = block;
-			ret = inflate(&zstream, Z_NO_FLUSH);
-
-			if (ret != Z_STREAM_END && ret != Z_OK) {
-				ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .XGL file");
-			}
-			const size_t have = MYBLOCK - zstream.avail_out;
-			total += have;
-			uncompressed.resize(total);
-			memcpy(uncompressed.data() + total - have, block, have);
-		} while (ret != Z_STREAM_END);
-
-		// terminate zlib
-		inflateEnd(&zstream);
-
+        Compression compression;
+        size_t total = 0l;
+        if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, -Compression::MaxWBits)) {
+            // skip two extra bytes, zgl files do carry a crc16 upfront (I think)
+            raw_reader->IncPtr(2);
+            total = compression.decompress((unsigned char *)raw_reader->GetPtr(), raw_reader->GetRemainingSize(), uncompressed);
+            compression.close();
+        }
 		// replace the input stream with a memory stream
-		stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t *>(uncompressed.data()), total));
+		stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(uncompressed.data()), total));
 #endif
 	}
 
@@ -239,7 +200,7 @@ void XGLImporter::ReadWorld(XmlNode &node, TempScope &scope) {
 	if (!nd) {
 		ThrowException("failure reading <world>");
 	}
-	if (!nd->mName.length) {
+	if (nd->mName.length == 0) {
 		nd->mName.Set("WORLD");
 	}
 
@@ -291,7 +252,8 @@ aiNode *XGLImporter::ReadObject(XmlNode &node, TempScope &scope) {
 			const std::string &s = ai_stdStrToLower(child.name());
 			if (s == "mesh") {
 				const size_t prev = scope.meshes_linear.size();
-				if (ReadMesh(child, scope)) {
+                bool empty;
+				if (ReadMesh(child, scope, empty)) {
 					const size_t newc = scope.meshes_linear.size();
 					for (size_t i = 0; i < newc - prev; ++i) {
 						meshes.push_back(static_cast<unsigned int>(i + prev));
@@ -475,12 +437,12 @@ aiMesh *XGLImporter::ToOutputMesh(const TempMaterialMesh &m) {
 }
 
 // ------------------------------------------------------------------------------------------------
-bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) {
+bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope, bool &empty) {
 	TempMesh t;
 
 	std::map<unsigned int, TempMaterialMesh> bymat;
     const unsigned int mesh_id = ReadIDAttr(node);
-
+    bool empty_mesh = true;
 	for (XmlNode &child : node.children()) {
         const std::string &s = ai_stdStrToLower(child.name());
 
@@ -539,6 +501,9 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) {
 					mid = ResolveMaterialRef(sub_child, scope);
 				}
 			}
+            if (has[0] || has[1] || has[2]) {
+                empty_mesh = false;
+            }
 
 			if (mid == ~0u) {
 				ThrowException("missing material index");
@@ -590,6 +555,11 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) {
 			scope.meshes.insert(std::pair<unsigned int, aiMesh *>(mesh_id, m));
 		}
 	}
+    if (empty_mesh) {
+        LogWarn("Mesh is empty, skipping.");
+        empty = empty_mesh;
+        return false;
+    }
 
 	// no id == not a reference, insert this mesh right *here*
 	return mesh_id == ~0u;
@@ -759,7 +729,7 @@ aiVector2D XGLImporter::ReadVec2(XmlNode &node) {
     std::string val;
     XmlParser::getValueAsString(node, val);
     const char *s = val.c_str();
-	ai_real v[2];
+    ai_real v[2] = {};
 	for (int i = 0; i < 2; ++i) {
 		if (!SkipSpaces(&s)) {
 			LogError("unexpected EOL, failed to parse vec2");
@@ -814,4 +784,4 @@ aiColor3D XGLImporter::ReadCol3(XmlNode &node) {
 	return aiColor3D(v.x, v.y, v.z);
 }
 
-#endif
+#endif // ASSIMP_BUILD_NO_XGL_IMPORTER

+ 1 - 1
code/AssetLib/XGL/XGLLoader.h

@@ -186,7 +186,7 @@ private:
     void ReadLighting(XmlNode &node, TempScope &scope);
     aiLight *ReadDirectionalLight(XmlNode &node);
     aiNode *ReadObject(XmlNode &node, TempScope &scope);
-    bool ReadMesh(XmlNode &node, TempScope &scope);
+    bool ReadMesh(XmlNode &node, TempScope &scope, bool &empty);
     void ReadMaterial(XmlNode &node, TempScope &scope);
     aiVector2D ReadVec2(XmlNode &node);
     aiVector3D ReadVec3(XmlNode &node);

+ 56 - 107
code/AssetLib/glTF/glTFAsset.h

@@ -260,20 +260,9 @@ public:
         VEC4,
         MAT2,
         MAT3,
-        MAT4 };
-
-private:
-    static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
-
-    struct Info {
-        const char *name;
-        unsigned int numComponents;
+        MAT4 
     };
 
-    template <int N>
-    struct data { static const Info infos[NUM_VALUES]; };
-
-public:
     inline static Value FromString(const char *str) {
         for (size_t i = 0; i < NUM_VALUES; ++i) {
             if (strcmp(data<0>::infos[i].name, str) == 0) {
@@ -290,40 +279,31 @@ public:
     inline static unsigned int GetNumComponents(Value type) {
         return data<0>::infos[static_cast<size_t>(type)].numComponents;
     }
+
+private:
+    static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
+    struct Info {
+        const char *name;
+        unsigned int numComponents;
+    };
+
+    template <int N>
+    struct data { 
+        static const Info infos[NUM_VALUES]; 
+    };
 };
 
 // must match the order of the AttribTypeTraits::Value enum!
 template <int N>
-const AttribType::Info
-        AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
-            { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 }
-        };
-
-/*
-    //! A reference to one top-level object, which is valid
-    //! until the Asset instance is destroyed
-    template<class T>
-    class Ref
-    {
-        std::vector<T*>* vector;
-        unsigned int index;
-
-    public:
-        Ref() : vector(0), index(0) {}
-        Ref(std::vector<T*>& vec, unsigned int idx) : vector(&vec), index(idx) {}
-
-        inline unsigned int GetIndex() const
-            { return index; }
-
-        operator bool() const
-            { return vector != 0; }
-
-        T* operator->()
-            { return (*vector)[index]; }
-
-        T& operator*()
-            { return *((*vector)[index]); }
-    };*/
+const AttribType::Info AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
+    { "SCALAR", 1 },
+    { "VEC2", 2 }, 
+    { "VEC3", 3 }, 
+    { "VEC4", 4 }, 
+    { "MAT2", 4 }, 
+    { "MAT3", 9 }, 
+    { "MAT4", 16 }
+};
 
 //! Base class for all glTF top-level objects
 struct Object {
@@ -333,6 +313,7 @@ struct Object {
     //! Objects marked as special are not exported (used to emulate the binary body buffer)
     virtual bool IsSpecial() const { return false; }
 
+    Object() = default;
     virtual ~Object() {}
 
     //! Maps special IDs to another ID, where needed. Subclasses may override it (statically)
@@ -401,21 +382,19 @@ struct Accessor : public Object {
         return Indexer(*this);
     }
 
-    Accessor() {}
+    Accessor() = default;
     void Read(Value &obj, Asset &r);
 };
 
 //! A buffer points to binary geometry, animation, or skins.
 struct Buffer : public Object {
     /********************* Types *********************/
-public:
     enum Type {
         Type_arraybuffer,
         Type_text
     };
 
-    /// \struct SEncodedRegion
-    /// Descriptor of encoded region in "bufferView".
+    /// @brief  Descriptor of encoded region in "bufferView".
     struct SEncodedRegion {
         const size_t Offset; ///< Offset from begin of "bufferView" to encoded region, in bytes.
         const size_t EncodedData_Length; ///< Size of encoded region, in bytes.
@@ -423,8 +402,7 @@ public:
         const size_t DecodedData_Length; ///< Size of decoded region, in bytes.
         const std::string ID; ///< ID of the region.
 
-        /// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID)
-        /// Constructor.
+        /// @brief Constructor.
         /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
         /// \param [in] pEncodedData_Length - size of encoded region, in bytes.
         /// \param [in] pDecodedData - pointer to decoded data array.
@@ -433,16 +411,13 @@ public:
         SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) :
                 Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {}
 
-        /// \fn ~SEncodedRegion()
         /// Destructor.
         ~SEncodedRegion() { delete[] DecodedData; }
     };
 
     /******************* Variables *******************/
 
-    //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
     size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
-    //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
 
     Type type;
 
@@ -486,7 +461,6 @@ public:
 
     bool LoadFromStream(IOStream &stream, size_t length = 0, size_t baseOffset = 0);
 
-    /// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
     /// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data.
     /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
     /// \param [in] pEncodedData_Length - size of encoded region, in bytes.
@@ -495,12 +469,10 @@ public:
     /// \param [in] pID - ID of the region.
     void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID);
 
-    /// \fn void EncodedRegion_SetCurrent(const std::string& pID)
     /// Select current encoded region by ID. \sa EncodedRegion_Current.
     /// \param [in] pID - ID of the region.
     void EncodedRegion_SetCurrent(const std::string &pID);
 
-    /// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
     /// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions.
     /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed.
     /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced.
@@ -558,37 +530,29 @@ struct Camera : public Object {
         } ortographic;
     };
 
-    Camera() {}
+    Camera() = default;
     void Read(Value &obj, Asset &r);
 };
 
 //! Image data used to create a texture.
 struct Image : public Object {
     std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required)
-
     Ref<BufferView> bufferView;
-
     std::string mimeType;
-
     int width, height;
 
-private:
-    std::unique_ptr<uint8_t[]> mData;
-    size_t mDataLength;
-
 public:
     Image();
     void Read(Value &obj, Asset &r);
-
     inline bool HasData() const { return mDataLength > 0; }
-
     inline size_t GetDataLength() const { return mDataLength; }
-
     inline const uint8_t *GetData() const { return mData.get(); }
-
     inline uint8_t *StealData();
-
     inline void SetData(uint8_t *data, size_t length, Asset &r);
+
+private:
+    std::unique_ptr<uint8_t[]> mData;
+    size_t mDataLength;
 };
 
 //! Holds a material property that can be a texture or a color
@@ -671,6 +635,7 @@ struct Mesh : public Object {
     };
 
 #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+
     /// \struct SCompression_Open3DGC
     /// Compression of mesh data using Open3DGC algorithm.
     struct SCompression_Open3DGC : public SExtension {
@@ -703,7 +668,6 @@ struct Mesh : public Object {
 
     Mesh() {}
 
-    /// \fn ~Mesh()
     /// Destructor.
     ~Mesh() {
         for (std::list<SExtension *>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) {
@@ -711,15 +675,13 @@ struct Mesh : public Object {
         };
     }
 
-    /// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root)
-    /// Get mesh data from JSON-object and place them to root asset.
+    /// @brief Get mesh data from JSON-object and place them to root asset.
     /// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
     /// \param [out] pAsset_Root - reference to root asset where data will be stored.
     void Read(Value &pJSON_Object, Asset &pAsset_Root);
 
 #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-    /// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
-    /// Decode part of "buffer" which encoded with Open3DGC algorithm.
+    /// @brief Decode part of "buffer" which encoded with Open3DGC algorithm.
     /// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region.
     /// \param [out] pAsset_Root - reference to root assed where data will be stored.
     void Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DGC, Asset &pAsset_Root);
@@ -759,7 +721,7 @@ struct Sampler : public Object {
     SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required)
     SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required)
 
-    Sampler() {}
+    Sampler() = default;
     void Read(Value &obj, Asset &r);
     void SetDefaults();
 };
@@ -767,12 +729,12 @@ struct Sampler : public Object {
 struct Scene : public Object {
     std::vector<Ref<Node>> nodes;
 
-    Scene() {}
+    Scene() = default;
     void Read(Value &obj, Asset &r);
 };
 
 struct Shader : public Object {
-    Shader() {}
+    Shader() = default;
     void Read(Value &obj, Asset &r);
 };
 
@@ -782,7 +744,7 @@ struct Skin : public Object {
     std::vector<Ref<Node>> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin.
     std::string name; //!< The user-defined name of this object.
 
-    Skin() {}
+    Skin() = default;
     void Read(Value &obj, Asset &r);
 };
 
@@ -796,7 +758,7 @@ struct Technique : public Object {
     struct Functions {
     };
 
-    Technique() {}
+    Technique() = default;
     void Read(Value &obj, Asset &r);
 };
 
@@ -805,13 +767,7 @@ struct Texture : public Object {
     Ref<Sampler> sampler; //!< The ID of the sampler used by this texture. (required)
     Ref<Image> source; //!< The ID of the image used by this texture. (required)
 
-    //TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA)
-    //TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA)
-
-    //TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D)
-    //TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE)
-
-    Texture() {}
+    Texture() = default;
     void Read(Value &obj, Asset &r);
 };
 
@@ -826,7 +782,6 @@ struct Light : public Object {
     };
 
     Type type;
-
     vec4 color;
     float distance;
     float constantAttenuation;
@@ -835,9 +790,8 @@ struct Light : public Object {
     float falloffAngle;
     float falloffExponent;
 
-    Light() {}
+    Light() = default;
     void Read(Value &obj, Asset &r);
-
     void SetDefaults();
 };
 
@@ -865,15 +819,11 @@ struct Animation : public Object {
         Ref<Accessor> translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors.
     };
 
-    // AnimChannel Channels[3];            //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
-    // AnimParameters Parameters;          //!< The samplers that interpolate between the key-frames.
-    // AnimSampler Samplers[3];            //!< The parameterized inputs representing the key-frame data.
-
     std::vector<AnimChannel> Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
     AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
     std::vector<AnimSampler> Samplers; //!< The parameterized inputs representing the key-frame data.
 
-    Animation() {}
+    Animation() = default;
     void Read(Value &obj, Asset &r);
 };
 
@@ -963,13 +913,11 @@ struct AssetMetadata {
 
 //! Root object for a glTF asset
 class Asset {
-    typedef std::gltf_unordered_map<std::string, int> IdMap;
+    using IdMap = std::gltf_unordered_map<std::string, int>;
 
     template <class T>
     friend class LazyDict;
-
     friend struct Buffer; // To access OpenFile
-
     friend class AssetWriter;
 
 private:
@@ -1010,12 +958,9 @@ public:
     LazyDict<Material> materials;
     LazyDict<Mesh> meshes;
     LazyDict<Node> nodes;
-    //LazyDict<Program>   programs;
     LazyDict<Sampler> samplers;
     LazyDict<Scene> scenes;
-    //LazyDict<Shader>    shaders;
     LazyDict<Skin> skins;
-    //LazyDict<Technique> techniques;
     LazyDict<Texture> textures;
 
     LazyDict<Light> lights; // KHR_materials_common ext
@@ -1024,16 +969,20 @@ public:
 
 public:
     Asset(IOSystem *io = 0) :
-            mIOSystem(io), asset(), accessors(*this, "accessors"), animations(*this, "animations"), buffers(*this, "buffers"), bufferViews(*this, "bufferViews"), cameras(*this, "cameras"), images(*this, "images"), materials(*this, "materials"), meshes(*this, "meshes"), nodes(*this, "nodes")
-            //, programs    (*this, "programs")
-            ,
+            mIOSystem(io), 
+            asset(), 
+            accessors(*this, "accessors"), 
+            animations(*this, "animations"), 
+            buffers(*this, "buffers"), 
+            bufferViews(*this, "bufferViews"), 
+            cameras(*this, "cameras"), 
+            images(*this, "images"), 
+            materials(*this, "materials"), 
+            meshes(*this, "meshes"), 
+            nodes(*this, "nodes"),
             samplers(*this, "samplers"),
-            scenes(*this, "scenes")
-            //, shaders     (*this, "shaders")
-            ,
-            skins(*this, "skins")
-            //, techniques  (*this, "techniques")
-            ,
+            scenes(*this, "scenes"),
+            skins(*this, "skins"),
             textures(*this, "textures"),
             lights(*this, "lights", "KHR_materials_common") {
         memset(&extensionsUsed, 0, sizeof(extensionsUsed));

+ 0 - 2
code/AssetLib/glTF/glTFCommon.h

@@ -237,8 +237,6 @@ bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out);
 #define CHECK_EXT(EXT) \
     if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
 
-
-
 //! Helper struct to represent values that might not be present
 template <class T>
 struct Nullable {

+ 47 - 29
code/AssetLib/glTF2/glTF2Asset.h

@@ -106,7 +106,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #       define gltf_unordered_map tr1::unordered_map
 #       define gltf_unordered_set tr1::unordered_set
 #   else
-#      define gltf_unordered_map unordered_map
+#       define gltf_unordered_map unordered_map
 #       define gltf_unordered_set unordered_set
 #   endif
 #endif
@@ -1087,29 +1087,11 @@ class Asset {
 
     template <class T>
     friend class LazyDict;
-
     friend struct Buffer; // To access OpenFile
-
     friend class AssetWriter;
 
-private:
-    IOSystem *mIOSystem;
-    rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
-
-    std::string mCurrentAssetDir;
-
-    size_t mSceneLength;
-    size_t mBodyOffset, mBodyLength;
-
     std::vector<LazyDictBase *> mDicts;
 
-    IdMap mUsedIds;
-
-    Ref<Buffer> mBodyBuffer;
-
-    Asset(Asset &);
-    Asset &operator=(const Asset &);
-
 public:
     //! Keeps info about the enabled extensions
     struct Extensions {
@@ -1125,16 +1107,36 @@ public:
         bool KHR_draco_mesh_compression;
         bool FB_ngon_encoding;
         bool KHR_texture_basisu;
+
+        Extensions() :
+                KHR_materials_pbrSpecularGlossiness(false), 
+                KHR_materials_unlit(false), 
+                KHR_lights_punctual(false), 
+                KHR_texture_transform(false), 
+                KHR_materials_sheen(false), 
+                KHR_materials_clearcoat(false), 
+                KHR_materials_transmission(false), 
+                KHR_materials_volume(false),
+                KHR_materials_ior(false),
+                KHR_draco_mesh_compression(false),
+                FB_ngon_encoding(false),
+                KHR_texture_basisu(false) {
+            // empty
+        }
     } extensionsUsed;
 
     //! Keeps info about the required extensions
     struct RequiredExtensions {
         bool KHR_draco_mesh_compression;
         bool KHR_texture_basisu;
+
+        RequiredExtensions() : KHR_draco_mesh_compression(false), KHR_texture_basisu(false) {
+            // empty
+        }
     } extensionsRequired;
 
     AssetMetadata asset;
-    Value *extras = nullptr;
+    Value *extras;
 
     // Dictionaries for each type of object
 
@@ -1156,10 +1158,12 @@ public:
     Ref<Scene> scene;
 
 public:
-    Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) : 
-            mIOSystem(io),
-            mSchemaDocumentProvider(schemaDocumentProvider),
+    Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) :
+            mDicts(),
+            extensionsUsed(),
+            extensionsRequired(),
             asset(),
+            extras(nullptr),
             accessors(*this, "accessors"),
             animations(*this, "animations"),
             buffers(*this, "buffers"),
@@ -1173,9 +1177,10 @@ public:
             samplers(*this, "samplers"),
             scenes(*this, "scenes"),
             skins(*this, "skins"),
-            textures(*this, "textures") {
-        memset(&extensionsUsed, 0, sizeof(extensionsUsed));
-        memset(&extensionsRequired, 0, sizeof(extensionsRequired));
+            textures(*this, "textures") ,
+            mIOSystem(io),
+            mSchemaDocumentProvider(schemaDocumentProvider) {
+        // empty
     }
 
     //! Main function
@@ -1192,18 +1197,31 @@ public:
 
     Ref<Buffer> GetBodyBuffer() { return mBodyBuffer; }
 
+    Asset(Asset &) = delete;
+    Asset &operator=(const Asset &) = delete;
+
 private:
     void ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData);
 
-    //! Obtain a JSON document from the stream.
-    // \param second argument is a buffer used by the document. It must be kept
-    // alive while the document is in use.
+    /// Obtain a JSON document from the stream.
+    /// \param second argument is a buffer used by the document. It must be kept
+    /// alive while the document is in use.
     Document ReadDocument(IOStream& stream, bool isBinary, std::vector<char>& sceneData);
 
     void ReadExtensionsUsed(Document &doc);
     void ReadExtensionsRequired(Document &doc);
 
     IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false);
+
+private:
+    IOSystem *mIOSystem;
+    rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
+    std::string mCurrentAssetDir;
+    size_t mSceneLength;
+    size_t mBodyOffset;
+    size_t mBodyLength;
+    IdMap mUsedIds;
+    Ref<Buffer> mBodyBuffer;
 };
 
 inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) {

+ 99 - 91
code/AssetLib/glTF2/glTF2Exporter.cpp

@@ -515,72 +515,74 @@ void glTF2Exporter::GetMatTexProp(const aiMaterial &mat, float &prop, const char
 }
 
 void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot = 0) {
-    if (mat.GetTextureCount(tt) > 0) {
-        aiString tex;
-
-        // Read texcoord (UV map index)
-        mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord);
+    if (mat.GetTextureCount(tt) == 0) {
+        return;
+    }
+        
+    aiString tex;
 
-        if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
-            std::string path = tex.C_Str();
+    // Read texcoord (UV map index)
+    mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord);
 
-            if (path.size() > 0) {
-                std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path);
-                if (it != mTexturesByPath.end()) {
-                    texture = mAsset->textures.Get(it->second);
-                }
+    if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
+        std::string path = tex.C_Str();
 
-                bool useBasisUniversal = false;
-                if (!texture) {
-                    std::string texId = mAsset->FindUniqueID("", "texture");
-                    texture = mAsset->textures.Create(texId);
-                    mTexturesByPath[path] = texture.GetIndex();
-
-                    std::string imgId = mAsset->FindUniqueID("", "image");
-                    texture->source = mAsset->images.Create(imgId);
-
-                    const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str());
-                    if (curTex != nullptr) { // embedded
-                        texture->source->name = curTex->mFilename.C_Str();
-
-                        //basisu: embedded ktx2, bu
-                        if (curTex->achFormatHint[0]) {
-                            std::string mimeType = "image/";
-                            if (memcmp(curTex->achFormatHint, "jpg", 3) == 0)
-                                mimeType += "jpeg";
-                            else if (memcmp(curTex->achFormatHint, "ktx", 3) == 0) {
-                                useBasisUniversal = true;
-                                mimeType += "ktx";
-                            } else if (memcmp(curTex->achFormatHint, "kx2", 3) == 0) {
-                                useBasisUniversal = true;
-                                mimeType += "ktx2";
-                            } else if (memcmp(curTex->achFormatHint, "bu", 2) == 0) {
-                                useBasisUniversal = true;
-                                mimeType += "basis";
-                            } else
-                                mimeType += curTex->achFormatHint;
-                            texture->source->mimeType = mimeType;
-                        }
+        if (path.size() > 0) {
+            std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path);
+            if (it != mTexturesByPath.end()) {
+                texture = mAsset->textures.Get(it->second);
+            }
 
-                        // The asset has its own buffer, see Image::SetData
-                        //basisu: "image/ktx2", "image/basis" as is
-                        texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
-                    } else {
-                        texture->source->uri = path;
-                        if (texture->source->uri.find(".ktx") != std::string::npos ||
-                                texture->source->uri.find(".basis") != std::string::npos) {
+            bool useBasisUniversal = false;
+            if (!texture) {
+                std::string texId = mAsset->FindUniqueID("", "texture");
+                texture = mAsset->textures.Create(texId);
+                mTexturesByPath[path] = texture.GetIndex();
+
+                std::string imgId = mAsset->FindUniqueID("", "image");
+                texture->source = mAsset->images.Create(imgId);
+
+                const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str());
+                if (curTex != nullptr) { // embedded
+                    texture->source->name = curTex->mFilename.C_Str();
+
+                    //basisu: embedded ktx2, bu
+                    if (curTex->achFormatHint[0]) {
+                        std::string mimeType = "image/";
+                        if (memcmp(curTex->achFormatHint, "jpg", 3) == 0)
+                            mimeType += "jpeg";
+                        else if (memcmp(curTex->achFormatHint, "ktx", 3) == 0) {
                             useBasisUniversal = true;
-                        }
+                            mimeType += "ktx";
+                        } else if (memcmp(curTex->achFormatHint, "kx2", 3) == 0) {
+                            useBasisUniversal = true;
+                            mimeType += "ktx2";
+                        } else if (memcmp(curTex->achFormatHint, "bu", 2) == 0) {
+                            useBasisUniversal = true;
+                            mimeType += "basis";
+                        } else
+                            mimeType += curTex->achFormatHint;
+                        texture->source->mimeType = mimeType;
                     }
 
-                    //basisu
-                    if (useBasisUniversal) {
-                        mAsset->extensionsUsed.KHR_texture_basisu = true;
-                        mAsset->extensionsRequired.KHR_texture_basisu = true;
+                    // The asset has its own buffer, see Image::SetData
+                    //basisu: "image/ktx2", "image/basis" as is
+                    texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
+                } else {
+                    texture->source->uri = path;
+                    if (texture->source->uri.find(".ktx") != std::string::npos ||
+                            texture->source->uri.find(".basis") != std::string::npos) {
+                        useBasisUniversal = true;
                     }
+                }
 
-                    GetTexSampler(mat, texture, tt, slot);
+                //basisu
+                if (useBasisUniversal) {
+                    mAsset->extensionsUsed.KHR_texture_basisu = true;
+                    mAsset->extensionsRequired.KHR_texture_basisu = true;
                 }
+
+                GetTexSampler(mat, texture, tt, slot);
             }
         }
     }
@@ -588,12 +590,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
 
 void glTF2Exporter::GetMatTex(const aiMaterial &mat, TextureInfo &prop, aiTextureType tt, unsigned int slot = 0) {
     Ref<Texture> &texture = prop.texture;
-
     GetMatTex(mat, texture, prop.texCoord, tt, slot);
-
-    //if (texture) {
-    //    GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
-    //}
 }
 
 void glTF2Exporter::GetMatTex(const aiMaterial &mat, NormalTextureInfo &prop, aiTextureType tt, unsigned int slot = 0) {
@@ -681,12 +678,14 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
 
 bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) {
     // Return true if got any valid Sheen properties or textures
-    if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS)
+    if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) {
         return false;
+    }
 
     // Default Sheen color factor {0,0,0} disables Sheen, so do not export
-    if (sheen.sheenColorFactor == defaultSheenFactor)
+    if (sheen.sheenColorFactor == defaultSheenFactor) {
         return false;
+    }
 
     mat.Get(AI_MATKEY_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor);
 
@@ -781,9 +780,7 @@ void glTF2Exporter::ExportMaterials() {
             aiColor4D specularColor;
             ai_real shininess;
 
-            if (
-                    mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS &&
-                    mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
+            if (mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
                 // convert specular color to luminance
                 float specularIntensity = specularColor[0] * 0.2125f + specularColor[1] * 0.7154f + specularColor[2] * 0.0721f;
                 //normalize shininess (assuming max is 1000) with an inverse exponentional curve
@@ -916,7 +913,8 @@ Ref<Node> FindSkeletonRootJoint(Ref<Skin> &skinRef) {
     return parentNodeRef;
 }
 
-void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buffer> &bufferRef, Ref<Skin> &skinRef, std::vector<aiMatrix4x4> &inverseBindMatricesData) {
+void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buffer> &bufferRef, Ref<Skin> &skinRef, 
+        std::vector<aiMatrix4x4> &inverseBindMatricesData) {
     if (aimesh->mNumBones < 1) {
         return;
     }
@@ -986,7 +984,8 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buf
     } // End: for-loop mNumMeshes
 
     Mesh::Primitive &p = meshRef->primitives.back();
-    Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
+    Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, 
+        vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
     if (vertexJointAccessor) {
         size_t offset = vertexJointAccessor->bufferView->byteOffset;
         size_t bytesLen = vertexJointAccessor->bufferView->byteLength;
@@ -1069,8 +1068,11 @@ void glTF2Exporter::ExportMeshes() {
         p.ngonEncoded = (aim->mPrimitiveTypes & aiPrimitiveType_NGONEncodingFlag) != 0;
 
         /******************* Vertices ********************/
-        Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
-        if (v) p.attributes.position.push_back(v);
+        Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3,
+            AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
+        if (v) {
+            p.attributes.position.push_back(v);
+        }
 
         /******************** Normals ********************/
         // Normalize all normals as the validator can emit a warning otherwise
@@ -1080,13 +1082,17 @@ void glTF2Exporter::ExportMeshes() {
             }
         }
 
-        Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
-        if (n) p.attributes.normal.push_back(n);
+        Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, 
+            AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
+        if (n) {
+            p.attributes.normal.push_back(n);
+        }
 
         /************** Texture coordinates **************/
         for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
-            if (!aim->HasTextureCoords(i))
+            if (!aim->HasTextureCoords(i)) {
                 continue;
+            }
 
             // Flip UV y coords
             if (aim->mNumUVComponents[i] > 1) {
@@ -1098,16 +1104,21 @@ void glTF2Exporter::ExportMeshes() {
             if (aim->mNumUVComponents[i] > 0) {
                 AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
 
-                Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
-                if (tc) p.attributes.texcoord.push_back(tc);
+                Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], 
+                    AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
+                if (tc) {
+                    p.attributes.texcoord.push_back(tc);
+                }
             }
         }
 
         /*************** Vertex colors ****************/
         for (unsigned int indexColorChannel = 0; indexColorChannel < aim->GetNumColorChannels(); ++indexColorChannel) {
-            Ref<Accessor> c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel], AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
-            if (c)
+            Ref<Accessor> c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel],
+                AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
+            if (c) {
                 p.attributes.color.push_back(c);
+            }
         }
 
         /*************** Vertices indices ****************/
@@ -1121,7 +1132,8 @@ void glTF2Exporter::ExportMeshes() {
                 }
             }
 
-            p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER);
+            p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR, 
+                ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER);
         }
 
         switch (aim->mPrimitiveTypes) {
@@ -1136,6 +1148,7 @@ void glTF2Exporter::ExportMeshes() {
             break;
         default: // aiPrimitiveType_TRIANGLE
             p.mode = PrimitiveMode_TRIANGLES;
+            break;
         }
 
         /*************** Skins ****************/
@@ -1155,8 +1168,9 @@ void glTF2Exporter::ExportMeshes() {
             p.targets.resize(aim->mNumAnimMeshes);
             for (unsigned int am = 0; am < aim->mNumAnimMeshes; ++am) {
                 aiAnimMesh *pAnimMesh = aim->mAnimMeshes[am];
-                if (bExportTargetNames)
-                    m->targetNames.push_back(pAnimMesh->mName.data);
+                if (bExportTargetNames) {
+                    m->targetNames.emplace_back(pAnimMesh->mName.data);
+                }
                 // position
                 if (pAnimMesh->HasPositions()) {
                     // NOTE: in gltf it is the diff stored
@@ -1319,12 +1333,12 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) {
     }
 
     for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
-        node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
+        node->meshes.emplace_back(mAsset->meshes.Get(n->mMeshes[i]));
     }
 
     for (unsigned int i = 0; i < n->mNumChildren; ++i) {
         unsigned int idx = ExportNode(n->mChildren[i], node);
-        node->children.push_back(mAsset->nodes.Get(idx));
+        node->children.emplace_back(mAsset->nodes.Get(idx));
     }
 
     return node.GetIndex();
@@ -1366,12 +1380,12 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref<Node> &parent) {
     }
 
     for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
-        node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
+        node->meshes.emplace_back(mAsset->meshes.Get(n->mMeshes[i]));
     }
 
     for (unsigned int i = 0; i < n->mNumChildren; ++i) {
         unsigned int idx = ExportNode(n->mChildren[i], node);
-        node->children.push_back(mAsset->nodes.Get(idx));
+        node->children.emplace_back(mAsset->nodes.Get(idx));
     }
 
     return node.GetIndex();
@@ -1386,7 +1400,7 @@ void glTF2Exporter::ExportScene() {
 
     // root node will be the first one exported (idx 0)
     if (mAsset->nodes.Size() > 0) {
-        scene->nodes.push_back(mAsset->nodes.Get(0u));
+        scene->nodes.emplace_back(mAsset->nodes.Get(0u));
     }
 
     // set as the default scene
@@ -1521,12 +1535,6 @@ void glTF2Exporter::ExportAnimations() {
                 AddSampler(animRef, animNode, scaleSampler, AnimationPath_SCALE);
             }
         }
-
-        // Assimp documentation states this is not used (not implemented)
-        // for (unsigned int channelIndex = 0; channelIndex < anim->mNumMeshChannels; ++channelIndex) {
-        //     const aiMeshAnim* meshChannel = anim->mMeshChannels[channelIndex];
-        // }
-
     } // End: for-loop mNumAnimations
 }
 

+ 6 - 5
code/CMakeLists.txt

@@ -166,6 +166,8 @@ SET( Logging_SRCS
 SOURCE_GROUP(Logging FILES ${Logging_SRCS})
 
 SET( Common_SRCS
+  Common/Compression.cpp
+  Common/Compression.h
   Common/BaseImporter.cpp
   Common/BaseProcess.cpp
   Common/BaseProcess.h
@@ -1315,11 +1317,10 @@ ENDIF ()
 
 INSTALL( TARGETS assimp
   EXPORT "${TARGETS_EXPORT_NAME}"
-  LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
-  ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
-  RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR}
-  FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
-  COMPONENT ${LIBASSIMP_COMPONENT}
+  LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}
+  ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP-DEV_COMPONENT}
+  RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}
+  FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}
   INCLUDES DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
 )
 INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)

+ 14 - 16
code/Common/Base64.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2021, assimp team
+Copyright (c) 2006-2022, assimp team
 
 All rights reserved.
 
@@ -57,7 +57,7 @@ static const uint8_t tableDecodeBase64[128] = {
     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0
 };
 
-static const char* tableEncodeBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+static const char *tableEncodeBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
 
 static inline char EncodeChar(uint8_t b) {
     return tableEncodeBase64[size_t(b)];
@@ -104,17 +104,16 @@ void Encode(const uint8_t *in, size_t inLength, std::string &out) {
     }
 }
 
-void Encode(const std::vector<uint8_t>& in, std::string &out) {
-    Encode (in.data (), in.size (), out);
+void Encode(const std::vector<uint8_t> &in, std::string &out) {
+    Encode(in.data(), in.size(), out);
 }
 
-std::string Encode (const std::vector<uint8_t>& in) {
+std::string Encode(const std::vector<uint8_t> &in) {
     std::string encoded;
-    Encode (in, encoded);
+    Encode(in, encoded);
     return encoded;
 }
 
-
 size_t Decode(const char *in, size_t inLength, uint8_t *&out) {
     if (inLength % 4 != 0) {
         throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)), "\", length:", inLength);
@@ -159,23 +158,22 @@ size_t Decode(const char *in, size_t inLength, uint8_t *&out) {
     return outLength;
 }
 
-size_t Decode(const std::string& in, std::vector<uint8_t>& out) {
-    uint8_t* outPtr = nullptr;
-    size_t decodedSize = Decode (in.data (), in.size (), outPtr);
+size_t Decode(const std::string &in, std::vector<uint8_t> &out) {
+    uint8_t *outPtr = nullptr;
+    size_t decodedSize = Decode(in.data(), in.size(), outPtr);
     if (outPtr == nullptr) {
         return 0;
     }
-    out.assign (outPtr, outPtr + decodedSize);
+    out.assign(outPtr, outPtr + decodedSize);
     delete[] outPtr;
     return decodedSize;
 }
 
-std::vector<uint8_t> Decode (const std::string& in) {
+std::vector<uint8_t> Decode(const std::string &in) {
     std::vector<uint8_t> result;
-    Decode (in, result);
+    Decode(in, result);
     return result;
 }
 
-}
-
-}
+} // namespace Base64
+} // namespace Assimp

+ 214 - 0
code/Common/Compression.cpp

@@ -0,0 +1,214 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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 "Compression.h"
+#include <assimp/ai_assert.h>
+#include <assimp/Exceptional.h>
+
+namespace Assimp {
+
+struct Compression::impl {
+    bool mOpen;
+    z_stream mZSstream;
+    FlushMode mFlushMode;
+
+    impl() :
+            mOpen(false),
+            mZSstream(),
+            mFlushMode(Compression::FlushMode::NoFlush) {
+        // empty
+    }
+};
+
+Compression::Compression() :
+        mImpl(new impl) {
+    // empty
+}
+
+Compression::~Compression() {
+    ai_assert(mImpl != nullptr);
+
+    delete mImpl;
+}
+
+bool Compression::open(Format format, FlushMode flush, int windowBits) {
+    ai_assert(mImpl != nullptr);
+
+    if (mImpl->mOpen) {
+        return false;
+    }
+
+    // build a zlib stream
+    mImpl->mZSstream.opaque = Z_NULL;
+    mImpl->mZSstream.zalloc = Z_NULL;
+    mImpl->mZSstream.zfree = Z_NULL;
+    mImpl->mFlushMode = flush;
+    if (format == Format::Binary) {
+        mImpl->mZSstream.data_type = Z_BINARY;
+    } else {
+        mImpl->mZSstream.data_type = Z_ASCII;
+    }
+
+    // raw decompression without a zlib or gzip header
+    if (windowBits == 0) {
+        inflateInit(&mImpl->mZSstream);
+    } else {
+        inflateInit2(&mImpl->mZSstream, windowBits);
+    }
+    mImpl->mOpen = true;
+
+    return mImpl->mOpen;
+}
+
+static int getFlushMode(Compression::FlushMode flush) {
+    int z_flush = 0;
+    switch (flush) {
+        case Compression::FlushMode::NoFlush:
+            z_flush = Z_NO_FLUSH;
+            break;
+        case Compression::FlushMode::Block:
+            z_flush = Z_BLOCK;
+            break;
+        case Compression::FlushMode::Tree:
+            z_flush = Z_TREES;
+            break;
+        case Compression::FlushMode::SyncFlush:
+            z_flush = Z_SYNC_FLUSH;
+            break;
+        case Compression::FlushMode::Finish:
+            z_flush = Z_FINISH;
+            break;
+        default:
+            ai_assert(false);
+            break;
+    }
+
+    return z_flush;
+}
+
+constexpr size_t MYBLOCK = 32786;
+
+size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
+    ai_assert(mImpl != nullptr);
+    if (data == nullptr || in == 0) {
+        return 0l;
+    }
+
+    mImpl->mZSstream.next_in = (Bytef*)(data);
+    mImpl->mZSstream.avail_in = (uInt)in;
+
+    int ret = 0;
+    size_t total = 0l;
+    const int flushMode = getFlushMode(mImpl->mFlushMode);
+    if (flushMode == Z_FINISH) {
+        mImpl->mZSstream.avail_out = static_cast<uInt>(uncompressed.size());
+        mImpl->mZSstream.next_out = reinterpret_cast<Bytef *>(&*uncompressed.begin());
+        ret = inflate(&mImpl->mZSstream, Z_FINISH);
+
+        if (ret != Z_STREAM_END && ret != Z_OK) {
+            throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
+        }
+        total = mImpl->mZSstream.avail_out;
+    } else {
+        do {
+            Bytef block[MYBLOCK] = {};
+            mImpl->mZSstream.avail_out = MYBLOCK;
+            mImpl->mZSstream.next_out = block;
+
+            ret = inflate(&mImpl->mZSstream, flushMode);
+
+            if (ret != Z_STREAM_END && ret != Z_OK) {
+                throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
+            }
+            const size_t have = MYBLOCK - mImpl->mZSstream.avail_out;
+            total += have;
+            uncompressed.resize(total);
+            ::memcpy(uncompressed.data() + total - have, block, have);
+        } while (ret != Z_STREAM_END);
+    }
+
+    return total;
+}
+
+size_t Compression::decompressBlock(const void *data, size_t in, char *out, size_t availableOut) {
+    ai_assert(mImpl != nullptr);
+    if (data == nullptr || in == 0 || out == nullptr || availableOut == 0) {
+        return 0l;
+    }
+
+    // push data to the stream
+    mImpl->mZSstream.next_in = (Bytef *)data;
+    mImpl->mZSstream.avail_in = (uInt)in;
+    mImpl->mZSstream.next_out = (Bytef *)out;
+    mImpl->mZSstream.avail_out = (uInt)availableOut;
+
+    // and decompress the data ....
+    int ret = ::inflate(&mImpl->mZSstream, Z_SYNC_FLUSH);
+    if (ret != Z_OK && ret != Z_STREAM_END) {
+        throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
+    }
+
+    ::inflateReset(&mImpl->mZSstream);
+    ::inflateSetDictionary(&mImpl->mZSstream, (const Bytef *)out, (uInt)availableOut - mImpl->mZSstream.avail_out);
+
+    return availableOut - (size_t)mImpl->mZSstream.avail_out;
+}
+
+bool Compression::isOpen() const {
+    ai_assert(mImpl != nullptr);
+
+    return mImpl->mOpen;
+}
+
+bool Compression::close() {
+    ai_assert(mImpl != nullptr);
+
+    if (!mImpl->mOpen) {
+        return false;
+    }
+
+    inflateEnd(&mImpl->mZSstream);
+    mImpl->mOpen = false;
+
+    return true;
+}
+
+} // namespace Assimp

+ 121 - 0
code/Common/Compression.h

@@ -0,0 +1,121 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2022, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#pragma once
+
+#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#include <zlib.h>
+#else
+#include "../contrib/zlib/zlib.h"
+#endif
+
+#include <vector>
+#include <cstddef> // size_t
+
+namespace Assimp {
+
+/// @brief This class provides the decompression of zlib-compressed data.
+class Compression {
+public:
+    static const int MaxWBits = MAX_WBITS;
+
+    /// @brief Describes the format data type
+    enum class Format {
+        InvalidFormat = -1, ///< Invalid enum type.
+        Binary = 0,         ///< Binary format.
+        ASCII,              ///< ASCII format.
+
+        NumFormats          ///< The number of supported formats.
+    };
+
+    /// @brief The supported flush mode, used for blocked access.
+    enum class FlushMode {
+        InvalidFormat = -1, ///< Invalid enum type.
+        NoFlush = 0,        ///< No flush, will be done on inflate end.
+        Block,              ///< Assists in combination of compress.
+        Tree,               ///< Assists in combination of compress and returns if stream is finish.
+        SyncFlush,          ///< Synced flush mode.
+        Finish,             ///< Finish mode, all in once, no block access.
+
+        NumModes            ///< The number of supported modes.
+    };
+
+    /// @brief  The class constructor.
+    Compression();
+
+    ///	@brief  The class destructor.
+    ~Compression();
+
+    /// @brief  Will open the access to the compression.
+    /// @param[in] format       The format type
+    /// @param[in] flush        The flush mode.
+    /// @param[in] windowBits   The windows history working size, shall be between 8 and 15.
+    /// @return true if close was successful, false if not.
+    bool open(Format format, FlushMode flush, int windowBits);
+
+    /// @brief  Will return the open state.
+    /// @return true if the access is opened, false if not.
+    bool isOpen() const;
+
+    /// @brief  Will close the decompress access.
+    /// @return true if close was successful, false if not.
+    bool close();
+
+    /// @brief Will decompress the data buffer in one step.
+    /// @param[in] data         The data to decompress
+    /// @param[in] in           The size of the data.
+    /// @param[out uncompressed A std::vector containing the decompressed data.
+    size_t decompress(const void *data, size_t in, std::vector<char> &uncompressed);
+
+    /// @brief Will decompress the data buffer block-wise.
+    /// @param[in]  data         The compressed data
+    /// @param[in]  in           The size of the data buffer
+    /// @param[out] out          The output buffer
+    /// @param[out] availableOut The upper limit of the output buffer.
+    /// @return The size of the decompressed data buffer.
+    size_t decompressBlock(const void *data, size_t in, char *out, size_t availableOut);
+
+private:
+    struct impl;
+    impl *mImpl;
+};
+
+} // namespace Assimp

+ 1 - 1
code/Common/IOSystem.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2022, assimp team
 
 All rights reserved.
 

+ 1 - 2
code/Common/Version.cpp

@@ -5,7 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -53,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 static const char *LEGAL_INFORMATION =
         "Open Asset Import Library (Assimp).\n"
         "A free C/C++ library to import various 3D file formats into applications\n\n"
-        "(c) 2006-2021, Assimp team\n"
+        "(c) 2006-2022, Assimp team\n"
         "License under the terms and conditions of the 3-clause BSD license\n"
         "https://www.assimp.org\n";
 

+ 0 - 1
code/Common/material.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,

+ 0 - 2
code/Common/simd.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,

+ 4 - 4
code/PostProcessing/CalcTangentsProcess.cpp

@@ -191,9 +191,9 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
         tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
         tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
         tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
-        bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
-        bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
-        bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
+        bitangent.x = (- w.x * sx + v.x * tx) * dirCorrection;
+        bitangent.y = (- w.y * sx + v.y * tx) * dirCorrection;
+        bitangent.z = (- w.z * sx + v.z * tx) * dirCorrection;
 
         // store for every vertex of that face
         for (unsigned int b = 0; b < face.mNumIndices; ++b) {
@@ -201,7 +201,7 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
 
             // project tangent and bitangent into the plane formed by the vertex' normal
             aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
-            aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
+            aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]) - localTangent * (bitangent * localTangent);
             localTangent.NormalizeSafe();
             localBitangent.NormalizeSafe();
 

+ 1 - 1
code/PostProcessing/FindDegenerates.cpp

@@ -221,7 +221,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
             if ( mConfigCheckAreaOfTriangle ) {
                 if ( face.mNumIndices == 3 ) {
                     ai_real area = calculateAreaOfTriangle( face, mesh );
-                    if ( area < 1e-6 ) {
+                    if (area < ai_epsilon) {
                         if ( mConfigRemoveDegenerates ) {
                             remove_me[ a ] = true;
                             ++deg;

+ 4 - 0
include/assimp/Base64.hpp

@@ -50,6 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace Base64 {
 
+/// @brief Will encode the given 
+/// @param in 
+/// @param inLength 
+/// @param out 
 void Encode(const uint8_t *in, size_t inLength, std::string &out);
 void Encode(const std::vector<uint8_t>& in, std::string &out);
 std::string Encode(const std::vector<uint8_t>& in);

+ 14 - 14
include/assimp/ByteSwapper.h

@@ -211,7 +211,7 @@ template <typename T> struct ByteSwap::_swapper<T,8> {
 // --------------------------------------------------------------------------------------
 #if (defined AI_BUILD_BIG_ENDIAN)
 #   define AI_LE(t) (t)
-#   define AI_BE(t) ByteSwap::Swapped(t)
+#   define AI_BE(t) Assimp::ByteSwap::Swapped(t)
 #   define AI_LSWAP2(p)
 #   define AI_LSWAP4(p)
 #   define AI_LSWAP8(p)
@@ -219,16 +219,16 @@ template <typename T> struct ByteSwap::_swapper<T,8> {
 #   define AI_LSWAP4P(p)
 #   define AI_LSWAP8P(p)
 #   define LE_NCONST const
-#   define AI_SWAP2(p) ByteSwap::Swap2(&(p))
-#   define AI_SWAP4(p) ByteSwap::Swap4(&(p))
-#   define AI_SWAP8(p) ByteSwap::Swap8(&(p))
-#   define AI_SWAP2P(p) ByteSwap::Swap2((p))
-#   define AI_SWAP4P(p) ByteSwap::Swap4((p))
-#   define AI_SWAP8P(p) ByteSwap::Swap8((p))
+#   define AI_SWAP2(p) Assimp::ByteSwap::Swap2(&(p))
+#   define AI_SWAP4(p) Assimp::ByteSwap::Swap4(&(p))
+#   define AI_SWAP8(p) Assimp::ByteSwap::Swap8(&(p))
+#   define AI_SWAP2P(p) Assimp::ByteSwap::Swap2((p))
+#   define AI_SWAP4P(p) Assimp::ByteSwap::Swap4((p))
+#   define AI_SWAP8P(p) Assimp::ByteSwap::Swap8((p))
 #   define BE_NCONST
 #else
 #   define AI_BE(t) (t)
-#   define AI_LE(t) ByteSwap::Swapped(t)
+#   define AI_LE(t) Assimp::ByteSwap::Swapped(t)
 #   define AI_SWAP2(p)
 #   define AI_SWAP4(p)
 #   define AI_SWAP8(p)
@@ -236,12 +236,12 @@ template <typename T> struct ByteSwap::_swapper<T,8> {
 #   define AI_SWAP4P(p)
 #   define AI_SWAP8P(p)
 #   define BE_NCONST const
-#   define AI_LSWAP2(p)     ByteSwap::Swap2(&(p))
-#   define AI_LSWAP4(p)     ByteSwap::Swap4(&(p))
-#   define AI_LSWAP8(p)     ByteSwap::Swap8(&(p))
-#   define AI_LSWAP2P(p)    ByteSwap::Swap2((p))
-#   define AI_LSWAP4P(p)    ByteSwap::Swap4((p))
-#   define AI_LSWAP8P(p)    ByteSwap::Swap8((p))
+#   define AI_LSWAP2(p)     Assimp::ByteSwap::Swap2(&(p))
+#   define AI_LSWAP4(p)     Assimp::ByteSwap::Swap4(&(p))
+#   define AI_LSWAP8(p)     Assimp::ByteSwap::Swap8(&(p))
+#   define AI_LSWAP2P(p)    Assimp::ByteSwap::Swap2((p))
+#   define AI_LSWAP4P(p)    Assimp::ByteSwap::Swap4((p))
+#   define AI_LSWAP8P(p)    Assimp::ByteSwap::Swap8((p))
 #   define LE_NCONST
 #endif
 

+ 0 - 8
include/assimp/Exceptional.h

@@ -98,10 +98,6 @@ public:
             DeadlyErrorBase(Assimp::Formatter::format(), std::forward<T>(args)...) {
         // empty
     }
-
-#if defined(_MSC_VER) && defined(__clang__)
-    DeadlyImportError(DeadlyImportError& other) = delete;
-#endif
 };
 
 // ---------------------------------------------------------------------------
@@ -114,10 +110,6 @@ public:
     template<typename... T>
     explicit DeadlyExportError(T&&... args) :
             DeadlyErrorBase(Assimp::Formatter::format(), std::forward<T>(args)...) {}
-
-#if defined(_MSC_VER) && defined(__clang__)
-    DeadlyExportError(DeadlyExportError& other) = delete;
-#endif
 };
 
 #ifdef _MSC_VER

+ 7 - 3
include/assimp/Hash.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -76,7 +75,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 inline uint32_t SuperFastHash (const char * data, uint32_t len = 0, uint32_t hash = 0) {
 uint32_t tmp;
 int rem;
-
+size_t offset;
+    
     if (!data) return 0;
     if (!len)len = (uint32_t)::strlen(data);
 
@@ -96,7 +96,11 @@ int rem;
     switch (rem) {
         case 3: hash += get16bits (data);
                 hash ^= hash << 16;
-                hash ^= data[sizeof (uint16_t)] << 18;
+                offset = static_cast<size_t>(sizeof(uint16_t));
+                if (offset < 0) {
+                    return 0;
+                }
+                hash ^= data[offset] << 18;
                 hash += hash >> 11;
                 break;
         case 2: hash += get16bits (data);

+ 84 - 0
include/assimp/ObjMaterial.h

@@ -0,0 +1,84 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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 OBJMATERIAL.h
+ *  @brief Obj-specific material macros
+ *  
+ */
+
+#ifndef AI_OBJMATERIAL_H_INC
+#define AI_OBJMATERIAL_H_INC
+
+#ifdef __GNUC__
+#   pragma GCC system_header
+#endif
+
+#include <assimp/material.h>
+
+// ---------------------------------------------------------------------------
+
+// the original illum property
+#define AI_MATKEY_OBJ_ILLUM "$mat.illum", 0, 0
+
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// Pure key names for all obj texture-related properties
+//! @cond MATS_DOC_FULL
+
+// support for bump -bm 
+#define _AI_MATKEY_OBJ_BUMPMULT_BASE "$tex.bumpmult"
+//! @endcond
+
+// ---------------------------------------------------------------------------
+#define AI_MATKEY_OBJ_BUMPMULT(type, N) _AI_MATKEY_OBJ_BUMPMULT_BASE, type, N
+
+//! @cond MATS_DOC_FULL
+#define AI_MATKEY_OBJ_BUMPMULT_NORMALS(N) \
+    AI_MATKEY_OBJ_BUMPMULT(aiTextureType_NORMALS, N)
+
+#define AI_MATKEY_OBJ_BUMPMULT_HEIGHT(N) \
+    AI_MATKEY_OBJ_BUMPMULT(aiTextureType_HEIGHT, N)
+
+//! @endcond
+
+
+#endif

+ 19 - 7
include/assimp/TinyFormatter.h

@@ -119,29 +119,41 @@ public:
      * work for const references, so many function prototypes will
      * include const basic_formatter<T>& s but might still want to
      * modify the formatted string without the need for a full copy.*/
-    template <typename TToken>
-    const basic_formatter& operator << (const TToken& s) const {
+    template <typename TToken, typename std::enable_if<!std::is_base_of<std::exception, TToken>::value>::type * = nullptr>
+    const basic_formatter &operator<<(const TToken &s) const {
         underlying << s;
         return *this;
     }
 
-    template <typename TToken>
-    basic_formatter& operator << (const TToken& s) {
+    template <typename TToken, typename std::enable_if<std::is_base_of<std::exception, TToken>::value>::type * = nullptr>
+    const basic_formatter &operator<<(const TToken &s) const {
+        underlying << s.what();
+        return *this;
+    }
+
+    template <typename TToken, typename std::enable_if<!std::is_base_of<std::exception, TToken>::value>::type * = nullptr>
+    basic_formatter &operator<<(const TToken &s) {
         underlying << s;
         return *this;
     }
 
+    template <typename TToken, typename std::enable_if<std::is_base_of<std::exception, TToken>::value>::type * = nullptr>
+    basic_formatter &operator<<(const TToken &s) {
+        underlying << s.what();
+        return *this;
+    }
+
 
     // comma operator overloaded as well, choose your preferred way.
     template <typename TToken>
     const basic_formatter& operator, (const TToken& s) const {
-        underlying << s;
+        *this << s;
         return *this;
     }
 
     template <typename TToken>
     basic_formatter& operator, (const TToken& s) {
-        underlying << s;
+        *this << s;
         return *this;
     }
 
@@ -149,7 +161,7 @@ public:
     // See https://sourceforge.net/projects/assimp/forums/forum/817654/topic/4372824
     template <typename TToken>
     basic_formatter& operator, (TToken& s) {
-        underlying << s;
+        *this << s;
         return *this;
     }
 

+ 3 - 3
include/assimp/defs.h

@@ -279,11 +279,11 @@ typedef unsigned int ai_uint;
 #define AI_MATH_HALF_PI_F (AI_MATH_PI_F * 0.5f)
 
 /* Tiny macro to convert from radians to degrees and back */
-#define AI_DEG_TO_RAD(x) ((x) * (ai_real)0.0174532925)
-#define AI_RAD_TO_DEG(x) ((x) * (ai_real)57.2957795)
+#define AI_DEG_TO_RAD(x) ((x) * (ai_real) 0.0174532925)
+#define AI_RAD_TO_DEG(x) ((x) * (ai_real) 57.2957795)
 
 /* Numerical limits */
-static const ai_real ai_epsilon = (ai_real)0.00001;
+static const ai_real ai_epsilon = (ai_real) 1e-6;
 
 /* Support for big-endian builds */
 #if defined(__BYTE_ORDER__)

+ 1 - 1
include/assimp/matrix3x3.h

@@ -95,7 +95,7 @@ public:
     bool operator== (const aiMatrix3x3t<TReal>& m) const;
     bool operator!= (const aiMatrix3x3t<TReal>& m) const;
 
-    bool Equal(const aiMatrix3x3t<TReal>& m, TReal epsilon = 1e-6) const;
+    bool Equal(const aiMatrix3x3t<TReal> &m, TReal epsilon = ai_epsilon) const;
 
     template <typename TOther>
     operator aiMatrix3x3t<TOther> () const;

+ 1 - 1
include/assimp/matrix4x4.h

@@ -110,7 +110,7 @@ public:
     bool operator== (const aiMatrix4x4t& m) const;
     bool operator!= (const aiMatrix4x4t& m) const;
 
-    bool Equal(const aiMatrix4x4t& m, TReal epsilon = 1e-6) const;
+    bool Equal(const aiMatrix4x4t &m, TReal epsilon = ai_epsilon) const;
 
     // matrix multiplication.
     aiMatrix4x4t& operator *= (const aiMatrix4x4t& m);

+ 1 - 1
include/assimp/quaternion.h

@@ -92,7 +92,7 @@ public:
     // transform vector by matrix
     aiQuaterniont& operator *= (const aiMatrix4x4t<TReal>& mat);
 
-    bool Equal(const aiQuaterniont& o, TReal epsilon = 1e-6) const;
+    bool Equal(const aiQuaterniont &o, TReal epsilon = ai_epsilon) const;
 
 public:
 

+ 1 - 1
include/assimp/vector2.h

@@ -85,7 +85,7 @@ public:
     bool operator== (const aiVector2t& other) const;
     bool operator!= (const aiVector2t& other) const;
 
-    bool Equal(const aiVector2t& other, TReal epsilon = 1e-6) const;
+    bool Equal(const aiVector2t &other, TReal epsilon = ai_epsilon) const;
 
     aiVector2t& operator= (TReal f);
     const aiVector2t SymMul(const aiVector2t& o);

+ 1 - 1
include/assimp/vector3.h

@@ -114,7 +114,7 @@ public:
     bool operator < (const aiVector3t& other) const;
 
     /// @brief  
-    bool Equal(const aiVector3t& other, TReal epsilon = 1e-6) const;
+    bool Equal(const aiVector3t &other, TReal epsilon = ai_epsilon) const;
 
     template <typename TOther>
     operator aiVector3t<TOther> () const;

+ 6 - 5
test/unit/Common/utMesh.cpp

@@ -60,7 +60,7 @@ protected:
 };
 
 TEST_F(utMesh, emptyMeshHasNoContentTest) {
-  EXPECT_EQ(0, mesh->mName.length);
+  EXPECT_EQ(0u, mesh->mName.length);
   EXPECT_FALSE(mesh->HasPositions());
   EXPECT_FALSE(mesh->HasFaces());
   EXPECT_FALSE(mesh->HasNormals());
@@ -69,8 +69,8 @@ TEST_F(utMesh, emptyMeshHasNoContentTest) {
   EXPECT_FALSE(mesh->HasVertexColors(AI_MAX_NUMBER_OF_COLOR_SETS));
   EXPECT_FALSE(mesh->HasTextureCoords(0));
   EXPECT_FALSE(mesh->HasTextureCoords(AI_MAX_NUMBER_OF_TEXTURECOORDS));
-  EXPECT_EQ(0, mesh->GetNumUVChannels());
-  EXPECT_EQ(0, mesh->GetNumColorChannels());
+  EXPECT_EQ(0u, mesh->GetNumUVChannels());
+  EXPECT_EQ(0u, mesh->GetNumColorChannels());
   EXPECT_FALSE(mesh->HasBones());
   EXPECT_FALSE(mesh->HasTextureCoordsName(0));
   EXPECT_FALSE(mesh->HasTextureCoordsName(AI_MAX_NUMBER_OF_TEXTURECOORDS));
@@ -80,8 +80,8 @@ TEST_F(utMesh, setTextureCoordsName) {
   EXPECT_FALSE(mesh->HasTextureCoordsName(0));
   const aiString texcoords_name("texcoord_name");
   mesh->SetTextureCoordsName(0, texcoords_name);
-  EXPECT_TRUE(mesh->HasTextureCoordsName(0));
-  EXPECT_FALSE(mesh->HasTextureCoordsName(1));
+  EXPECT_TRUE(mesh->HasTextureCoordsName(0u));
+  EXPECT_FALSE(mesh->HasTextureCoordsName(1u));
   ASSERT_NE(nullptr, mesh->mTextureCoordsNames);
   ASSERT_NE(nullptr, mesh->mTextureCoordsNames[0]);
   EXPECT_STREQ(texcoords_name.C_Str(), mesh->mTextureCoordsNames[0]->C_Str());
@@ -94,3 +94,4 @@ TEST_F(utMesh, setTextureCoordsName) {
   EXPECT_EQ(nullptr, mesh->mTextureCoordsNames[0]);
   EXPECT_EQ(nullptr, mesh->GetTextureCoordsName(0));
 }
+

+ 2 - 2
test/unit/utColladaExport.cpp

@@ -124,9 +124,9 @@ TEST_F(utColladaExport, testExportLight) {
     ASSERT_NE(pTest, nullptr);
     ASSERT_TRUE(pTest->HasLights());
 
-    const unsigned int origNumLights(pTest->mNumLights);
+    const unsigned int origNumLights = pTest->mNumLights;
     // There are FIVE!!! LIGHTS!!!
-    EXPECT_EQ(5, origNumLights) << "lights.dae should contain five lights";
+    EXPECT_EQ(5u, origNumLights) << "lights.dae should contain five lights";
 
     std::vector<aiLight> origLights(5);
     for (size_t i = 0; i < origNumLights; i++) {

+ 1 - 1
test/unit/utFBXImporterExporter.cpp

@@ -53,7 +53,7 @@ using namespace Assimp;
 
 class utFBXImporterExporter : public AbstractImportExportBase {
 public:
-    virtual bool importerTest() {
+    bool importerTest() override {
         Assimp::Importer importer;
         const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/spider.fbx", aiProcess_ValidateDataStructure);
         return nullptr != scene;

+ 3 - 3
test/unit/utVersion.cpp

@@ -48,12 +48,12 @@ TEST_F( utVersion, aiGetLegalStringTest ) {
     EXPECT_NE( lv, nullptr );
     std::string text( lv );
 
-    size_t pos = text.find(std::string("2021"));
+    size_t pos = text.find(std::string("2022"));
     EXPECT_NE(pos, std::string::npos);
 }
 
 TEST_F( utVersion, aiGetVersionMinorTest ) {
-    EXPECT_EQ(aiGetVersionMinor(), 1U);
+    EXPECT_EQ(aiGetVersionMinor(), 2U);
 }
 
 TEST_F( utVersion, aiGetVersionMajorTest ) {
@@ -61,7 +61,7 @@ TEST_F( utVersion, aiGetVersionMajorTest ) {
 }
 
 TEST_F( utVersion, aiGetVersionPatchTest ) {
-    EXPECT_EQ(aiGetVersionPatch(), 6U );   
+    EXPECT_EQ(aiGetVersionPatch(), 0U );   
 }
 
 TEST_F( utVersion, aiGetCompileFlagsTest ) {

+ 1 - 1
test/unit/utglTF2ImportExport.cpp

@@ -573,7 +573,7 @@ TEST_F(utglTF2ImportExport, export_normalized_normals) {
     scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals_out.glb", aiProcess_ValidateDataStructure);
     for ( auto i = 0u; i < scene->mMeshes[0]->mNumVertices; ++i ) {
         const auto length = scene->mMeshes[0]->mNormals[i].Length();
-        EXPECT_TRUE(abs(length) < 1e-6 || abs(length - 1) < 1e-6);
+        EXPECT_TRUE(abs(length) < 1e-6 || abs(length - 1) < ai_epsilon);
     }
 }