diff --git a/CMakeLists.txt b/CMakeLists.txt
index 59b79d1c6..42f975c79 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -583,17 +583,19 @@ ENDIF()
 ADD_SUBDIRECTORY( code/ )
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
   # The viewer for windows only
-  IF ( WIN32 AND DirectX_D3DX9_LIBRARY )
-    OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
+  IF ( WIN32 )
+    OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF )
     IF ( ASSIMP_BUILD_ASSIMP_VIEW )
       ADD_SUBDIRECTORY( tools/assimp_view/ )
     ENDIF ()
   ENDIF ()
-  # Te command line tool
+  # The command line tool
   ADD_SUBDIRECTORY( tools/assimp_cmd/ )
 ENDIF ()
 
 IF ( ASSIMP_BUILD_SAMPLES)
+  SET( SAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/samples )
+  SET( SAMPLES_SHARED_CODE_DIR ${SAMPLES_DIR}/SharedCode )
   IF ( WIN32 )
     ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ )
     ADD_SUBDIRECTORY( samples/SimpleTexturedDirectx11 )
diff --git a/assimp.pc.in b/assimp.pc.in
index c659e19f2..02cf59dc4 100644
--- a/assimp.pc.in
+++ b/assimp.pc.in
@@ -1,7 +1,7 @@
 prefix=@CMAKE_INSTALL_PREFIX@
 exec_prefix=@CMAKE_INSTALL_PREFIX@/
 libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@
-includedir=@CMAKE_INSTALL_PREFIX@/../include/@ASSIMP_INCLUDE_INSTALL_DIR@
+includedir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_INCLUDE_INSTALL_DIR@
 
 Name: @CMAKE_PROJECT_NAME@
 Description: Import various well-known 3D model formats in an uniform manner.
diff --git a/assimpTargets-debug.cmake.in b/assimpTargets-debug.cmake.in
index cefdd038a..eba5e220e 100644
--- a/assimpTargets-debug.cmake.in
+++ b/assimpTargets-debug.cmake.in
@@ -43,7 +43,7 @@ if(MSVC)
   endif()
   set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
 
-  file(TO_NATIVE_PATH ${_IMPORT_PREFIX} _IMPORT_PREFIX)
+  file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX)
 
   if(ASSIMP_BUILD_SHARED_LIBS)
     set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
diff --git a/assimpTargets-release.cmake.in b/assimpTargets-release.cmake.in
index ec2daf1ba..b66c6403c 100644
--- a/assimpTargets-release.cmake.in
+++ b/assimpTargets-release.cmake.in
@@ -43,7 +43,7 @@ if(MSVC)
   endif()
   set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
   	
-  file(TO_NATIVE_PATH ${_IMPORT_PREFIX} _IMPORT_PREFIX)
+  file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX)
 
   if(ASSIMP_BUILD_SHARED_LIBS)
     set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt
index 0cef480f2..0dff5d9e4 100644
--- a/code/CMakeLists.txt
+++ b/code/CMakeLists.txt
@@ -185,8 +185,6 @@ SET( Common_SRCS
   Common/ScenePreprocessor.cpp
   Common/ScenePreprocessor.h
   Common/SkeletonMeshBuilder.cpp
-  Common/SplitByBoneCountProcess.cpp
-  Common/SplitByBoneCountProcess.h
   Common/StandardShapes.cpp
   Common/TargetAnimation.cpp
   Common/TargetAnimation.h
@@ -252,35 +250,39 @@ MACRO(ADD_ASSIMP_IMPORTER name)
   ENDIF()
 ENDMACRO()
 
-# if this variable is set to TRUE, the user can manually disable exporters by setting
-# ASSIMP_BUILD_XXX_EXPORTER to FALSE for each exporter
-# if this variable is set to FALSE, the user can manually enable exporters by setting
-# ASSIMP_BUILD_XXX_EXPORTER to TRUE for each exporter
-OPTION(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_EXPORTER values" TRUE)
+if (NOT ASSIMP_NO_EXPORT)
 
-# macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader
-# this way selective loaders can be compiled (reduces filesize + compile time)
-MACRO(ADD_ASSIMP_EXPORTER name)
-  IF (ASSIMP_NO_EXPORT)
-	set(ASSIMP_EXPORTER_ENABLED FALSE)
-  ELSEIF (ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT)
-    set(ASSIMP_EXPORTER_ENABLED TRUE)
-    IF (DEFINED ASSIMP_BUILD_${name}_EXPORTER AND NOT ASSIMP_BUILD_${name}_EXPORTER)
+  # if this variable is set to TRUE, the user can manually disable exporters by setting
+  # ASSIMP_BUILD_XXX_EXPORTER to FALSE for each exporter
+  # if this variable is set to FALSE, the user can manually enable exporters by setting
+  # ASSIMP_BUILD_XXX_EXPORTER to TRUE for each exporter
+  OPTION(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_EXPORTER values" TRUE)
+
+  # macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader
+  # this way selective loaders can be compiled (reduces filesize + compile time)
+  MACRO(ADD_ASSIMP_EXPORTER name)
+    IF (ASSIMP_NO_EXPORT)
       set(ASSIMP_EXPORTER_ENABLED FALSE)
+    ELSEIF (ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT)
+      set(ASSIMP_EXPORTER_ENABLED TRUE)
+      IF (DEFINED ASSIMP_BUILD_${name}_EXPORTER AND NOT ASSIMP_BUILD_${name}_EXPORTER)
+        set(ASSIMP_EXPORTER_ENABLED FALSE)
+      ENDIF ()
+    ELSE ()
+      set(ASSIMP_EXPORTER_ENABLED ${ASSIMP_BUILD_${name}_EXPORTER})
     ENDIF ()
-  ELSE ()
-    set(ASSIMP_EXPORTER_ENABLED ${ASSIMP_BUILD_${name}_EXPORTER})
-  ENDIF ()
 
-  IF (ASSIMP_EXPORTER_ENABLED)
-    SET(ASSIMP_EXPORTERS_ENABLED "${ASSIMP_EXPORTERS_ENABLED} ${name}")
-	LIST(APPEND ASSIMP_EXPORTER_SRCS ${ARGN})
-    SOURCE_GROUP(${name}_EXPORTER FILES ${ARGN})
-  ELSE()
-    SET(ASSIMP_EXPORTERS_DISABLED "${ASSIMP_EXPORTERS_DISABLED} ${name}")
-    add_definitions(-DASSIMP_BUILD_NO_${name}_EXPORTER)
-  ENDIF()
-ENDMACRO()
+    IF (ASSIMP_EXPORTER_ENABLED)
+      SET(ASSIMP_EXPORTERS_ENABLED "${ASSIMP_EXPORTERS_ENABLED} ${name}")
+      LIST(APPEND ASSIMP_EXPORTER_SRCS ${ARGN})
+      SOURCE_GROUP(${name}_EXPORTER FILES ${ARGN})
+    ELSE()
+      SET(ASSIMP_EXPORTERS_DISABLED "${ASSIMP_EXPORTERS_DISABLED} ${name}")
+      add_definitions(-DASSIMP_BUILD_NO_${name}_EXPORTER)
+    ENDIF()
+  ENDMACRO()
+
+endif()
 
 SET(ASSIMP_LOADER_SRCS "")
 SET(ASSIMP_IMPORTERS_ENABLED "") # list of enabled importers
@@ -307,11 +309,6 @@ ADD_ASSIMP_IMPORTER( 3DS
   3DS/3DSLoader.h
 )
 
-ADD_ASSIMP_EXPORTER( 3DS
-  3DS/3DSExporter.h
-  3DS/3DSExporter.cpp
-)
-
 ADD_ASSIMP_IMPORTER( AC
   AC/ACLoader.cpp
   AC/ACLoader.h
@@ -329,20 +326,6 @@ ADD_ASSIMP_IMPORTER( ASSBIN
   Assbin/AssbinLoader.cpp
 )
 
-ADD_ASSIMP_EXPORTER( ASSBIN
-  Assbin/AssbinExporter.h
-  Assbin/AssbinExporter.cpp
-  Assbin/AssbinFileWriter.h
-  Assbin/AssbinFileWriter.cpp
-)
-
-ADD_ASSIMP_EXPORTER( ASSXML
-  Assxml/AssxmlExporter.h
-  Assxml/AssxmlExporter.cpp
-  Assxml/AssxmlFileWriter.h
-  Assxml/AssxmlFileWriter.cpp
-)
-
 ADD_ASSIMP_IMPORTER( B3D
   B3D/B3DImporter.cpp
   B3D/B3DImporter.h
@@ -362,11 +345,6 @@ ADD_ASSIMP_IMPORTER( COLLADA
   Collada/ColladaParser.h
 )
 
-ADD_ASSIMP_EXPORTER( COLLADA
-  Collada/ColladaExporter.h
-  Collada/ColladaExporter.cpp
-)
-
 ADD_ASSIMP_IMPORTER( DXF
   DXF/DXFLoader.cpp
   DXF/DXFLoader.h
@@ -423,11 +401,6 @@ ADD_ASSIMP_IMPORTER( M3D
   M3D/m3d.h
 )
 
-ADD_ASSIMP_EXPORTER( M3D
-  M3D/M3DExporter.h
-  M3D/M3DExporter.cpp
-)
-
 ADD_ASSIMP_IMPORTER( MD2
   MD2/MD2FileData.h
   MD2/MD2Loader.cpp
@@ -505,11 +478,6 @@ ADD_ASSIMP_IMPORTER( OBJ
   Obj/ObjTools.h
 )
 
-ADD_ASSIMP_EXPORTER( OBJ
-  Obj/ObjExporter.h
-  Obj/ObjExporter.cpp
-)
-
 ADD_ASSIMP_IMPORTER( OGRE
   Ogre/OgreImporter.h
   Ogre/OgreStructs.h
@@ -529,11 +497,6 @@ ADD_ASSIMP_IMPORTER( OPENGEX
   OpenGEX/OpenGEXStructs.h
 )
 
-ADD_ASSIMP_EXPORTER( OPENGEX
-  OpenGEX/OpenGEXExporter.cpp
-  OpenGEX/OpenGEXExporter.h
-)
-
 ADD_ASSIMP_IMPORTER( PLY
   Ply/PlyLoader.cpp
   Ply/PlyLoader.h
@@ -541,11 +504,6 @@ ADD_ASSIMP_IMPORTER( PLY
   Ply/PlyParser.h
 )
 
-ADD_ASSIMP_EXPORTER( PLY
-  Ply/PlyExporter.cpp
-  Ply/PlyExporter.h
-)
-
 ADD_ASSIMP_IMPORTER( MS3D
   MS3D/MS3DLoader.cpp
   MS3D/MS3DLoader.h
@@ -635,14 +593,86 @@ ADD_ASSIMP_IMPORTER( FBX
   FBX/FBXCommon.h
 )
 
-ADD_ASSIMP_EXPORTER( FBX
-  FBX/FBXExporter.h
-  FBX/FBXExporter.cpp
-  FBX/FBXExportNode.h
-  FBX/FBXExportNode.cpp
-  FBX/FBXExportProperty.h
-  FBX/FBXExportProperty.cpp
-)
+if (NOT ASSIMP_NO_EXPORT)
+
+  ADD_ASSIMP_EXPORTER( OBJ
+    Obj/ObjExporter.h
+    Obj/ObjExporter.cpp)
+
+  ADD_ASSIMP_EXPORTER( OPENGEX
+    OpenGEX/OpenGEXExporter.cpp
+    OpenGEX/OpenGEXExporter.h)
+
+  ADD_ASSIMP_EXPORTER( PLY
+    Ply/PlyExporter.cpp
+    Ply/PlyExporter.h)
+
+  ADD_ASSIMP_EXPORTER( 3DS
+    3DS/3DSExporter.h
+    3DS/3DSExporter.cpp)
+
+  ADD_ASSIMP_EXPORTER( ASSBIN
+    Assbin/AssbinExporter.h
+    Assbin/AssbinExporter.cpp
+    Assbin/AssbinFileWriter.h
+    Assbin/AssbinFileWriter.cpp)
+
+  ADD_ASSIMP_EXPORTER( ASSXML
+    Assxml/AssxmlExporter.h
+    Assxml/AssxmlExporter.cpp
+    Assxml/AssxmlFileWriter.h
+    Assxml/AssxmlFileWriter.cpp)
+
+  ADD_ASSIMP_EXPORTER(M3D
+    M3D/M3DExporter.h
+    M3D/M3DExporter.cpp)
+
+  ADD_ASSIMP_EXPORTER(COLLADA
+    Collada/ColladaExporter.h
+    Collada/ColladaExporter.cpp)
+
+  ADD_ASSIMP_EXPORTER( FBX
+    FBX/FBXExporter.h
+    FBX/FBXExporter.cpp
+    FBX/FBXExportNode.h
+    FBX/FBXExportNode.cpp
+    FBX/FBXExportProperty.h
+    FBX/FBXExportProperty.cpp)
+
+  ADD_ASSIMP_EXPORTER( STL
+    STL/STLExporter.h
+    STL/STLExporter.cpp)
+
+  ADD_ASSIMP_EXPORTER( X
+    X/XFileExporter.h
+    X/XFileExporter.cpp)
+
+  ADD_ASSIMP_EXPORTER( X3D
+    X3D/X3DExporter.cpp
+    X3D/X3DExporter.hpp)
+
+  ADD_ASSIMP_EXPORTER( GLTF
+    glTF/glTFExporter.h
+    glTF/glTFExporter.cpp
+    glTF2/glTF2Exporter.h
+    glTF2/glTF2Exporter.cpp)
+
+  ADD_ASSIMP_EXPORTER( 3MF
+    3MF/D3MFExporter.h
+    3MF/D3MFExporter.cpp)
+
+  ADD_ASSIMP_EXPORTER( ASSJSON
+    Assjson/cencode.c
+    Assjson/cencode.h
+    Assjson/json_exporter.cpp
+    Assjson/mesh_splitter.cpp
+    Assjson/mesh_splitter.h)
+
+  ADD_ASSIMP_EXPORTER( STEP
+    Step/StepExporter.h
+    Step/StepExporter.cpp)
+
+endif()
 
 SET( PostProcessing_SRCS
   PostProcessing/CalcTangentsProcess.cpp
@@ -705,6 +735,8 @@ SET( PostProcessing_SRCS
   PostProcessing/ArmaturePopulate.h
   PostProcessing/GenBoundingBoxesProcess.cpp
   PostProcessing/GenBoundingBoxesProcess.h
+  PostProcessing/SplitByBoneCountProcess.cpp
+  PostProcessing/SplitByBoneCountProcess.h
 )
 SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS})
 
@@ -744,11 +776,6 @@ ADD_ASSIMP_IMPORTER( STL
   STL/STLLoader.h
 )
 
-ADD_ASSIMP_EXPORTER( STL
-  STL/STLExporter.h
-  STL/STLExporter.cpp
-)
-
 ADD_ASSIMP_IMPORTER( TERRAGEN
   Terragen/TerragenLoader.cpp
   Terragen/TerragenLoader.h
@@ -767,11 +794,6 @@ ADD_ASSIMP_IMPORTER( X
   X/XFileParser.h
 )
 
-ADD_ASSIMP_EXPORTER( X
-  X/XFileExporter.h
-  X/XFileExporter.cpp
-)
-
 ADD_ASSIMP_IMPORTER( X3D
   X3D/X3DImporter.cpp
   X3D/X3DImporter.hpp
@@ -792,11 +814,6 @@ ADD_ASSIMP_IMPORTER( X3D
   X3D/X3DVocabulary.cpp
 )
 
-ADD_ASSIMP_EXPORTER( X3D
-  X3D/X3DExporter.cpp
-  X3D/X3DExporter.hpp
-)
-
 ADD_ASSIMP_IMPORTER( GLTF
   glTF/glTFCommon.h
   glTF/glTFCommon.cpp
@@ -814,13 +831,6 @@ ADD_ASSIMP_IMPORTER( GLTF
   glTF2/glTF2Importer.h
 )
 
-ADD_ASSIMP_EXPORTER( GLTF
-  glTF/glTFExporter.h
-  glTF/glTFExporter.cpp
-  glTF2/glTF2Exporter.h
-  glTF2/glTF2Exporter.cpp
-)
-
 ADD_ASSIMP_IMPORTER( 3MF
   3MF/D3MFImporter.h
   3MF/D3MFImporter.cpp
@@ -829,11 +839,6 @@ ADD_ASSIMP_IMPORTER( 3MF
   3MF/3MFXmlTags.h
 )
 
-ADD_ASSIMP_EXPORTER( 3MF
-  3MF/D3MFExporter.h
-  3MF/D3MFExporter.cpp
-)
-
 ADD_ASSIMP_IMPORTER( MMD
   MMD/MMDCpp14.h
   MMD/MMDImporter.cpp
@@ -844,14 +849,6 @@ ADD_ASSIMP_IMPORTER( MMD
   MMD/MMDVmdParser.h
 )
 
-ADD_ASSIMP_EXPORTER( ASSJSON
-  Assjson/cencode.c
-  Assjson/cencode.h
-  Assjson/json_exporter.cpp
-  Assjson/mesh_splitter.cpp
-  Assjson/mesh_splitter.h
-)
-
 # Workaround for issue #2406 - force problematic large file to be optimized to prevent string table overflow error
 # Used -Os instead of -O2 as previous issues had mentioned, since -Os is roughly speaking -O2, excluding any
 # optimizations that take up extra space. Given that the issue is a string table overflowing, -Os seemed appropriate
@@ -874,11 +871,6 @@ ADD_ASSIMP_IMPORTER( STEP
     Importer/StepFile/StepReaderGen.h
 )
 
-ADD_ASSIMP_EXPORTER( STEP
-    Step/StepExporter.h
-    Step/StepExporter.cpp
-)
-
 if ((NOT ASSIMP_NO_EXPORT) OR (NOT ASSIMP_EXPORTERS_ENABLED STREQUAL ""))
 	SET( Exporter_SRCS
 	  Common/Exporter.cpp
@@ -1088,8 +1080,10 @@ ENDIF()
 MESSAGE(STATUS "Enabled importer formats:${ASSIMP_IMPORTERS_ENABLED}")
 MESSAGE(STATUS "Disabled importer formats:${ASSIMP_IMPORTERS_DISABLED}")
 
-MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}")
-MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}")
+if (NOT ASSIMP_NO_EXPORT)
+  MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}")
+  MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}")
+endif()
 
 SOURCE_GROUP( include\\assimp    FILES ${PUBLIC_HEADERS} )
 
diff --git a/code/Common/BaseProcess.cpp b/code/Common/BaseProcess.cpp
index 974af68db..d02653cf2 100644
--- a/code/Common/BaseProcess.cpp
+++ b/code/Common/BaseProcess.cpp
@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2020, assimp team
 
-
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -43,45 +41,43 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 /** @file Implementation of BaseProcess */
 
-#include <assimp/BaseImporter.h>
 #include "BaseProcess.h"
-#include <assimp/DefaultLogger.hpp>
-#include <assimp/scene.h>
 #include "Importer.h"
+#include <assimp/BaseImporter.h>
+#include <assimp/scene.h>
+#include <assimp/DefaultLogger.hpp>
 
 using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 BaseProcess::BaseProcess() AI_NO_EXCEPT
-: shared()
-, progress()
-{
+        : shared(),
+          progress() {
+    // empty
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
-BaseProcess::~BaseProcess()
-{
+BaseProcess::~BaseProcess() {
     // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
-void BaseProcess::ExecuteOnScene( Importer* pImp)
-{
-    ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene);
+void BaseProcess::ExecuteOnScene(Importer *pImp) {
+    ai_assert( nullptr != pImp );
+    ai_assert( nullptr != pImp->Pimpl()->mScene);
 
     progress = pImp->GetProgressHandler();
-    ai_assert(progress);
+    ai_assert(nullptr != progress);
 
-    SetupProperties( pImp );
+    SetupProperties(pImp);
 
     // catch exceptions thrown inside the PostProcess-Step
-    try
-    {
+    try {
         Execute(pImp->Pimpl()->mScene);
 
-    } catch( const std::exception& err )    {
+    } catch (const std::exception &err) {
 
         // extract error description
         pImp->Pimpl()->mErrorString = err.what();
@@ -94,14 +90,11 @@ void BaseProcess::ExecuteOnScene( Importer* pImp)
 }
 
 // ------------------------------------------------------------------------------------------------
-void BaseProcess::SetupProperties(const Importer* /*pImp*/)
-{
+void BaseProcess::SetupProperties(const Importer * /*pImp*/) {
     // the default implementation does nothing
 }
 
 // ------------------------------------------------------------------------------------------------
-bool BaseProcess::RequireVerboseFormat() const
-{
+bool BaseProcess::RequireVerboseFormat() const {
     return true;
 }
-
diff --git a/code/Common/BaseProcess.h b/code/Common/BaseProcess.h
index a7e48bba3..bf1f2586f 100644
--- a/code/Common/BaseProcess.h
+++ b/code/Common/BaseProcess.h
@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2020, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -44,12 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_BASEPROCESS_H
 #define INCLUDED_AI_BASEPROCESS_H
 
-#include <map>
 #include <assimp/GenericProperty.h>
 
+#include <map>
+
 struct aiScene;
 
-namespace Assimp    {
+namespace Assimp {
 
 class Importer;
 
@@ -60,64 +60,50 @@ class Importer;
  *  to provide additional information to other steps. This is primarily
  *  intended for cross-step optimizations.
  */
-class SharedPostProcessInfo
-{
+class SharedPostProcessInfo {
 public:
-
-    struct Base
-    {
-        virtual ~Base()
-        {}
+    struct Base {
+        virtual ~Base() {}
     };
 
     //! Represents data that is allocated on the heap, thus needs to be deleted
     template <typename T>
-    struct THeapData : public Base
-    {
-        explicit THeapData(T* in)
-            : data (in)
-        {}
+    struct THeapData : public Base {
+        explicit THeapData(T *in) :
+                data(in) {}
 
-        ~THeapData()
-        {
+        ~THeapData() {
             delete data;
         }
-        T* data;
+        T *data;
     };
 
     //! Represents static, by-value data not allocated on the heap
     template <typename T>
-    struct TStaticData : public Base
-    {
-        explicit TStaticData(T in)
-            : data (in)
-        {}
+    struct TStaticData : public Base {
+        explicit TStaticData(T in) :
+                data(in) {}
 
-        ~TStaticData()
-        {}
+        ~TStaticData() {}
 
         T data;
     };
 
     // some typedefs for cleaner code
     typedef unsigned int KeyType;
-    typedef std::map<KeyType, Base*>  PropertyMap;
+    typedef std::map<KeyType, Base *> PropertyMap;
 
 public:
-
     //! Destructor
-    ~SharedPostProcessInfo()
-    {
+    ~SharedPostProcessInfo() {
         Clean();
     }
 
     //! Remove all stored properties from the table
-    void Clean()
-    {
+    void Clean() {
         // invoke the virtual destructor for all stored properties
         for (PropertyMap::iterator it = pmap.begin(), end = pmap.end();
-             it != end; ++it)
-        {
+                it != end; ++it) {
             delete (*it).second;
         }
         pmap.clear();
@@ -125,24 +111,21 @@ public:
 
     //! Add a heap property to the list
     template <typename T>
-    void AddProperty( const char* name, T* in ){
-        AddProperty(name,(Base*)new THeapData<T>(in));
+    void AddProperty(const char *name, T *in) {
+        AddProperty(name, (Base *)new THeapData<T>(in));
     }
 
     //! Add a static by-value property to the list
     template <typename T>
-    void AddProperty( const char* name, T in ){
-        AddProperty(name,(Base*)new TStaticData<T>(in));
+    void AddProperty(const char *name, T in) {
+        AddProperty(name, (Base *)new TStaticData<T>(in));
     }
 
-
     //! Get a heap property
     template <typename T>
-    bool GetProperty( const char* name, T*& out ) const
-    {
-        THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name);
-        if(!t)
-        {
+    bool GetProperty(const char *name, T *&out) const {
+        THeapData<T> *t = (THeapData<T> *)GetPropertyInternal(name);
+        if (!t) {
             out = NULL;
             return false;
         }
@@ -152,53 +135,34 @@ public:
 
     //! Get a static, by-value property
     template <typename T>
-    bool GetProperty( const char* name, T& out ) const
-    {
-        TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name);
-        if(!t)return false;
+    bool GetProperty(const char *name, T &out) const {
+        TStaticData<T> *t = (TStaticData<T> *)GetPropertyInternal(name);
+        if ( nullptr == t) {
+            return false;
+        }
         out = t->data;
         return true;
     }
 
     //! Remove a property of a specific type
-    void RemoveProperty( const char* name)  {
-        SetGenericPropertyPtr<Base>(pmap,name,NULL);
+    void RemoveProperty(const char *name) {
+        SetGenericPropertyPtr<Base>(pmap, name, nullptr );
     }
 
 private:
-
-    void AddProperty( const char* name, Base* data) {
-        SetGenericPropertyPtr<Base>(pmap,name,data);
+    void AddProperty(const char *name, Base *data) {
+        SetGenericPropertyPtr<Base>(pmap, name, data);
     }
 
-    Base* GetPropertyInternal( const char* name) const  {
-        return GetGenericProperty<Base*>(pmap,name,NULL);
+    Base *GetPropertyInternal(const char *name) const {
+        return GetGenericProperty<Base *>(pmap, name, nullptr );
     }
 
 private:
-
     //! Map of all stored properties
     PropertyMap pmap;
 };
 
-#if 0
-
-// ---------------------------------------------------------------------------
-/** @brief Represents a dependency table for a postprocessing steps.
- *
- *  For future use.
- */
- struct PPDependencyTable
- {
-     unsigned int execute_me_before_these;
-     unsigned int execute_me_after_these;
-     unsigned int only_if_these_are_not_specified;
-     unsigned int mutually_exclusive_with;
- };
-
-#endif
-
-
 #define AI_SPP_SPATIAL_SORT "$Spat"
 
 // ---------------------------------------------------------------------------
@@ -228,7 +192,7 @@ public:
      * @return true if the process is present in this flag fields,
      *   false if not.
     */
-    virtual bool IsActive( unsigned int pFlags) const = 0;
+    virtual bool IsActive(unsigned int pFlags) const = 0;
 
     // -------------------------------------------------------------------
     /** Check whether this step expects its input vertex data to be
@@ -241,14 +205,14 @@ public:
     * the object pointer will be set to NULL).
     * @param pImp Importer instance (pImp->mScene must be valid)
     */
-    void ExecuteOnScene( Importer* pImp);
+    void ExecuteOnScene(Importer *pImp);
 
     // -------------------------------------------------------------------
     /** 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);
 
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
@@ -256,35 +220,32 @@ public:
     * This method must be implemented by deriving classes.
     * @param pScene The imported data to work at.
     */
-    virtual void Execute( aiScene* pScene) = 0;
-
+    virtual void Execute(aiScene *pScene) = 0;
 
     // -------------------------------------------------------------------
     /** Assign a new SharedPostProcessInfo to the step. This object
      *  allows multiple postprocess steps to share data.
      * @param sh May be NULL
     */
-    inline void SetSharedData(SharedPostProcessInfo* sh)    {
+    inline void SetSharedData(SharedPostProcessInfo *sh) {
         shared = sh;
     }
 
     // -------------------------------------------------------------------
     /** Get the shared data that is assigned to the step.
     */
-    inline SharedPostProcessInfo* GetSharedData()   {
+    inline SharedPostProcessInfo *GetSharedData() {
         return shared;
     }
 
 protected:
-
     /** See the doc of #SharedPostProcessInfo for more details */
-    SharedPostProcessInfo* shared;
+    SharedPostProcessInfo *shared;
 
     /** Currently active progress handler */
-    ProgressHandler* progress;
+    ProgressHandler *progress;
 };
 
-
 } // end of namespace Assimp
 
 #endif // AI_BASEPROCESS_H_INC
diff --git a/code/Common/PostStepRegistry.cpp b/code/Common/PostStepRegistry.cpp
index 21bd2af95..19382165f 100644
--- a/code/Common/PostStepRegistry.cpp
+++ b/code/Common/PostStepRegistry.cpp
@@ -123,7 +123,7 @@ corresponding preprocessor flag to selectively disable steps.
 #   include "PostProcessing/OptimizeGraph.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS
-#   include "Common/SplitByBoneCountProcess.h"
+#   include "PostProcessing/SplitByBoneCountProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS
 #   include "PostProcessing/DeboneProcess.h"
diff --git a/code/Common/SplitByBoneCountProcess.cpp b/code/PostProcessing/SplitByBoneCountProcess.cpp
similarity index 95%
rename from code/Common/SplitByBoneCountProcess.cpp
rename to code/PostProcessing/SplitByBoneCountProcess.cpp
index b472cb359..ab7a1fe00 100644
--- a/code/Common/SplitByBoneCountProcess.cpp
+++ b/code/PostProcessing/SplitByBoneCountProcess.cpp
@@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <limits>
 #include <assimp/TinyFormatter.h>
+#include <assimp/Exceptional.h>
 
 using namespace Assimp;
 using namespace Assimp::Formatter;
@@ -94,7 +95,10 @@ void SplitByBoneCountProcess::Execute( aiScene* pScene)
     bool isNecessary = false;
     for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
         if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount )
+        {
             isNecessary = true;
+            break;
+        }
 
     if( !isNecessary )
     {
@@ -155,7 +159,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
 {
     // skip if not necessary
     if( pMesh->mNumBones <= mMaxBoneCount )
+    {
         return;
+    }
 
     // necessary optimisation: build a list of all affecting bones for each vertex
     // TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays
@@ -165,7 +171,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
     {
         const aiBone* bone = pMesh->mBones[a];
         for( unsigned int b = 0; b < bone->mNumWeights; ++b)
+        {
             vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight));
+        }
     }
 
     unsigned int numFacesHandled = 0;
@@ -189,7 +197,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         {
             // skip if the face is already stored in a submesh
             if( isFaceHandled[a] )
+            {
                 continue;
+            }
 
             const aiFace& face = pMesh->mFaces[a];
             // check every vertex if its bones would still fit into the current submesh
@@ -201,17 +211,27 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
                     unsigned int boneIndex = vb[c].first;
                     // if the bone is already used in this submesh, it's ok
                     if( isBoneUsed[boneIndex] )
+                    {
                         continue;
+                    }
 
                     // if it's not used, yet, we would need to add it. Store its bone index
                     if( std::find( newBonesAtCurrentFace.begin(), newBonesAtCurrentFace.end(), boneIndex) == newBonesAtCurrentFace.end() )
+                    {
                         newBonesAtCurrentFace.push_back( boneIndex);
+                    }
                 }
             }
 
+            if (newBonesAtCurrentFace.size() > mMaxBoneCount)
+            {
+                throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!");
+            }
             // 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 )
+            {
                 continue;
+            }
 
             // mark all new bones as necessary
             while( !newBonesAtCurrentFace.empty() )
@@ -219,7 +239,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
                 unsigned int newIndex = newBonesAtCurrentFace.back();
                 newBonesAtCurrentFace.pop_back(); // this also avoids the deallocation which comes with a clear()
                 if( isBoneUsed[newIndex] )
+                {
                     continue;
+                }
 
                 isBoneUsed[newIndex] = true;
                 numBones++;
@@ -237,7 +259,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         // create a new mesh to hold this subset of the source mesh
         aiMesh* newMesh = new aiMesh;
         if( pMesh->mName.length > 0 )
+        {
             newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size());
+        }
         newMesh->mMaterialIndex = pMesh->mMaterialIndex;
         newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes;
         poNewMeshes.push_back( newMesh);
@@ -247,7 +271,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
         newMesh->mVertices = new aiVector3D[newMesh->mNumVertices];
         if( pMesh->HasNormals() )
+        {
             newMesh->mNormals = new aiVector3D[newMesh->mNumVertices];
+        }
         if( pMesh->HasTangentsAndBitangents() )
         {
             newMesh->mTangents = new aiVector3D[newMesh->mNumVertices];
@@ -256,13 +282,17 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         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) )
+            {
                 newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices];
+            }
         }
 
         // and copy over the data, generating faces with linear indices along the way
@@ -285,7 +315,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
 
                 newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
                 if( pMesh->HasNormals() )
+                {
                     newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
+                }
                 if( pMesh->HasTangentsAndBitangents() )
                 {
                     newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
@@ -294,12 +326,16 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
                 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) )
+                    {
                         newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
+                    }
                 }
 
                 nvi++;
@@ -316,7 +352,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         for( unsigned int a = 0; a < pMesh->mNumBones; ++a )
         {
             if( !isBoneUsed[a] )
+            {
                 continue;
+            }
 
             // create the new bone
             const aiBone* srcBone = pMesh->mBones[a];
@@ -340,7 +378,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
             {
                 unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
                 if( newBoneIndex != std::numeric_limits<unsigned int>::max() )
+                {
                     newMesh->mBones[newBoneIndex]->mNumWeights++;
+                }
             }
         }
 
diff --git a/code/Common/SplitByBoneCountProcess.h b/code/PostProcessing/SplitByBoneCountProcess.h
similarity index 99%
rename from code/Common/SplitByBoneCountProcess.h
rename to code/PostProcessing/SplitByBoneCountProcess.h
index 7185d0330..b99830fde 100644
--- a/code/Common/SplitByBoneCountProcess.h
+++ b/code/PostProcessing/SplitByBoneCountProcess.h
@@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_SPLITBYBONECOUNTPROCESS_H_INC
 
 #include <vector>
-#include "BaseProcess.h"
+#include "Common/BaseProcess.h"
 
 #include <assimp/mesh.h>
 #include <assimp/scene.h>
diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp
index 5e137ed79..8c33674e1 100644
--- a/code/glTF2/glTF2Importer.cpp
+++ b/code/glTF2/glTF2Importer.cpp
@@ -111,8 +111,9 @@ const aiImporterDesc *glTF2Importer::GetInfo() const {
 bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
 	const std::string &extension = GetExtension(pFile);
 
-	if (extension != "gltf" && extension != "glb")
+	if (extension != "gltf" && extension != "glb") {
 		return false;
+	}
 
 	if (pIOHandler) {
 		glTF2::Asset asset(pIOHandler);
@@ -323,8 +324,9 @@ static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsign
 	for (unsigned i = 0; i < nFaces; ++i) {
 		for (unsigned j = 0; j < faces[i].mNumIndices; ++j) {
 			unsigned idx = faces[i].mIndices[j];
-			if (idx >= nVerts)
+			if (idx >= nVerts) {
 				return false;
+			}
 		}
 	}
 	return true;
@@ -861,7 +863,19 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
 		if (node.skin) {
 			for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) {
 				aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo];
-				mesh->mNumBones = static_cast<unsigned int>(node.skin->jointNames.size());
+				unsigned int numBones =static_cast<unsigned int>(node.skin->jointNames.size());
+
+				std::vector<std::vector<aiVertexWeight>> weighting(numBones);
+				BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
+
+				unsigned int realNumBones = 0;
+				for (uint32_t i = 0; i < numBones; ++i) {
+					if (weighting[i].size() > 0) {
+						realNumBones++;
+					}
+				}
+
+				mesh->mNumBones = static_cast<unsigned int>(realNumBones);
 				mesh->mBones = new aiBone *[mesh->mNumBones];
 
 				// GLTF and Assimp choose to store bone weights differently.
@@ -873,43 +887,33 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
 				// both because it's somewhat slow and because, for many applications,
 				// we then need to reconvert the data back into the vertex-to-bone
 				// mapping which makes things doubly-slow.
-				std::vector<std::vector<aiVertexWeight>> weighting(mesh->mNumBones);
-				BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
 
 				mat4 *pbindMatrices = nullptr;
 				node.skin->inverseBindMatrices->ExtractData(pbindMatrices);
 
-				for (uint32_t i = 0; i < mesh->mNumBones; ++i) {
-					aiBone *bone = new aiBone();
+				int cb = 0;
+				for (uint32_t i = 0; i < numBones; ++i) {
+					const std::vector<aiVertexWeight> &weights = weighting[i];
+					if (weights.size() > 0) {
+						aiBone *bone = new aiBone();
 
-					Ref<Node> joint = node.skin->jointNames[i];
-					if (!joint->name.empty()) {
-						bone->mName = joint->name;
-					} else {
-						// Assimp expects each bone to have a unique name.
-						static const std::string kDefaultName = "bone_";
-						char postfix[10] = { 0 };
-						ASSIMP_itoa10(postfix, i);
-						bone->mName = (kDefaultName + postfix);
-					}
-					GetNodeTransform(bone->mOffsetMatrix, *joint);
-
-					CopyValue(pbindMatrices[i], bone->mOffsetMatrix);
-
-					std::vector<aiVertexWeight> &weights = weighting[i];
-
-					bone->mNumWeights = static_cast<uint32_t>(weights.size());
-					if (bone->mNumWeights > 0) {
+						Ref<Node> joint = node.skin->jointNames[i];
+						if (!joint->name.empty()) {
+							bone->mName = joint->name;
+						} else {
+							// Assimp expects each bone to have a unique name.
+							static const std::string kDefaultName = "bone_";
+							char postfix[10] = { 0 };
+							ASSIMP_itoa10(postfix, i);
+							bone->mName = (kDefaultName + postfix);
+						}
+						GetNodeTransform(bone->mOffsetMatrix, *joint);
+						CopyValue(pbindMatrices[i], bone->mOffsetMatrix);
+						bone->mNumWeights = static_cast<uint32_t>(weights.size());
 						bone->mWeights = new aiVertexWeight[bone->mNumWeights];
 						memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
-					} else {
-						// Assimp expects all bones to have at least 1 weight.
-						bone->mWeights = new aiVertexWeight[1];
-						bone->mNumWeights = 1;
-						bone->mWeights->mVertexId = 0;
-						bone->mWeights->mWeight = 0.f;
+						mesh->mBones[cb++] = bone;
 					}
-					mesh->mBones[i] = bone;
 				}
 
 				if (pbindMatrices) {
@@ -1232,8 +1236,9 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
 
 	int numEmbeddedTexs = 0;
 	for (size_t i = 0; i < r.images.Size(); ++i) {
-		if (r.images[i].HasData())
+		if (r.images[i].HasData()) {
 			numEmbeddedTexs += 1;
+		}
 	}
 
 	if (numEmbeddedTexs == 0)
@@ -1244,7 +1249,9 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
 	// Add the embedded textures
 	for (size_t i = 0; i < r.images.Size(); ++i) {
 		Image &img = r.images[i];
-		if (!img.HasData()) continue;
+		if (!img.HasData()) {
+			continue;
+		}
 
 		int idx = mScene->mNumTextures++;
 		embeddedTexIdxs[i] = idx;
diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt
index 77916d2e1..f194649ed 100644
--- a/contrib/zip/CMakeLists.txt
+++ b/contrib/zip/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
 
 project(zip
   LANGUAGES C
-  VERSION "0.1.15")
+  VERSION "0.1.18")
 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
 
 option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
@@ -16,10 +16,6 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
         "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
         "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
-  if(ENABLE_COVERAGE)
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
-  endif()
 endif (MSVC)
 
 # zip
@@ -35,7 +31,7 @@ if (NOT CMAKE_DISABLE_TESTING)
   enable_testing()
   add_subdirectory(test)
   find_package(Sanitizers)
-  add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
+  add_sanitizers(${PROJECT_NAME} ${test_out})
 endif()
 
 ####
diff --git a/contrib/zip/README.md b/contrib/zip/README.md
index 14eb9a34c..bdd0822b6 100644
--- a/contrib/zip/README.md
+++ b/contrib/zip/README.md
@@ -1,10 +1,8 @@
 ### A portable (OSX/Linux/Windows), simple zip library written in C
 This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library and layering functions on top of the miniz v1.15 API.
 
-[![Windows](https://ci.appveyor.com/api/projects/status/bph8dr3jacgmjv32/branch/master?svg=true&label=windows)](https://ci.appveyor.com/project/kuba--/zip)
-[![Linux](https://travis-ci.org/kuba--/zip.svg?branch=master&label=linux%2fosx)](https://travis-ci.org/kuba--/zip)
+[![Build](https://github.com/kuba--/zip/workflows/build/badge.svg)](https://github.com/kuba--/zip/actions?query=workflow%3Abuild)
 [![Version](https://badge.fury.io/gh/kuba--%2Fzip.svg)](https://github.com/kuba--/zip/releases)
-[![Codecov](https://codecov.io/gh/kuba--/zip/branch/master/graph/badge.svg)](https://codecov.io/gh/kuba--/zip)
 
 
 # The Idea
@@ -213,6 +211,53 @@ func main() {
 }
 ```
 
+### Rust (ffi)
+```rust
+extern crate libc;
+use std::ffi::CString;
+
+#[repr(C)]
+pub struct Zip {
+    _private: [u8; 0],
+}
+
+#[link(name = "zip")]
+extern "C" {
+    fn zip_open(path: *const libc::c_char, level: libc::c_int, mode: libc::c_char) -> *mut Zip;
+    fn zip_close(zip: *mut Zip) -> libc::c_void;
+
+    fn zip_entry_open(zip: *mut Zip, entryname: *const libc::c_char) -> libc::c_int;
+    fn zip_entry_close(zip: *mut Zip) -> libc::c_int;
+    fn zip_entry_write(
+        zip: *mut Zip,
+        buf: *const libc::c_void,
+        bufsize: libc::size_t,
+    ) -> libc::c_int;
+}
+
+fn main() {
+    let path = CString::new("/tmp/test.zip").unwrap();
+    let mode: libc::c_char = 'w' as libc::c_char;
+
+    let entryname = CString::new("test.txt").unwrap();
+    let content = "test content\0";
+
+    unsafe {
+        let zip: *mut Zip = zip_open(path.as_ptr(), 5, mode);
+        {
+            zip_entry_open(zip, entryname.as_ptr());
+            {
+                let buf = content.as_ptr() as *const libc::c_void;
+                let bufsize = content.len() as libc::size_t;
+                zip_entry_write(zip, buf, bufsize);
+            }
+            zip_entry_close(zip);
+        }
+        zip_close(zip);
+    }
+}
+```
+
 ### Ruby (ffi)
 Install _ffi_ gem.
 ```shell
diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c
index 1abcfd8fd..3b2821e6a 100644
--- a/contrib/zip/src/zip.c
+++ b/contrib/zip/src/zip.c
@@ -222,6 +222,20 @@ void zip_close(struct zip_t *zip) {
   }
 }
 
+int zip_is64(struct zip_t *zip) {
+  if (!zip) {
+    // zip_t handler is not initialized
+    return -1;
+  }
+
+  if (!zip->archive.m_pState) {
+    // zip state is not initialized
+    return -1;
+  }
+
+  return (int)zip->archive.m_pState->m_zip64;
+}
+
 int zip_entry_open(struct zip_t *zip, const char *entryname) {
   size_t entrylen = 0;
   mz_zip_archive *pzip = NULL;
@@ -794,7 +808,8 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) {
 
     if (MZ_FILE_STAT(name, &file_stat) != 0) {
       // problem getting information - check errno
-      return -1;
+      status = -1;
+      break;
     }
 
     if ((file_stat.st_mode & 0200) == 0) {
diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h
index a48d64d6d..cd3ab5cd0 100644
--- a/contrib/zip/src/zip.h
+++ b/contrib/zip/src/zip.h
@@ -21,7 +21,7 @@ extern "C" {
 
 #if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) &&               \
     !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) &&              \
-    !defined(_SSIZE_T) && !defined(_SSIZE_T_)
+    !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(_SSIZE_T_DECLARED)
 
 // 64-bit Windows is the only mainstream platform
 // where sizeof(long) != sizeof(void*)
@@ -37,6 +37,7 @@ typedef long ssize_t; /* byte count or error */
 #define __ssize_t_defined
 #define _SSIZE_T
 #define _SSIZE_T_
+#define _SSIZE_T_DECLARED
 
 #endif
 
@@ -90,6 +91,16 @@ extern struct zip_t *zip_open(const char *zipname, int level, char mode);
  */
 extern void zip_close(struct zip_t *zip);
 
+/**
+ * Determines if the archive has a zip64 end of central directory headers.
+ *
+ * @param zip zip archive handler.
+ *
+ * @return the return code - 1 (true), 0 (false), negative number (< 0) on
+ *         error.
+ */
+extern int zip_is64(struct zip_t *zip);
+
 /**
  * Opens an entry by name in the zip archive.
  *
diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt
index cc060b00f..122411585 100644
--- a/contrib/zip/test/CMakeLists.txt
+++ b/contrib/zip/test/CMakeLists.txt
@@ -2,15 +2,10 @@ cmake_minimum_required(VERSION 2.8)
 
 # test
 set(test_out test.out)
-set(test_miniz_out test_miniz.out)
 
 add_executable(${test_out} test.c)
 target_link_libraries(${test_out} zip)
-add_executable(${test_miniz_out} test_miniz.c)
-target_link_libraries(${test_miniz_out} zip)
 
 add_test(NAME ${test_out} COMMAND ${test_out})
-add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
 
 set(test_out ${test_out} PARENT_SCOPE)
-set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c
index a9b2ddab1..9cc2248ac 100644
--- a/contrib/zip/test/test.c
+++ b/contrib/zip/test/test.c
@@ -47,7 +47,7 @@ static void test_write(void) {
   assert(CRC32DATA1 == zip_entry_crc32(zip));
   ++total_entries;
   assert(0 == zip_entry_close(zip));
-
+  assert(0 == zip_is64(zip));
   zip_close(zip);
 }
 
@@ -92,6 +92,7 @@ static void test_read(void) {
   size_t buftmp;
   struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
   assert(zip != NULL);
+  assert(0 == zip_is64(zip));
 
   assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
   assert(strlen(TESTDATA1) == zip_entry_size(zip));
@@ -310,6 +311,7 @@ static void test_fwrite(void) {
   assert(0 == zip_entry_open(zip, WFILE));
   assert(0 == zip_entry_fwrite(zip, WFILE));
   assert(0 == zip_entry_close(zip));
+  assert(0 == zip_is64(zip));
 
   zip_close(zip);
   remove(WFILE);
diff --git a/include/assimp/GenericProperty.h b/include/assimp/GenericProperty.h
index 30f4988f9..c1891c7b6 100644
--- a/include/assimp/GenericProperty.h
+++ b/include/assimp/GenericProperty.h
@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2020, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -45,26 +44,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_GENERIC_PROPERTY_H_INCLUDED
 
 #ifdef __GNUC__
-#   pragma GCC system_header
+#    pragma GCC system_header
 #endif
 
-#include <assimp/Importer.hpp>
-#include <assimp/ai_assert.h>
 #include <assimp/Hash.h>
+#include <assimp/ai_assert.h>
+#include <assimp/Importer.hpp>
 
 #include <map>
 
 // ------------------------------------------------------------------------------------------------
 template <class T>
-inline
-bool SetGenericProperty(std::map< unsigned int, T >& list,
-        const char* szName, const T& value) {
+inline bool SetGenericProperty(std::map<unsigned int, T> &list,
+        const char *szName, const T &value) {
     ai_assert(nullptr != szName);
     const uint32_t hash = SuperFastHash(szName);
 
     typename std::map<unsigned int, T>::iterator it = list.find(hash);
-    if (it == list.end())   {
-        list.insert(std::pair<unsigned int, T>( hash, value ));
+    if (it == list.end()) {
+        list.insert(std::pair<unsigned int, T>(hash, value));
         return false;
     }
     (*it).second = value;
@@ -74,9 +72,8 @@ bool SetGenericProperty(std::map< unsigned int, T >& list,
 
 // ------------------------------------------------------------------------------------------------
 template <class T>
-inline
-const T& GetGenericProperty(const std::map< unsigned int, T >& list,
-        const char* szName, const T& errorReturn) {
+inline const T &GetGenericProperty(const std::map<unsigned int, T> &list,
+        const char *szName, const T &errorReturn) {
     ai_assert(nullptr != szName);
     const uint32_t hash = SuperFastHash(szName);
 
@@ -92,22 +89,21 @@ const T& GetGenericProperty(const std::map< unsigned int, T >& list,
 // Special version for pointer types - they will be deleted when replaced with another value
 // passing NULL removes the whole property
 template <class T>
-inline
-void SetGenericPropertyPtr(std::map< unsigned int, T* >& list,
-        const char* szName, T* value, bool* bWasExisting = nullptr ) {
+inline void SetGenericPropertyPtr(std::map<unsigned int, T *> &list,
+        const char *szName, T *value, bool *bWasExisting = nullptr) {
     ai_assert(nullptr != szName);
     const uint32_t hash = SuperFastHash(szName);
 
-    typename std::map<unsigned int, T*>::iterator it = list.find(hash);
-    if (it == list.end())   {
+    typename std::map<unsigned int, T *>::iterator it = list.find(hash);
+    if (it == list.end()) {
         if (bWasExisting) {
             *bWasExisting = false;
         }
 
-        list.insert(std::pair<unsigned int,T*>( hash, value ));
+        list.insert(std::pair<unsigned int, T *>(hash, value));
         return;
     }
-    if ((*it).second != value)  {
+    if ((*it).second != value) {
         delete (*it).second;
         (*it).second = value;
     }
@@ -121,9 +117,8 @@ void SetGenericPropertyPtr(std::map< unsigned int, T* >& list,
 
 // ------------------------------------------------------------------------------------------------
 template <class T>
-inline
-bool HasGenericProperty(const std::map< unsigned int, T >& list,
-        const char* szName) {
+inline bool HasGenericProperty(const std::map<unsigned int, T> &list,
+        const char *szName) {
     ai_assert(nullptr != szName);
     const uint32_t hash = SuperFastHash(szName);
 
diff --git a/include/assimp/matrix3x3.h b/include/assimp/matrix3x3.h
index f9880ab9e..9f11b6b83 100644
--- a/include/assimp/matrix3x3.h
+++ b/include/assimp/matrix3x3.h
@@ -93,10 +93,10 @@ public:
     const TReal* operator[] (unsigned int p_iIndex) const;
 
     // comparison operators
-    bool operator== (const aiMatrix4x4t<TReal>& m) const;
-    bool operator!= (const aiMatrix4x4t<TReal>& m) const;
+    bool operator== (const aiMatrix3x3t<TReal>& m) const;
+    bool operator!= (const aiMatrix3x3t<TReal>& m) const;
 
-    bool Equal(const aiMatrix4x4t<TReal>& m, TReal epsilon = 1e-6) const;
+    bool Equal(const aiMatrix3x3t<TReal>& m, TReal epsilon = 1e-6) const;
 
     template <typename TOther>
     operator aiMatrix3x3t<TOther> () const;
diff --git a/include/assimp/matrix3x3.inl b/include/assimp/matrix3x3.inl
index b11e036b1..0b9565604 100644
--- a/include/assimp/matrix3x3.inl
+++ b/include/assimp/matrix3x3.inl
@@ -141,7 +141,7 @@ const TReal* aiMatrix3x3t<TReal>::operator[] (unsigned int p_iIndex) const {
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 AI_FORCE_INLINE
-bool aiMatrix3x3t<TReal>::operator== (const aiMatrix4x4t<TReal>& m) const {
+bool aiMatrix3x3t<TReal>::operator== (const aiMatrix3x3t<TReal>& m) const {
     return a1 == m.a1 && a2 == m.a2 && a3 == m.a3 &&
            b1 == m.b1 && b2 == m.b2 && b3 == m.b3 &&
            c1 == m.c1 && c2 == m.c2 && c3 == m.c3;
@@ -150,14 +150,14 @@ bool aiMatrix3x3t<TReal>::operator== (const aiMatrix4x4t<TReal>& m) const {
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 AI_FORCE_INLINE
-bool aiMatrix3x3t<TReal>::operator!= (const aiMatrix4x4t<TReal>& m) const {
+bool aiMatrix3x3t<TReal>::operator!= (const aiMatrix3x3t<TReal>& m) const {
     return !(*this == m);
 }
 
 // ---------------------------------------------------------------------------
 template<typename TReal>
 AI_FORCE_INLINE
-bool aiMatrix3x3t<TReal>::Equal(const aiMatrix4x4t<TReal>& m, TReal epsilon) const {
+bool aiMatrix3x3t<TReal>::Equal(const aiMatrix3x3t<TReal>& m, TReal epsilon) const {
     return
         std::abs(a1 - m.a1) <= epsilon &&
         std::abs(a2 - m.a2) <= epsilon &&
diff --git a/port/PyAssimp/pyassimp/core.py b/port/PyAssimp/pyassimp/core.py
index c346e2652..85cfe8233 100644
--- a/port/PyAssimp/pyassimp/core.py
+++ b/port/PyAssimp/pyassimp/core.py
@@ -138,7 +138,7 @@ def _init(self, target = None, parent = None):
             logger.debug(str(self) + ": Added array " + str(getattr(target, name)) +  " as self." + name.lower())
             continue
 
-        if m.startswith('m'):
+        if m.startswith('m') and len(m) > 1 and m[1].upper() == m[1]:
 
             if name == "parent":
                 setattr(target, name, parent)
diff --git a/samples/SharedCode/UTFConverter.cpp b/samples/SharedCode/UTFConverter.cpp
new file mode 100644
index 000000000..a1bff7e4b
--- /dev/null
+++ b/samples/SharedCode/UTFConverter.cpp
@@ -0,0 +1,52 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#include "UTFConverter.h"
+
+namespace AssimpSamples {
+namespace SharedCode {
+
+typename UTFConverter::UTFConverterImpl UTFConverter::impl_;
+
+}
+}
diff --git a/samples/SharedCode/UTFConverter.h b/samples/SharedCode/UTFConverter.h
new file mode 100644
index 000000000..17e89ee4d
--- /dev/null
+++ b/samples/SharedCode/UTFConverter.h
@@ -0,0 +1,92 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#ifndef ASSIMP_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_;
+};
+
+}
+}
+
+#endif // ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H
diff --git a/samples/SimpleTexturedDirectx11/CMakeLists.txt b/samples/SimpleTexturedDirectx11/CMakeLists.txt
index b1882500e..9eec738f5 100644
--- a/samples/SimpleTexturedDirectx11/CMakeLists.txt
+++ b/samples/SimpleTexturedDirectx11/CMakeLists.txt
@@ -10,12 +10,12 @@ if ( MSVC )
   REMOVE_DEFINITIONS( -DUNICODE -D_UNICODE )
 endif ()
 
+ADD_COMPILE_DEFINITIONS(SHADER_PATH="${CMAKE_CURRENT_SOURCE_DIR}/SimpleTexturedDirectx11/")
+
 INCLUDE_DIRECTORIES(
   ${Assimp_SOURCE_DIR}/include
   ${Assimp_SOURCE_DIR}/code
-  ${OPENGL_INCLUDE_DIR}
-  ${GLUT_INCLUDE_DIR}
-  ${Assimp_SOURCE_DIR}/samples/freeglut/include
+  ${SAMPLES_SHARED_CODE_DIR}
 )
 
 LINK_DIRECTORIES(
@@ -32,11 +32,14 @@ ADD_EXECUTABLE( assimp_simpletextureddirectx11 WIN32
   SimpleTexturedDirectx11/TextureLoader.h 
   #SimpleTexturedDirectx11/VertexShader.hlsl  
   SimpleTexturedDirectx11/main.cpp
+  SimpleTexturedDirectx11/SafeRelease.hpp
+  ${SAMPLES_SHARED_CODE_DIR}/UTFConverter.cpp
+  ${SAMPLES_SHARED_CODE_DIR}/UTFConverter.h
 )
 
 SET_PROPERTY(TARGET assimp_simpletextureddirectx11 PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
 
-TARGET_LINK_LIBRARIES( assimp_simpletextureddirectx11 assimp ${DirectX_LIBRARY} comctl32.lib winmm.lib )
+TARGET_LINK_LIBRARIES( assimp_simpletextureddirectx11 assimp comctl32.lib winmm.lib )
 SET_TARGET_PROPERTIES( assimp_simpletextureddirectx11 PROPERTIES
   OUTPUT_NAME assimp_simpletextureddirectx11
 )
diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h
index 87433219f..125b3e585 100644
--- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h
+++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h
@@ -6,97 +6,102 @@
 #include <sstream>
 #include <iostream>
 #include <vector>
-using namespace std;
-
-#include <vector>
+#include <stdexcept>
 #include <d3d11_1.h>
 #include <DirectXMath.h>
+
 using namespace DirectX;
 
+#include "SafeRelease.hpp"
+
 struct VERTEX {
 	FLOAT X, Y, Z;
 	XMFLOAT2 texcoord;
 };
 
 struct Texture {
-	string type;
-	string path;
+	std::string type;
+	std::string path;
 	ID3D11ShaderResourceView *texture;
+
+	void Release() {
+		SafeRelease(texture);
+	}
 };
 
 class Mesh {
 public:
-	vector<VERTEX> vertices;
-	vector<UINT> indices;
-	vector<Texture> textures;
-	ID3D11Device *dev;
+    std::vector<VERTEX> vertices;
+    std::vector<UINT> indices;
+    std::vector<Texture> textures;
+    ID3D11Device *dev;
 
-	Mesh(ID3D11Device *dev, vector<VERTEX> vertices, vector<UINT> indices, vector<Texture> textures)
-	{
-		this->vertices = vertices;
-		this->indices = indices;
-		this->textures = textures;
+    Mesh(ID3D11Device *dev, const std::vector<VERTEX>& vertices, const std::vector<UINT>& indices, const std::vector<Texture>& textures) :
+            vertices(vertices),
+            indices(indices),
+            textures(textures),
+            dev(dev),
+            VertexBuffer(nullptr),
+            IndexBuffer(nullptr) {
+        this->setupMesh(this->dev);
+    }
 
-		this->dev = dev;
+    void Draw(ID3D11DeviceContext *devcon) {
+        UINT stride = sizeof(VERTEX);
+        UINT offset = 0;
 
-		this->setupMesh(dev);
-	}
+        devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
+        devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
 
-	void Draw(ID3D11DeviceContext *devcon)
-	{
-		UINT stride = sizeof(VERTEX);
-		UINT offset = 0;
+        devcon->PSSetShaderResources(0, 1, &textures[0].texture);
 
-		devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
-		devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
+        devcon->DrawIndexed(static_cast<UINT>(indices.size()), 0, 0);
+    }
 
-		devcon->PSSetShaderResources(0, 1, &textures[0].texture);
-
-		devcon->DrawIndexed(indices.size(), 0, 0);
-	}
-
-	void Close()
-	{
-		VertexBuffer->Release();
-		IndexBuffer->Release();
-	}
+    void Close() {
+        SafeRelease(VertexBuffer);
+        SafeRelease(IndexBuffer);
+    }
 private:
-	/*  Render data  */
-	ID3D11Buffer *VertexBuffer, *IndexBuffer;
+    // Render data
+    ID3D11Buffer *VertexBuffer, *IndexBuffer;
 
-	/*  Functions    */
-	// Initializes all the buffer objects/arrays
-	bool setupMesh(ID3D11Device *dev)
-	{
-		HRESULT hr;
+    // Functions
+    // Initializes all the buffer objects/arrays
+    void setupMesh(ID3D11Device *dev) {
+        HRESULT hr;
 
-		D3D11_BUFFER_DESC vbd;
-		vbd.Usage = D3D11_USAGE_IMMUTABLE;
-		vbd.ByteWidth = sizeof(VERTEX) * vertices.size();
-		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
-		vbd.CPUAccessFlags = 0;
-		vbd.MiscFlags = 0;
+        D3D11_BUFFER_DESC vbd;
+        vbd.Usage = D3D11_USAGE_IMMUTABLE;
+        vbd.ByteWidth = static_cast<UINT>(sizeof(VERTEX) * vertices.size());
+        vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+        vbd.CPUAccessFlags = 0;
+        vbd.MiscFlags = 0;
 
-		D3D11_SUBRESOURCE_DATA initData;
-		initData.pSysMem = &vertices[0];
+        D3D11_SUBRESOURCE_DATA initData;
+        initData.pSysMem = &vertices[0];
 
-		hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer);
-		if (FAILED(hr))
-			return false;
+        hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer);
+        if (FAILED(hr)) {
+            Close();
+            throw std::runtime_error("Failed to create vertex buffer.");
+        }
 
-		D3D11_BUFFER_DESC ibd;
-		ibd.Usage = D3D11_USAGE_IMMUTABLE;
-		ibd.ByteWidth = sizeof(UINT) * indices.size();
-		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
-		ibd.CPUAccessFlags = 0;
-		ibd.MiscFlags = 0;
+        D3D11_BUFFER_DESC ibd;
+        ibd.Usage = D3D11_USAGE_IMMUTABLE;
+        ibd.ByteWidth = static_cast<UINT>(sizeof(UINT) * indices.size());
+        ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
+        ibd.CPUAccessFlags = 0;
+        ibd.MiscFlags = 0;
 
-		initData.pSysMem = &indices[0];
+        initData.pSysMem = &indices[0];
 
-		hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer);
-		if (FAILED(hr))
-			return false;
-	}
+        hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer);
+        if (FAILED(hr)) {
+            Close();
+            throw std::runtime_error("Failed to create index buffer.");
+        }
+    }
 };
 
 #endif
diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp
index 10ba07a98..806320144 100644
--- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp
+++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp
@@ -1,16 +1,21 @@
 #include "ModelLoader.h"
 
-ModelLoader::ModelLoader()
-{
+ModelLoader::ModelLoader() : 
+        dev(nullptr),
+        devcon(nullptr),
+        meshes(),
+        directory(),
+        textures_loaded(),
+        hwnd(nullptr) {
+    // empty
 }
 
 
-ModelLoader::~ModelLoader()
-{
+ModelLoader::~ModelLoader() {
+    // empty
 }
 
-bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename)
-{
+bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename) {
 	Assimp::Importer importer;
 
 	const aiScene* pScene = importer.ReadFile(filename,
@@ -20,9 +25,10 @@ bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devc
 	if (pScene == NULL)
 		return false;
 
-	this->directory = filename.substr(0, filename.find_last_of('/'));
+	this->directory = filename.substr(0, filename.find_last_of("/\\"));
 
 	this->dev = dev;
+	this->devcon = devcon;
 	this->hwnd = hwnd;
 
 	processNode(pScene->mRootNode, pScene);
@@ -30,41 +36,37 @@ bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devc
 	return true;
 }
 
-void ModelLoader::Draw(ID3D11DeviceContext * devcon)
-{
-	for (int i = 0; i < meshes.size(); i++)
-	{
+void ModelLoader::Draw(ID3D11DeviceContext * devcon) {
+	for (int i = 0; i < meshes.size(); ++i ) {
 		meshes[i].Draw(devcon);
 	}
 }
 
-string textype;
+std::string textype;
 
-Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene)
-{
+Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) {
 	// Data to fill
-	vector<VERTEX> vertices;
-	vector<UINT> indices;
-	vector<Texture> textures;
+	std::vector<VERTEX> vertices;
+	std::vector<UINT> indices;
+	std::vector<Texture> textures;
 
-	if (mesh->mMaterialIndex >= 0)
-	{
+	if (mesh->mMaterialIndex >= 0) {
 		aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
 
-		if (textype.empty()) textype = determineTextureType(scene, mat);
+		if (textype.empty()) {
+            textype = determineTextureType(scene, mat);
+        }
 	}
 
 	// Walk through each of the mesh's vertices
-	for (UINT i = 0; i < mesh->mNumVertices; i++)
-	{
+	for (UINT i = 0; i < mesh->mNumVertices; i++) {
 		VERTEX vertex;
 
 		vertex.X = mesh->mVertices[i].x;
 		vertex.Y = mesh->mVertices[i].y;
 		vertex.Z = mesh->mVertices[i].z;
 
-		if (mesh->mTextureCoords[0])
-		{
+		if (mesh->mTextureCoords[0]) {
 			vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x;
 			vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y;
 		}
@@ -72,57 +74,47 @@ Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene)
 		vertices.push_back(vertex);
 	}
 
-	for (UINT i = 0; i < mesh->mNumFaces; i++)
-	{
+	for (UINT i = 0; i < mesh->mNumFaces; i++) {
 		aiFace face = mesh->mFaces[i];
 
 		for (UINT j = 0; j < face.mNumIndices; j++)
 			indices.push_back(face.mIndices[j]);
 	}
 
-	if (mesh->mMaterialIndex >= 0)
-	{
+	if (mesh->mMaterialIndex >= 0) {
 		aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
 
-		vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene);
+		std::vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene);
 		textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
 	}
 
 	return Mesh(dev, vertices, indices, textures);
 }
 
-vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene)
-{
-	vector<Texture> textures;
-	for (UINT i = 0; i < mat->GetTextureCount(type); i++)
-	{
+std::vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, std::string typeName, const aiScene * scene) {
+	std::vector<Texture> textures;
+	for (UINT i = 0; i < mat->GetTextureCount(type); i++) {
 		aiString str;
 		mat->GetTexture(type, i, &str);
 		// Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture
 		bool skip = false;
-		for (UINT j = 0; j < textures_loaded.size(); j++)
-		{
-			if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0)
-			{
+		for (UINT j = 0; j < textures_loaded.size(); j++) {
+			if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0) {
 				textures.push_back(textures_loaded[j]);
 				skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization)
 				break;
 			}
 		}
-		if (!skip)
-		{   // If texture hasn't been loaded already, load it
+		if (!skip) {   // If texture hasn't been loaded already, load it
 			HRESULT hr;
 			Texture texture;
-			if (textype == "embedded compressed texture")
-			{
+			if (textype == "embedded compressed texture") {
 				int textureindex = getTextureIndex(&str);
 				texture.texture = getTextureFromModel(scene, textureindex);
-			}
-			else
-			{
-				string filename = string(str.C_Str());
+			} else {
+				std::string filename = std::string(str.C_Str());
 				filename = directory + '/' + filename;
-				wstring filenamews = wstring(filename.begin(), filename.end());
+				std::wstring filenamews = std::wstring(filename.begin(), filename.end());
 				hr = CreateWICTextureFromFile(dev, devcon, filenamews.c_str(), nullptr, &texture.texture);
 				if (FAILED(hr))
 					MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK);
@@ -136,64 +128,52 @@ vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureTyp
 	return textures;
 }
 
-void ModelLoader::Close()
-{
-	for (int i = 0; i < meshes.size(); i++)
-	{
+void ModelLoader::Close() {
+	for (auto& t : textures_loaded)
+		t.Release();
+
+	for (int i = 0; i < meshes.size(); i++) {
 		meshes[i].Close();
 	}
-
-	dev->Release();
 }
 
-void ModelLoader::processNode(aiNode * node, const aiScene * scene)
-{
-	for (UINT i = 0; i < node->mNumMeshes; i++)
-	{
+void ModelLoader::processNode(aiNode * node, const aiScene * scene) {
+	for (UINT i = 0; i < node->mNumMeshes; i++) {
 		aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
 		meshes.push_back(this->processMesh(mesh, scene));
 	}
 
-	for (UINT i = 0; i < node->mNumChildren; i++)
-	{
+	for (UINT i = 0; i < node->mNumChildren; i++) {
 		this->processNode(node->mChildren[i], scene);
 	}
 }
 
-string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat)
-{
+std::string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat) {
 	aiString textypeStr;
 	mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr);
-	string textypeteststr = textypeStr.C_Str();
-	if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5")
-	{
-		if (scene->mTextures[0]->mHeight == 0)
-		{
+	std::string textypeteststr = textypeStr.C_Str();
+	if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5") {
+		if (scene->mTextures[0]->mHeight == 0) {
 			return "embedded compressed texture";
-		}
-		else
-		{
+		} else {
 			return "embedded non-compressed texture";
 		}
 	}
-	if (textypeteststr.find('.') != string::npos)
-	{
+	if (textypeteststr.find('.') != std::string::npos) {
 		return "textures are on disk";
 	}
 
     return ".";
 }
 
-int ModelLoader::getTextureIndex(aiString * str)
-{
-	string tistr;
+int ModelLoader::getTextureIndex(aiString * str) {
+	std::string tistr;
 	tistr = str->C_Str();
 	tistr = tistr.substr(1);
 	return stoi(tistr);
 }
 
-ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex)
-{
+ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex) {
 	HRESULT hr;
 	ID3D11ShaderResourceView *texture;
 
diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h
index 9b4a53c27..18ad03fa0 100644
--- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h
+++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h
@@ -28,14 +28,14 @@ private:
 	ID3D11Device *dev;
 	ID3D11DeviceContext *devcon;
 	std::vector<Mesh> meshes;
-	string directory;
-	vector<Texture> textures_loaded;
+	std::string directory;
+	std::vector<Texture> textures_loaded;
 	HWND hwnd;
 
 	void processNode(aiNode* node, const aiScene* scene);
 	Mesh processMesh(aiMesh* mesh, const aiScene* scene);
-	vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName, const aiScene* scene);
-	string determineTextureType(const aiScene* scene, aiMaterial* mat);
+	std::vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName, const aiScene* scene);
+	std::string determineTextureType(const aiScene* scene, aiMaterial* mat);
 	int getTextureIndex(aiString* str);
 	ID3D11ShaderResourceView* getTextureFromModel(const aiScene* scene, int textureindex);
 };
diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SafeRelease.hpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SafeRelease.hpp
new file mode 100644
index 000000000..2fd80db6c
--- /dev/null
+++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SafeRelease.hpp
@@ -0,0 +1,57 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+/* Used to reduce to reduce the number of lines when calling Release()
+   on a D3D interface. Implemented as a template instead of a 'SAFE_RELEASE'
+   MACRO to ease debugging. */
+template<typename T>
+inline void SafeRelease(T*& x) {
+    if (x) {
+        x->Release();
+        x = nullptr;
+    }
+}
diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp
index 2d847095a..781fe89e5 100644
--- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp
+++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp
@@ -14,12 +14,16 @@
 // ---------------------------------------------------------------------------
 
 #include <Windows.h>
+#include <shellapi.h>
+#include <stdexcept>
 #include <windowsx.h>
 #include <d3d11_1.h>
 #include <dxgi1_2.h>
 #include <DirectXMath.h>
 #include <d3dcompiler.h>
 #include "ModelLoader.h"
+#include "UTFConverter.h"
+#include "SafeRelease.hpp"
 
 #pragma comment (lib, "d3d11.lib")
 #pragma comment (lib, "Dxgi.lib")
@@ -27,6 +31,10 @@
 #pragma comment (lib, "dxguid.lib")
 
 using namespace DirectX;
+using namespace AssimpSamples::SharedCode;
+
+#define VERTEX_SHADER_FILE L"VertexShader.hlsl"
+#define PIXEL_SHADER_FILE L"PixelShader.hlsl"
 
 // ------------------------------------------------------------
 //                        Structs
@@ -45,29 +53,32 @@ struct ConstantBuffer {
 
 const char g_szClassName[] = "directxWindowClass";
 
+static std::string g_ModelPath;
 
 UINT width, height;
-HWND hwnd;
+HWND hwnd = nullptr;
 
 // ------------------------------------------------------------
 //                        DirectX Variables
 // ------------------------------------------------------------
 D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
 D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
-ID3D11Device *dev;
-ID3D11Device1 *dev1;
-ID3D11DeviceContext *devcon;
-ID3D11DeviceContext1 *devcon1;
-IDXGISwapChain *swapchain;
-IDXGISwapChain1 *swapchain1;
-ID3D11RenderTargetView *backbuffer;
-ID3D11VertexShader *pVS;
-ID3D11PixelShader *pPS;
-ID3D11InputLayout *pLayout;
-ID3D11Buffer *pConstantBuffer;
-ID3D11Texture2D *g_pDepthStencil;
-ID3D11DepthStencilView *g_pDepthStencilView;
-ID3D11SamplerState *TexSamplerState;
+ID3D11Device *dev = nullptr;
+ID3D11Device1 *dev1 = nullptr;
+ID3D11DeviceContext *devcon = nullptr;
+ID3D11DeviceContext1 *devcon1 = nullptr;
+IDXGISwapChain *swapchain = nullptr;
+IDXGISwapChain1 *swapchain1 = nullptr;
+ID3D11RenderTargetView *backbuffer = nullptr;
+ID3D11VertexShader *pVS = nullptr;
+ID3D11PixelShader *pPS = nullptr;
+ID3D11InputLayout *pLayout = nullptr;
+ID3D11Buffer *pConstantBuffer = nullptr;
+ID3D11Texture2D *g_pDepthStencil = nullptr;
+ID3D11DepthStencilView *g_pDepthStencilView = nullptr;
+ID3D11SamplerState *TexSamplerState = nullptr;
+ID3D11RasterizerState *rasterstate = nullptr;
+ID3D11Debug* d3d11debug = nullptr;
 
 XMMATRIX m_World;
 XMMATRIX m_View;
@@ -91,7 +102,7 @@ void Throwanerror(LPCSTR errormessage);
 //                        Our Model
 // ------------------------------------------------------------
 
-ModelLoader *ourModel;
+ModelLoader *ourModel = nullptr;
 
 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
@@ -109,9 +120,42 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 	return 0;
 }
 
-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
-	LPSTR lpCmdLine, int nCmdShow)
+int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+	LPWSTR lpCmdLine, int nCmdShow)
 {
+	int argc;
+	LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
+	if (!argv) {
+		MessageBox(NULL, 
+			TEXT("An error occured while reading command line arguments."),
+			TEXT("Error!"),
+			MB_ICONERROR | MB_OK);
+		return EXIT_FAILURE;
+	}
+
+	// Free memory allocated from CommandLineToArgvW.
+	auto free_command_line_allocated_memory = [&argv]() {
+		if (argv) {
+			LocalFree(argv);
+			argv = nullptr;
+		}
+	};
+
+	// Ensure that a model file has been specified.
+	if (argc < 2) {
+		MessageBox(NULL, 
+			TEXT("No model file specified. The program will now close."), 
+			TEXT("Error!"),
+			MB_ICONERROR | MB_OK);
+		free_command_line_allocated_memory();
+		return EXIT_FAILURE;
+	}
+
+	// Retrieve the model file path.
+	g_ModelPath = UTFConverter(argv[1]).str();
+
+	free_command_line_allocated_memory();
+	
 	WNDCLASSEX wc;
 	MSG msg;
 
@@ -160,26 +204,35 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 	width = wr.right - wr.left;
 	height = wr.bottom - wr.top;
 
-	InitD3D(hInstance, hwnd);
+	try {
+		InitD3D(hInstance, hwnd);
 
-	while (true)
-	{
-
-		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+		while (true)
 		{
-			TranslateMessage(&msg);
-			DispatchMessage(&msg);
 
-			if (msg.message == WM_QUIT)
-				break;
+			if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+			{
+				TranslateMessage(&msg);
+				DispatchMessage(&msg);
+
+				if (msg.message == WM_QUIT)
+					break;
+			}
+
+			RenderFrame();
 		}
 
-		RenderFrame();
+		CleanD3D();
+		return static_cast<int>(msg.wParam);
+	} catch (const std::exception& e) {
+		MessageBox(hwnd, e.what(), TEXT("Error!"), MB_ICONERROR | MB_OK);
+		CleanD3D();
+		return EXIT_FAILURE;
+	} catch (...) {
+		MessageBox(hwnd, TEXT("Caught an unknown exception."), TEXT("Error!"), MB_ICONERROR | MB_OK);
+		CleanD3D();
+		return EXIT_FAILURE;
 	}
-
-	CleanD3D();
-
-	return msg.wParam;
 }
 
 void InitD3D(HINSTANCE hinstance, HWND hWnd)
@@ -227,6 +280,12 @@ void InitD3D(HINSTANCE hinstance, HWND hWnd)
 	if (FAILED(hr))
 		Throwanerror("Directx Device Creation Failed!");
 
+#if _DEBUG
+	hr = dev->QueryInterface(IID_PPV_ARGS(&d3d11debug));
+	if (FAILED(hr))
+		OutputDebugString(TEXT("Failed to retrieve DirectX 11 debug interface.\n"));
+#endif
+
 	UINT m4xMsaaQuality;
 	dev->CheckMultisampleQualityLevels(
 		DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality);
@@ -348,7 +407,6 @@ void InitD3D(HINSTANCE hinstance, HWND hWnd)
 	devcon->OMSetRenderTargets(1, &backbuffer, g_pDepthStencilView);
 
 	D3D11_RASTERIZER_DESC rasterDesc;
-	ID3D11RasterizerState *rasterState;
 	rasterDesc.AntialiasedLineEnable = false;
 	rasterDesc.CullMode = D3D11_CULL_BACK;
 	rasterDesc.DepthBias = 0;
@@ -360,8 +418,8 @@ void InitD3D(HINSTANCE hinstance, HWND hWnd)
 	rasterDesc.ScissorEnable = false;
 	rasterDesc.SlopeScaledDepthBias = 0.0f;
 
-	dev->CreateRasterizerState(&rasterDesc, &rasterState);
-	devcon->RSSetState(rasterState);
+	dev->CreateRasterizerState(&rasterDesc, &rasterstate);
+	devcon->RSSetState(rasterstate);
 
 	D3D11_VIEWPORT viewport;
 	ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
@@ -381,19 +439,38 @@ void InitD3D(HINSTANCE hinstance, HWND hWnd)
 
 void CleanD3D(void)
 {
-	swapchain->SetFullscreenState(FALSE, NULL);
+	if (swapchain)
+		swapchain->SetFullscreenState(FALSE, NULL);
 
-	ourModel->Close();
-	g_pDepthStencil->Release();
-	g_pDepthStencilView->Release();
-	pLayout->Release();
-	pVS->Release();
-	pPS->Release();
-	pConstantBuffer->Release();
-	swapchain->Release();
-	backbuffer->Release();
-	dev->Release();
-	devcon->Release();
+	if (ourModel) {
+		ourModel->Close();
+		delete ourModel;
+		ourModel = nullptr;
+	}
+	SafeRelease(TexSamplerState);
+	SafeRelease(pConstantBuffer);
+	SafeRelease(pLayout);
+	SafeRelease(pVS);
+	SafeRelease(pPS);
+	SafeRelease(rasterstate);
+	SafeRelease(g_pDepthStencilView);
+	SafeRelease(g_pDepthStencil);
+	SafeRelease(backbuffer);
+	SafeRelease(swapchain);
+	SafeRelease(swapchain1);
+	SafeRelease(devcon1);
+	SafeRelease(dev1);
+	SafeRelease(devcon);
+#if _DEBUG
+	if (d3d11debug) {
+		OutputDebugString(TEXT("Dumping DirectX 11 live objects.\n"));
+		d3d11debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
+		SafeRelease(d3d11debug);
+	} else {
+		OutputDebugString(TEXT("Unable to dump live objects: no DirectX 11 debug interface available.\n"));
+	}
+#endif
+	SafeRelease(dev);
 }
 
 void RenderFrame(void)
@@ -431,8 +508,10 @@ void RenderFrame(void)
 void InitPipeline()
 {
 	ID3DBlob *VS, *PS;
-	CompileShaderFromFile(L"VertexShader.hlsl", 0, "main", "vs_4_0", &VS);
-	CompileShaderFromFile(L"PixelShader.hlsl", 0, "main", "ps_4_0", &PS);
+	if(FAILED(CompileShaderFromFile(SHADER_PATH VERTEX_SHADER_FILE, 0, "main", "vs_4_0", &VS)))
+		Throwanerror(UTFConverter(L"Failed to compile shader from file " VERTEX_SHADER_FILE).c_str());
+	if(FAILED(CompileShaderFromFile(SHADER_PATH PIXEL_SHADER_FILE, 0, "main", "ps_4_0", &PS)))
+		Throwanerror(UTFConverter(L"Failed to compile shader from file " PIXEL_SHADER_FILE).c_str());
 
 	dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
 	dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);
@@ -485,7 +564,7 @@ void InitGraphics()
 	m_View = XMMatrixLookAtLH(Eye, At, Up);
 
 	ourModel = new ModelLoader;
-	if (!ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx"))
+	if (!ourModel->Load(hwnd, dev, devcon, g_ModelPath))
 		Throwanerror("Model couldn't be loaded");
 }
 
@@ -514,5 +593,5 @@ HRESULT	CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefine
 
 void Throwanerror(LPCSTR errormessage)
 {
-	MessageBox(hwnd, errormessage, "Error!", MB_ICONERROR | MB_OK);
-}
\ No newline at end of file
+	throw std::runtime_error(errormessage);
+}
diff --git a/samples/SimpleTexturedOpenGL/CMakeLists.txt b/samples/SimpleTexturedOpenGL/CMakeLists.txt
index adcf882a8..e40c40f29 100644
--- a/samples/SimpleTexturedOpenGL/CMakeLists.txt
+++ b/samples/SimpleTexturedOpenGL/CMakeLists.txt
@@ -21,6 +21,7 @@ INCLUDE_DIRECTORIES(
   ${Assimp_SOURCE_DIR}/code
   ${OPENGL_INCLUDE_DIR}
   ${GLUT_INCLUDE_DIR}
+  ${SAMPLES_SHARED_CODE_DIR}
 )
 
 LINK_DIRECTORIES(
@@ -31,6 +32,8 @@ LINK_DIRECTORIES(
 ADD_EXECUTABLE( assimp_simpletexturedogl WIN32
   SimpleTexturedOpenGL/include/boost_includes.h
   SimpleTexturedOpenGL/src/model_loading.cpp
+  ${SAMPLES_SHARED_CODE_DIR}/UTFConverter.cpp
+  ${SAMPLES_SHARED_CODE_DIR}/UTFConverter.h
 )
 
 SET_PROPERTY(TARGET assimp_simpletexturedogl PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
diff --git a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp
index 8c2a08b2e..452c0715c 100644
--- a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp
+++ b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp
@@ -21,8 +21,6 @@
 #define STB_IMAGE_IMPLEMENTATION
 #include "contrib/stb_image/stb_image.h"
 
-#include <locale>
-#include <codecvt>
 #include <fstream>
 
 //to map image filenames to textureIds
@@ -35,7 +33,7 @@
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/LogStream.hpp>
-
+#include "UTFConverter.h"
 
 // The default hard-coded path. Can be overridden by supplying a path through the command line.
 static std::string modelpath = "../../test/models/OBJ/spider.obj";
@@ -77,35 +75,7 @@ GLuint*		textureIds;							// pointer to texture Array
 // Create an instance of the Importer class
 Assimp::Importer importer;
 
-// 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 std::string& s) :
-		s_(s),
-		ws_(impl_.from_bytes(s)) {
-	}
-	UTFConverter(const std::wstring& s) :
-		s_(impl_.to_bytes(s)),
-		ws_(s) {
-	}
-	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_;
-};
-
-typename UTFConverter::UTFConverterImpl UTFConverter::impl_;
+using namespace AssimpSamples::SharedCode;
 
 void createAILogger()
 {
diff --git a/tools/assimp_cmd/CMakeLists.txt b/tools/assimp_cmd/CMakeLists.txt
index 848b8f81c..d46d09c2b 100644
--- a/tools/assimp_cmd/CMakeLists.txt
+++ b/tools/assimp_cmd/CMakeLists.txt
@@ -37,7 +37,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 #----------------------------------------------------------------------
-cmake_minimum_required( VERSION 2.6 )
+cmake_minimum_required( VERSION 3.0 )
 
 INCLUDE_DIRECTORIES(
   ${Assimp_SOURCE_DIR}/include
diff --git a/tools/assimp_view/CMakeLists.txt b/tools/assimp_view/CMakeLists.txt
index a77f13041..96b21db40 100644
--- a/tools/assimp_view/CMakeLists.txt
+++ b/tools/assimp_view/CMakeLists.txt
@@ -37,7 +37,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 #----------------------------------------------------------------------
-cmake_minimum_required( VERSION 2.6 )
+cmake_minimum_required( VERSION 3.0 )
 
 FIND_PACKAGE(DirectX REQUIRED)