Selaa lähdekoodia

Merge branch 'master' into 1-3193

Kim Kulling 2 vuotta sitten
vanhempi
commit
e7e4e3100f
100 muutettua tiedostoa jossa 2451 lisäystä ja 2024 poistoa
  1. 10 0
      .github/workflows/sanitizer.yml
  2. 0 1
      Readme.md
  3. 1 1
      code/AssetLib/Blender/BlenderScene.cpp
  4. 4 0
      code/AssetLib/FBX/FBXConverter.cpp
  5. 39 5
      code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp
  6. 11 1
      code/AssetLib/MDL/HalfLife/HL1MDLLoader.h
  7. 1 1
      code/AssetLib/Ogre/OgreXmlSerializer.cpp
  8. 0 2
      code/CApi/AssimpCExport.cpp
  9. 10 10
      code/CApi/CInterfaceIOWrapper.cpp
  10. 33 22
      code/CApi/CInterfaceIOWrapper.h
  11. 7 0
      code/CMakeLists.txt
  12. 4 1
      code/Common/Subdivision.cpp
  13. 40 53
      code/Geometry/GeometryUtils.cpp
  14. 29 14
      code/Geometry/GeometryUtils.h
  15. 0 4
      code/PostProcessing/CalcTangentsProcess.cpp
  16. 6 13
      code/PostProcessing/CalcTangentsProcess.h
  17. 0 8
      code/PostProcessing/ComputeUVMappingProcess.cpp
  18. 7 12
      code/PostProcessing/ComputeUVMappingProcess.h
  19. 0 16
      code/PostProcessing/ConvertToLHProcess.cpp
  20. 10 17
      code/PostProcessing/ConvertToLHProcess.h
  21. 28 51
      code/PostProcessing/DeboneProcess.cpp
  22. 4 4
      code/PostProcessing/DeboneProcess.h
  23. 0 8
      code/PostProcessing/DropFaceNormalsProcess.cpp
  24. 4 5
      code/PostProcessing/DropFaceNormalsProcess.h
  25. 0 4
      code/PostProcessing/EmbedTexturesProcess.cpp
  26. 5 5
      code/PostProcessing/EmbedTexturesProcess.h
  27. 2 36
      code/PostProcessing/FindDegenerates.cpp
  28. 8 12
      code/PostProcessing/FindDegenerates.h
  29. 0 4
      code/PostProcessing/FindInstancesProcess.cpp
  30. 10 15
      code/PostProcessing/FindInstancesProcess.h
  31. 0 4
      code/PostProcessing/FindInvalidDataProcess.cpp
  32. 16 14
      code/PostProcessing/FindInvalidDataProcess.h
  33. 2 13
      code/PostProcessing/FixNormalsStep.cpp
  34. 7 6
      code/PostProcessing/FixNormalsStep.h
  35. 0 4
      code/PostProcessing/GenBoundingBoxesProcess.cpp
  36. 14 9
      code/PostProcessing/GenBoundingBoxesProcess.h
  37. 0 8
      code/PostProcessing/GenFaceNormalsProcess.cpp
  38. 11 13
      code/PostProcessing/GenFaceNormalsProcess.h
  39. 5 8
      code/PostProcessing/GenVertexNormalsProcess.cpp
  40. 6 5
      code/PostProcessing/GenVertexNormalsProcess.h
  41. 0 4
      code/PostProcessing/ImproveCacheLocality.cpp
  42. 8 11
      code/PostProcessing/ImproveCacheLocality.h
  43. 6 10
      code/PostProcessing/JoinVerticesProcess.h
  44. 3 5
      code/PostProcessing/LimitBoneWeightsProcess.cpp
  45. 12 10
      code/PostProcessing/LimitBoneWeightsProcess.h
  46. 0 4
      code/PostProcessing/MakeVerboseFormat.cpp
  47. 7 10
      code/PostProcessing/MakeVerboseFormat.h
  48. 0 4
      code/PostProcessing/OptimizeGraph.cpp
  49. 3 1
      code/PostProcessing/OptimizeGraph.h
  50. 0 4
      code/PostProcessing/OptimizeMeshes.cpp
  51. 6 9
      code/PostProcessing/OptimizeMeshes.h
  52. 0 4
      code/PostProcessing/PretransformVertices.cpp
  53. 3 1
      code/PostProcessing/PretransformVertices.h
  54. 0 4
      code/PostProcessing/RemoveRedundantMaterials.cpp
  55. 6 7
      code/PostProcessing/RemoveRedundantMaterials.h
  56. 0 4
      code/PostProcessing/RemoveVCProcess.cpp
  57. 8 11
      code/PostProcessing/RemoveVCProcess.h
  58. 19 24
      code/PostProcessing/ScaleProcess.cpp
  59. 6 7
      code/PostProcessing/ScaleProcess.h
  60. 0 4
      code/PostProcessing/SortByPTypeProcess.cpp
  61. 6 4
      code/PostProcessing/SortByPTypeProcess.h
  62. 63 121
      code/PostProcessing/SplitByBoneCountProcess.cpp
  63. 19 27
      code/PostProcessing/SplitByBoneCountProcess.h
  64. 0 6
      code/PostProcessing/SplitLargeMeshes.cpp
  65. 12 24
      code/PostProcessing/SplitLargeMeshes.h
  66. 10 24
      code/PostProcessing/TextureTransform.cpp
  67. 9 15
      code/PostProcessing/TextureTransform.h
  68. 15 9
      code/PostProcessing/TriangulateProcess.cpp
  69. 6 4
      code/PostProcessing/TriangulateProcess.h
  70. 1 6
      code/PostProcessing/ValidateDataStructure.cpp
  71. 6 8
      code/PostProcessing/ValidateDataStructure.h
  72. 126 91
      contrib/draco/.cmake-format.py
  73. 1 0
      contrib/draco/.gitattributes
  74. 12 0
      contrib/draco/.gitmodules
  75. 80 6
      contrib/draco/BUILDING.md
  76. 607 413
      contrib/draco/CMakeLists.txt
  77. 140 10
      contrib/draco/README.md
  78. 0 3
      contrib/draco/cmake/DracoConfig.cmake
  79. 0 56
      contrib/draco/cmake/FindDraco.cmake
  80. 0 220
      contrib/draco/cmake/compiler_flags.cmake
  81. 0 103
      contrib/draco/cmake/compiler_tests.cmake
  82. 3 2
      contrib/draco/cmake/draco-config.cmake.template
  83. 2 7
      contrib/draco/cmake/draco.pc.template
  84. 56 23
      contrib/draco/cmake/draco_build_definitions.cmake
  85. 14 0
      contrib/draco/cmake/draco_cpu_detection.cmake
  86. 136 0
      contrib/draco/cmake/draco_dependencies.cmake
  87. 112 65
      contrib/draco/cmake/draco_emscripten.cmake
  88. 48 3
      contrib/draco/cmake/draco_flags.cmake
  89. 14 0
      contrib/draco/cmake/draco_helpers.cmake
  90. 82 40
      contrib/draco/cmake/draco_install.cmake
  91. 22 12
      contrib/draco/cmake/draco_intrinsics.cmake
  92. 150 35
      contrib/draco/cmake/draco_options.cmake
  93. 19 3
      contrib/draco/cmake/draco_sanitizer.cmake
  94. 96 51
      contrib/draco/cmake/draco_targets.cmake
  95. 15 0
      contrib/draco/cmake/draco_test_config.h.cmake
  96. 98 60
      contrib/draco/cmake/draco_tests.cmake
  97. 22 7
      contrib/draco/cmake/draco_variables.cmake
  98. 0 19
      contrib/draco/cmake/sanitizers.cmake
  99. 14 0
      contrib/draco/cmake/toolchains/aarch64-linux-gnu.cmake
  100. 14 0
      contrib/draco/cmake/toolchains/android-ndk-common.cmake

+ 10 - 0
.github/workflows/sanitizer.yml

@@ -57,3 +57,13 @@ jobs:
     - name: test
       run: cd build/bin && ./unit
       shell: bash
+
+  job3:
+    name: printf-sanitizer
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v3
+    
+    - name: run scan_printf script
+      run: ./scripts/scan_printf.sh
+      shell: bash

+ 0 - 1
Readme.md

@@ -14,7 +14,6 @@ A library to import and export various 3d-model-formats including scene-post-pro
 [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue")
 [![Percentage of issues still open](http://isitmaintained.com/badge/open/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Percentage of issues still open")
-[![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
 <br>
 
 APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.

+ 1 - 1
code/AssetLib/Blender/BlenderScene.cpp

@@ -569,7 +569,7 @@ void Structure ::Convert<MVert>(
         const FileDatabase &db) const {
 
     ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db);
-    ReadFieldArray<ErrorPolicy_Fail>(dest.no, "no", db);
+    ReadFieldArray<ErrorPolicy_Warn>(dest.no, "no", db);
     ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
     //ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
     ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);

+ 4 - 0
code/AssetLib/FBX/FBXConverter.cpp

@@ -873,8 +873,12 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
             data->Set(index++, prop.first, interpretedBool->Value());
         } else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
             data->Set(index++, prop.first, interpretedInt->Value());
+        } else if (const TypedProperty<uint32_t> *interpretedUInt = prop.second->As<TypedProperty<uint32_t>>()) {
+            data->Set(index++, prop.first, interpretedUInt->Value());
         } else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) {
             data->Set(index++, prop.first, interpretedUint64->Value());
+        } else if (const TypedProperty<int64_t> *interpretedint64 = prop.second->As<TypedProperty<int64_t>>()) {
+            data->Set(index++, prop.first, interpretedint64->Value());
         } else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
             data->Set(index++, prop.first, interpretedFloat->Value());
         } else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {

+ 39 - 5
code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp

@@ -470,14 +470,16 @@ void HL1MDLLoader::read_bones() {
 
     temp_bones_.resize(header_->numbones);
 
+    // Create the main 'bones' node that will contain all MDL root bones.
     aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES);
     rootnode_children_.push_back(bones_node);
-    bones_node->mNumChildren = static_cast<unsigned int>(header_->numbones);
-    bones_node->mChildren = new aiNode *[bones_node->mNumChildren];
+
+    // Store roots bones IDs temporarily.
+    std::vector<int> roots;
 
     // Create bone matrices in local space.
     for (int i = 0; i < header_->numbones; ++i) {
-        aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]);
+        aiNode *bone_node = temp_bones_[i].node = new aiNode(unique_bones_names[i]);
 
         aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]);
         temp_bones_[i].absolute_transform = bone_node->mTransformation =
@@ -485,9 +487,11 @@ void HL1MDLLoader::read_bones() {
                         aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2]));
 
         if (pbone[i].parent == -1) {
-            bone_node->mParent = scene_->mRootNode;
+            bone_node->mParent = bones_node;
+            roots.push_back(i); // This bone has no parent. Add it to the roots list.
         } else {
-            bone_node->mParent = bones_node->mChildren[pbone[i].parent];
+            bone_node->mParent = temp_bones_[pbone[i].parent].node;
+            temp_bones_[pbone[i].parent].children.push_back(i); // Add this bone to the parent bone's children list.
 
             temp_bones_[i].absolute_transform =
                     temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation;
@@ -496,6 +500,36 @@ void HL1MDLLoader::read_bones() {
         temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform;
         temp_bones_[i].offset_matrix.Inverse();
     }
+
+    // Allocate memory for each MDL root bone.
+    bones_node->mNumChildren = static_cast<unsigned int>(roots.size());
+    bones_node->mChildren = new aiNode *[bones_node->mNumChildren];
+
+    // Build all bones children hierarchy starting from each MDL root bone.
+    for (size_t i = 0; i < roots.size(); ++i)
+    {
+        const TempBone &root_bone = temp_bones_[roots[i]];
+        bones_node->mChildren[i] = root_bone.node;
+        build_bone_children_hierarchy(root_bone);
+    }
+}
+
+void HL1MDLLoader::build_bone_children_hierarchy(const TempBone &bone)
+{
+    if (bone.children.empty())
+        return;
+
+    aiNode* bone_node = bone.node;
+    bone_node->mNumChildren = static_cast<unsigned int>(bone.children.size());
+    bone_node->mChildren = new aiNode *[bone_node->mNumChildren];
+
+    // Build each child bone's hierarchy recursively.
+    for (size_t i = 0; i < bone.children.size(); ++i)
+    {
+        const TempBone &child_bone = temp_bones_[bone.children[i]];
+        bone_node->mChildren[i] = child_bone.node;
+        build_bone_children_hierarchy(child_bone);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------

+ 11 - 1
code/AssetLib/MDL/HalfLife/HL1MDLLoader.h

@@ -143,6 +143,14 @@ private:
      */
     static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers);
 
+    /**
+     *  \brief Build a bone's node children hierarchy.
+     *
+     * \param[in] bone The bone for which we must build all children hierarchy.
+     */
+    struct TempBone;
+    void build_bone_children_hierarchy(const TempBone& bone);
+
     /** Output scene to be filled */
     aiScene *scene_;
 
@@ -198,11 +206,13 @@ private:
         TempBone() :
             node(nullptr),
             absolute_transform(),
-            offset_matrix() {}
+            offset_matrix(),
+            children() {}
 
         aiNode *node;
         aiMatrix4x4 absolute_transform;
         aiMatrix4x4 offset_matrix;
+        std::vector<int> children; // Bone children
     };
 
     std::vector<TempBone> temp_bones_;

+ 1 - 1
code/AssetLib/Ogre/OgreXmlSerializer.cpp

@@ -490,7 +490,7 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me
     OgreXmlSerializer serializer(xmlParser.get());
     XmlNode root = xmlParser->getRootNode();
     if (std::string(root.name()) != nnSkeleton) {
-        printf("\nSkeleton is not a valid root: %s\n", root.name());
+        ASSIMP_LOG_VERBOSE_DEBUG("nSkeleton is not a valid root: ", root.name(), ".");
         for (auto &a : root.children()) {
             if (std::string(a.name()) == nnSkeleton) {
                 root = a;

+ 0 - 2
code/CApi/AssimpCExport.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,

+ 10 - 10
code/CApi/CInterfaceIOWrapper.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,
@@ -47,14 +45,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp {
 
+// ------------------------------------------------------------------------------------------------
 CIOStreamWrapper::~CIOStreamWrapper() {
-    /* Various places depend on this destructor to close the file */
-    if (mFile) {
+    // Various places depend on this destructor to close the file
+    if (mFile != nullptr) {
+        
         mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile);
     }
 }
 
-// ...................................................................
+// ------------------------------------------------------------------------------------------------
 size_t CIOStreamWrapper::Read(void *pvBuffer,
         size_t pSize,
         size_t pCount) {
@@ -62,7 +62,7 @@ size_t CIOStreamWrapper::Read(void *pvBuffer,
     return mFile->ReadProc(mFile, (char *)pvBuffer, pSize, pCount);
 }
 
-// ...................................................................
+// ------------------------------------------------------------------------------------------------
 size_t CIOStreamWrapper::Write(const void *pvBuffer,
         size_t pSize,
         size_t pCount) {
@@ -70,23 +70,23 @@ size_t CIOStreamWrapper::Write(const void *pvBuffer,
     return mFile->WriteProc(mFile, (const char *)pvBuffer, pSize, pCount);
 }
 
-// ...................................................................
+// ------------------------------------------------------------------------------------------------
 aiReturn CIOStreamWrapper::Seek(size_t pOffset,
         aiOrigin pOrigin) {
     return mFile->SeekProc(mFile, pOffset, pOrigin);
 }
 
-// ...................................................................
+// ------------------------------------------------------------------------------------------------
 size_t CIOStreamWrapper::Tell() const {
     return mFile->TellProc(mFile);
 }
 
-// ...................................................................
+// ------------------------------------------------------------------------------------------------
 size_t CIOStreamWrapper::FileSize() const {
     return mFile->FileSizeProc(mFile);
 }
 
-// ...................................................................
+// ------------------------------------------------------------------------------------------------
 void CIOStreamWrapper::Flush() {
     return mFile->FlushProc(mFile);
 }

+ 33 - 22
code/CApi/CInterfaceIOWrapper.h

@@ -47,48 +47,59 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/cfileio.h>
 #include <assimp/IOStream.hpp>
 #include <assimp/IOSystem.hpp>
+#include <assimp/ai_assert.h>
 
 namespace Assimp {
 
 class CIOSystemWrapper;
 
 // ------------------------------------------------------------------------------------------------
-// Custom IOStream implementation for the C-API
-class CIOStreamWrapper : public IOStream {
+/// @brief Custom IOStream implementation for the C-API-
+// ------------------------------------------------------------------------------------------------
+class CIOStreamWrapper final : public IOStream {
 public:
-    explicit CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io) :
-            mFile(pFile),
-            mIO(io) {}
-    ~CIOStreamWrapper(void);
-
-    size_t Read(void *pvBuffer, size_t pSize, size_t pCount);
-    size_t Write(const void *pvBuffer, size_t pSize, size_t pCount);
-    aiReturn Seek(size_t pOffset, aiOrigin pOrigin);
-    size_t Tell(void) const;
-    size_t FileSize() const;
-    void Flush();
+    explicit CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io);
+    ~CIOStreamWrapper() override;
+    size_t Read(void *pvBuffer, size_t pSize, size_t pCount) override;
+    size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) override;
+    aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override;
+    size_t Tell(void) const override;
+    size_t FileSize() const override;
+    void Flush() override;
 
 private:
     aiFile *mFile;
     CIOSystemWrapper *mIO;
 };
 
-class CIOSystemWrapper : public IOSystem {
+inline CIOStreamWrapper::CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io) :
+        mFile(pFile),
+        mIO(io) {
+    ai_assert(io != nullptr);
+}
+
+// ------------------------------------------------------------------------------------------------
+/// @brief Custom IO-System wrapper implementation for the C-API.
+// ------------------------------------------------------------------------------------------------
+class CIOSystemWrapper final : public IOSystem {
     friend class CIOStreamWrapper;
 
 public:
-    explicit CIOSystemWrapper(aiFileIO *pFile) :
-            mFileSystem(pFile) {}
-
-    bool Exists(const char *pFile) const;
-    char getOsSeparator() const;
-    IOStream *Open(const char *pFile, const char *pMode = "rb");
-    void Close(IOStream *pFile);
+    explicit CIOSystemWrapper(aiFileIO *pFile);
+    ~CIOSystemWrapper() override = default;
+    bool Exists(const char *pFile) const override;
+    char getOsSeparator() const override;
+    IOStream *Open(const char *pFile, const char *pMode = "rb") override;
+    void Close(IOStream *pFile) override;
 
 private:
     aiFileIO *mFileSystem;
 };
 
+inline CIOSystemWrapper::CIOSystemWrapper(aiFileIO *pFile) : mFileSystem(pFile) {
+    ai_assert(pFile != nullptr);
+}
+
 } // namespace Assimp
 
-#endif
+#endif // AI_CIOSYSTEM_H_INCLUDED

+ 7 - 0
code/CMakeLists.txt

@@ -218,6 +218,12 @@ SET( CApi_SRCS
 )
 SOURCE_GROUP(CApi FILES ${CApi_SRCS})
 
+SET(Geometry_SRCS
+  Geometry/GeometryUtils.h
+  Geometry/GeometryUtils.cpp
+)
+SOURCE_GROUP(Geometry FILES ${Geometry_SRCS})
+
 SET( STEPParser_SRCS
   AssetLib/STEPParser/STEPFileReader.h
   AssetLib/STEPParser/STEPFileReader.cpp
@@ -1129,6 +1135,7 @@ SET( assimp_src
   ${Core_SRCS}
   ${CApi_SRCS}
   ${Common_SRCS}
+  ${Geometry_SRCS}
   ${Logging_SRCS}
   ${Exporter_SRCS}
   ${PostProcessing_SRCS}

+ 4 - 1
code/Common/Subdivision.cpp

@@ -50,7 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdio.h>
 
+#include <unordered_map>
+
 using namespace Assimp;
+
 void mydummy() {}
 
 #ifdef _MSC_VER
@@ -78,7 +81,7 @@ public:
     };
 
     typedef std::vector<unsigned int> UIntVector;
-    typedef std::map<uint64_t, Edge> EdgeMap;
+    typedef std::unordered_map<uint64_t, Edge> EdgeMap;
 
     // ---------------------------------------------------------------------------
     // Hashing function to derive an index into an #EdgeMap from two given

+ 40 - 53
samples/SharedCode/UTFConverter.h → code/Geometry/GeometryUtils.cpp

@@ -1,17 +1,14 @@
 /*
----------------------------------------------------------------------------
 Open Asset Import Library (assimp)
----------------------------------------------------------------------------
-
-Copyright (c) 2006-2020, assimp team
-
+----------------------------------------------------------------------
 
+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:
+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
@@ -38,55 +35,45 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
+
+----------------------------------------------------------------------
 */
 
-#ifndef ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H
-#define ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H
-
-#include <string>
-#include <locale>
-#include <codecvt>
-
-namespace AssimpSamples {
-namespace SharedCode {
-
-// Used to convert between multibyte and unicode strings.
-class UTFConverter {
-    using UTFConverterImpl = std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>;
-public:
-    UTFConverter(const char* s) :
-        s_(s),
-        ws_(impl_.from_bytes(s)) {
-    }
-    UTFConverter(const wchar_t* s) :
-        s_(impl_.to_bytes(s)),
-        ws_(s) {
-    }
-    UTFConverter(const std::string& s) :
-        s_(s),
-        ws_(impl_.from_bytes(s)) {
-    }
-    UTFConverter(const std::wstring& s) :
-        s_(impl_.to_bytes(s)),
-        ws_(s) {
-    }
-    inline const char* c_str() const {
-        return s_.c_str();
-    }
-    inline const std::string& str() const {
-        return s_;
-    }
-    inline const wchar_t* c_wstr() const {
-        return ws_.c_str();
-    }
-private:
-    static UTFConverterImpl impl_;
-    std::string s_;
-    std::wstring ws_;
-};
+#include "GeometryUtils.h"
+
+#include <assimp/vector3.h>
+
+namespace Assimp {
+
+ai_real GeometryUtils::heron( ai_real a, ai_real b, ai_real c ) {
+    ai_real s = (a + b + c) / 2;
+    ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 );
+    return area;
+}
+
+ai_real GeometryUtils::distance3D( const aiVector3D &vA, aiVector3D &vB ) {
+    const ai_real lx = ( vB.x - vA.x );
+    const ai_real ly = ( vB.y - vA.y );
+    const ai_real lz = ( vB.z - vA.z );
+    ai_real a = lx*lx + ly*ly + lz*lz;
+    ai_real d = pow( a, (ai_real)0.5 );
 
+    return d;
 }
+
+ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
+    ai_real area = 0;
+
+    aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
+    aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
+    aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
+
+    ai_real a( distance3D( vA, vB ) );
+    ai_real b( distance3D( vB, vC ) );
+    ai_real c( distance3D( vC, vA ) );
+    area = heron( a, b, c );
+
+    return area;
 }
 
-#endif // ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H
+} // namespace Assimp

+ 29 - 14
samples/SharedCode/UTFConverter.cpp → code/Geometry/GeometryUtils.h

@@ -1,17 +1,14 @@
 /*
----------------------------------------------------------------------------
 Open Asset Import Library (assimp)
----------------------------------------------------------------------------
-
-Copyright (c) 2006-2020, assimp team
-
+----------------------------------------------------------------------
 
+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:
+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
@@ -38,15 +35,33 @@ 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 "UTFConverter.h"
+#include <assimp/types.h>
+#include <assimp/mesh.h>
+
+namespace Assimp {
 
-namespace AssimpSamples {
-namespace SharedCode {
+// ---------------------------------------------------------------------------
+/// @brief This helper class supports some basic geometry algorithms.
+// ---------------------------------------------------------------------------
+class GeometryUtils {
+public:
+    static ai_real heron( ai_real a, ai_real b, ai_real c );
+    
+    /// @brief Will compute the distance between 2 3D-vectors
+    /// @param vA  Vector a.
+    /// @param vB  Vector b.
+    /// @return The distance.
+    static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB );
 
-typename UTFConverter::UTFConverterImpl UTFConverter::impl_;
+    /// @brief Will calculate the area of a triangle described by a aiFace.
+    /// @param face   The face
+    /// @param mesh   The mesh containing the face
+    /// @return The area.
+    static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh );
+};
 
-}
-}
+} // namespace Assimp

+ 0 - 4
code/PostProcessing/CalcTangentsProcess.cpp

@@ -60,10 +60,6 @@ CalcTangentsProcess::CalcTangentsProcess() :
     // nothing to do here
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-CalcTangentsProcess::~CalcTangentsProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {

+ 6 - 13
code/PostProcessing/CalcTangentsProcess.h

@@ -59,14 +59,11 @@ namespace Assimp
  * because the joining of vertices also considers tangents and bitangents for
  * uniqueness.
  */
-class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess
-{
+class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess {
 public:
-
     CalcTangentsProcess();
-    ~CalcTangentsProcess();
+    ~CalcTangentsProcess() override = default;
 
-public:
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag.
     * @param pFlags The processing flags the importer was called with.
@@ -74,24 +71,21 @@ public:
     * @return true if the process is present in this flag fields,
     *   false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Called prior to ExecuteOnScene().
     * The function is a request to the process to update its configuration
     * basing on the Importer's configuration property list.
     */
-    void SetupProperties(const Importer* pImp);
-
+    void SetupProperties(const Importer* pImp) override;
 
     // setter for configMaxAngle
-    inline void SetMaxSmoothAngle(float f)
-    {
+    void SetMaxSmoothAngle(float f) {
         configMaxAngle =f;
     }
 
 protected:
-
     // -------------------------------------------------------------------
     /** Calculates tangents and bitangents for a specific mesh.
     * @param pMesh The mesh to process.
@@ -103,10 +97,9 @@ protected:
     /** Executes the post processing step on the given imported data.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
 private:
-
     /** Configuration option: maximum smoothing angle, in radians*/
     float configMaxAngle;
     unsigned int configSourceUV;

+ 0 - 8
code/PostProcessing/ComputeUVMappingProcess.cpp

@@ -57,14 +57,6 @@ namespace {
     const static ai_real angle_epsilon = ai_real( 0.95 );
 }
 
-// ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by Importer
-ComputeUVMappingProcess::ComputeUVMappingProcess() = default;
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-ComputeUVMappingProcess::~ComputeUVMappingProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const

+ 7 - 12
code/PostProcessing/ComputeUVMappingProcess.h

@@ -59,13 +59,10 @@ namespace Assimp {
 /** ComputeUVMappingProcess - converts special mappings, such as spherical,
  *  cylindrical or boxed to proper UV coordinates for rendering.
 */
-class ComputeUVMappingProcess : public BaseProcess
-{
-public:
-    ComputeUVMappingProcess();
-    ~ComputeUVMappingProcess();
-
+class ComputeUVMappingProcess : public BaseProcess {
 public:
+    ComputeUVMappingProcess() = default;
+    ~ComputeUVMappingProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
@@ -73,14 +70,14 @@ public:
     *   combination of #aiPostProcessSteps.
     * @return true if the process is present in this flag fields, false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
 protected:
 
@@ -125,8 +122,7 @@ protected:
 private:
 
     // temporary structure to describe a mapping
-    struct MappingInfo
-    {
+    struct MappingInfo {
         explicit MappingInfo(aiTextureMapping _type)
             : type  (_type)
             , axis  (0.f,1.f,0.f)
@@ -137,8 +133,7 @@ private:
         aiVector3D axis;
         unsigned int uv;
 
-        bool operator== (const MappingInfo& other)
-        {
+        bool operator== (const MappingInfo& other) {
             return type == other.type && axis == other.axis;
         }
     };

+ 0 - 16
code/PostProcessing/ConvertToLHProcess.cpp

@@ -79,14 +79,6 @@ void flipUVs(aiMeshType *pMesh) {
 
 } // namespace
 
-// ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by Importer
-MakeLeftHandedProcess::MakeLeftHandedProcess() = default;
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-MakeLeftHandedProcess::~MakeLeftHandedProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool MakeLeftHandedProcess::IsActive(unsigned int pFlags) const {
@@ -305,14 +297,6 @@ void FlipUVsProcess::ProcessMesh(aiMesh *pMesh) {
 #ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
 // # FlipWindingOrderProcess
 
-// ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by Importer
-FlipWindingOrderProcess::FlipWindingOrderProcess() = default;
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-FlipWindingOrderProcess::~FlipWindingOrderProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool FlipWindingOrderProcess::IsActive(unsigned int pFlags) const {

+ 10 - 17
code/PostProcessing/ConvertToLHProcess.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,
@@ -72,22 +71,18 @@ namespace Assimp    {
  *
  * @note RH-LH and LH-RH is the same, so this class can be used for both
  */
-class MakeLeftHandedProcess : public BaseProcess
-{
-
-
+class MakeLeftHandedProcess : public BaseProcess {
 public:
-    MakeLeftHandedProcess();
-    ~MakeLeftHandedProcess();
+    MakeLeftHandedProcess() = default;
+    ~MakeLeftHandedProcess() override = default;
 
     // -------------------------------------------------------------------
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
 protected:
-
     // -------------------------------------------------------------------
     /** Recursively converts a node and all of its children
      */
@@ -120,24 +115,22 @@ protected:
 // ---------------------------------------------------------------------------
 /** Postprocessing step to flip the face order of the imported data
  */
-class FlipWindingOrderProcess : public BaseProcess
-{
+class FlipWindingOrderProcess : public BaseProcess {
     friend class Importer;
 
 public:
     /** Constructor to be privately used by Importer */
-    FlipWindingOrderProcess();
+    FlipWindingOrderProcess() = default;
 
     /** Destructor, private as well */
-    ~FlipWindingOrderProcess();
+    ~FlipWindingOrderProcess() override = default;
 
     // -------------------------------------------------------------------
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
-public:
     /** Some other types of post-processing require winding order flips */
     static void ProcessMesh( aiMesh* pMesh);
 };

+ 28 - 51
code/PostProcessing/DeboneProcess.cpp

@@ -43,42 +43,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /// @file DeboneProcess.cpp
 /** Implementation of the DeboneProcess post processing step */
 
-
-
 // internal headers of the post-processing framework
 #include "ProcessHelper.h"
 #include "DeboneProcess.h"
 #include <stdio.h>
 
-
 using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-DeboneProcess::DeboneProcess()
-{
-    mNumBones = 0;
-    mNumBonesCanDoWithout = 0;
-
-    mThreshold = AI_DEBONE_THRESHOLD;
-    mAllOrNone = false;
-}
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-DeboneProcess::~DeboneProcess() = default;
+DeboneProcess::DeboneProcess() : mNumBones(0), mNumBonesCanDoWithout(0), mThreshold(AI_DEBONE_THRESHOLD), mAllOrNone(false) {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool DeboneProcess::IsActive( unsigned int pFlags) const
-{
+bool DeboneProcess::IsActive( unsigned int pFlags) const {
     return (pFlags & aiProcess_Debone) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void DeboneProcess::SetupProperties(const Importer* pImp)
-{
+void DeboneProcess::SetupProperties(const Importer* pImp) {
     // get the current value of the property
     mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
     mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD);
@@ -86,8 +70,7 @@ void DeboneProcess::SetupProperties(const Importer* pImp)
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void DeboneProcess::Execute( aiScene* pScene)
-{
+void DeboneProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("DeboneProcess begin");
 
     if(!pScene->mNumMeshes) {
@@ -117,10 +100,8 @@ void DeboneProcess::Execute( aiScene* pScene)
         // build a new array of meshes for the scene
         std::vector<aiMesh*> meshes;
 
-        for(unsigned int a=0;a<pScene->mNumMeshes;a++)
-        {
+        for (unsigned int a=0;a<pScene->mNumMeshes; ++a) {
             aiMesh* srcMesh = pScene->mMeshes[a];
-
             std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
 
             if(splitList[a]) {
@@ -150,8 +131,7 @@ void DeboneProcess::Execute( aiScene* pScene)
 
                 // and destroy the source mesh. It should be completely contained inside the new submeshes
                 delete srcMesh;
-            }
-            else    {
+            } else {
                 // Mesh is kept unchanged - store it's new place in the mesh array
                 mSubMeshIndices[a].emplace_back(static_cast<unsigned int>(meshes.size()), (aiNode *)nullptr);
                 meshes.push_back(srcMesh);
@@ -173,8 +153,7 @@ void DeboneProcess::Execute( aiScene* pScene)
 
 // ------------------------------------------------------------------------------------------------
 // Counts bones total/removable in a given mesh.
-bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
-{
+bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) {
     if(!pMesh->HasBones()) {
         return false;
     }
@@ -193,25 +172,23 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
     for(unsigned int i=0;i<pMesh->mNumBones;i++)    {
         for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++)   {
             float w = pMesh->mBones[i]->mWeights[j].mWeight;
-
-            if(w==0.0f) {
+            if (w == 0.0f) {
                 continue;
             }
 
             unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
-            if(w>=mThreshold)   {
-
-                if(vertexBones[vid]!=cUnowned)  {
-                    if(vertexBones[vid]==i) //double entry
-                    {
+            if (w >= mThreshold)   {
+                if (vertexBones[vid] != cUnowned) {
+                    //double entry
+                    if(vertexBones[vid]==i)  {
                         ASSIMP_LOG_WARN("Encountered double entry in bone weights");
-                    }
-                    else //TODO: track attraction in order to break tie
-                    {
+                    } else  {
+                        //TODO: track attraction in order to break tie
                         vertexBones[vid] = cCoowned;
                     }
-                }
-                else vertexBones[vid] = i;
+                } else {
+                    vertexBones[vid] = i;
+                } 
             }
 
             if(!isBoneNecessary[i]) {
@@ -227,13 +204,16 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
     if(isInterstitialRequired) {
         for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
             unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
-
-            for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
+            for (unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
                 unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
 
-                if(v!=w)    {
-                    if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
-                    if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
+                if (v != w) {
+                    if(v<pMesh->mNumBones) {
+                        isBoneNecessary[v] = true;
+                    }
+                    if (w<pMesh->mNumBones) {
+                        isBoneNecessary[w] = true;
+                    }
                 }
             }
         }
@@ -252,8 +232,7 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
 
 // ------------------------------------------------------------------------------------------------
 // Splits the given mesh by bone count.
-void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const
-{
+void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const {
     // same deal here as ConsiderMesh basically
 
     std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
@@ -371,8 +350,7 @@ void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMe
 
 // ------------------------------------------------------------------------------------------------
 // Recursively updates the node's mesh list to account for the changed mesh list
-void DeboneProcess::UpdateNode(aiNode* pNode) const
-{
+void DeboneProcess::UpdateNode(aiNode* pNode) const {
     // rebuild the node's mesh index list
 
     std::vector<unsigned int> newMeshList;
@@ -430,8 +408,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const
 
 // ------------------------------------------------------------------------------------------------
 // Apply the node transformation to a mesh
-void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const
-{
+void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const {
     // Check whether we need to transform the coordinates at all
     if (!mat.IsIdentity()) {
 

+ 4 - 4
code/PostProcessing/DeboneProcess.h

@@ -70,7 +70,7 @@ namespace Assimp {
 class DeboneProcess : public BaseProcess {
 public:
     DeboneProcess();
-    ~DeboneProcess();
+    ~DeboneProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag.
@@ -79,14 +79,14 @@ public:
     * @return true if the process is present in this flag fields,
     *   false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Called prior to ExecuteOnScene().
     * The function is a request to the process to update its configuration
     * basing on the Importer's configuration property list.
     */
-    void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer* pImp) override;
 
 protected:
     // -------------------------------------------------------------------
@@ -94,7 +94,7 @@ protected:
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     /** Counts bones total/removable in a given mesh.

+ 0 - 8
code/PostProcessing/DropFaceNormalsProcess.cpp

@@ -54,14 +54,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 
-// ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by Importer
-DropFaceNormalsProcess::DropFaceNormalsProcess() = default;
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-DropFaceNormalsProcess::~DropFaceNormalsProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const {

+ 4 - 5
code/PostProcessing/DropFaceNormalsProcess.h

@@ -55,8 +55,8 @@ namespace Assimp {
 */
 class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess {
 public:
-    DropFaceNormalsProcess();
-    ~DropFaceNormalsProcess();
+    DropFaceNormalsProcess() = default;
+    ~DropFaceNormalsProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
@@ -64,15 +64,14 @@ public:
     *   combination of #aiPostProcessSteps.
     * @return true if the process is present in this flag fields, false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
-
+    void Execute( aiScene* pScene) override;
 
 private:
     bool DropMeshFaceNormals(aiMesh* pcMesh);

+ 0 - 4
code/PostProcessing/EmbedTexturesProcess.cpp

@@ -49,10 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 
-EmbedTexturesProcess::EmbedTexturesProcess() = default;
-
-EmbedTexturesProcess::~EmbedTexturesProcess() = default;
-
 bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
     return (pFlags & aiProcess_EmbedTextures) != 0;
 }

+ 5 - 5
code/PostProcessing/EmbedTexturesProcess.h

@@ -62,19 +62,19 @@ namespace Assimp {
 class ASSIMP_API EmbedTexturesProcess : public BaseProcess {
 public:
     /// The default class constructor.
-    EmbedTexturesProcess();
+    EmbedTexturesProcess() = default;
 
     /// The class destructor.
-    virtual ~EmbedTexturesProcess();
+    ~EmbedTexturesProcess() override = default;
 
     /// Overwritten, @see BaseProcess
-    virtual bool IsActive(unsigned int pFlags) const;
+    bool IsActive(unsigned int pFlags) const override;
 
     /// Overwritten, @see BaseProcess
-    virtual void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer* pImp) override;
 
     /// Overwritten, @see BaseProcess
-    virtual void Execute(aiScene* pScene);
+    virtual void Execute(aiScene* pScene) override;
 
 private:
     // Resolve the path and add the file content to the scene as a texture.

+ 2 - 36
code/PostProcessing/FindDegenerates.cpp

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "ProcessHelper.h"
 #include "FindDegenerates.h"
+#include "Geometry/GeometryUtils.h"
 
 #include <assimp/Exceptional.h>
 
@@ -63,10 +64,6 @@ FindDegeneratesProcess::FindDegeneratesProcess() :
     // empty
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-FindDegeneratesProcess::~FindDegeneratesProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const {
@@ -132,37 +129,6 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned in
     }
 }
 
-static ai_real heron( ai_real a, ai_real b, ai_real c ) {
-    ai_real s = (a + b + c) / 2;
-    ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 );
-    return area;
-}
-
-static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB ) {
-    const ai_real lx = ( vB.x - vA.x );
-    const ai_real ly = ( vB.y - vA.y );
-    const ai_real lz = ( vB.z - vA.z );
-    ai_real a = lx*lx + ly*ly + lz*lz;
-    ai_real d = pow( a, (ai_real)0.5 );
-
-    return d;
-}
-
-static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
-    ai_real area = 0;
-
-    aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
-    aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
-    aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
-
-    ai_real a( distance3D( vA, vB ) );
-    ai_real b( distance3D( vB, vC ) );
-    ai_real c( distance3D( vC, vA ) );
-    area = heron( a, b, c );
-
-    return area;
-}
-
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported mesh
 bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
@@ -218,7 +184,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
 
             if ( mConfigCheckAreaOfTriangle ) {
                 if ( face.mNumIndices == 3 ) {
-                    ai_real area = calculateAreaOfTriangle( face, mesh );
+                    ai_real area = GeometryUtils::calculateAreaOfTriangle( face, mesh );
                     if (area < ai_epsilon) {
                         if ( mConfigRemoveDegenerates ) {
                             remove_me[ a ] = true;

+ 8 - 12
code/PostProcessing/FindDegenerates.h

@@ -59,19 +59,19 @@ namespace Assimp    {
 class ASSIMP_API FindDegeneratesProcess : public BaseProcess {
 public:
     FindDegeneratesProcess();
-    ~FindDegeneratesProcess();
+    ~FindDegeneratesProcess() override = default;
 
     // -------------------------------------------------------------------
     // Check whether step is active
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     // Execute step on a given scene
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     // Setup import settings
-    void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer* pImp) override;
 
     // -------------------------------------------------------------------
     // Execute step on a given mesh
@@ -105,23 +105,19 @@ private:
     bool mConfigCheckAreaOfTriangle;
 };
 
-inline
-void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) {
+inline void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) {
     mConfigRemoveDegenerates = enabled;
 }
 
-inline
-bool FindDegeneratesProcess::IsInstantRemoval() const {
+inline bool FindDegeneratesProcess::IsInstantRemoval() const {
     return mConfigRemoveDegenerates;
 }
 
-inline
-void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) {
+inline void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) {
     mConfigCheckAreaOfTriangle = enabled;
 }
 
-inline
-bool FindDegeneratesProcess::isAreaCheckEnabled() const {
+inline bool FindDegeneratesProcess::isAreaCheckEnabled() const {
     return mConfigCheckAreaOfTriangle;
 }
 

+ 0 - 4
code/PostProcessing/FindInstancesProcess.cpp

@@ -58,10 +58,6 @@ FindInstancesProcess::FindInstancesProcess()
 :   configSpeedFlag (false)
 {}
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-FindInstancesProcess::~FindInstancesProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool FindInstancesProcess::IsActive( unsigned int pFlags) const

+ 10 - 15
code/PostProcessing/FindInstancesProcess.h

@@ -50,7 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "PostProcessing/ProcessHelper.h"
 
 class FindInstancesProcessTest;
-namespace Assimp    {
+
+namespace Assimp {
 
 // -------------------------------------------------------------------------------
 /** @brief Get a pseudo(!)-hash representing a mesh.
@@ -60,8 +61,7 @@ namespace Assimp    {
  *  @param in Input mesh
  *  @return Hash.
  */
-inline
-uint64_t GetMeshHash(aiMesh* in) {
+inline uint64_t GetMeshHash(aiMesh* in) {
     ai_assert(nullptr != in);
 
     // ... get an unique value representing the vertex format of the mesh
@@ -83,8 +83,7 @@ uint64_t GetMeshHash(aiMesh* in) {
  *  @param e Epsilon
  *  @return true if the arrays are identical
  */
-inline
-bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
+inline bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
         unsigned int size, float e) {
     for (const aiVector3D* end = first+size; first != end; ++first,++second) {
         if ( (*first - *second).SquareLength() >= e)
@@ -107,31 +106,27 @@ inline bool CompareArrays(const aiColor4D* first, const aiColor4D* second,
 // ---------------------------------------------------------------------------
 /** @brief A post-processing steps to search for instanced meshes
 */
-class FindInstancesProcess : public BaseProcess
-{
+class FindInstancesProcess : public BaseProcess {
 public:
-
     FindInstancesProcess();
-    ~FindInstancesProcess();
+    ~FindInstancesProcess() override = default;
 
-public:
     // -------------------------------------------------------------------
     // Check whether step is active in given flags combination
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     // Execute step on a given scene
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     // Setup properties prior to executing the process
-    void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer* pImp) override;
 
 private:
-
     bool configSpeedFlag;
-
 }; // ! end class FindInstancesProcess
+
 }  // ! end namespace Assimp
 
 #endif // !! AI_FINDINSTANCES_H_INC

+ 0 - 4
code/PostProcessing/FindInvalidDataProcess.cpp

@@ -60,10 +60,6 @@ FindInvalidDataProcess::FindInvalidDataProcess() :
     // nothing to do here
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-FindInvalidDataProcess::~FindInvalidDataProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {

+ 16 - 14
code/PostProcessing/FindInvalidDataProcess.h

@@ -64,35 +64,37 @@ namespace Assimp {
  *  which have zero normal vectors. */
 class ASSIMP_API FindInvalidDataProcess : public BaseProcess {
 public:
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     FindInvalidDataProcess();
-    ~FindInvalidDataProcess();
+    ~FindInvalidDataProcess() override = default;
 
     // -------------------------------------------------------------------
-    //
-    bool IsActive(unsigned int pFlags) const;
+    /// Returns active state.
+    bool IsActive(unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
-    // Setup import settings
-    void SetupProperties(const Importer *pImp);
+    /// Setup import settings
+    void SetupProperties(const Importer *pImp) override;
 
     // -------------------------------------------------------------------
-    // Run the step
-    void Execute(aiScene *pScene);
+    /// Run the step
+    void Execute(aiScene *pScene) override;
 
     // -------------------------------------------------------------------
-    /** Executes the post-processing step on the given mesh
-     * @param pMesh The mesh to process.
-     * @return 0 - nothing, 1 - removed sth, 2 - please delete me  */
+    /// Executes the post-processing step on the given mesh
+    /// @param pMesh The mesh to process.
+    /// @return 0 - nothing, 1 - removed sth, 2 - please delete me  */
     int ProcessMesh(aiMesh *pMesh);
 
     // -------------------------------------------------------------------
-    /** Executes the post-processing step on the given animation
-     * @param anim The animation to process.  */
+    /// Executes the post-processing step on the given animation
+    /// @param anim The animation to process.  */
     void ProcessAnimation(aiAnimation *anim);
 
     // -------------------------------------------------------------------
-    /** Executes the post-processing step on the given anim channel
-     * @param anim The animation channel to process.*/
+    /// Executes the post-processing step on the given anim channel
+    /// @param anim The animation channel to process.*/
     void ProcessAnimationChannel(aiNodeAnim *anim);
 
 private:

+ 2 - 13
code/PostProcessing/FixNormalsStep.cpp

@@ -56,26 +56,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 
-
-// ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by Importer
-FixInfacingNormalsProcess::FixInfacingNormalsProcess() = default;
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-FixInfacingNormalsProcess::~FixInfacingNormalsProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const
-{
+bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const {
     return (pFlags & aiProcess_FixInfacingNormals) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void FixInfacingNormalsProcess::Execute( aiScene* pScene)
-{
+void FixInfacingNormalsProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess begin");
 
     bool bHas( false );

+ 7 - 6
code/PostProcessing/FixNormalsStep.h

@@ -49,8 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiMesh;
 
-namespace Assimp
-{
+namespace Assimp {
 
 // ---------------------------------------------------------------------------
 /** The FixInfacingNormalsProcess tries to determine whether the normal
@@ -59,8 +58,10 @@ namespace Assimp
  */
 class FixInfacingNormalsProcess : public BaseProcess {
 public:
-    FixInfacingNormalsProcess();
-    ~FixInfacingNormalsProcess();
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
+    FixInfacingNormalsProcess() = default;
+    ~FixInfacingNormalsProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
@@ -68,14 +69,14 @@ public:
      *   combination of #aiPostProcessSteps.
      * @return true if the process is present in this flag fields, false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
 protected:
 

+ 0 - 4
code/PostProcessing/GenBoundingBoxesProcess.cpp

@@ -48,10 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp {
 
-GenBoundingBoxesProcess::GenBoundingBoxesProcess() = default;
-
-GenBoundingBoxesProcess::~GenBoundingBoxesProcess() = default;
-
 bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const {
     return 0 != ( pFlags & aiProcess_GenBoundingBoxes );
 }

+ 14 - 9
code/PostProcessing/GenBoundingBoxesProcess.h

@@ -19,7 +19,7 @@ conditions are met:
   copyright notice, this list of conditions and the
   following disclaimer in the documentation and/or other
   materials provided with the distribution.
-
+s
 * 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
@@ -54,18 +54,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp {
 
-/** Post-processing process to find axis-aligned bounding volumes for amm meshes
- *  used in a scene
+/** 
+ * @brief Post-processing process to find axis-aligned bounding volumes for amm meshes
+ *        used in a scene.
  */
 class ASSIMP_API GenBoundingBoxesProcess : public BaseProcess {
 public:
-    /// The class constructor.
-    GenBoundingBoxesProcess();
-    /// The class destructor.
-    ~GenBoundingBoxesProcess();
-    /// Will return true, if aiProcess_GenBoundingBoxes is defined.
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
+    GenBoundingBoxesProcess() = default;
+    ~GenBoundingBoxesProcess() override = default;
+
+    // -------------------------------------------------------------------
+    /// @brief Will return true, if aiProcess_GenBoundingBoxes is defined.
     bool IsActive(unsigned int pFlags) const override;
-    /// The execution callback.
+
+    // -------------------------------------------------------------------
+    /// @brief The execution callback.
     void Execute(aiScene* pScene) override;
 };
 

+ 0 - 8
code/PostProcessing/GenFaceNormalsProcess.cpp

@@ -54,14 +54,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 
-// ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by Importer
-GenFaceNormalsProcess::GenFaceNormalsProcess() = default;
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-GenFaceNormalsProcess::~GenFaceNormalsProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const {

+ 11 - 13
code/PostProcessing/GenFaceNormalsProcess.h

@@ -47,35 +47,33 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "Common/BaseProcess.h"
 #include <assimp/mesh.h>
 
-namespace Assimp
-{
+namespace Assimp {
 
 // ---------------------------------------------------------------------------
-/** The GenFaceNormalsProcess computes face normals for all faces of all meshes
-*/
-class ASSIMP_API_WINONLY GenFaceNormalsProcess : public BaseProcess
-{
+/** 
+ * @brief The GenFaceNormalsProcess computes face normals for all faces of all meshes
+ */
+class ASSIMP_API_WINONLY GenFaceNormalsProcess : public BaseProcess {
 public:
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
+    GenFaceNormalsProcess() = default;
+    ~GenFaceNormalsProcess() override = default;
 
-    GenFaceNormalsProcess();
-    ~GenFaceNormalsProcess();
-
-public:
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
     * @param pFlags The processing flags the importer was called with. A bitwise
     *   combination of #aiPostProcessSteps.
     * @return true if the process is present in this flag fields, false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
-
+    void Execute( aiScene* pScene) override;
 
 private:
     bool GenMeshFaceNormals(aiMesh* pcMesh);

+ 5 - 8
code/PostProcessing/GenVertexNormalsProcess.cpp

@@ -60,10 +60,6 @@ GenVertexNormalsProcess::GenVertexNormalsProcess() :
     // empty
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-GenVertexNormalsProcess::~GenVertexNormalsProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool GenVertexNormalsProcess::IsActive(unsigned int pFlags) const {
@@ -109,10 +105,10 @@ void GenVertexNormalsProcess::Execute(aiScene *pScene) {
 // Executes the post processing step on the given imported data.
 bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int meshIndex) {
     if (nullptr != pMesh->mNormals) {
-        if (force_)
-            delete[] pMesh->mNormals;
-        else
+        if (!force_) {
             return false;
+        }
+        delete[] pMesh->mNormals;
     }
 
     // If the mesh consists of lines and/or points but not of
@@ -144,8 +140,9 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int m
         const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]];
         // Boolean XOR - if either but not both of these flags is set, then the winding order has
         // changed and the cross product to calculate the normal needs to be reversed
-        if (flippedWindingOrder_ != leftHanded_)
+        if (flippedWindingOrder_ != leftHanded_) {
             std::swap(pV2, pV3);
+        }
         const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
 
         for (unsigned int i = 0; i < face.mNumIndices; ++i) {

+ 6 - 5
code/PostProcessing/GenVertexNormalsProcess.h

@@ -60,8 +60,10 @@ namespace Assimp {
 */
 class ASSIMP_API GenVertexNormalsProcess : public BaseProcess {
 public:
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     GenVertexNormalsProcess();
-    ~GenVertexNormalsProcess();
+    ~GenVertexNormalsProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag.
@@ -70,22 +72,21 @@ public:
     * @return true if the process is present in this flag fields,
     *   false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Called prior to ExecuteOnScene().
     * The function is a request to the process to update its configuration
     * basing on the Importer's configuration property list.
     */
-    void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer* pImp) override;
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
-
+    void Execute( aiScene* pScene) override;
 
     // setter for configMaxAngle
     inline void SetMaxSmoothAngle(ai_real f) {

+ 0 - 4
code/PostProcessing/ImproveCacheLocality.cpp

@@ -68,10 +68,6 @@ ImproveCacheLocalityProcess::ImproveCacheLocalityProcess()
     // empty
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-ImproveCacheLocalityProcess::~ImproveCacheLocalityProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const {

+ 8 - 11
code/PostProcessing/ImproveCacheLocality.h

@@ -51,8 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiMesh;
 
-namespace Assimp
-{
+namespace Assimp {
 
 // ---------------------------------------------------------------------------
 /** The ImproveCacheLocalityProcess reorders all faces for improved vertex
@@ -61,26 +60,24 @@ namespace Assimp
  *
  *  @note This step expects triagulated input data.
  */
-class ImproveCacheLocalityProcess : public BaseProcess
-{
+class ImproveCacheLocalityProcess : public BaseProcess {
 public:
-
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     ImproveCacheLocalityProcess();
-    ~ImproveCacheLocalityProcess();
-
-public:
+    ~ImproveCacheLocalityProcess() override = default;
 
     // -------------------------------------------------------------------
     // Check whether the pp step is active
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     // Executes the pp step on a given scene
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     // Configures the pp step
-    void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer* pImp) override;
 
 protected:
     // -------------------------------------------------------------------

+ 6 - 10
code/PostProcessing/JoinVerticesProcess.h

@@ -51,8 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiMesh;
 
-namespace Assimp
-{
+namespace Assimp {
 
 // ---------------------------------------------------------------------------
 /** The JoinVerticesProcess unites identical vertices in all imported meshes.
@@ -65,12 +64,9 @@ namespace Assimp
 class ASSIMP_API JoinVerticesProcess : public BaseProcess {
 public:
     // -------------------------------------------------------------------
-    /// @brief  The default class constructor.
-    JoinVerticesProcess() = default;
-    
-    // -------------------------------------------------------------------
-    /// @brief  The default class destructor.
-    ~JoinVerticesProcess() = default;
+    /// The default class constructor / destructor.
+    JoinVerticesProcess() = default;    
+    ~JoinVerticesProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
@@ -78,14 +74,14 @@ public:
      *   combination of #aiPostProcessSteps.
      * @return true if the process is present in this flag fields, false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     /** Unites identical vertices in the given mesh.

+ 3 - 5
code/PostProcessing/LimitBoneWeightsProcess.cpp

@@ -53,11 +53,9 @@ namespace Assimp {
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-LimitBoneWeightsProcess::LimitBoneWeightsProcess() : mMaxWeights(AI_LMW_MAX_WEIGHTS) {}
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-LimitBoneWeightsProcess::~LimitBoneWeightsProcess() = default;
+LimitBoneWeightsProcess::LimitBoneWeightsProcess() : mMaxWeights(AI_LMW_MAX_WEIGHTS) {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.

+ 12 - 10
code/PostProcessing/LimitBoneWeightsProcess.h

@@ -74,8 +74,10 @@ namespace Assimp {
 */
 class ASSIMP_API LimitBoneWeightsProcess : public BaseProcess {
 public:
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     LimitBoneWeightsProcess();
-    ~LimitBoneWeightsProcess();
+    ~LimitBoneWeightsProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag.
@@ -84,27 +86,27 @@ public:
     * @return true if the process is present in this flag fields,
     *   false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Called prior to ExecuteOnScene().
     * The function is a request to the process to update its configuration
     * basing on the Importer's configuration property list.
     */
-    void SetupProperties(const Importer* pImp);
-
-    // -------------------------------------------------------------------
-    /** Limits the bone weight count for all vertices in the given mesh.
-    * @param pMesh The mesh to process.
-    */
-    void ProcessMesh( aiMesh* pMesh);
+    void SetupProperties(const Importer* pImp) override;
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
+
+    // -------------------------------------------------------------------
+    /** Limits the bone weight count for all vertices in the given mesh.
+    * @param pMesh The mesh to process.
+    */
+    void ProcessMesh( aiMesh* pMesh);
 
     // -------------------------------------------------------------------
     /** Describes a bone weight on a vertex */

+ 0 - 4
code/PostProcessing/MakeVerboseFormat.cpp

@@ -49,10 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 
-// ------------------------------------------------------------------------------------------------
-MakeVerboseFormatProcess::MakeVerboseFormatProcess() = default;
-// ------------------------------------------------------------------------------------------------
-MakeVerboseFormatProcess::~MakeVerboseFormatProcess() = default;
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 void MakeVerboseFormatProcess::Execute(aiScene *pScene) {

+ 7 - 10
code/PostProcessing/MakeVerboseFormat.h

@@ -66,22 +66,19 @@ namespace Assimp    {
  * The step has been added because it was required by the viewer, however
  * it has been moved to the main library since others might find it
  * useful, too. */
-class ASSIMP_API_WINONLY MakeVerboseFormatProcess : public BaseProcess
-{
-public:
-
-
-    MakeVerboseFormatProcess();
-    ~MakeVerboseFormatProcess();
-
+class ASSIMP_API_WINONLY MakeVerboseFormatProcess : public BaseProcess {
 public:
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
+    MakeVerboseFormatProcess() = default;
+    ~MakeVerboseFormatProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
     * @param pFlags The processing flags the importer was called with. A bitwise
     *   combination of #aiPostProcessSteps.
     * @return true if the process is present in this flag fields, false if not */
-    bool IsActive( unsigned int /*pFlags*/ ) const
+    bool IsActive( unsigned int /*pFlags*/ ) const  override
     {
         // NOTE: There is no direct flag that corresponds to
         // this postprocess step.
@@ -92,7 +89,7 @@ public:
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at. */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
 public:
 

+ 0 - 4
code/PostProcessing/OptimizeGraph.cpp

@@ -78,10 +78,6 @@ OptimizeGraphProcess::OptimizeGraphProcess() :
 	// empty
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-OptimizeGraphProcess::~OptimizeGraphProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const {

+ 3 - 1
code/PostProcessing/OptimizeGraph.h

@@ -71,8 +71,10 @@ namespace Assimp    {
  */
 class OptimizeGraphProcess : public BaseProcess {
 public:
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     OptimizeGraphProcess();
-    ~OptimizeGraphProcess();
+    ~OptimizeGraphProcess() override = default;
 
     // -------------------------------------------------------------------
     bool IsActive( unsigned int pFlags) const override;

+ 0 - 4
code/PostProcessing/OptimizeMeshes.cpp

@@ -69,10 +69,6 @@ OptimizeMeshesProcess::OptimizeMeshesProcess()
     // empty
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-OptimizeMeshesProcess::~OptimizeMeshesProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const

+ 6 - 9
code/PostProcessing/OptimizeMeshes.h

@@ -68,11 +68,10 @@ namespace Assimp    {
  */
 class OptimizeMeshesProcess : public BaseProcess {
 public:
-    /// @brief  The class constructor.
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     OptimizeMeshesProcess();
-
-    /// @brief  The class destructor.
-    ~OptimizeMeshesProcess();
+    ~OptimizeMeshesProcess() override = default;
 
     /** @brief Internal utility to store additional mesh info
      */
@@ -94,16 +93,14 @@ public:
         unsigned int output_id;
     };
 
-public:
     // -------------------------------------------------------------------
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
-    void SetupProperties(const Importer* pImp);
-
+    void SetupProperties(const Importer* pImp) override;
 
     // -------------------------------------------------------------------
     /** @brief Specify whether you want meshes with different

+ 0 - 4
code/PostProcessing/PretransformVertices.cpp

@@ -68,10 +68,6 @@ PretransformVertices::PretransformVertices() :
 	// empty
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-PretransformVertices::~PretransformVertices() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool PretransformVertices::IsActive(unsigned int pFlags) const {

+ 3 - 1
code/PostProcessing/PretransformVertices.h

@@ -68,8 +68,10 @@ namespace Assimp {
 */
 class ASSIMP_API PretransformVertices : public BaseProcess {
 public:
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
 	PretransformVertices();
-	~PretransformVertices();
+	~PretransformVertices() override = default;
 
 	// -------------------------------------------------------------------
 	// Check whether step is active

+ 0 - 4
code/PostProcessing/RemoveRedundantMaterials.cpp

@@ -62,10 +62,6 @@ RemoveRedundantMatsProcess::RemoveRedundantMatsProcess()
     // nothing to do here
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const

+ 6 - 7
code/PostProcessing/RemoveRedundantMaterials.h

@@ -59,23 +59,22 @@ namespace Assimp    {
  */
 class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess {
 public:
-    /// The default class constructor.
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     RemoveRedundantMatsProcess();
-
-    /// The class destructor.
-    ~RemoveRedundantMatsProcess();
+    ~RemoveRedundantMatsProcess() override = default;
 
     // -------------------------------------------------------------------
     // Check whether step is active
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     // Execute step on a given scene
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     // Setup import settings
-    void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer* pImp) override;
 
     // -------------------------------------------------------------------
     /** @brief Set list of fixed (inmutable) materials

+ 0 - 4
code/PostProcessing/RemoveVCProcess.cpp

@@ -56,10 +56,6 @@ using namespace Assimp;
 RemoveVCProcess::RemoveVCProcess() :
         configDeleteFlags(), mScene() {}
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-RemoveVCProcess::~RemoveVCProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool RemoveVCProcess::IsActive(unsigned int pFlags) const {

+ 8 - 11
code/PostProcessing/RemoveVCProcess.h

@@ -58,11 +58,10 @@ namespace Assimp {
 */
 class ASSIMP_API RemoveVCProcess : public BaseProcess {
 public:
-    /// The default class constructor.
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     RemoveVCProcess();
-
-    /// The class destructor.
-    ~RemoveVCProcess();
+    ~RemoveVCProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
@@ -70,37 +69,35 @@ public:
     *   combination of #aiPostProcessSteps.
     * @return true if the process is present in this flag fields, false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     /** Called prior to ExecuteOnScene().
     * The function is a request to the process to update its configuration
     * basing on the Importer's configuration property list.
     */
-    virtual void SetupProperties(const Importer* pImp);
+    virtual void SetupProperties(const Importer* pImp) override;
 
     // -------------------------------------------------------------------
     /** Manually setup the configuration flags for the step
      *
      *  @param Bitwise combination of the #aiComponent enumerated values.
     */
-    void SetDeleteFlags(unsigned int f)
-    {
+    void SetDeleteFlags(unsigned int f) {
         configDeleteFlags = f;
     }
 
     // -------------------------------------------------------------------
     /** Query the current configuration.
     */
-    unsigned int GetDeleteFlags() const
-    {
+    unsigned int GetDeleteFlags() const {
         return configDeleteFlags;
     }
 

+ 19 - 24
code/PostProcessing/ScaleProcess.cpp

@@ -47,25 +47,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp {
 
-ScaleProcess::ScaleProcess()
-: BaseProcess()
-, mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) {
+// ------------------------------------------------------------------------------------------------
+ScaleProcess::ScaleProcess() : BaseProcess(), mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) {
+    // empty
 }
 
-ScaleProcess::~ScaleProcess() = default;
-
+// ------------------------------------------------------------------------------------------------
 void ScaleProcess::setScale( ai_real scale ) {
     mScale = scale;
 }
 
+// ------------------------------------------------------------------------------------------------
 ai_real ScaleProcess::getScale() const {
     return mScale;
 }
 
+// ------------------------------------------------------------------------------------------------
 bool ScaleProcess::IsActive( unsigned int pFlags ) const {
     return ( pFlags & aiProcess_GlobalScale ) != 0;
 }
 
+// ------------------------------------------------------------------------------------------------
 void ScaleProcess::SetupProperties( const Importer* pImp ) {
     // User scaling
     mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f );
@@ -78,6 +80,7 @@ void ScaleProcess::SetupProperties( const Importer* pImp ) {
     mScale *= importerScale;
 }
 
+// ------------------------------------------------------------------------------------------------
 void ScaleProcess::Execute( aiScene* pScene ) {
     if(mScale == 1.0f)  {
         return; // nothing to scale
@@ -96,37 +99,30 @@ void ScaleProcess::Execute( aiScene* pScene ) {
     }
 
     // Process animations and update position transform to new unit system
-    for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ )
-    {
+    for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ ) {
         aiAnimation* animation = pScene->mAnimations[animationID];
 
-        for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++)
-        {
+        for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++) {
             aiNodeAnim* anim = animation->mChannels[animationChannel];
 
-            for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++)
-            {
+            for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++) {
                 aiVectorKey& vectorKey = anim->mPositionKeys[posKey];
                 vectorKey.mValue *= mScale;
             }
         }
     }
 
-    for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++)
-    {
+    for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++) {
         aiMesh *mesh = pScene->mMeshes[meshID];
 
         // Reconstruct mesh vertices to the new unit system
-        for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++)
-        {
+        for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++) {
             aiVector3D& vertex = mesh->mVertices[vertexID];
             vertex *= mScale;
         }
 
-
         // bone placement / scaling
-        for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++)
-        {
+        for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++) {
             // Reconstruct matrix by transform rather than by scale
             // This prevent scale values being changed which can
             // be meaningful in some cases
@@ -152,12 +148,10 @@ void ScaleProcess::Execute( aiScene* pScene ) {
 
         // animation mesh processing
         // convert by position rather than scale.
-        for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++)
-        {
+        for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++) {
             aiAnimMesh * animMesh = mesh->mAnimMeshes[animMeshID];
 
-            for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++)
-            {
+            for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++) {
                 aiVector3D& vertex = animMesh->mVertices[vertexID];
                 vertex *= mScale;
             }
@@ -167,16 +161,17 @@ void ScaleProcess::Execute( aiScene* pScene ) {
     traverseNodes( pScene->mRootNode );
 }
 
+// ------------------------------------------------------------------------------------------------
 void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) {
     applyScaling( node );
 
-    for( size_t i = 0; i < node->mNumChildren; i++)
-    {
+    for( size_t i = 0; i < node->mNumChildren; i++) {
         // recurse into the tree until we are done!
         traverseNodes( node->mChildren[i], nested_node_id+1 );
     }
 }
 
+// ------------------------------------------------------------------------------------------------
 void ScaleProcess::applyScaling( aiNode *currentNode ) {
     if ( nullptr != currentNode ) {
         // Reconstruct matrix by transform rather than by scale

+ 6 - 7
code/PostProcessing/ScaleProcess.h

@@ -62,11 +62,10 @@ namespace Assimp {
 */
 class ASSIMP_API ScaleProcess : public BaseProcess {
 public:
-    /// The default class constructor.
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     ScaleProcess();
-
-    /// The class destructor.
-    virtual ~ScaleProcess();
+    ~ScaleProcess() override = default;
 
     /// Will set the scale manually.
     void setScale( ai_real scale );
@@ -75,13 +74,13 @@ public:
     ai_real getScale() const;
 
     /// Overwritten, @see BaseProcess
-    virtual bool IsActive( unsigned int pFlags ) const;
+    virtual bool IsActive( unsigned int pFlags ) const override;
 
     /// Overwritten, @see BaseProcess
-    virtual void SetupProperties( const Importer* pImp );
+    virtual void SetupProperties( const Importer* pImp ) override;
 
     /// Overwritten, @see BaseProcess
-    virtual void Execute( aiScene* pScene );
+    virtual void Execute( aiScene* pScene ) override;
 
 private:
     void traverseNodes( aiNode *currentNode, unsigned int nested_node_id = 0 );

+ 0 - 4
code/PostProcessing/SortByPTypeProcess.cpp

@@ -59,10 +59,6 @@ SortByPTypeProcess::SortByPTypeProcess() :
     // empty
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-SortByPTypeProcess::~SortByPTypeProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool SortByPTypeProcess::IsActive(unsigned int pFlags) const {

+ 6 - 4
code/PostProcessing/SortByPTypeProcess.h

@@ -60,17 +60,19 @@ namespace Assimp    {
 */
 class ASSIMP_API SortByPTypeProcess : public BaseProcess {
 public:
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     SortByPTypeProcess();
-    ~SortByPTypeProcess();
+    ~SortByPTypeProcess() override = default;
 
     // -------------------------------------------------------------------
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
-    void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer* pImp) override;
 
 private:
     int mConfigRemoveMeshes;

+ 63 - 121
code/PostProcessing/SplitByBoneCountProcess.cpp

@@ -40,7 +40,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
-
 /// @file SplitByBoneCountProcess.cpp
 /// Implementation of the SplitByBoneCount postprocessing step
 
@@ -59,47 +58,36 @@ using namespace Assimp::Formatter;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor
-SplitByBoneCountProcess::SplitByBoneCountProcess()
-{
-    // set default, might be overridden by importer config
-    mMaxBoneCount = AI_SBBC_DEFAULT_MAX_BONES;
+SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) {
+    // empty
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor
-SplitByBoneCountProcess::~SplitByBoneCountProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag.
-bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const
-{
+bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const {
     return !!(pFlags & aiProcess_SplitByBoneCount);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Updates internal properties
-void SplitByBoneCountProcess::SetupProperties(const Importer* pImp)
-{
+void SplitByBoneCountProcess::SetupProperties(const Importer* pImp) {
     mMaxBoneCount = pImp->GetPropertyInteger(AI_CONFIG_PP_SBBC_MAX_BONES,AI_SBBC_DEFAULT_MAX_BONES);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void SplitByBoneCountProcess::Execute( aiScene* pScene)
-{
+void SplitByBoneCountProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("SplitByBoneCountProcess begin");
 
     // early out
     bool isNecessary = false;
     for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
-        if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount )
-        {
+        if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount ) {
             isNecessary = true;
             break;
         }
 
-    if( !isNecessary )
-    {
+    if( !isNecessary ) {
         ASSIMP_LOG_DEBUG("SplitByBoneCountProcess early-out: no meshes with more than ", mMaxBoneCount, " bones." );
         return;
     }
@@ -111,28 +99,23 @@ void SplitByBoneCountProcess::Execute( aiScene* pScene)
     // build a new array of meshes for the scene
     std::vector<aiMesh*> meshes;
 
-    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
-    {
+    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
         aiMesh* srcMesh = pScene->mMeshes[a];
 
         std::vector<aiMesh*> newMeshes;
         SplitMesh( pScene->mMeshes[a], newMeshes);
 
         // mesh was split
-        if( !newMeshes.empty() )
-        {
+        if( !newMeshes.empty() ) {
             // store new meshes and indices of the new meshes
-            for( unsigned int b = 0; b < newMeshes.size(); ++b)
-            {
+            for( unsigned int b = 0; b < newMeshes.size(); ++b) {
                 mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size()));
                 meshes.push_back( newMeshes[b]);
             }
 
             // and destroy the source mesh. It should be completely contained inside the new submeshes
             delete srcMesh;
-        }
-        else
-        {
+        } else {
             // Mesh is kept unchanged - store it's new place in the mesh array
             mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size()));
             meshes.push_back( srcMesh);
@@ -153,11 +136,9 @@ void SplitByBoneCountProcess::Execute( aiScene* pScene)
 
 // ------------------------------------------------------------------------------------------------
 // Splits the given mesh by bone count.
-void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const
-{
+void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const {
     // skip if not necessary
-    if( pMesh->mNumBones <= mMaxBoneCount )
-    {
+    if( pMesh->mNumBones <= mMaxBoneCount ) {
         return;
     }
 
@@ -165,27 +146,22 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
     // TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays
     typedef std::pair<unsigned int, float> BoneWeight;
     std::vector< std::vector<BoneWeight> > vertexBones( pMesh->mNumVertices);
-    for( unsigned int a = 0; a < pMesh->mNumBones; ++a)
-    {
+    for( unsigned int a = 0; a < pMesh->mNumBones; ++a) {
         const aiBone* bone = pMesh->mBones[a];
-        for( unsigned int b = 0; b < bone->mNumWeights; ++b)
-        {
-          if (bone->mWeights[b].mWeight > 0.0f)
-          {
-            int vertexId = bone->mWeights[b].mVertexId;
-            vertexBones[vertexId].emplace_back(a, bone->mWeights[b].mWeight);
-            if (vertexBones[vertexId].size() > mMaxBoneCount)
-            {
-              throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!");
+        for( unsigned int b = 0; b < bone->mNumWeights; ++b) {
+            if (bone->mWeights[b].mWeight > 0.0f) {
+                int vertexId = bone->mWeights[b].mVertexId;
+                vertexBones[vertexId].emplace_back(a, bone->mWeights[b].mWeight);
+                if (vertexBones[vertexId].size() > mMaxBoneCount) {
+                    throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!");
+                }
             }
-          }
         }
     }
 
     unsigned int numFacesHandled = 0;
     std::vector<bool> isFaceHandled( pMesh->mNumFaces, false);
-    while( numFacesHandled < pMesh->mNumFaces )
-    {
+    while( numFacesHandled < pMesh->mNumFaces ) {
         // which bones are used in the current submesh
         unsigned int numBones = 0;
         std::vector<bool> isBoneUsed( pMesh->mNumBones, false);
@@ -196,11 +172,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         unsigned int numSubMeshVertices = 0;
 
         // add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit
-        for( unsigned int a = 0; a < pMesh->mNumFaces; ++a)
-        {
+        for( unsigned int a = 0; a < pMesh->mNumFaces; ++a) {
             // skip if the face is already stored in a submesh
-            if( isFaceHandled[a] )
-            {
+            if( isFaceHandled[a] ) {
                 continue;
             }
             // a small local set of new bones for the current face. State of all used bones for that face
@@ -209,33 +183,27 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
 
             const aiFace& face = pMesh->mFaces[a];
             // check every vertex if its bones would still fit into the current submesh
-            for( unsigned int b = 0; b < face.mNumIndices; ++b )
-            {
-              const std::vector<BoneWeight>& vb = vertexBones[face.mIndices[b]];
-              for( unsigned int c = 0; c < vb.size(); ++c)
-              {
-                unsigned int boneIndex = vb[c].first;
-                if( !isBoneUsed[boneIndex] )
-                {
-                  newBonesAtCurrentFace.insert(boneIndex);
+            for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
+                const std::vector<BoneWeight>& vb = vertexBones[face.mIndices[b]];
+                for( unsigned int c = 0; c < vb.size(); ++c) {
+                    unsigned int boneIndex = vb[c].first;
+                    if( !isBoneUsed[boneIndex] ) {
+                        newBonesAtCurrentFace.insert(boneIndex);
+                    }
                 }
-              }
             }
 
             // leave out the face if the new bones required for this face don't fit the bone count limit anymore
-            if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount )
-            {
+            if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount ) {
                 continue;
             }
 
             // mark all new bones as necessary
-            for (std::set<unsigned int>::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it)
-            {
-              if (!isBoneUsed[*it])
-              {
-                isBoneUsed[*it] = true;
-                numBones++;
-              }
+            for (std::set<unsigned int>::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it) {
+                if (!isBoneUsed[*it]) {
+                    isBoneUsed[*it] = true;
+                    numBones++;
+                }
             }
 
             // store the face index and the vertex count
@@ -261,27 +229,21 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         newMesh->mNumVertices = numSubMeshVertices;
         newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
         newMesh->mVertices = new aiVector3D[newMesh->mNumVertices];
-        if( pMesh->HasNormals() )
-        {
+        if( pMesh->HasNormals() ) {
             newMesh->mNormals = new aiVector3D[newMesh->mNumVertices];
         }
-        if( pMesh->HasTangentsAndBitangents() )
-        {
+        if( pMesh->HasTangentsAndBitangents() ) {
             newMesh->mTangents = new aiVector3D[newMesh->mNumVertices];
             newMesh->mBitangents = new aiVector3D[newMesh->mNumVertices];
         }
-        for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
-        {
-            if( pMesh->HasTextureCoords( a) )
-            {
+        for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) {
+            if( pMesh->HasTextureCoords( a) ) {
                 newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices];
             }
             newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
         }
-        for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
-        {
-            if( pMesh->HasVertexColors( a) )
-            {
+        for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) {
+            if( pMesh->HasVertexColors( a) ) {
                 newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices];
             }
         }
@@ -290,41 +252,33 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         newMesh->mFaces = new aiFace[subMeshFaces.size()];
         unsigned int nvi = 0; // next vertex index
         std::vector<unsigned int> previousVertexIndices( numSubMeshVertices, std::numeric_limits<unsigned int>::max()); // per new vertex: its index in the source mesh
-        for( unsigned int a = 0; a < subMeshFaces.size(); ++a )
-        {
+        for( unsigned int a = 0; a < subMeshFaces.size(); ++a ) {
             const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]];
             aiFace& dstFace = newMesh->mFaces[a];
             dstFace.mNumIndices = srcFace.mNumIndices;
             dstFace.mIndices = new unsigned int[dstFace.mNumIndices];
 
             // accumulate linearly all the vertices of the source face
-            for( unsigned int b = 0; b < dstFace.mNumIndices; ++b )
-            {
+            for( unsigned int b = 0; b < dstFace.mNumIndices; ++b ) {
                 unsigned int srcIndex = srcFace.mIndices[b];
                 dstFace.mIndices[b] = nvi;
                 previousVertexIndices[nvi] = srcIndex;
 
                 newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
-                if( pMesh->HasNormals() )
-                {
+                if( pMesh->HasNormals() ) {
                     newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
                 }
-                if( pMesh->HasTangentsAndBitangents() )
-                {
+                if( pMesh->HasTangentsAndBitangents() ) {
                     newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
                     newMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex];
                 }
-                for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c )
-                {
-                    if( pMesh->HasTextureCoords( c) )
-                    {
+                for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) {
+                    if( pMesh->HasTextureCoords( c) ) {
                         newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
                     }
                 }
-                for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c )
-                {
-                    if( pMesh->HasVertexColors( c) )
-                    {
+                for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) {
+                    if( pMesh->HasVertexColors( c) ) {
                         newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
                     }
                 }
@@ -340,10 +294,8 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         newMesh->mBones = new aiBone*[numBones];
 
         std::vector<unsigned int> mappedBoneIndex( pMesh->mNumBones, std::numeric_limits<unsigned int>::max());
-        for( unsigned int a = 0; a < pMesh->mNumBones; ++a )
-        {
-            if( !isBoneUsed[a] )
-            {
+        for( unsigned int a = 0; a < pMesh->mNumBones; ++a ) {
+            if( !isBoneUsed[a] ) {
                 continue;
             }
 
@@ -360,24 +312,20 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         ai_assert( newMesh->mNumBones == numBones );
 
         // iterate over all new vertices and count which bones affected its old vertex in the source mesh
-        for( unsigned int a = 0; a < numSubMeshVertices; ++a )
-        {
+        for( unsigned int a = 0; a < numSubMeshVertices; ++a ) {
             unsigned int oldIndex = previousVertexIndices[a];
             const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[oldIndex];
 
-            for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b )
-            {
+            for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b ) {
                 unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
-                if( newBoneIndex != std::numeric_limits<unsigned int>::max() )
-                {
+                if( newBoneIndex != std::numeric_limits<unsigned int>::max() ) {
                     newMesh->mBones[newBoneIndex]->mNumWeights++;
                 }
             }
         }
 
         // allocate all bone weight arrays accordingly
-        for( unsigned int a = 0; a < newMesh->mNumBones; ++a )
-        {
+        for( unsigned int a = 0; a < newMesh->mNumBones; ++a ) {
             aiBone* bone = newMesh->mBones[a];
             ai_assert( bone->mNumWeights > 0 );
             bone->mWeights = new aiVertexWeight[bone->mNumWeights];
@@ -385,16 +333,14 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         }
 
         // now copy all the bone vertex weights for all the vertices which made it into the new submesh
-        for( unsigned int a = 0; a < numSubMeshVertices; ++a)
-        {
+        for( unsigned int a = 0; a < numSubMeshVertices; ++a) {
             // find the source vertex for it in the source mesh
             unsigned int previousIndex = previousVertexIndices[a];
             // these bones were affecting it
             const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[previousIndex];
             // all of the bones affecting it should be present in the new submesh, or else
             // the face it comprises shouldn't be present
-            for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b)
-            {
+            for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b) {
                 unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
                 ai_assert( newBoneIndex != std::numeric_limits<unsigned int>::max() );
                 aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights;
@@ -450,14 +396,11 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
 
 // ------------------------------------------------------------------------------------------------
 // Recursively updates the node's mesh list to account for the changed mesh list
-void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const
-{
+void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const {
     // rebuild the node's mesh index list
-    if( pNode->mNumMeshes > 0 )
-    {
+    if( pNode->mNumMeshes == 0 ) {
         std::vector<unsigned int> newMeshList;
-        for( unsigned int a = 0; a < pNode->mNumMeshes; ++a)
-        {
+        for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) {
             unsigned int srcIndex = pNode->mMeshes[a];
             const std::vector<unsigned int>& replaceMeshes = mSubMeshIndices[srcIndex];
             newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end());
@@ -470,8 +413,7 @@ void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const
     }
 
     // do that also recursively for all children
-    for( unsigned int a = 0; a < pNode->mNumChildren; ++a )
-    {
+    for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) {
         UpdateNode( pNode->mChildren[a]);
     }
 }

+ 19 - 27
code/PostProcessing/SplitByBoneCountProcess.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,
@@ -51,9 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/mesh.h>
 #include <assimp/scene.h>
 
-namespace Assimp
-{
-
+namespace Assimp {
 
 /** Postprocessing filter to split meshes with many bones into submeshes
  * so that each submesh has a certain max bone count.
@@ -61,34 +58,29 @@ namespace Assimp
  * Applied BEFORE the JoinVertices-Step occurs.
  * Returns NON-UNIQUE vertices, splits by bone count.
 */
-class SplitByBoneCountProcess : public BaseProcess
-{
+class SplitByBoneCountProcess : public BaseProcess {
 public:
-
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     SplitByBoneCountProcess();
-    ~SplitByBoneCountProcess();
+    ~SplitByBoneCountProcess() override = default;
 
-public:
-    /** Returns whether the processing step is present in the given flag.
-    * @param pFlags The processing flags the importer was called with. A
-    *   bitwise combination of #aiPostProcessSteps.
-    * @return true if the process is present in this flag fields,
-    *   false if not.
-    */
-    bool IsActive( unsigned int pFlags) const;
-
-    /** Called prior to ExecuteOnScene().
-    * The function is a request to the process to update its configuration
-    * basing on the Importer's configuration property list.
-    */
-    virtual void SetupProperties(const Importer* pImp);
+    /// @brief Returns whether the processing step is present in the given flag.
+    /// @param pFlags The processing flags the importer was called with. A
+    ///        bitwise combination of #aiPostProcessSteps.
+    /// @return true if the process is present in this flag fields, false if not.
+    bool IsActive( unsigned int pFlags) const override;
+
+    /// @brief Called prior to ExecuteOnScene().
+    /// The function is a request to the process to update its configuration
+    /// basing on the Importer's configuration property list.
+    virtual void SetupProperties(const Importer* pImp) override;
 
 protected:
-    /** Executes the post processing step on the given imported data.
-    * At the moment a process is not supposed to fail.
-    * @param pScene The imported data to work at.
-    */
-    void Execute( aiScene* pScene);
+    /// Executes the post processing step on the given imported data.
+    /// At the moment a process is not supposed to fail.
+    /// @param pScene The imported data to work at.
+    void Execute( aiScene* pScene) override;
 
     /// Splits the given mesh by bone count.
     /// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.

+ 0 - 6
code/PostProcessing/SplitLargeMeshes.cpp

@@ -55,9 +55,6 @@ SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() {
     LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
 }
 
-// ------------------------------------------------------------------------------------------------
-SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const {
@@ -329,9 +326,6 @@ SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() {
     LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
 }
 
-// ------------------------------------------------------------------------------------------------
-SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const {

+ 12 - 24
code/PostProcessing/SplitLargeMeshes.h

@@ -83,16 +83,15 @@ class SplitLargeMeshesProcess_Vertex;
  * Applied BEFORE the JoinVertices-Step occurs.
  * Returns NON-UNIQUE vertices, splits by triangle number.
 */
-class ASSIMP_API SplitLargeMeshesProcess_Triangle : public BaseProcess
-{
+class ASSIMP_API SplitLargeMeshesProcess_Triangle : public BaseProcess {
     friend class SplitLargeMeshesProcess_Vertex;
 
 public:
-
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     SplitLargeMeshesProcess_Triangle();
-    ~SplitLargeMeshesProcess_Triangle();
+    ~SplitLargeMeshesProcess_Triangle() override = default;
 
-public:
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag.
     * @param pFlags The processing flags the importer was called with. A
@@ -100,16 +99,14 @@ public:
     * @return true if the process is present in this flag fields,
     *   false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
-
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Called prior to ExecuteOnScene().
     * The function is a request to the process to update its configuration
     * basing on the Importer's configuration property list.
     */
-    virtual void SetupProperties(const Importer* pImp);
-
+    void SetupProperties(const Importer* pImp) override;
 
     //! Set the split limit - needed for unit testing
     inline void SetLimit(unsigned int l)
@@ -119,14 +116,12 @@ public:
     inline unsigned int GetLimit() const
         {return LIMIT;}
 
-public:
-
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     //! Apply the algorithm to a given mesh
@@ -144,36 +139,31 @@ public:
     unsigned int LIMIT;
 };
 
-
 // ---------------------------------------------------------------------------
 /** Post-processing filter to split large meshes into sub-meshes
  *
  * Applied AFTER the JoinVertices-Step occurs.
  * Returns UNIQUE vertices, splits by vertex number.
 */
-class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess
-{
+class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess {
 public:
-
     SplitLargeMeshesProcess_Vertex();
-    ~SplitLargeMeshesProcess_Vertex();
+    ~SplitLargeMeshesProcess_Vertex() override = default;
 
-public:
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
     * @param pFlags The processing flags the importer was called with. A bitwise
     *   combination of #aiPostProcessSteps.
     * @return true if the process is present in this flag fields, false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Called prior to ExecuteOnScene().
     * The function is a request to the process to update its configuration
     * basing on the Importer's configuration property list.
     */
-    virtual void SetupProperties(const Importer* pImp);
-
+    void SetupProperties(const Importer* pImp) override;
 
     //! Set the split limit - needed for unit testing
     inline void SetLimit(unsigned int l)
@@ -183,14 +173,12 @@ public:
     inline unsigned int GetLimit() const
         {return LIMIT;}
 
-public:
-
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     //! Apply the algorithm to a given mesh

+ 10 - 24
code/PostProcessing/TextureTransform.cpp

@@ -56,33 +56,24 @@ using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-TextureTransformStep::TextureTransformStep() :
-    configFlags()
-{
+TextureTransformStep::TextureTransformStep() : configFlags()  {
     // nothing to do here
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-TextureTransformStep::~TextureTransformStep() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool TextureTransformStep::IsActive( unsigned int pFlags) const
-{
+bool TextureTransformStep::IsActive( unsigned int pFlags) const {
     return  (pFlags & aiProcess_TransformUVCoords) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup properties
-void TextureTransformStep::SetupProperties(const Importer* pImp)
-{
+void TextureTransformStep::SetupProperties(const Importer* pImp) {
     configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL);
 }
 
 // ------------------------------------------------------------------------------------------------
-void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
-{
+void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) {
     /*  This function tries to simplify the input UV transformation.
      *  That's very important as it allows us to reduce the number
      *  of output UV channels. The order in which the transformations
@@ -90,7 +81,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
      */
 
 	int rounded;
-	char szTemp[512];
+	char szTemp[512] = {};
 
     /* Optimize the rotation angle. That's slightly difficult as
      * we have an inprecise floating-point number (when comparing
@@ -98,12 +89,10 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
      * an epsilon of 5 degrees). If there is a rotation value, we can't
      * perform any further optimizations.
      */
-    if (info.mRotation)
-    {
+    if (info.mRotation) {
         float out = info.mRotation;
         rounded = static_cast<int>((info.mRotation / static_cast<float>(AI_MATH_TWO_PI)));
-        if (rounded)
-        {
+        if (rounded) {
             out -= rounded * static_cast<float>(AI_MATH_PI);
             ASSIMP_LOG_INFO("Texture coordinate rotation ", info.mRotation, " can be simplified to ", out);
         }
@@ -187,8 +176,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
 }
 
 // ------------------------------------------------------------------------------------------------
-void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n)
-{
+void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n) {
     // Don't set if == 0 && wasn't set before
     for (std::list<TTUpdateInfo>::const_iterator it = l.begin();it != l.end(); ++it) {
         const TTUpdateInfo& info = *it;
@@ -203,8 +191,7 @@ void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n)
 }
 
 // ------------------------------------------------------------------------------------------------
-inline const char* MappingModeToChar(aiTextureMapMode map)
-{
+inline static const char* MappingModeToChar(aiTextureMapMode map) {
     if (aiTextureMapMode_Wrap == map)
         return "-w";
 
@@ -215,8 +202,7 @@ inline const char* MappingModeToChar(aiTextureMapMode map)
 }
 
 // ------------------------------------------------------------------------------------------------
-void TextureTransformStep::Execute( aiScene* pScene)
-{
+void TextureTransformStep::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("TransformUVCoordsProcess begin");
 
 

+ 9 - 15
code/PostProcessing/TextureTransform.h

@@ -193,28 +193,23 @@ struct STransformVecInfo : public aiUVTransform {
 /** Helper step to compute final UV coordinate sets if there are scalings
  *  or rotations in the original data read from the file.
 */
-class TextureTransformStep : public BaseProcess
-{
+class TextureTransformStep : public BaseProcess {
 public:
-
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     TextureTransformStep();
-    ~TextureTransformStep();
-
-public:
+    ~TextureTransformStep() override = default;
 
     // -------------------------------------------------------------------
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
-    void SetupProperties(const Importer* pImp);
-
+    void SetupProperties(const Importer* pImp) override;
 
 protected:
-
-
     // -------------------------------------------------------------------
     /** Preprocess a specific UV transformation setup
      *
@@ -223,10 +218,9 @@ protected:
     void PreProcessUVTransform(STransformVecInfo& info);
 
 private:
-
     unsigned int configFlags;
 };
-
-}
+ 
+} // namespace Assimp
 
 #endif //! AI_TEXTURE_TRANSFORM_H_INCLUDED

+ 15 - 9
code/PostProcessing/TriangulateProcess.cpp

@@ -156,15 +156,6 @@ namespace {
 
 }
 
-
-// ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by Importer
-TriangulateProcess::TriangulateProcess() = default;
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-TriangulateProcess::~TriangulateProcess() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool TriangulateProcess::IsActive( unsigned int pFlags) const
@@ -468,6 +459,21 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
                         continue;
                     }
 
+                    // Skip when three point is in a line
+                    aiVector2D left = *pnt0 - *pnt1;
+                    aiVector2D right = *pnt2 - *pnt1;
+
+                    left.Normalize();
+                    right.Normalize();
+                    auto mul = left * right;
+
+                    // if the angle is 0 or 180
+                    if (std::abs(mul - 1.f) < ai_epsilon || std::abs(mul + 1.f) < ai_epsilon) {
+                        // skip this ear
+                        ASSIMP_LOG_WARN("Skip a ear, due to its angle is near 0 or 180.");
+                        continue;
+                    }
+
                     // and no other point may be contained in this triangle
                     for ( tmp = 0; tmp < max; ++tmp) {
 

+ 6 - 4
code/PostProcessing/TriangulateProcess.h

@@ -61,8 +61,10 @@ namespace Assimp {
  */
 class ASSIMP_API TriangulateProcess : public BaseProcess {
 public:
-    TriangulateProcess();
-    ~TriangulateProcess();
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
+    TriangulateProcess() = default;
+    ~TriangulateProcess() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
@@ -70,14 +72,14 @@ public:
      *   combination of #aiPostProcessSteps.
      * @return true if the process is present in this flag fields, false if not.
     */
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.
     * @param pScene The imported data to work at.
     */
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
     // -------------------------------------------------------------------
     /** Triangulates the given mesh.

+ 1 - 6
code/PostProcessing/ValidateDataStructure.cpp

@@ -60,12 +60,7 @@ using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-ValidateDSProcess::ValidateDSProcess() :
-        mScene() {}
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-ValidateDSProcess::~ValidateDSProcess() = default;
+ValidateDSProcess::ValidateDSProcess() : mScene(nullptr) {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.

+ 6 - 8
code/PostProcessing/ValidateDataStructure.h

@@ -69,22 +69,20 @@ namespace Assimp    {
 /** Validates the whole ASSIMP scene data structure for correctness.
  *  ImportErrorException is thrown of the scene is corrupt.*/
 // --------------------------------------------------------------------------------------
-class ValidateDSProcess : public BaseProcess
-{
+class ValidateDSProcess : public BaseProcess {
 public:
-
+    // -------------------------------------------------------------------
+    /// The default class constructor / destructor.
     ValidateDSProcess();
-    ~ValidateDSProcess();
+    ~ValidateDSProcess() override = default;
 
-public:
     // -------------------------------------------------------------------
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
     // -------------------------------------------------------------------
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
 protected:
-
     // -------------------------------------------------------------------
     /** Report a validation error. This will throw an exception,
      *  control won't return.

+ 126 - 91
contrib/draco/.cmake-format.py

@@ -1,102 +1,137 @@
-# Generated with cmake-format 0.5.1
-# How wide to allow formatted cmake files
-line_width = 80
-
-# How many spaces to tab for indent
-tab_size = 2
-
-# If arglists are longer than this, break them always
-max_subargs_per_line = 10
-
-# If true, separate flow control names from their parentheses with a space
-separate_ctrl_name_with_space = False
-
-# If true, separate function names from parentheses with a space
-separate_fn_name_with_space = False
-
-# If a statement is wrapped to more than one line, than dangle the closing
-# parenthesis on its own line
-dangle_parens = False
-
-# What character to use for bulleted lists
-bullet_char = '*'
-
-# What character to use as punctuation after numerals in an enumerated list
-enum_char = '.'
-
-# What style line endings to use in the output.
-line_ending = u'unix'
-
-# Format command names consistently as 'lower' or 'upper' case
-command_case = u'lower'
-
-# Format keywords consistently as 'lower' or 'upper' case
-keyword_case = u'unchanged'
-
-# Specify structure for custom cmake functions
-additional_commands = {
-  "foo": {
-    "flags": [
-      "BAR",
-      "BAZ"
-    ],
-    "kwargs": {
-      "HEADERS": "*",
-      "DEPENDS": "*",
-      "SOURCES": "*"
-    }
+with section('parse'):
+  # Specify structure for custom cmake functions
+  additional_commands = {
+      'draco_add_emscripten_executable': {
+          'kwargs': {
+              'NAME': '*',
+              'SOURCES': '*',
+              'OUTPUT_NAME': '*',
+              'DEFINES': '*',
+              'INCLUDES': '*',
+              'COMPILE_FLAGS': '*',
+              'LINK_FLAGS': '*',
+              'OBJLIB_DEPS': '*',
+              'LIB_DEPS': '*',
+              'GLUE_PATH': '*',
+              'PRE_LINK_JS_SOURCES': '*',
+              'POST_LINK_JS_SOURCES': '*',
+              'FEATURES': '*',
+          },
+          'pargs': 0,
+      },
+      'draco_add_executable': {
+          'kwargs': {
+              'NAME': '*',
+              'SOURCES': '*',
+              'OUTPUT_NAME': '*',
+              'TEST': 0,
+              'DEFINES': '*',
+              'INCLUDES': '*',
+              'COMPILE_FLAGS': '*',
+              'LINK_FLAGS': '*',
+              'OBJLIB_DEPS': '*',
+              'LIB_DEPS': '*',
+          },
+          'pargs': 0,
+      },
+      'draco_add_library': {
+          'kwargs': {
+              'NAME': '*',
+              'TYPE': '*',
+              'SOURCES': '*',
+              'TEST': 0,
+              'OUTPUT_NAME': '*',
+              'DEFINES': '*',
+              'INCLUDES': '*',
+              'COMPILE_FLAGS': '*',
+              'LINK_FLAGS': '*',
+              'OBJLIB_DEPS': '*',
+              'LIB_DEPS': '*',
+              'PUBLIC_INCLUDES': '*',
+          },
+          'pargs': 0,
+      },
+      'draco_generate_emscripten_glue': {
+          'kwargs': {
+              'INPUT_IDL': '*',
+              'OUTPUT_PATH': '*',
+          },
+          'pargs': 0,
+      },
+      'draco_get_required_emscripten_flags': {
+          'kwargs': {
+              'FLAG_LIST_VAR_COMPILER': '*',
+              'FLAG_LIST_VAR_LINKER': '*',
+          },
+          'pargs': 0,
+      },
+      'draco_option': {
+          'kwargs': {
+              'NAME': '*',
+              'HELPSTRING': '*',
+              'VALUE': '*',
+          },
+          'pargs': 0,
+      },
+      # Rules for built in CMake commands and those from dependencies.
+      'list': {
+          'kwargs': {
+              'APPEND': '*',
+              'FILTER': '*',
+              'FIND': '*',
+              'GET': '*',
+              'INSERT': '*',
+              'JOIN': '*',
+              'LENGTH': '*',
+              'POP_BACK': '*',
+              'POP_FRONT': '*',
+              'PREPEND': '*',
+              'REMOVE_DUPLICATES': '*',
+              'REMOVE_ITEM': '*',
+              'REVERSE': '*',
+              'SORT': '*',
+              'SUBLIST': '*',
+              'TRANSFORM': '*',
+          },
+      },
+      'protobuf_generate': {
+        'kwargs': {
+            'IMPORT_DIRS': '*',
+            'LANGUAGE': '*',
+            'OUT_VAR': '*',
+            'PROTOC_OUT_DIR': '*',
+            'PROTOS': '*',
+        },
+      },
   }
-}
-
-# A list of command names which should always be wrapped
-always_wrap = []
-
-# Specify the order of wrapping algorithms during successive reflow attempts
-algorithm_order = [0, 1, 2, 3, 4]
-
-# If true, the argument lists which are known to be sortable will be sorted
-# lexicographicall
-autosort = False
-
-# enable comment markup parsing and reflow
-enable_markup = True
 
-# If comment markup is enabled, don't reflow the first comment block in
-# eachlistfile. Use this to preserve formatting of your
-# copyright/licensestatements.
-first_comment_is_literal = False
+with section('format'):
+  # Formatting options.
 
-# If comment markup is enabled, don't reflow any comment block which matchesthis
-# (regex) pattern. Default is `None` (disabled).
-literal_comment_pattern = None
+  # How wide to allow formatted cmake files
+  line_width = 80
 
-# Regular expression to match preformat fences in comments
-# default=r'^\s*([`~]{3}[`~]*)(.*)$'
-fence_pattern = u'^\\s*([`~]{3}[`~]*)(.*)$'
+  # How many spaces to tab for indent
+  tab_size = 2
 
-# Regular expression to match rulers in comments
-# default=r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'
-ruler_pattern = u'^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
+  # If true, separate flow control names from their parentheses with a space
+  separate_ctrl_name_with_space = False
 
-# If true, emit the unicode byte-order mark (BOM) at the start of the file
-emit_byteorder_mark = False
+  # If true, separate function names from parentheses with a space
+  separate_fn_name_with_space = False
 
-# If a comment line starts with at least this many consecutive hash characters,
-# then don't lstrip() them off. This allows for lazy hash rulers where the first
-# hash char is not separated by space
-hashruler_min_length = 10
+  # If a statement is wrapped to more than one line, than dangle the closing
+  # parenthesis on its own line.
+  dangle_parens = False
 
-# If true, then insert a space between the first hash char and remaining hash
-# chars in a hash ruler, and normalize its length to fill the column
-canonicalize_hashrulers = True
+  # Do not sort argument lists.
+  enable_sort = False
 
-# Specify the encoding of the input file. Defaults to utf-8.
-input_encoding = u'utf-8'
+  # What style line endings to use in the output.
+  line_ending = 'unix'
 
-# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
-# only claims to support utf-8 so be careful when using anything else
-output_encoding = u'utf-8'
+  # Format command names consistently as 'lower' or 'upper' case
+  command_case = 'canonical'
 
-# A dictionary containing any per-command configuration overrides. Currently
-# only `command_case` is supported.
-per_command = {}
+  # Format keywords consistently as 'lower' or 'upper' case
+  keyword_case = 'upper'

+ 1 - 0
contrib/draco/.gitattributes

@@ -0,0 +1 @@
+*.obj eol=lf

+ 12 - 0
contrib/draco/.gitmodules

@@ -0,0 +1,12 @@
+[submodule "third_party/googletest"]
+  path = third_party/googletest
+  url = https://github.com/google/googletest.git
+[submodule "third_party/eigen"]
+  path = third_party/eigen
+  url = https://gitlab.com/libeigen/eigen.git
+[submodule "third_party/tinygltf"]
+  path = third_party/tinygltf
+  url = https://github.com/syoyo/tinygltf.git
+[submodule "third_party/filesystem"]
+  path = third_party/filesystem
+  url = https://github.com/gulrak/filesystem

+ 80 - 6
contrib/draco/BUILDING.md

@@ -4,8 +4,10 @@ _**Contents**_
   * [Mac OS X](#mac-os-x)
   * [Windows](#windows)
   * [CMake Build Configuration](#cmake-build-configuration)
+    * [Transcoder](#transcoder)
     * [Debugging and Optimization](#debugging-and-optimization)
     * [Googletest Integration](#googletest-integration)
+    * [Third Party Libraries](#third-party-libraries)
     * [Javascript Encoder/Decoder](#javascript-encoderdecoder)
     * [WebAssembly Decoder](#webassembly-decoder)
     * [WebAssembly Mesh Only Decoder](#webassembly-mesh-only-decoder)
@@ -72,6 +74,43 @@ C:\Users\nobody> cmake ../ -G "Visual Studio 16 2019" -A x64
 CMake Build Configuration
 -------------------------
 
+Transcoder
+----------
+
+Before attempting to build Draco with transcoding support you must run an
+additional Git command to obtain the submodules:
+
+~~~~~ bash
+# Run this command from within your Draco clone.
+$ git submodule update --init
+# See below if you prefer to use existing versions of Draco dependencies.
+~~~~~
+
+In order to build the `draco_transcoder` target, the transcoding support needs
+to be explicitly enabled when you run `cmake`, for example:
+
+~~~~~ bash
+$ cmake ../ -DDRACO_TRANSCODER_SUPPORTED=ON
+~~~~~
+
+The above option is currently not compatible with our Javascript or WebAssembly
+builds but all other use cases are supported. Note that binaries and libraries
+built with the transcoder support may result in increased binary sizes of the
+produced libraries and executables compared to the default CMake settings.
+
+The following CMake variables can be used to configure Draco to use local
+copies of third party dependencies instead of git submodules.
+
+- `DRACO_EIGEN_PATH`: this path must contain an Eigen directory that includes
+  the Eigen sources.
+- `DRACO_FILESYSTEM_PATH`: this path must contain the ghc directory where the
+  filesystem includes are located.
+- `DRACO_TINYGLTF_PATH`: this path must contain tiny_gltf.h and its
+  dependencies.
+
+When not specified the Draco build requires the presence of the submodules that
+are stored within `draco/third_party`.
+
 Debugging and Optimization
 --------------------------
 
@@ -114,17 +153,52 @@ $ cmake ../ -DDRACO_SANITIZE=address
 Googletest Integration
 ----------------------
 
-Draco includes testing support built using Googletest. To enable Googletest unit
-test support the DRACO_TESTS cmake variable must be turned on at cmake
-generation time:
+Draco includes testing support built using Googletest. The Googletest repository
+is included as a submodule of the Draco git repository. Run the following
+command to clone the Googletest repository:
+
+~~~~~ bash
+$ git submodule update --init
+~~~~~
+
+To enable Googletest unit test support the DRACO_TESTS cmake variable must be
+turned on at cmake generation time:
 
 ~~~~~ bash
 $ cmake ../ -DDRACO_TESTS=ON
 ~~~~~
 
-When cmake is used as shown in the above example the googletest directory must
-be a sibling of the Draco repository root directory. To run the tests execute
-`draco_tests` from your build output directory.
+To run the tests execute `draco_tests` from your build output directory:
+
+~~~~~ bash
+$ ./draco_tests
+~~~~~
+
+Draco can be configured to use a local Googletest installation. The
+`DRACO_GOOGLETEST_PATH` variable overrides the behavior described above and
+configures Draco to use the Googletest at the specified path.
+
+Third Party Libraries
+---------------------
+
+When Draco is built with transcoding and/or testing support enabled the project
+has dependencies on third party libraries:
+
+- [Eigen](https://eigen.tuxfamily.org/)
+  - Provides various math utilites.
+- [Googletest](https://github.com/google/googletest)
+  - Provides testing support.
+- [Gulrak/filesystem](https://github.com/gulrak/filesystem)
+  - Provides C++17 std::filesystem emulation for pre-C++17 environments.
+- [TinyGLTF](https://github.com/syoyo/tinygltf)
+  - Provides GLTF I/O support.
+
+These dependencies are managed as Git submodules. To obtain the dependencies
+run the following command in your Draco repository:
+
+~~~~~ bash
+$ git submodule update --init
+~~~~~
 
 WebAssembly Decoder
 -------------------

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 607 - 413
contrib/draco/CMakeLists.txt


+ 140 - 10
contrib/draco/README.md

@@ -2,10 +2,93 @@
 <img width="350px" src="docs/artwork/draco3d-vert.svg" />
 </p>
 
-[![Build Status](https://github.com/google/draco/workflows/Build/badge.svg)](https://github.com/google/draco/actions?query=workflow%3ABuild)
+[![draco-ci](https://github.com/google/draco/workflows/draco-ci/badge.svg?branch=master)](https://github.com/google/draco/actions/workflows/ci.yml)
 
 News
 =======
+
+Attention GStatic users: the Draco team strongly recommends using the versioned
+URLs for accessing Draco GStatic content. If you are using the URLs that include
+the `v1/decoders` substring within the URL, edge caching and GStatic propagation
+delays can result in transient errors that can be difficult to diagnose when
+new Draco releases are launched. To avoid the issue pin your sites to a
+versioned release.
+
+### Version 1.5.6 release:
+* Using the versioned www.gstatic.com WASM and Javascript decoders continues
+  to be recommended. To use v1.5.6, use this URL:
+  * https://www.gstatic.com/draco/versioned/decoders/1.5.6/*
+* The CMake flag DRACO_DEBUG_MSVC_WARNINGS has been replaced with
+  DRACO_DEBUG_COMPILER_WARNINGS, and the behavior has changed. It is now a
+  boolean flag defined in draco_options.cmake.
+* Bug fixes.
+* Security fixes.
+
+### Version 1.5.5 release:
+* Using the versioned www.gstatic.com WASM and Javascript decoders continues
+  to be recommended. To use v1.5.5, use this URL:
+  * https://www.gstatic.com/draco/versioned/decoders/1.5.5/*
+* Bug fix: https://github.com/google/draco/issues/935
+
+### Version 1.5.4 release:
+* Using the versioned www.gstatic.com WASM and Javascript decoders continues
+  to be recommended. To use v1.5.4, use this URL:
+  * https://www.gstatic.com/draco/versioned/decoders/1.5.4/*
+* Added partial support for glTF extensions EXT_mesh_features and
+  EXT_structural_metadata.
+* Bug fixes.
+* Security fixes.
+
+### Version 1.5.3 release:
+* Using the versioned www.gstatic.com WASM and Javascript decoders continues
+  to be recommended. To use v1.5.3, use this URL:
+  * https://www.gstatic.com/draco/versioned/decoders/1.5.3/*
+* Bug fixes.
+
+### Version 1.5.2 release
+* This is the same as v1.5.1 with the following two bug fixes:
+  * Fixes DRACO_TRANSCODER_SUPPORTED enabled builds.
+  * ABI version updated.
+
+### Version 1.5.1 release
+* Adds assertion enabled Emscripten builds to the release, and a subset of the
+  assertion enabled builds to GStatic. See the file listing below.
+* Custom paths to third party dependencies are now supported. See BUILDING.md
+  for more information.
+* The CMake configuration file draco-config.cmake is now tested and known to
+  work for using Draco in Linux, MacOS, and Windows CMake projects. See the
+  `install_test` subdirectory of `src/draco/tools` for more information.
+* Bug fixes.
+
+### Version 1.5.0 release
+* Adds the draco_transcoder tool. See the section below on the glTF transcoding
+  tool, and BUILDING.md for build and dependency information.
+* Some changes to configuration variables have been made for this release:
+  - The DRACO_GLTF flag has been renamed to DRACO_GLTF_BITSTREAM to help
+    increase understanding of its purpose, which is to limit Draco features to
+    those included in the Draco glTF specification.
+  - Variables exported in CMake via draco-config.cmake and find-draco.cmake
+    (formerly FindDraco.cmake) have been renamed. It's unlikely that this
+    impacts any existing projects as the aforementioned files were not formed
+    correctly. See [PR775](https://github.com/google/draco/pull/775) for full
+    details of the changes.
+* A CMake version file has been added.
+* The CMake install target now uses absolute paths direct from CMake instead
+  of building them using CMAKE_INSTALL_PREFIX. This was done to make Draco
+  easier to use for downstream packagers and should have little to no impact on
+  users picking up Draco from source.
+* Certain MSVC warnings have had their levels changed via compiler flag to
+  reduce the amount of noise output by the MSVC compilers. Set MSVC warning
+  level to 4, or define DRACO_DEBUG_MSVC_WARNINGS at CMake configuration time
+  to restore previous behavior.
+* Bug fixes.
+
+### Version 1.4.3 release
+* Using the versioned www.gstatic.com WASM and Javascript decoders continues
+  to be recommended. To use v1.4.3, use this URL:
+  * https://www.gstatic.com/draco/versioned/decoders/1.4.3/*
+* Bug fixes
+
 ### Version 1.4.1 release
 * Using the versioned www.gstatic.com WASM and Javascript decoders is now
   recommended. To use v1.4.1, use this URL:
@@ -129,6 +212,7 @@ _**Contents**_
     * [Encoding Tool](#encoding-tool)
     * [Encoding Point Clouds](#encoding-point-clouds)
     * [Decoding Tool](#decoding-tool)
+    * [glTF Transcoding Tool](#gltf-transcoding-tool)
     * [C++ Decoder API](#c-decoder-api)
     * [Javascript Encoder API](#javascript-encoder-api)
     * [Javascript Decoder API](#javascript-decoder-api)
@@ -136,6 +220,7 @@ _**Contents**_
     * [Metadata API](#metadata-api)
     * [NPM Package](#npm-package)
     * [three.js Renderer Example](#threejs-renderer-example)
+  * [GStatic Javascript Builds](#gstatic-javascript-builds)
   * [Support](#support)
   * [License](#license)
   * [References](#references)
@@ -170,16 +255,18 @@ Command Line Applications
 ------------------------
 
 The default target created from the build files will be the `draco_encoder`
-and `draco_decoder` command line applications. For both applications, if you
-run them without any arguments or `-h`, the applications will output usage and
-options.
+and `draco_decoder` command line applications. Additionally, `draco_transcoder`
+is generated when CMake is run with the DRACO_TRANSCODER_SUPPORTED variable set
+to ON (see [BUILDING](BUILDING.md#transcoder) for more details). For all
+applications, if you run them without any arguments or `-h`, the applications
+will output usage and options.
 
 Encoding Tool
 -------------
 
-`draco_encoder` will read OBJ or PLY files as input, and output Draco-encoded
-files. We have included Stanford's [Bunny] mesh for testing. The basic command
-line looks like this:
+`draco_encoder` will read OBJ, STL or PLY files as input, and output
+Draco-encoded files. We have included Stanford's [Bunny] mesh for testing. The
+basic command line looks like this:
 
 ~~~~~ bash
 ./draco_encoder -i testdata/bun_zipper.ply -o out.drc
@@ -232,15 +319,34 @@ and denser point clouds.
 Decoding Tool
 -------------
 
-`draco_decoder` will read Draco files as input, and output OBJ or PLY files.
-The basic command line looks like this:
+`draco_decoder` will read Draco files as input, and output OBJ, STL or PLY
+files. The basic command line looks like this:
 
 ~~~~~ bash
 ./draco_decoder -i in.drc -o out.obj
 ~~~~~
 
+glTF Transcoding Tool
+---------------------
+
+`draco_transcoder` can be used to add Draco compression to glTF assets. The
+basic command line looks like this:
+
+~~~~~ bash
+./draco_transcoder -i in.glb -o out.glb
+~~~~~
+
+This command line will add geometry compression to all meshes in the `in.glb`
+file. Quantization values for different glTF attributes can be specified
+similarly to the `draco_encoder` tool. For example `-qp` can be used to define
+quantization of the position attribute:
+
+~~~~~ bash
+./draco_transcoder -i in.glb -o out.glb -qp 12
+~~~~~
+
 C++ Decoder API
--------------
+---------------
 
 If you'd like to add decoding to your applications you will need to include
 the `draco_dec` library. In order to use the Draco decoder you need to
@@ -442,6 +548,30 @@ Javascript decoder using the `three.js` renderer.
 
 Please see the [javascript/example/README.md](javascript/example/README.md) file for more information.
 
+GStatic Javascript Builds
+=========================
+
+Prebuilt versions of the Emscripten-built Draco javascript decoders are hosted
+on www.gstatic.com in version labeled directories:
+
+https://www.gstatic.com/draco/versioned/decoders/VERSION/*
+
+As of the v1.4.3 release the files available are:
+
+- [draco_decoder.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder.js)
+- [draco_decoder.wasm](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder.wasm)
+- [draco_decoder_gltf.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder_gltf.js)
+- [draco_decoder_gltf.wasm](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder_gltf.wasm)
+- [draco_wasm_wrapper.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_wasm_wrapper.js)
+- [draco_wasm_wrapper_gltf.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_wasm_wrapper_gltf.js)
+
+Beginning with the v1.5.1 release assertion enabled builds of the following
+files are available:
+
+- [draco_decoder.js](https://www.gstatic.com/draco/versioned/decoders/1.5.1/with_asserts/draco_decoder.js)
+- [draco_decoder.wasm](https://www.gstatic.com/draco/versioned/decoders/1.5.1/with_asserts/draco_decoder.wasm)
+- [draco_wasm_wrapper.js](https://www.gstatic.com/draco/versioned/decoders/1.5.1/with_asserts/draco_wasm_wrapper.js)
+
 Support
 =======
 

+ 0 - 3
contrib/draco/cmake/DracoConfig.cmake

@@ -1,3 +0,0 @@
-@PACKAGE_INIT@
-set_and_check(draco_INCLUDE_DIR "@PACKAGE_draco_include_install_dir@")
-set_and_check(draco_LIBRARY_DIR "@PACKAGE_draco_lib_install_dir@")

+ 0 - 56
contrib/draco/cmake/FindDraco.cmake

@@ -1,56 +0,0 @@
-# Finddraco
-#
-# Locates draco and sets the following variables:
-#
-# draco_FOUND draco_INCLUDE_DIRS draco_LIBARY_DIRS draco_LIBRARIES
-# draco_VERSION_STRING
-#
-# draco_FOUND is set to YES only when all other variables are successfully
-# configured.
-
-unset(draco_FOUND)
-unset(draco_INCLUDE_DIRS)
-unset(draco_LIBRARY_DIRS)
-unset(draco_LIBRARIES)
-unset(draco_VERSION_STRING)
-
-mark_as_advanced(draco_FOUND)
-mark_as_advanced(draco_INCLUDE_DIRS)
-mark_as_advanced(draco_LIBRARY_DIRS)
-mark_as_advanced(draco_LIBRARIES)
-mark_as_advanced(draco_VERSION_STRING)
-
-set(draco_version_file_no_prefix "draco/src/draco/core/draco_version.h")
-
-# Set draco_INCLUDE_DIRS
-find_path(draco_INCLUDE_DIRS NAMES "${draco_version_file_no_prefix}")
-
-# Extract the version string from draco_version.h.
-if(draco_INCLUDE_DIRS)
-  set(draco_version_file
-      "${draco_INCLUDE_DIRS}/draco/src/draco/core/draco_version.h")
-  file(STRINGS "${draco_version_file}" draco_version REGEX "kdracoVersion")
-  list(GET draco_version 0 draco_version)
-  string(REPLACE "static const char kdracoVersion[] = " "" draco_version
-                 "${draco_version}")
-  string(REPLACE ";" "" draco_version "${draco_version}")
-  string(REPLACE "\"" "" draco_version "${draco_version}")
-  set(draco_VERSION_STRING ${draco_version})
-endif()
-
-# Find the library.
-if(BUILD_SHARED_LIBS)
-  find_library(draco_LIBRARIES NAMES draco.dll libdraco.dylib libdraco.so)
-else()
-  find_library(draco_LIBRARIES NAMES draco.lib libdraco.a)
-endif()
-
-# Store path to library.
-get_filename_component(draco_LIBRARY_DIRS ${draco_LIBRARIES} DIRECTORY)
-
-if(draco_INCLUDE_DIRS
-   AND draco_LIBRARY_DIRS
-   AND draco_LIBRARIES
-   AND draco_VERSION_STRING)
-  set(draco_FOUND YES)
-endif()

+ 0 - 220
contrib/draco/cmake/compiler_flags.cmake

@@ -1,220 +0,0 @@
-if(DRACO_CMAKE_COMPILER_FLAGS_CMAKE_)
-  return()
-endif()
-set(DRACO_CMAKE_COMPILER_FLAGS_CMAKE_ 1)
-
-include(CheckCCompilerFlag)
-include(CheckCXXCompilerFlag)
-include("${draco_root}/cmake/compiler_tests.cmake")
-
-# Strings used to cache failed C/CXX flags.
-set(DRACO_FAILED_C_FLAGS)
-set(DRACO_FAILED_CXX_FLAGS)
-
-# Checks C compiler for support of $c_flag. Adds $c_flag to $CMAKE_C_FLAGS when
-# the compile test passes. Caches $c_flag in $DRACO_FAILED_C_FLAGS when the test
-# fails.
-macro(add_c_flag_if_supported c_flag)
-  unset(C_FLAG_FOUND CACHE)
-  string(FIND "${CMAKE_C_FLAGS}" "${c_flag}" C_FLAG_FOUND)
-  unset(C_FLAG_FAILED CACHE)
-  string(FIND "${DRACO_FAILED_C_FLAGS}" "${c_flag}" C_FLAG_FAILED)
-
-  if(${C_FLAG_FOUND} EQUAL -1 AND ${C_FLAG_FAILED} EQUAL -1)
-    unset(C_FLAG_SUPPORTED CACHE)
-    message("Checking C compiler flag support for: " ${c_flag})
-    check_c_compiler_flag("${c_flag}" C_FLAG_SUPPORTED)
-    if(${C_FLAG_SUPPORTED})
-      set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${c_flag}" CACHE STRING "")
-    else()
-      set(DRACO_FAILED_C_FLAGS
-          "${DRACO_FAILED_C_FLAGS} ${c_flag}"
-          CACHE STRING "" FORCE)
-    endif()
-  endif()
-endmacro()
-
-# Checks C++ compiler for support of $cxx_flag. Adds $cxx_flag to
-# $CMAKE_CXX_FLAGS when the compile test passes. Caches $c_flag in
-# $DRACO_FAILED_CXX_FLAGS when the test fails.
-macro(add_cxx_flag_if_supported cxx_flag)
-  unset(CXX_FLAG_FOUND CACHE)
-  string(FIND "${CMAKE_CXX_FLAGS}" "${cxx_flag}" CXX_FLAG_FOUND)
-  unset(CXX_FLAG_FAILED CACHE)
-  string(FIND "${DRACO_FAILED_CXX_FLAGS}" "${cxx_flag}" CXX_FLAG_FAILED)
-
-  if(${CXX_FLAG_FOUND} EQUAL -1 AND ${CXX_FLAG_FAILED} EQUAL -1)
-    unset(CXX_FLAG_SUPPORTED CACHE)
-    message("Checking CXX compiler flag support for: " ${cxx_flag})
-    check_cxx_compiler_flag("${cxx_flag}" CXX_FLAG_SUPPORTED)
-    if(${CXX_FLAG_SUPPORTED})
-      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cxx_flag}" CACHE STRING "")
-    else()
-      set(DRACO_FAILED_CXX_FLAGS
-          "${DRACO_FAILED_CXX_FLAGS} ${cxx_flag}"
-          CACHE STRING "" FORCE)
-    endif()
-  endif()
-endmacro()
-
-# Convenience method for adding a flag to both the C and C++ compiler command
-# lines.
-macro(add_compiler_flag_if_supported flag)
-  add_c_flag_if_supported(${flag})
-  add_cxx_flag_if_supported(${flag})
-endmacro()
-
-# Checks C compiler for support of $c_flag and terminates generation when
-# support is not present.
-macro(require_c_flag c_flag update_c_flags)
-  unset(C_FLAG_FOUND CACHE)
-  string(FIND "${CMAKE_C_FLAGS}" "${c_flag}" C_FLAG_FOUND)
-
-  if(${C_FLAG_FOUND} EQUAL -1)
-    unset(HAVE_C_FLAG CACHE)
-    message("Checking C compiler flag support for: " ${c_flag})
-    check_c_compiler_flag("${c_flag}" HAVE_C_FLAG)
-    if(NOT ${HAVE_C_FLAG})
-      message(
-        FATAL_ERROR "${PROJECT_NAME} requires support for C flag: ${c_flag}.")
-    endif()
-    if(${update_c_flags})
-      set(CMAKE_C_FLAGS "${c_flag} ${CMAKE_C_FLAGS}" CACHE STRING "" FORCE)
-    endif()
-  endif()
-endmacro()
-
-# Checks CXX compiler for support of $cxx_flag and terminates generation when
-# support is not present.
-macro(require_cxx_flag cxx_flag update_cxx_flags)
-  unset(CXX_FLAG_FOUND CACHE)
-  string(FIND "${CMAKE_CXX_FLAGS}" "${cxx_flag}" CXX_FLAG_FOUND)
-
-  if(${CXX_FLAG_FOUND} EQUAL -1)
-    unset(HAVE_CXX_FLAG CACHE)
-    message("Checking CXX compiler flag support for: " ${cxx_flag})
-    check_cxx_compiler_flag("${cxx_flag}" HAVE_CXX_FLAG)
-    if(NOT ${HAVE_CXX_FLAG})
-      message(
-        FATAL_ERROR
-          "${PROJECT_NAME} requires support for CXX flag: ${cxx_flag}.")
-    endif()
-    if(${update_cxx_flags})
-      set(CMAKE_CXX_FLAGS
-          "${cxx_flag} ${CMAKE_CXX_FLAGS}"
-          CACHE STRING "" FORCE)
-    endif()
-  endif()
-endmacro()
-
-# Checks for support of $flag by both the C and CXX compilers. Terminates
-# generation when support is not present in both compilers.
-macro(require_compiler_flag flag update_cmake_flags)
-  require_c_flag(${flag} ${update_cmake_flags})
-  require_cxx_flag(${flag} ${update_cmake_flags})
-endmacro()
-
-# Checks only non-MSVC targets for support of $c_flag and terminates generation
-# when support is not present.
-macro(require_c_flag_nomsvc c_flag update_c_flags)
-  if(NOT MSVC)
-    require_c_flag(${c_flag} ${update_c_flags})
-  endif()
-endmacro()
-
-# Checks only non-MSVC targets for support of $cxx_flag and terminates
-# generation when support is not present.
-macro(require_cxx_flag_nomsvc cxx_flag update_cxx_flags)
-  if(NOT MSVC)
-    require_cxx_flag(${cxx_flag} ${update_cxx_flags})
-  endif()
-endmacro()
-
-# Checks only non-MSVC targets for support of $flag by both the C and CXX
-# compilers. Terminates generation when support is not present in both
-# compilers.
-macro(require_compiler_flag_nomsvc flag update_cmake_flags)
-  require_c_flag_nomsvc(${flag} ${update_cmake_flags})
-  require_cxx_flag_nomsvc(${flag} ${update_cmake_flags})
-endmacro()
-
-# Adds $flag to assembler command line.
-macro(append_as_flag flag)
-  unset(AS_FLAG_FOUND CACHE)
-  string(FIND "${DRACO_AS_FLAGS}" "${flag}" AS_FLAG_FOUND)
-
-  if(${AS_FLAG_FOUND} EQUAL -1)
-    set(DRACO_AS_FLAGS "${DRACO_AS_FLAGS} ${flag}")
-  endif()
-endmacro()
-
-# Adds $flag to the C compiler command line.
-macro(append_c_flag flag)
-  unset(C_FLAG_FOUND CACHE)
-  string(FIND "${CMAKE_C_FLAGS}" "${flag}" C_FLAG_FOUND)
-
-  if(${C_FLAG_FOUND} EQUAL -1)
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
-  endif()
-endmacro()
-
-# Adds $flag to the CXX compiler command line.
-macro(append_cxx_flag flag)
-  unset(CXX_FLAG_FOUND CACHE)
-  string(FIND "${CMAKE_CXX_FLAGS}" "${flag}" CXX_FLAG_FOUND)
-
-  if(${CXX_FLAG_FOUND} EQUAL -1)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
-  endif()
-endmacro()
-
-# Adds $flag to the C and CXX compiler command lines.
-macro(append_compiler_flag flag)
-  append_c_flag(${flag})
-  append_cxx_flag(${flag})
-endmacro()
-
-# Adds $flag to the executable linker command line.
-macro(append_exe_linker_flag flag)
-  unset(LINKER_FLAG_FOUND CACHE)
-  string(FIND "${CMAKE_EXE_LINKER_FLAGS}" "${flag}" LINKER_FLAG_FOUND)
-
-  if(${LINKER_FLAG_FOUND} EQUAL -1)
-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${flag}")
-  endif()
-endmacro()
-
-# Adds $flag to the link flags for $target.
-function(append_link_flag_to_target target flags)
-  unset(target_link_flags)
-  get_target_property(target_link_flags ${target} LINK_FLAGS)
-
-  if(target_link_flags)
-    unset(link_flag_found)
-    string(FIND "${target_link_flags}" "${flags}" link_flag_found)
-
-    if(NOT ${link_flag_found} EQUAL -1)
-      return()
-    endif()
-
-    set(target_link_flags "${target_link_flags} ${flags}")
-  else()
-    set(target_link_flags "${flags}")
-  endif()
-
-  set_target_properties(${target} PROPERTIES LINK_FLAGS ${target_link_flags})
-endfunction()
-
-# Adds $flag to executable linker flags, and makes sure C/CXX builds still work.
-macro(require_linker_flag flag)
-  append_exe_linker_flag(${flag})
-
-  unset(c_passed)
-  draco_check_c_compiles("LINKER_FLAG_C_TEST(${flag})" "" c_passed)
-  unset(cxx_passed)
-  draco_check_cxx_compiles("LINKER_FLAG_CXX_TEST(${flag})" "" cxx_passed)
-
-  if(NOT c_passed OR NOT cxx_passed)
-    message(FATAL_ERROR "Linker flag test for ${flag} failed.")
-  endif()
-endmacro()

+ 0 - 103
contrib/draco/cmake/compiler_tests.cmake

@@ -1,103 +0,0 @@
-if(DRACO_CMAKE_COMPILER_TESTS_CMAKE_)
-  return()
-endif()
-set(DRACO_CMAKE_COMPILER_TESTS_CMAKE_ 1)
-
-include(CheckCSourceCompiles)
-include(CheckCXXSourceCompiles)
-
-# The basic main() macro used in all compile tests.
-set(DRACO_C_MAIN "\nint main(void) { return 0; }")
-set(DRACO_CXX_MAIN "\nint main() { return 0; }")
-
-# Strings containing the names of passed and failed tests.
-set(DRACO_C_PASSED_TESTS)
-set(DRACO_C_FAILED_TESTS)
-set(DRACO_CXX_PASSED_TESTS)
-set(DRACO_CXX_FAILED_TESTS)
-
-macro(draco_push_var var new_value)
-  set(SAVED_${var} ${var})
-  set(${var} ${new_value})
-endmacro()
-
-macro(draco_pop_var var)
-  set(var ${SAVED_${var}})
-  unset(SAVED_${var})
-endmacro()
-
-# Confirms $test_source compiles and stores $test_name in one of
-# $DRACO_C_PASSED_TESTS or $DRACO_C_FAILED_TESTS depending on out come. When the
-# test passes $result_var is set to 1. When it fails $result_var is unset. The
-# test is not run if the test name is found in either of the passed or failed
-# test variables.
-macro(draco_check_c_compiles test_name test_source result_var)
-  unset(C_TEST_PASSED CACHE)
-  unset(C_TEST_FAILED CACHE)
-  string(FIND "${DRACO_C_PASSED_TESTS}" "${test_name}" C_TEST_PASSED)
-  string(FIND "${DRACO_C_FAILED_TESTS}" "${test_name}" C_TEST_FAILED)
-  if(${C_TEST_PASSED} EQUAL -1 AND ${C_TEST_FAILED} EQUAL -1)
-    unset(C_TEST_COMPILED CACHE)
-    message("Running C compiler test: ${test_name}")
-    check_c_source_compiles("${test_source} ${DRACO_C_MAIN}" C_TEST_COMPILED)
-    set(${result_var} ${C_TEST_COMPILED})
-
-    if(${C_TEST_COMPILED})
-      set(DRACO_C_PASSED_TESTS "${DRACO_C_PASSED_TESTS} ${test_name}")
-    else()
-      set(DRACO_C_FAILED_TESTS "${DRACO_C_FAILED_TESTS} ${test_name}")
-      message("C Compiler test ${test_name} failed.")
-    endif()
-  elseif(NOT ${C_TEST_PASSED} EQUAL -1)
-    set(${result_var} 1)
-  else() # ${C_TEST_FAILED} NOT EQUAL -1
-    unset(${result_var})
-  endif()
-endmacro()
-
-# Confirms $test_source compiles and stores $test_name in one of
-# $DRACO_CXX_PASSED_TESTS or $DRACO_CXX_FAILED_TESTS depending on out come. When
-# the test passes $result_var is set to 1. When it fails $result_var is unset.
-# The test is not run if the test name is found in either of the passed or
-# failed test variables.
-macro(draco_check_cxx_compiles test_name test_source result_var)
-  unset(CXX_TEST_PASSED CACHE)
-  unset(CXX_TEST_FAILED CACHE)
-  string(FIND "${DRACO_CXX_PASSED_TESTS}" "${test_name}" CXX_TEST_PASSED)
-  string(FIND "${DRACO_CXX_FAILED_TESTS}" "${test_name}" CXX_TEST_FAILED)
-  if(${CXX_TEST_PASSED} EQUAL -1 AND ${CXX_TEST_FAILED} EQUAL -1)
-    unset(CXX_TEST_COMPILED CACHE)
-    message("Running CXX compiler test: ${test_name}")
-    check_cxx_source_compiles("${test_source} ${DRACO_CXX_MAIN}"
-                              CXX_TEST_COMPILED)
-    set(${result_var} ${CXX_TEST_COMPILED})
-
-    if(${CXX_TEST_COMPILED})
-      set(DRACO_CXX_PASSED_TESTS "${DRACO_CXX_PASSED_TESTS} ${test_name}")
-    else()
-      set(DRACO_CXX_FAILED_TESTS "${DRACO_CXX_FAILED_TESTS} ${test_name}")
-      message("CXX Compiler test ${test_name} failed.")
-    endif()
-  elseif(NOT ${CXX_TEST_PASSED} EQUAL -1)
-    set(${result_var} 1)
-  else() # ${CXX_TEST_FAILED} NOT EQUAL -1
-    unset(${result_var})
-  endif()
-endmacro()
-
-# Convenience macro that confirms $test_source compiles as C and C++.
-# $result_var is set to 1 when both tests are successful, and 0 when one or both
-# tests fail. Note: This macro is intended to be used to write to result
-# variables that are expanded via configure_file(). $result_var is set to 1 or 0
-# to allow direct usage of the value in generated source files.
-macro(draco_check_source_compiles test_name test_source result_var)
-  unset(C_PASSED)
-  unset(CXX_PASSED)
-  draco_check_c_compiles(${test_name} ${test_source} C_PASSED)
-  draco_check_cxx_compiles(${test_name} ${test_source} CXX_PASSED)
-  if(${C_PASSED} AND ${CXX_PASSED})
-    set(${result_var} 1)
-  else()
-    set(${result_var} 0)
-  endif()
-endmacro()

+ 3 - 2
contrib/draco/cmake/draco-config.cmake.template

@@ -1,2 +1,3 @@
-set(DRACO_INCLUDE_DIRS "@DRACO_INCLUDE_DIRS@")
-set(DRACO_LIBRARIES "draco")
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/draco-targets.cmake")

+ 2 - 7
contrib/draco/cmake/draco.pc.template

@@ -1,11 +1,6 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
 Name: @PROJECT_NAME@
 Description: Draco geometry de(com)pression library.
 Version: @DRACO_VERSION@
-Cflags: -I${includedir}
-Libs: -L${libdir} -ldraco
+Cflags: -I@includes_path@
+Libs: -L@libs_path@ -ldraco
 Libs.private: @CMAKE_THREAD_LIBS_INIT@

+ 56 - 23
contrib/draco/cmake/draco_build_definitions.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_
@@ -17,10 +31,6 @@ macro(set_draco_target)
     endif()
     set(draco_plugin_dependency draco_static)
   endif()
-
-  if(BUILD_SHARED_LIBS)
-    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
-  endif()
 endmacro()
 
 # Configures flags and sets build system globals.
@@ -36,23 +46,37 @@ macro(draco_set_build_definitions)
   endif()
 
   draco_load_version_info()
-  set(DRACO_SOVERSION 1)
+
+  # Library version info. See the libtool docs for updating the values:
+  # https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
+  #
+  # c=<current>, r=<revision>, a=<age>
+  #
+  # libtool generates a .so file as .so.[c-a].a.r, while -version-info c:r:a is
+  # passed to libtool.
+  #
+  # We set DRACO_SOVERSION = [c-a].a.r
+  set(LT_CURRENT 8)
+  set(LT_REVISION 0)
+  set(LT_AGE 0)
+  math(EXPR DRACO_SOVERSION_MAJOR "${LT_CURRENT} - ${LT_AGE}")
+  set(DRACO_SOVERSION "${DRACO_SOVERSION_MAJOR}.${LT_AGE}.${LT_REVISION}")
+  unset(LT_CURRENT)
+  unset(LT_REVISION)
+  unset(LT_AGE)
 
   list(APPEND draco_include_paths "${draco_root}" "${draco_root}/src"
               "${draco_build}")
 
-  if(DRACO_ABSL)
-    list(APPEND draco_include_path "${draco_root}/third_party/abseil-cpp")
+  if(DRACO_TRANSCODER_SUPPORTED)
+    draco_setup_eigen()
+    draco_setup_filesystem()
+    draco_setup_tinygltf()
+
+
   endif()
 
 
-  list(APPEND draco_gtest_include_paths
-              "${draco_root}/../googletest/googlemock/include"
-              "${draco_root}/../googletest/googlemock"
-              "${draco_root}/../googletest/googletest/include"
-              "${draco_root}/../googletest/googletest")
-  list(APPEND draco_test_include_paths ${draco_include_paths}
-              ${draco_gtest_include_paths})
   list(APPEND draco_defines "DRACO_CMAKE=1"
               "DRACO_FLAGS_SRCDIR=\"${draco_root}\""
               "DRACO_FLAGS_TMPDIR=\"/tmp\"")
@@ -63,11 +87,22 @@ macro(draco_set_build_definitions)
     if(BUILD_SHARED_LIBS)
       set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
     endif()
-  else()
+  endif()
+
+  if(NOT MSVC)
     if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
       # Ensure 64-bit platforms can support large files.
       list(APPEND draco_defines "_LARGEFILE_SOURCE" "_FILE_OFFSET_BITS=64")
     endif()
+
+    if(NOT DRACO_DEBUG_COMPILER_WARNINGS)
+      if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+        list(APPEND draco_clang_cxx_flags
+                    "-Wno-implicit-const-int-float-conversion")
+      else()
+        list(APPEND draco_base_cxx_flags "-Wno-deprecated-declarations")
+      endif()
+    endif()
   endif()
 
   if(ANDROID)
@@ -102,13 +137,9 @@ macro(draco_set_build_definitions)
   set(draco_neon_source_file_suffix "neon.cc")
   set(draco_sse4_source_file_suffix "sse4.cc")
 
-  if((${CMAKE_CXX_COMPILER_ID}
-      STREQUAL
-      "GNU"
-      AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 5)
-     OR (${CMAKE_CXX_COMPILER_ID}
-         STREQUAL
-         "Clang"
+  if((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION}
+                                                  VERSION_LESS 5)
+     OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"
          AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4))
     message(
       WARNING "GNU/GCC < v5 or Clang/LLVM < v4, ENABLING COMPATIBILITY MODE.")
@@ -117,7 +148,9 @@ macro(draco_set_build_definitions)
 
   if(EMSCRIPTEN)
     draco_check_emscripten_environment()
-    draco_get_required_emscripten_flags(FLAG_LIST_VAR draco_base_cxx_flags)
+    draco_get_required_emscripten_flags(
+      FLAG_LIST_VAR_COMPILER draco_base_cxx_flags
+      FLAG_LIST_VAR_LINKER draco_base_exe_linker_flags)
   endif()
 
   draco_configure_sanitizer()

+ 14 - 0
contrib/draco/cmake/draco_cpu_detection.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_CPU_DETECTION_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_CPU_DETECTION_CMAKE_

+ 136 - 0
contrib/draco/cmake/draco_dependencies.cmake

@@ -0,0 +1,136 @@
+# Copyright 2022 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+if(DRACO_CMAKE_DRACO_DEPENDENCIES_CMAKE)
+  return()
+endif()
+set(DRACO_CMAKE_DRACO_DEPENDENCIES_CMAKE 1)
+
+include("${draco_root}/cmake/draco_variables.cmake")
+
+# Each variable holds a user specified custom path to a local copy of the
+# sources that belong to each project that Draco depends on. When paths are
+# empty the build will be generated pointing to the Draco git submodules.
+# Otherwise the paths specified by the user will be used in the build
+# configuration.
+
+# Path to the Eigen. The path must contain the Eigen directory.
+set(DRACO_EIGEN_PATH)
+draco_track_configuration_variable(DRACO_EIGEN_PATH)
+
+# Path to the gulrak/filesystem installation. The path specified must contain
+# the ghc subdirectory that houses the filesystem includes.
+set(DRACO_FILESYSTEM_PATH)
+draco_track_configuration_variable(DRACO_FILESYSTEM_PATH)
+
+# Path to the googletest installation. The path must be to the root of the
+# Googletest project directory.
+set(DRACO_GOOGLETEST_PATH)
+draco_track_configuration_variable(DRACO_GOOGLETEST_PATH)
+
+# Path to the syoyo/tinygltf installation. The path must be to the root of the
+# project directory.
+set(DRACO_TINYGLTF_PATH)
+draco_track_configuration_variable(DRACO_TINYGLTF_PATH)
+
+# Utility macro for killing the build due to a missing submodule directory.
+macro(draco_die_missing_submodule dir)
+  message(FATAL_ERROR "${dir} missing, run git submodule update --init")
+endmacro()
+
+# Determines the Eigen location and updates the build configuration accordingly.
+macro(draco_setup_eigen)
+  if(DRACO_EIGEN_PATH)
+    set(eigen_path "${DRACO_EIGEN_PATH}")
+
+    if(NOT IS_DIRECTORY "${eigen_path}")
+      message(FATAL_ERROR "DRACO_EIGEN_PATH does not exist.")
+    endif()
+  else()
+    set(eigen_path "${draco_root}/third_party/eigen")
+
+    if(NOT IS_DIRECTORY "${eigen_path}")
+      draco_die_missing_submodule("${eigen_path}")
+    endif()
+  endif()
+
+  set(eigen_include_path "${eigen_path}/Eigen")
+
+  if(NOT EXISTS "${eigen_path}/Eigen")
+    message(FATAL_ERROR "The eigen path does not contain an Eigen directory.")
+  endif()
+
+  list(APPEND draco_include_paths "${eigen_path}")
+endmacro()
+
+# Determines the gulrak/filesystem location and updates the build configuration
+# accordingly.
+macro(draco_setup_filesystem)
+  if(DRACO_FILESYSTEM_PATH)
+    set(fs_path "${DRACO_FILESYSTEM_PATH}")
+
+    if(NOT IS_DIRECTORY "${fs_path}")
+      message(FATAL_ERROR "DRACO_FILESYSTEM_PATH does not exist.")
+    endif()
+  else()
+    set(fs_path "${draco_root}/third_party/filesystem/include")
+
+    if(NOT IS_DIRECTORY "${fs_path}")
+      draco_die_missing_submodule("${fs_path}")
+    endif()
+  endif()
+
+  list(APPEND draco_include_paths "${fs_path}")
+endmacro()
+
+# Determines the Googletest location and sets up include and source list vars
+# for the draco_tests build.
+macro(draco_setup_googletest)
+  if(DRACO_GOOGLETEST_PATH)
+    set(gtest_path "${DRACO_GOOGLETEST_PATH}")
+    if(NOT IS_DIRECTORY "${gtest_path}")
+      message(FATAL_ERROR "DRACO_GOOGLETEST_PATH does not exist.")
+    endif()
+  else()
+    set(gtest_path "${draco_root}/third_party/googletest")
+  endif()
+
+  list(APPEND draco_test_include_paths ${draco_include_paths}
+              "${gtest_path}/include" "${gtest_path}/googlemock"
+              "${gtest_path}/googletest/include" "${gtest_path}/googletest")
+
+  list(APPEND draco_gtest_all "${gtest_path}/googletest/src/gtest-all.cc")
+  list(APPEND draco_gtest_main "${gtest_path}/googletest/src/gtest_main.cc")
+endmacro()
+
+
+# Determines the location of TinyGLTF and updates the build configuration
+# accordingly.
+macro(draco_setup_tinygltf)
+  if(DRACO_TINYGLTF_PATH)
+    set(tinygltf_path "${DRACO_TINYGLTF_PATH}")
+
+    if(NOT IS_DIRECTORY "${tinygltf_path}")
+      message(FATAL_ERROR "DRACO_TINYGLTF_PATH does not exist.")
+    endif()
+  else()
+    set(tinygltf_path "${draco_root}/third_party/tinygltf")
+
+    if(NOT IS_DIRECTORY "${tinygltf_path}")
+      draco_die_missing_submodule("${tinygltf_path}")
+    endif()
+  endif()
+
+  list(APPEND draco_include_paths "${tinygltf_path}")
+endmacro()

+ 112 - 65
contrib/draco/cmake/draco_emscripten.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_
@@ -18,39 +32,64 @@ endmacro()
 
 # Obtains the required Emscripten flags for Draco targets.
 macro(draco_get_required_emscripten_flags)
-  set(em_FLAG_LIST_VAR)
+  set(em_FLAG_LIST_VAR_COMPILER)
+  set(em_FLAG_LIST_VAR_LINKER)
   set(em_flags)
-  set(em_single_arg_opts FLAG_LIST_VAR)
+  set(em_single_arg_opts FLAG_LIST_VAR_COMPILER FLAG_LIST_VAR_LINKER)
   set(em_multi_arg_opts)
   cmake_parse_arguments(em "${em_flags}" "${em_single_arg_opts}"
                         "${em_multi_arg_opts}" ${ARGN})
-  if(NOT em_FLAG_LIST_VAR)
-    message(FATAL "draco_get_required_emscripten_flags: FLAG_LIST_VAR required")
+  if(NOT em_FLAG_LIST_VAR_COMPILER)
+    message(
+      FATAL
+      "draco_get_required_emscripten_flags: FLAG_LIST_VAR_COMPILER required")
+  endif()
+
+  if(NOT em_FLAG_LIST_VAR_LINKER)
+    message(
+      FATAL
+      "draco_get_required_emscripten_flags: FLAG_LIST_VAR_LINKER required")
   endif()
 
   if(DRACO_JS_GLUE)
     unset(required_flags)
-    list(APPEND ${em_FLAG_LIST_VAR} "-sALLOW_MEMORY_GROWTH=1")
-    list(APPEND ${em_FLAG_LIST_VAR} "-Wno-almost-asm")
-    list(APPEND ${em_FLAG_LIST_VAR} "--memory-init-file" "0")
-    list(APPEND ${em_FLAG_LIST_VAR} "-fno-omit-frame-pointer")
-    list(APPEND ${em_FLAG_LIST_VAR} "-sMODULARIZE=1")
-    list(APPEND ${em_FLAG_LIST_VAR} "-sNO_FILESYSTEM=1")
-    list(APPEND ${em_FLAG_LIST_VAR} "-sEXPORTED_RUNTIME_METHODS=[]")
-    list(APPEND ${em_FLAG_LIST_VAR} "-sPRECISE_F32=1")
-    list(APPEND ${em_FLAG_LIST_VAR} "-sNODEJS_CATCH_EXIT=0")
-    list(APPEND ${em_FLAG_LIST_VAR} "-sNODEJS_CATCH_REJECTION=0")
+    # TODO(tomfinegan): Revisit splitting of compile/link flags for Emscripten,
+    # and drop -Wno-unused-command-line-argument. Emscripten complains about
+    # what are supposedly link-only flags sent with compile commands, but then
+    # proceeds to produce broken code if the warnings are heeded.
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER}
+                "-Wno-unused-command-line-argument")
+
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-Wno-almost-asm")
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "--memory-init-file" "0")
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-fno-omit-frame-pointer")
+
+    # According to Emscripten the following flags are linker only, but sending
+    # these flags (en masse) to only the linker results in a broken Emscripten
+    # build with an empty DracoDecoderModule.
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sALLOW_MEMORY_GROWTH=1")
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sMODULARIZE=1")
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sFILESYSTEM=0")
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER}
+                "-sEXPORTED_FUNCTIONS=[\"_free\",\"_malloc\"]")
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sPRECISE_F32=1")
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sNODEJS_CATCH_EXIT=0")
+    list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sNODEJS_CATCH_REJECTION=0")
 
     if(DRACO_FAST)
-      list(APPEND ${em_FLAG_LIST_VAR} "--llvm-lto" "1")
+      list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "--llvm-lto" "1")
     endif()
+
+    # The WASM flag is reported as linker only.
     if(DRACO_WASM)
-      list(APPEND ${em_FLAG_LIST_VAR} "-sWASM=1")
+      list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sWASM=1")
     else()
-      list(APPEND ${em_FLAG_LIST_VAR} "-sWASM=0")
+      list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sWASM=0")
     endif()
+
+    # The LEGACY_VM_SUPPORT flag is reported as linker only.
     if(DRACO_IE_COMPATIBLE)
-      list(APPEND ${em_FLAG_LIST_VAR} "-sLEGACY_VM_SUPPORT=1")
+      list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sLEGACY_VM_SUPPORT=1")
     endif()
   endif()
 endmacro()
@@ -66,10 +105,11 @@ macro(draco_generate_emscripten_glue)
                         "${glue_multi_arg_opts}" ${ARGN})
 
   if(DRACO_VERBOSE GREATER 1)
-    message("--------- draco_generate_emscripten_glue -----------\n"
-            "glue_INPUT_IDL=${glue_INPUT_IDL}\n"
-            "glue_OUTPUT_PATH=${glue_OUTPUT_PATH}\n" ]
-            "----------------------------------------------------\n")
+    message(
+      "--------- draco_generate_emscripten_glue -----------\n"
+      "glue_INPUT_IDL=${glue_INPUT_IDL}\n"
+      "glue_OUTPUT_PATH=${glue_OUTPUT_PATH}\n"
+      "----------------------------------------------------\n")
   endif()
 
   if(NOT glue_INPUT_IDL OR NOT glue_OUTPUT_PATH)
@@ -79,22 +119,22 @@ macro(draco_generate_emscripten_glue)
   endif()
 
   # Generate the glue source.
-  execute_process(COMMAND ${PYTHON_EXECUTABLE}
-                          $ENV{EMSCRIPTEN}/tools/webidl_binder.py
-                          ${glue_INPUT_IDL} ${glue_OUTPUT_PATH})
+  execute_process(
+    COMMAND ${PYTHON_EXECUTABLE} $ENV{EMSCRIPTEN}/tools/webidl_binder.py
+            ${glue_INPUT_IDL} ${glue_OUTPUT_PATH})
   if(NOT EXISTS "${glue_OUTPUT_PATH}.cpp")
     message(FATAL_ERROR "JS glue generation failed for ${glue_INPUT_IDL}.")
   endif()
 
   # Create a dependency so that it regenerated on edits.
-  add_custom_command(OUTPUT "${glue_OUTPUT_PATH}.cpp"
-                     COMMAND ${PYTHON_EXECUTABLE}
-                             $ENV{EMSCRIPTEN}/tools/webidl_binder.py
-                             ${glue_INPUT_IDL} ${glue_OUTPUT_PATH}
-                     DEPENDS ${draco_js_dec_idl}
-                     COMMENT "Generating ${glue_OUTPUT_PATH}.cpp."
-                     WORKING_DIRECTORY ${draco_build}
-                     VERBATIM)
+  add_custom_command(
+    OUTPUT "${glue_OUTPUT_PATH}.cpp"
+    COMMAND ${PYTHON_EXECUTABLE} $ENV{EMSCRIPTEN}/tools/webidl_binder.py
+            ${glue_INPUT_IDL} ${glue_OUTPUT_PATH}
+    DEPENDS ${draco_js_dec_idl}
+    COMMENT "Generating ${glue_OUTPUT_PATH}.cpp."
+    WORKING_DIRECTORY ${draco_build}
+    VERBATIM)
 endmacro()
 
 # Wrapper for draco_add_executable() that handles the extra work necessary for
@@ -120,8 +160,14 @@ macro(draco_add_emscripten_executable)
   unset(emexe_LINK_FLAGS)
   set(optional_args)
   set(single_value_args NAME GLUE_PATH)
-  set(multi_value_args SOURCES DEFINES FEATURES INCLUDES LINK_FLAGS
-                       PRE_LINK_JS_SOURCES POST_LINK_JS_SOURCES)
+  set(multi_value_args
+      SOURCES
+      DEFINES
+      FEATURES
+      INCLUDES
+      LINK_FLAGS
+      PRE_LINK_JS_SOURCES
+      POST_LINK_JS_SOURCES)
 
   cmake_parse_arguments(emexe "${optional_args}" "${single_value_args}"
                         "${multi_value_args}" ${ARGN})
@@ -136,49 +182,50 @@ macro(draco_add_emscripten_executable)
   endif()
 
   if(DRACO_VERBOSE GREATER 1)
-    message("--------- draco_add_emscripten_executable ---------\n"
-            "emexe_NAME=${emexe_NAME}\n"
-            "emexe_SOURCES=${emexe_SOURCES}\n"
-            "emexe_DEFINES=${emexe_DEFINES}\n"
-            "emexe_INCLUDES=${emexe_INCLUDES}\n"
-            "emexe_LINK_FLAGS=${emexe_LINK_FLAGS}\n"
-            "emexe_GLUE_PATH=${emexe_GLUE_PATH}\n"
-            "emexe_FEATURES=${emexe_FEATURES}\n"
-            "emexe_PRE_LINK_JS_SOURCES=${emexe_PRE_LINK_JS_SOURCES}\n"
-            "emexe_POST_LINK_JS_SOURCES=${emexe_POST_LINK_JS_SOURCES}\n"
-            "----------------------------------------------------\n")
+    message(
+      "--------- draco_add_emscripten_executable ---------\n"
+      "emexe_NAME=${emexe_NAME}\n"
+      "emexe_SOURCES=${emexe_SOURCES}\n"
+      "emexe_DEFINES=${emexe_DEFINES}\n"
+      "emexe_INCLUDES=${emexe_INCLUDES}\n"
+      "emexe_LINK_FLAGS=${emexe_LINK_FLAGS}\n"
+      "emexe_GLUE_PATH=${emexe_GLUE_PATH}\n"
+      "emexe_FEATURES=${emexe_FEATURES}\n"
+      "emexe_PRE_LINK_JS_SOURCES=${emexe_PRE_LINK_JS_SOURCES}\n"
+      "emexe_POST_LINK_JS_SOURCES=${emexe_POST_LINK_JS_SOURCES}\n"
+      "----------------------------------------------------\n")
   endif()
 
   # The Emscripten linker needs the C++ flags in addition to whatever has been
   # passed in with the target.
   list(APPEND emexe_LINK_FLAGS ${DRACO_CXX_FLAGS})
 
-  if(DRACO_GLTF)
-    draco_add_executable(NAME
-                         ${emexe_NAME}
-                         OUTPUT_NAME
-                         ${emexe_NAME}_gltf
-                         SOURCES
-                         ${emexe_SOURCES}
-                         DEFINES
-                         ${emexe_DEFINES}
-                         INCLUDES
-                         ${emexe_INCLUDES}
-                         LINK_FLAGS
-                         ${emexe_LINK_FLAGS})
+  if(DRACO_GLTF_BITSTREAM)
+    # Add "_gltf" suffix to target output name.
+    draco_add_executable(
+      NAME ${emexe_NAME}
+      OUTPUT_NAME ${emexe_NAME}_gltf
+      SOURCES ${emexe_SOURCES}
+      DEFINES ${emexe_DEFINES}
+      INCLUDES ${emexe_INCLUDES}
+      LINK_FLAGS ${emexe_LINK_FLAGS})
   else()
-    draco_add_executable(NAME ${emexe_NAME} SOURCES ${emexe_SOURCES} DEFINES
-                         ${emexe_DEFINES} INCLUDES ${emexe_INCLUDES} LINK_FLAGS
-                         ${emexe_LINK_FLAGS})
+    draco_add_executable(
+      NAME ${emexe_NAME}
+      SOURCES ${emexe_SOURCES}
+      DEFINES ${emexe_DEFINES}
+      INCLUDES ${emexe_INCLUDES}
+      LINK_FLAGS ${emexe_LINK_FLAGS})
   endif()
 
   foreach(feature ${emexe_FEATURES})
     draco_enable_feature(FEATURE ${feature} TARGETS ${emexe_NAME})
   endforeach()
 
-  set_property(SOURCE ${emexe_SOURCES}
-               APPEND
-               PROPERTY OBJECT_DEPENDS "${emexe_GLUE_PATH}.cpp")
+  set_property(
+    SOURCE ${emexe_SOURCES}
+    APPEND
+    PROPERTY OBJECT_DEPENDS "${emexe_GLUE_PATH}.cpp")
   em_link_pre_js(${emexe_NAME} ${emexe_PRE_LINK_JS_SOURCES})
   em_link_post_js(${emexe_NAME} "${emexe_GLUE_PATH}.js"
                   ${emexe_POST_LINK_JS_SOURCES})

+ 48 - 3
contrib/draco/cmake/draco_flags.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_FLAGS_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_FLAGS_CMAKE_
@@ -24,7 +38,7 @@ macro(draco_set_compiler_flags_for_sources)
   endif()
 
   set_source_files_properties(${compiler_SOURCES} PROPERTIES COMPILE_FLAGS
-                              ${compiler_FLAGS})
+                                                             ${compiler_FLAGS})
 
   if(DRACO_VERBOSE GREATER 1)
     foreach(source ${compiler_SOURCES})
@@ -85,8 +99,8 @@ macro(draco_test_cxx_flag)
   # are passed as a list it will remove the list separators, and attempt to run
   # a compile command using list entries concatenated together as a single
   # argument. Avoid the problem by forcing the argument to be a string.
-  draco_set_and_stringify(SOURCE_VARS all_cxx_flags DEST all_cxx_flags)
-  check_cxx_compiler_flag("${all_cxx_flags}" draco_all_cxx_flags_pass)
+  draco_set_and_stringify(SOURCE_VARS all_cxx_flags DEST all_cxx_flags_string)
+  check_cxx_compiler_flag("${all_cxx_flags_string}" draco_all_cxx_flags_pass)
 
   if(cxx_test_FLAG_REQUIRED AND NOT draco_all_cxx_flags_pass)
     draco_die("Flag test failed for required flag(s): "
@@ -245,3 +259,34 @@ macro(draco_set_cxx_flags)
     draco_test_cxx_flag(FLAG_LIST_VAR_NAMES ${cxx_flag_lists})
   endif()
 endmacro()
+
+# Collects Draco built-in and user-specified linker flags and tests them. Halts
+# configuration and reports the error when any flags cause the build to fail.
+#
+# Note: draco_test_exe_linker_flag() does the real work of setting the flags and
+# running the test compile commands.
+macro(draco_set_exe_linker_flags)
+  unset(linker_flag_lists)
+
+  if(DRACO_VERBOSE)
+    message("draco_set_exe_linker_flags: "
+            "draco_base_exe_linker_flags=${draco_base_exe_linker_flags}")
+  endif()
+
+  if(draco_base_exe_linker_flags)
+    list(APPEND linker_flag_lists draco_base_exe_linker_flags)
+  endif()
+
+  if(linker_flag_lists)
+    unset(test_linker_flags)
+
+    if(DRACO_VERBOSE)
+      message("draco_set_exe_linker_flags: "
+              "linker_flag_lists=${linker_flag_lists}")
+    endif()
+
+    draco_set_and_stringify(DEST test_linker_flags SOURCE_VARS
+                            ${linker_flag_lists})
+    draco_test_exe_linker_flag(FLAG_LIST_VAR_NAME test_linker_flags)
+  endif()
+endmacro()

+ 14 - 0
contrib/draco/cmake/draco_helpers.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_HELPERS_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_HELPERS_CMAKE_

+ 82 - 40
contrib/draco/cmake/draco_install.cmake

@@ -1,32 +1,32 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_INSTALL_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_INSTALL_CMAKE_
 set(DRACO_CMAKE_DRACO_INSTALL_CMAKE_ 1)
 
+include(CMakePackageConfigHelpers)
+include(GNUInstallDirs)
+
 # Sets up the draco install targets. Must be called after the static library
 # target is created.
 macro(draco_setup_install_target)
-  include(GNUInstallDirs)
-
-  # pkg-config: draco.pc
-  set(prefix "${CMAKE_INSTALL_PREFIX}")
-  set(exec_prefix "\${prefix}")
-  set(libdir "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
-  set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
-  set(draco_lib_name "draco")
-
-  configure_file("${draco_root}/cmake/draco.pc.template"
-                 "${draco_build}/draco.pc" @ONLY NEWLINE_STYLE UNIX)
-  install(FILES "${draco_build}/draco.pc"
-          DESTINATION "${prefix}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
-
-  # CMake config: draco-config.cmake
-  set(DRACO_INCLUDE_DIRS "${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
-  configure_file("${draco_root}/cmake/draco-config.cmake.template"
-                 "${draco_build}/draco-config.cmake" @ONLY NEWLINE_STYLE UNIX)
-  install(
-    FILES "${draco_build}/draco-config.cmake"
-    DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/cmake")
+  set(bin_path "${CMAKE_INSTALL_BINDIR}")
+  set(data_path "${CMAKE_INSTALL_DATAROOTDIR}")
+  set(includes_path "${CMAKE_INSTALL_INCLUDEDIR}")
+  set(libs_path "${CMAKE_INSTALL_LIBDIR}")
 
   foreach(file ${draco_sources})
     if(file MATCHES "h$")
@@ -34,46 +34,88 @@ macro(draco_setup_install_target)
     endif()
   endforeach()
 
+  list(REMOVE_DUPLICATES draco_api_includes)
+
   # Strip $draco_src_root from the file paths: we need to install relative to
   # $include_directory.
   list(TRANSFORM draco_api_includes REPLACE "${draco_src_root}/" "")
-  set(include_directory "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}")
 
   foreach(draco_api_include ${draco_api_includes})
     get_filename_component(file_directory ${draco_api_include} DIRECTORY)
-    set(target_directory "${include_directory}/draco/${file_directory}")
+    set(target_directory "${includes_path}/draco/${file_directory}")
     install(FILES ${draco_src_root}/${draco_api_include}
             DESTINATION "${target_directory}")
   endforeach()
 
-  install(
-    FILES "${draco_build}/draco/draco_features.h"
-    DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/draco/")
+  install(FILES "${draco_build}/draco/draco_features.h"
+          DESTINATION "${includes_path}/draco/")
+
+  install(TARGETS draco_decoder DESTINATION "${bin_path}")
+  install(TARGETS draco_encoder DESTINATION "${bin_path}")
 
-  install(TARGETS draco_decoder DESTINATION
-                  "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
-  install(TARGETS draco_encoder DESTINATION
-                  "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
+  if(DRACO_TRANSCODER_SUPPORTED)
+    install(TARGETS draco_transcoder DESTINATION "${bin_path}")
+  endif()
 
   if(MSVC)
-    install(TARGETS draco DESTINATION
-                    "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+    install(
+      TARGETS draco
+      EXPORT dracoExport
+      RUNTIME DESTINATION "${bin_path}"
+      ARCHIVE DESTINATION "${libs_path}"
+      LIBRARY DESTINATION "${libs_path}")
   else()
-    install(TARGETS draco_static DESTINATION
-                    "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+    install(
+      TARGETS draco_static
+      EXPORT dracoExport
+      DESTINATION "${libs_path}")
+
     if(BUILD_SHARED_LIBS)
-      install(TARGETS draco_shared DESTINATION
-                      "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+      install(
+        TARGETS draco_shared
+        EXPORT dracoExport
+        RUNTIME DESTINATION "${bin_path}"
+        ARCHIVE DESTINATION "${libs_path}"
+        LIBRARY DESTINATION "${libs_path}")
     endif()
   endif()
 
   if(DRACO_UNITY_PLUGIN)
-    install(TARGETS dracodec_unity DESTINATION
-                    "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+    install(TARGETS dracodec_unity DESTINATION "${libs_path}")
   endif()
+
   if(DRACO_MAYA_PLUGIN)
-    install(TARGETS draco_maya_wrapper DESTINATION
-                    "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+    install(TARGETS draco_maya_wrapper DESTINATION "${libs_path}")
   endif()
 
+  # pkg-config: draco.pc
+  configure_file("${draco_root}/cmake/draco.pc.template"
+                 "${draco_build}/draco.pc" @ONLY NEWLINE_STYLE UNIX)
+  install(FILES "${draco_build}/draco.pc" DESTINATION "${libs_path}/pkgconfig")
+
+  # CMake config: draco-config.cmake
+  configure_package_config_file(
+    "${draco_root}/cmake/draco-config.cmake.template"
+    "${draco_build}/draco-config.cmake"
+    INSTALL_DESTINATION "${data_path}/cmake/draco")
+
+  write_basic_package_version_file(
+    "${draco_build}/draco-config-version.cmake"
+    VERSION ${DRACO_VERSION}
+    COMPATIBILITY AnyNewerVersion)
+
+  export(
+    EXPORT dracoExport
+    NAMESPACE draco::
+    FILE "${draco_build}/draco-targets.cmake")
+
+  install(
+    EXPORT dracoExport
+    NAMESPACE draco::
+    FILE draco-targets.cmake
+    DESTINATION "${data_path}/cmake/draco")
+
+  install(FILES "${draco_build}/draco-config.cmake"
+                "${draco_build}/draco-config-version.cmake"
+          DESTINATION "${data_path}/cmake/draco")
 endmacro()

+ 22 - 12
contrib/draco/cmake/draco_intrinsics.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_
@@ -61,17 +75,15 @@ macro(draco_process_intrinsics_sources)
     unset(sse4_sources)
     list(APPEND sse4_sources ${arg_SOURCES})
 
-    list(FILTER sse4_sources INCLUDE REGEX
-         "${draco_sse4_source_file_suffix}$")
+    list(FILTER sse4_sources INCLUDE REGEX "${draco_sse4_source_file_suffix}$")
 
     if(sse4_sources)
       unset(sse4_flags)
-      draco_get_intrinsics_flag_for_suffix(SUFFIX
-                                             ${draco_sse4_source_file_suffix}
-                                             VARIABLE sse4_flags)
+      draco_get_intrinsics_flag_for_suffix(
+        SUFFIX ${draco_sse4_source_file_suffix} VARIABLE sse4_flags)
       if(sse4_flags)
         draco_set_compiler_flags_for_sources(SOURCES ${sse4_sources} FLAGS
-                                               ${sse4_flags})
+                                             ${sse4_flags})
       endif()
     endif()
   endif()
@@ -79,17 +91,15 @@ macro(draco_process_intrinsics_sources)
   if(DRACO_ENABLE_NEON AND draco_have_neon)
     unset(neon_sources)
     list(APPEND neon_sources ${arg_SOURCES})
-    list(FILTER neon_sources INCLUDE REGEX
-         "${draco_neon_source_file_suffix}$")
+    list(FILTER neon_sources INCLUDE REGEX "${draco_neon_source_file_suffix}$")
 
     if(neon_sources AND DRACO_NEON_INTRINSICS_FLAG)
       unset(neon_flags)
-      draco_get_intrinsics_flag_for_suffix(SUFFIX
-                                             ${draco_neon_source_file_suffix}
-                                             VARIABLE neon_flags)
+      draco_get_intrinsics_flag_for_suffix(
+        SUFFIX ${draco_neon_source_file_suffix} VARIABLE neon_flags)
       if(neon_flags)
         draco_set_compiler_flags_for_sources(SOURCES ${neon_sources} FLAGS
-                                               ${neon_flags})
+                                             ${neon_flags})
       endif()
     endif()
   endif()

+ 150 - 35
contrib/draco/cmake/draco_options.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_OPTIONS_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_OPTIONS_CMAKE_
@@ -18,17 +32,22 @@ macro(draco_option)
   cmake_parse_arguments(option "${optional_args}" "${single_value_args}"
                         "${multi_value_args}" ${ARGN})
 
-  if(NOT (option_NAME AND option_HELPSTRING AND DEFINED option_VALUE))
+  if(NOT
+     (option_NAME
+      AND option_HELPSTRING
+      AND DEFINED option_VALUE))
     message(FATAL_ERROR "draco_option: NAME HELPSTRING and VALUE required.")
   endif()
 
   option(${option_NAME} ${option_HELPSTRING} ${option_VALUE})
 
   if(DRACO_VERBOSE GREATER 2)
-    message("--------- draco_option ---------\n" "option_NAME=${option_NAME}\n"
-            "option_HELPSTRING=${option_HELPSTRING}\n"
-            "option_VALUE=${option_VALUE}\n"
-            "------------------------------------------\n")
+    message(
+      "--------- draco_option ---------\n"
+      "option_NAME=${option_NAME}\n"
+      "option_HELPSTRING=${option_HELPSTRING}\n"
+      "option_VALUE=${option_VALUE}\n"
+      "------------------------------------------\n")
   endif()
 
   list(APPEND draco_options ${option_NAME})
@@ -44,33 +63,74 @@ endmacro()
 
 # Set default options.
 macro(draco_set_default_options)
-  draco_option(NAME DRACO_FAST HELPSTRING "Try to build faster libs." VALUE OFF)
-  draco_option(NAME DRACO_JS_GLUE HELPSTRING
-               "Enable JS Glue and JS targets when using Emscripten." VALUE ON)
-  draco_option(NAME DRACO_IE_COMPATIBLE HELPSTRING
-               "Enable support for older IE builds when using Emscripten." VALUE
-               OFF)
-  draco_option(NAME DRACO_MESH_COMPRESSION HELPSTRING "Enable mesh compression."
-               VALUE ON)
-  draco_option(NAME DRACO_POINT_CLOUD_COMPRESSION HELPSTRING
-               "Enable point cloud compression." VALUE ON)
-  draco_option(NAME DRACO_PREDICTIVE_EDGEBREAKER HELPSTRING
-               "Enable predictive edgebreaker." VALUE ON)
-  draco_option(NAME DRACO_STANDARD_EDGEBREAKER HELPSTRING
-               "Enable stand edgebreaker." VALUE ON)
-  draco_option(NAME DRACO_BACKWARDS_COMPATIBILITY HELPSTRING
-               "Enable backwards compatibility." VALUE ON)
-  draco_option(NAME DRACO_DECODER_ATTRIBUTE_DEDUPLICATION HELPSTRING
-               "Enable attribute deduping." VALUE OFF)
-  draco_option(NAME DRACO_TESTS HELPSTRING "Enables tests." VALUE OFF)
-  draco_option(NAME DRACO_WASM HELPSTRING "Enables WASM support." VALUE OFF)
-  draco_option(NAME DRACO_UNITY_PLUGIN HELPSTRING
-               "Build plugin library for Unity." VALUE OFF)
-  draco_option(NAME DRACO_ANIMATION_ENCODING HELPSTRING "Enable animation."
-               VALUE OFF)
-  draco_option(NAME DRACO_GLTF HELPSTRING "Support GLTF." VALUE OFF)
-  draco_option(NAME DRACO_MAYA_PLUGIN HELPSTRING
-               "Build plugin library for Maya." VALUE OFF)
+  draco_option(
+    NAME DRACO_FAST
+    HELPSTRING "Try to build faster libs."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_JS_GLUE
+    HELPSTRING "Enable JS Glue and JS targets when using Emscripten."
+    VALUE ON)
+  draco_option(
+    NAME DRACO_IE_COMPATIBLE
+    HELPSTRING "Enable support for older IE builds when using Emscripten."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_MESH_COMPRESSION
+    HELPSTRING "Enable mesh compression."
+    VALUE ON)
+  draco_option(
+    NAME DRACO_POINT_CLOUD_COMPRESSION
+    HELPSTRING "Enable point cloud compression."
+    VALUE ON)
+  draco_option(
+    NAME DRACO_PREDICTIVE_EDGEBREAKER
+    HELPSTRING "Enable predictive edgebreaker."
+    VALUE ON)
+  draco_option(
+    NAME DRACO_STANDARD_EDGEBREAKER
+    HELPSTRING "Enable stand edgebreaker."
+    VALUE ON)
+  draco_option(
+    NAME DRACO_BACKWARDS_COMPATIBILITY
+    HELPSTRING "Enable backwards compatibility."
+    VALUE ON)
+  draco_option(
+    NAME DRACO_DECODER_ATTRIBUTE_DEDUPLICATION
+    HELPSTRING "Enable attribute deduping."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_TESTS
+    HELPSTRING "Enables tests."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_WASM
+    HELPSTRING "Enables WASM support."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_UNITY_PLUGIN
+    HELPSTRING "Build plugin library for Unity."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_ANIMATION_ENCODING
+    HELPSTRING "Enable animation."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_GLTF_BITSTREAM
+    HELPSTRING "Draco GLTF extension bitstream specified features only."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_MAYA_PLUGIN
+    HELPSTRING "Build plugin library for Maya."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_TRANSCODER_SUPPORTED
+    HELPSTRING "Enable the Draco transcoder."
+    VALUE OFF)
+  draco_option(
+    NAME DRACO_DEBUG_COMPILER_WARNINGS
+    HELPSTRING "Turn on more warnings."
+    VALUE OFF)
   draco_check_deprecated_options()
 endmacro()
 
@@ -117,14 +177,16 @@ macro(draco_check_deprecated_options)
                                  DRACO_MAYA_PLUGIN)
   draco_handle_deprecated_option(OLDNAME BUILD_USD_PLUGIN NEWNAME
                                  BUILD_SHARED_LIBS)
+  draco_handle_deprecated_option(OLDNAME DRACO_GLTF NEWNAME
+                                 DRACO_GLTF_BITSTREAM)
 
 endmacro()
 
 # Macro for setting Draco features based on user configuration. Features enabled
 # by this macro are Draco global.
 macro(draco_set_optional_features)
-  if(DRACO_GLTF)
-    # Override settings when building for GLTF.
+  if(DRACO_GLTF_BITSTREAM)
+    # Enable only the features included in the Draco GLTF bitstream spec.
     draco_enable_feature(FEATURE "DRACO_MESH_COMPRESSION_SUPPORTED")
     draco_enable_feature(FEATURE "DRACO_NORMAL_ENCODING_SUPPORTED")
     draco_enable_feature(FEATURE "DRACO_STANDARD_EDGEBREAKER_SUPPORTED")
@@ -170,6 +232,11 @@ macro(draco_set_optional_features)
     set(CMAKE_POSITION_INDEPENDENT_CODE ON)
   endif()
 
+  if(DRACO_TRANSCODER_SUPPORTED)
+    draco_enable_feature(FEATURE "DRACO_TRANSCODER_SUPPORTED")
+  endif()
+
+
 endmacro()
 
 # Macro that handles tracking of Draco preprocessor symbols for the purpose of
@@ -221,8 +288,56 @@ function(draco_generate_features_h)
     file(APPEND "${draco_features_file_name}.new" "#define ${feature}\n")
   endforeach()
 
+  if(MSVC)
+    if(NOT DRACO_DEBUG_COMPILER_WARNINGS)
+      file(APPEND "${draco_features_file_name}.new"
+           "// Enable DRACO_DEBUG_COMPILER_WARNINGS at CMake generation \n"
+           "// time to remove these pragmas.\n")
+
+      # warning C4018: '<operator>': signed/unsigned mismatch.
+      file(APPEND "${draco_features_file_name}.new"
+           "#pragma warning(disable:4018)\n")
+
+      # warning C4146: unary minus operator applied to unsigned type, result
+      # still unsigned
+      file(APPEND "${draco_features_file_name}.new"
+           "#pragma warning(disable:4146)\n")
+
+      # warning C4244: 'return': conversion from '<type>' to '<type>', possible
+      # loss of data.
+      file(APPEND "${draco_features_file_name}.new"
+           "#pragma warning(disable:4244)\n")
+
+      # warning C4267: 'initializing' conversion from '<type>' to '<type>',
+      # possible loss of data.
+      file(APPEND "${draco_features_file_name}.new"
+           "#pragma warning(disable:4267)\n")
+
+      # warning C4305: 'context' : truncation from 'type1' to 'type2'.
+      file(APPEND "${draco_features_file_name}.new"
+           "#pragma warning(disable:4305)\n")
+
+      # warning C4661: 'identifier' : no suitable definition provided for
+      # explicit template instantiation request.
+      file(APPEND "${draco_features_file_name}.new"
+           "#pragma warning(disable:4661)\n")
+
+      # warning C4800: Implicit conversion from 'type' to bool. Possible
+      # information loss.
+      # Also, in older MSVC releases:
+      # warning C4800: 'type' : forcing value to bool 'true' or 'false'
+      # (performance warning).
+      file(APPEND "${draco_features_file_name}.new"
+           "#pragma warning(disable:4800)\n")
+
+      # warning C4804: '<operator>': unsafe use of type '<type>' in operation.
+      file(APPEND "${draco_features_file_name}.new"
+           "#pragma warning(disable:4804)\n")
+    endif()
+  endif()
+
   file(APPEND "${draco_features_file_name}.new"
-       "\n#endif  // DRACO_FEATURES_H_")
+       "\n#endif  // DRACO_FEATURES_H_\n")
 
   # Will replace ${draco_features_file_name} only if the file content has
   # changed. This prevents forced Draco rebuilds after CMake runs.

+ 19 - 3
contrib/draco/cmake/draco_sanitizer.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_SANITIZER_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_SANITIZER_CMAKE_
@@ -5,7 +19,9 @@ set(DRACO_CMAKE_DRACO_SANITIZER_CMAKE_ 1)
 
 # Handles the details of enabling sanitizers.
 macro(draco_configure_sanitizer)
-  if(DRACO_SANITIZE AND NOT EMSCRIPTEN AND NOT MSVC)
+  if(DRACO_SANITIZE
+     AND NOT EMSCRIPTEN
+     AND NOT MSVC)
     if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
       if(DRACO_SANITIZE MATCHES "cfi")
         list(APPEND SAN_CXX_FLAGS "-flto" "-fno-sanitize-trap=cfi")
@@ -13,8 +29,8 @@ macro(draco_configure_sanitizer)
                     "-fuse-ld=gold")
       endif()
 
-      if(${CMAKE_SIZEOF_VOID_P} EQUAL 4
-         AND DRACO_SANITIZE MATCHES "integer|undefined")
+      if(${CMAKE_SIZEOF_VOID_P} EQUAL 4 AND DRACO_SANITIZE MATCHES
+                                            "integer|undefined")
         list(APPEND SAN_LINKER_FLAGS "--rtlib=compiler-rt" "-lgcc_s")
       endif()
     endif()

+ 96 - 51
contrib/draco/cmake/draco_targets.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_TARGETS_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_TARGETS_CMAKE_
@@ -51,26 +65,33 @@ macro(draco_add_executable)
   unset(exe_LIB_DEPS)
   set(optional_args TEST)
   set(single_value_args NAME OUTPUT_NAME)
-  set(multi_value_args SOURCES DEFINES INCLUDES COMPILE_FLAGS LINK_FLAGS
-                       OBJLIB_DEPS LIB_DEPS)
+  set(multi_value_args
+      SOURCES
+      DEFINES
+      INCLUDES
+      COMPILE_FLAGS
+      LINK_FLAGS
+      OBJLIB_DEPS
+      LIB_DEPS)
 
   cmake_parse_arguments(exe "${optional_args}" "${single_value_args}"
                         "${multi_value_args}" ${ARGN})
 
   if(DRACO_VERBOSE GREATER 1)
-    message("--------- draco_add_executable ---------\n"
-            "exe_TEST=${exe_TEST}\n"
-            "exe_TEST_DEFINES_MAIN=${exe_TEST_DEFINES_MAIN}\n"
-            "exe_NAME=${exe_NAME}\n"
-            "exe_OUTPUT_NAME=${exe_OUTPUT_NAME}\n"
-            "exe_SOURCES=${exe_SOURCES}\n"
-            "exe_DEFINES=${exe_DEFINES}\n"
-            "exe_INCLUDES=${exe_INCLUDES}\n"
-            "exe_COMPILE_FLAGS=${exe_COMPILE_FLAGS}\n"
-            "exe_LINK_FLAGS=${exe_LINK_FLAGS}\n"
-            "exe_OBJLIB_DEPS=${exe_OBJLIB_DEPS}\n"
-            "exe_LIB_DEPS=${exe_LIB_DEPS}\n"
-            "------------------------------------------\n")
+    message(
+      "--------- draco_add_executable ---------\n"
+      "exe_TEST=${exe_TEST}\n"
+      "exe_TEST_DEFINES_MAIN=${exe_TEST_DEFINES_MAIN}\n"
+      "exe_NAME=${exe_NAME}\n"
+      "exe_OUTPUT_NAME=${exe_OUTPUT_NAME}\n"
+      "exe_SOURCES=${exe_SOURCES}\n"
+      "exe_DEFINES=${exe_DEFINES}\n"
+      "exe_INCLUDES=${exe_INCLUDES}\n"
+      "exe_COMPILE_FLAGS=${exe_COMPILE_FLAGS}\n"
+      "exe_LINK_FLAGS=${exe_LINK_FLAGS}\n"
+      "exe_OBJLIB_DEPS=${exe_OBJLIB_DEPS}\n"
+      "exe_LIB_DEPS=${exe_LIB_DEPS}\n"
+      "------------------------------------------\n")
   endif()
 
   if(NOT (exe_NAME AND exe_SOURCES))
@@ -87,7 +108,12 @@ macro(draco_add_executable)
   endif()
 
   add_executable(${exe_NAME} ${exe_SOURCES})
-  set_target_properties(${exe_NAME} PROPERTIES VERSION ${DRACO_VERSION})
+
+    target_compile_features(${exe_NAME} PUBLIC cxx_std_11)
+
+  if(NOT EMSCRIPTEN)
+    set_target_properties(${exe_NAME} PROPERTIES VERSION ${DRACO_VERSION})
+  endif()
 
   if(exe_OUTPUT_NAME)
     set_target_properties(${exe_NAME} PROPERTIES OUTPUT_NAME ${exe_OUTPUT_NAME})
@@ -104,8 +130,8 @@ macro(draco_add_executable)
   endif()
 
   if(exe_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
-    target_compile_options(${exe_NAME}
-                           PRIVATE ${exe_COMPILE_FLAGS} ${DRACO_CXX_FLAGS})
+    target_compile_options(${exe_NAME} PRIVATE ${exe_COMPILE_FLAGS}
+                                               ${DRACO_CXX_FLAGS})
   endif()
 
   if(exe_LINK_FLAGS OR DRACO_EXE_LINKER_FLAGS)
@@ -113,8 +139,8 @@ macro(draco_add_executable)
       list(APPEND exe_LINK_FLAGS "${DRACO_EXE_LINKER_FLAGS}")
       # LINK_FLAGS is managed as a string.
       draco_set_and_stringify(SOURCE "${exe_LINK_FLAGS}" DEST exe_LINK_FLAGS)
-      set_target_properties(${exe_NAME}
-                            PROPERTIES LINK_FLAGS "${exe_LINK_FLAGS}")
+      set_target_properties(${exe_NAME} PROPERTIES LINK_FLAGS
+                                                   "${exe_LINK_FLAGS}")
     else()
       target_link_options(${exe_NAME} PRIVATE ${exe_LINK_FLAGS}
                           ${DRACO_EXE_LINKER_FLAGS})
@@ -136,12 +162,7 @@ macro(draco_add_executable)
   endif()
 
   if(exe_LIB_DEPS)
-    unset(exe_static)
-    if("${CMAKE_EXE_LINKER_FLAGS} ${DRACO_EXE_LINKER_FLAGS}" MATCHES "static")
-      set(exe_static ON)
-    endif()
-
-    if(exe_static AND CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
+    if(CMAKE_CXX_COMPILER_ID MATCHES "^Clang|^GNU")
       # Third party dependencies can introduce dependencies on system and test
       # libraries. Since the target created here is an executable, and CMake
       # does not provide a method of controlling order of link dependencies,
@@ -149,6 +170,10 @@ macro(draco_add_executable)
       # ensure that dependencies of third party targets can be resolved when
       # those dependencies happen to be resolved by dependencies of the current
       # target.
+      # TODO(tomfinegan): For portability use LINK_GROUP with RESCAN instead of
+      # directly (ab)using compiler/linker specific flags once CMake v3.24 is in
+      # wider use. See:
+      # https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:LINK_GROUP
       list(INSERT exe_LIB_DEPS 0 -Wl,--start-group)
       list(APPEND exe_LIB_DEPS -Wl,--end-group)
     endif()
@@ -209,27 +234,36 @@ macro(draco_add_library)
   unset(lib_TARGET_PROPERTIES)
   set(optional_args TEST)
   set(single_value_args NAME OUTPUT_NAME TYPE)
-  set(multi_value_args SOURCES DEFINES INCLUDES COMPILE_FLAGS LINK_FLAGS
-                       OBJLIB_DEPS LIB_DEPS PUBLIC_INCLUDES TARGET_PROPERTIES)
+  set(multi_value_args
+      SOURCES
+      DEFINES
+      INCLUDES
+      COMPILE_FLAGS
+      LINK_FLAGS
+      OBJLIB_DEPS
+      LIB_DEPS
+      PUBLIC_INCLUDES
+      TARGET_PROPERTIES)
 
   cmake_parse_arguments(lib "${optional_args}" "${single_value_args}"
                         "${multi_value_args}" ${ARGN})
 
   if(DRACO_VERBOSE GREATER 1)
-    message("--------- draco_add_library ---------\n"
-            "lib_TEST=${lib_TEST}\n"
-            "lib_NAME=${lib_NAME}\n"
-            "lib_OUTPUT_NAME=${lib_OUTPUT_NAME}\n"
-            "lib_TYPE=${lib_TYPE}\n"
-            "lib_SOURCES=${lib_SOURCES}\n"
-            "lib_DEFINES=${lib_DEFINES}\n"
-            "lib_INCLUDES=${lib_INCLUDES}\n"
-            "lib_COMPILE_FLAGS=${lib_COMPILE_FLAGS}\n"
-            "lib_LINK_FLAGS=${lib_LINK_FLAGS}\n"
-            "lib_OBJLIB_DEPS=${lib_OBJLIB_DEPS}\n"
-            "lib_LIB_DEPS=${lib_LIB_DEPS}\n"
-            "lib_PUBLIC_INCLUDES=${lib_PUBLIC_INCLUDES}\n"
-            "---------------------------------------\n")
+    message(
+      "--------- draco_add_library ---------\n"
+      "lib_TEST=${lib_TEST}\n"
+      "lib_NAME=${lib_NAME}\n"
+      "lib_OUTPUT_NAME=${lib_OUTPUT_NAME}\n"
+      "lib_TYPE=${lib_TYPE}\n"
+      "lib_SOURCES=${lib_SOURCES}\n"
+      "lib_DEFINES=${lib_DEFINES}\n"
+      "lib_INCLUDES=${lib_INCLUDES}\n"
+      "lib_COMPILE_FLAGS=${lib_COMPILE_FLAGS}\n"
+      "lib_LINK_FLAGS=${lib_LINK_FLAGS}\n"
+      "lib_OBJLIB_DEPS=${lib_OBJLIB_DEPS}\n"
+      "lib_LIB_DEPS=${lib_LIB_DEPS}\n"
+      "lib_PUBLIC_INCLUDES=${lib_PUBLIC_INCLUDES}\n"
+      "---------------------------------------\n")
   endif()
 
   if(NOT (lib_NAME AND lib_TYPE))
@@ -256,14 +290,24 @@ macro(draco_add_library)
   endif()
 
   add_library(${lib_NAME} ${lib_TYPE} ${lib_SOURCES})
+
+    target_compile_features(${lib_NAME} PUBLIC cxx_std_11)
+
+  target_include_directories(${lib_NAME} PUBLIC $<INSTALL_INTERFACE:include>)
+
+  if(BUILD_SHARED_LIBS)
+    # Enable PIC for all targets in shared configurations.
+    set_target_properties(${lib_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
+  endif()
+
   if(lib_SOURCES)
     draco_process_intrinsics_sources(TARGET ${lib_NAME} SOURCES ${lib_SOURCES})
   endif()
 
   if(lib_OUTPUT_NAME)
     if(NOT (BUILD_SHARED_LIBS AND MSVC))
-      set_target_properties(${lib_NAME}
-                            PROPERTIES OUTPUT_NAME ${lib_OUTPUT_NAME})
+      set_target_properties(${lib_NAME} PROPERTIES OUTPUT_NAME
+                                                   ${lib_OUTPUT_NAME})
     endif()
   endif()
 
@@ -280,8 +324,8 @@ macro(draco_add_library)
   endif()
 
   if(lib_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
-    target_compile_options(${lib_NAME}
-                           PRIVATE ${lib_COMPILE_FLAGS} ${DRACO_CXX_FLAGS})
+    target_compile_options(${lib_NAME} PRIVATE ${lib_COMPILE_FLAGS}
+                                               ${DRACO_CXX_FLAGS})
   endif()
 
   if(lib_LINK_FLAGS)
@@ -320,11 +364,12 @@ macro(draco_add_library)
     set_target_properties(${lib_NAME} PROPERTIES PREFIX "")
   endif()
 
-  # VERSION and SOVERSION as necessary
-  if(NOT lib_TYPE STREQUAL STATIC AND NOT lib_TYPE STREQUAL MODULE)
-    set_target_properties(${lib_NAME} PROPERTIES VERSION ${DRACO_VERSION})
-    if(NOT MSVC)
-      set_target_properties(${lib_NAME} PROPERTIES SOVERSION ${DRACO_SOVERSION})
+  if(NOT EMSCRIPTEN)
+    # VERSION and SOVERSION as necessary
+    if((lib_TYPE STREQUAL BUNDLE OR lib_TYPE STREQUAL SHARED) AND NOT MSVC)
+      set_target_properties(
+        ${lib_NAME} PROPERTIES VERSION ${DRACO_SOVERSION}
+                               SOVERSION ${DRACO_SOVERSION_MAJOR})
     endif()
   endif()
 

+ 15 - 0
contrib/draco/cmake/draco_test_config.h.cmake

@@ -1,3 +1,17 @@
+// Copyright 2021 The Draco Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #ifndef DRACO_TESTING_DRACO_TEST_CONFIG_H_
 #define DRACO_TESTING_DRACO_TEST_CONFIG_H_
 
@@ -9,5 +23,6 @@
 
 #define DRACO_TEST_DATA_DIR "${DRACO_TEST_DATA_DIR}"
 #define DRACO_TEST_TEMP_DIR "${DRACO_TEST_TEMP_DIR}"
+#define DRACO_TEST_ROOT_DIR "${DRACO_TEST_ROOT_DIR}"
 
 #endif  // DRACO_TESTING_DRACO_TEST_CONFIG_H_

+ 98 - 60
contrib/draco/cmake/draco_tests.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_TESTS_CMAKE)
   return()
 endif()
@@ -10,6 +24,13 @@ set(draco_factory_test_sources
     "${draco_src_root}/io/file_reader_factory_test.cc"
     "${draco_src_root}/io/file_writer_factory_test.cc")
 
+list(
+  APPEND draco_test_common_sources
+         "${draco_src_root}/core/draco_test_base.h"
+         "${draco_src_root}/core/draco_test_utils.cc"
+         "${draco_src_root}/core/draco_test_utils.h"
+         "${draco_src_root}/core/status.cc")
+
 list(
   APPEND
     draco_test_sources
@@ -30,22 +51,23 @@ list(
     "${draco_src_root}/compression/point_cloud/point_cloud_kd_tree_encoding_test.cc"
     "${draco_src_root}/compression/point_cloud/point_cloud_sequential_encoding_test.cc"
     "${draco_src_root}/core/buffer_bit_coding_test.cc"
-    "${draco_src_root}/core/draco_test_base.h"
-    "${draco_src_root}/core/draco_test_utils.cc"
-    "${draco_src_root}/core/draco_test_utils.h"
     "${draco_src_root}/core/math_utils_test.cc"
     "${draco_src_root}/core/quantization_utils_test.cc"
     "${draco_src_root}/core/status_test.cc"
     "${draco_src_root}/core/vector_d_test.cc"
     "${draco_src_root}/io/file_reader_test_common.h"
     "${draco_src_root}/io/file_utils_test.cc"
+    "${draco_src_root}/io/file_writer_utils_test.cc"
     "${draco_src_root}/io/stdio_file_reader_test.cc"
     "${draco_src_root}/io/stdio_file_writer_test.cc"
     "${draco_src_root}/io/obj_decoder_test.cc"
     "${draco_src_root}/io/obj_encoder_test.cc"
     "${draco_src_root}/io/ply_decoder_test.cc"
     "${draco_src_root}/io/ply_reader_test.cc"
+    "${draco_src_root}/io/stl_decoder_test.cc"
+    "${draco_src_root}/io/stl_encoder_test.cc"
     "${draco_src_root}/io/point_cloud_io_test.cc"
+    "${draco_src_root}/mesh/corner_table_test.cc"
     "${draco_src_root}/mesh/mesh_are_equivalent_test.cc"
     "${draco_src_root}/mesh/mesh_cleanup_test.cc"
     "${draco_src_root}/mesh/triangle_soup_mesh_builder_test.cc"
@@ -54,47 +76,71 @@ list(
     "${draco_src_root}/point_cloud/point_cloud_builder_test.cc"
     "${draco_src_root}/point_cloud/point_cloud_test.cc")
 
-list(APPEND draco_gtest_all
-            "${draco_root}/../googletest/googletest/src/gtest-all.cc")
-list(APPEND draco_gtest_main
-            "${draco_root}/../googletest/googletest/src/gtest_main.cc")
+if(DRACO_TRANSCODER_SUPPORTED)
+  list(
+    APPEND draco_test_sources
+           "${draco_src_root}/animation/animation_test.cc"
+           "${draco_src_root}/io/gltf_decoder_test.cc"
+           "${draco_src_root}/io/gltf_encoder_test.cc"
+           "${draco_src_root}/io/gltf_utils_test.cc"
+           "${draco_src_root}/io/gltf_test_helper.cc"
+           "${draco_src_root}/io/gltf_test_helper.h"
+           "${draco_src_root}/io/scene_io_test.cc"
+           "${draco_src_root}/io/texture_io_test.cc"
+           "${draco_src_root}/material/material_library_test.cc"
+           "${draco_src_root}/material/material_test.cc"
+           "${draco_src_root}/metadata/property_table_test.cc"
+           "${draco_src_root}/metadata/structural_metadata_test.cc"
+           "${draco_src_root}/scene/instance_array_test.cc"
+           "${draco_src_root}/scene/light_test.cc"
+           "${draco_src_root}/scene/mesh_group_test.cc"
+           "${draco_src_root}/scene/scene_test.cc"
+           "${draco_src_root}/scene/scene_are_equivalent_test.cc"
+           "${draco_src_root}/scene/scene_utils_test.cc"
+           "${draco_src_root}/scene/trs_matrix_test.cc"
+           "${draco_src_root}/texture/texture_library_test.cc"
+           "${draco_src_root}/texture/texture_map_test.cc"
+           "${draco_src_root}/texture/texture_transform_test.cc")
+
+endif()
 
 macro(draco_setup_test_targets)
   if(DRACO_TESTS)
+    draco_setup_googletest()
+
     if(NOT (EXISTS ${draco_gtest_all} AND EXISTS ${draco_gtest_main}))
-      message(FATAL "googletest must be a sibling directory of ${draco_root}.")
+      message(FATAL_ERROR "googletest missing, run git submodule update --init")
     endif()
 
     list(APPEND draco_test_defines GTEST_HAS_PTHREAD=0)
 
-    draco_add_library(TEST
-                      NAME
-                      draco_gtest
-                      TYPE
-                      STATIC
-                      SOURCES
-                      ${draco_gtest_all}
-                      DEFINES
-                      ${draco_defines}
-                      ${draco_test_defines}
-                      INCLUDES
-                      ${draco_test_include_paths})
-
-    draco_add_library(TEST
-                      NAME
-                      draco_gtest_main
-                      TYPE
-                      STATIC
-                      SOURCES
-                      ${draco_gtest_main}
-                      DEFINES
-                      ${draco_defines}
-                      ${draco_test_defines}
-                      INCLUDES
-                      ${draco_test_include_paths})
+    draco_add_library(
+      TEST
+      NAME draco_test_common
+      TYPE STATIC
+      SOURCES ${draco_test_common_sources}
+      DEFINES ${draco_defines} ${draco_test_defines}
+      INCLUDES ${draco_test_include_paths})
+
+    draco_add_library(
+      TEST
+      NAME draco_gtest
+      TYPE STATIC
+      SOURCES ${draco_gtest_all}
+      DEFINES ${draco_defines} ${draco_test_defines}
+      INCLUDES ${draco_test_include_paths})
+
+    draco_add_library(
+      TEST
+      NAME draco_gtest_main
+      TYPE STATIC
+      SOURCES ${draco_gtest_main}
+      DEFINES ${draco_defines} ${draco_test_defines}
+      INCLUDES ${draco_test_include_paths})
 
     set(DRACO_TEST_DATA_DIR "${draco_root}/testdata")
     set(DRACO_TEST_TEMP_DIR "${draco_build}/draco_test_temp")
+    set(DRACO_TEST_ROOT_DIR "${draco_root}")
     file(MAKE_DIRECTORY "${DRACO_TEST_TEMP_DIR}")
 
     # Sets DRACO_TEST_DATA_DIR and DRACO_TEST_TEMP_DIR.
@@ -102,32 +148,24 @@ macro(draco_setup_test_targets)
                    "${draco_build}/testing/draco_test_config.h")
 
     # Create the test targets.
-    draco_add_executable(NAME
-                         draco_tests
-                         SOURCES
-                         ${draco_test_sources}
-                         DEFINES
-                         ${draco_defines}
-                         ${draco_test_defines}
-                         INCLUDES
-                         ${draco_test_include_paths}
-                         LIB_DEPS
-                         draco_static
-                         draco_gtest
-                         draco_gtest_main)
-
-    draco_add_executable(NAME
-                         draco_factory_tests
-                         SOURCES
-                         ${draco_factory_test_sources}
-                         DEFINES
-                         ${draco_defines}
-                         ${draco_test_defines}
-                         INCLUDES
-                         ${draco_test_include_paths}
-                         LIB_DEPS
-                         draco_static
-                         draco_gtest
-                         draco_gtest_main)
+    draco_add_executable(
+      TEST
+      NAME draco_tests
+      SOURCES ${draco_test_sources}
+      DEFINES ${draco_defines} ${draco_test_defines}
+      INCLUDES ${draco_test_include_paths}
+      LIB_DEPS ${draco_dependency} draco_gtest draco_gtest_main
+               draco_test_common)
+
+    draco_add_executable(
+      TEST
+      NAME draco_factory_tests
+      SOURCES ${draco_factory_test_sources}
+      DEFINES ${draco_defines} ${draco_test_defines}
+      INCLUDES ${draco_test_include_paths}
+      LIB_DEPS ${draco_dependency} draco_gtest draco_gtest_main
+               draco_test_common)
+
+
   endif()
 endmacro()

+ 22 - 7
contrib/draco/cmake/draco_variables.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_DRACO_VARIABLES_CMAKE_)
   return()
 endif() # DRACO_CMAKE_DRACO_VARIABLES_CMAKE_
@@ -14,8 +28,7 @@ macro(draco_variable_must_be_directory variable_name)
 
   if("${${variable_name}}" STREQUAL "")
     message(
-      FATAL_ERROR
-        "Empty variable ${variable_name} is required to build draco.")
+      FATAL_ERROR "Empty variable ${variable_name} is required to build draco.")
   endif()
 
   if(NOT IS_DIRECTORY "${${variable_name}}")
@@ -44,11 +57,13 @@ macro(draco_dump_cmake_flag_variables)
   list(APPEND flag_variables "CMAKE_CXX_FLAGS_INIT" "CMAKE_CXX_FLAGS"
               "CMAKE_EXE_LINKER_FLAGS_INIT" "CMAKE_EXE_LINKER_FLAGS")
   if(CMAKE_BUILD_TYPE)
-    list(APPEND flag_variables "CMAKE_BUILD_TYPE"
-                "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
-                "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}"
-                "CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
-                "CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}")
+    list(
+      APPEND flag_variables
+             "CMAKE_BUILD_TYPE"
+             "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
+             "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}"
+             "CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
+             "CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}")
   endif()
   foreach(flag_variable ${flag_variables})
     message("${flag_variable}:${${flag_variable}}")

+ 0 - 19
contrib/draco/cmake/sanitizers.cmake

@@ -1,19 +0,0 @@
-if(DRACO_CMAKE_SANITIZERS_CMAKE_)
-  return()
-endif()
-set(DRACO_CMAKE_SANITIZERS_CMAKE_ 1)
-
-if(MSVC OR NOT SANITIZE)
-  return()
-endif()
-
-include("${draco_root}/cmake/compiler_flags.cmake")
-
-string(TOLOWER ${SANITIZE} SANITIZE)
-
-# Require the sanitizer requested.
-require_linker_flag("-fsanitize=${SANITIZE}")
-require_compiler_flag("-fsanitize=${SANITIZE}" YES)
-
-# Make callstacks accurate.
-require_compiler_flag("-fno-omit-frame-pointer -fno-optimize-sibling-calls" YES)

+ 14 - 0
contrib/draco/cmake/toolchains/aarch64-linux-gnu.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_TOOLCHAINS_AARCH64_LINUX_GNU_CMAKE_)
   return()
 endif() # DRACO_CMAKE_TOOLCHAINS_AARCH64_LINUX_GNU_CMAKE_

+ 14 - 0
contrib/draco/cmake/toolchains/android-ndk-common.cmake

@@ -1,3 +1,17 @@
+# Copyright 2021 The Draco Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
 if(DRACO_CMAKE_TOOLCHAINS_ANDROID_NDK_COMMON_CMAKE_)
   return()
 endif()

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä