Browse Source

Merge pull request #15 from assimp/master

Update Fork
Madrich 6 years ago
parent
commit
5fb77f8523
100 changed files with 2903 additions and 774 deletions
  1. 7 0
      .gitignore
  2. 162 74
      CMakeLists.txt
  3. 7 2
      Readme.md
  4. 70 34
      assimpTargets-debug.cmake.in
  5. 70 33
      assimpTargets-release.cmake.in
  6. 5 1
      assimpTargets.cmake.in
  7. 540 0
      cmake/HunterGate.cmake
  8. 14 0
      cmake/assimp-hunter-config.cmake.in
  9. 1 1
      code/3DS/3DSConverter.cpp
  10. 6 4
      code/3DS/3DSExporter.cpp
  11. 0 0
      code/3DS/3DSExporter.h
  12. 0 0
      code/3DS/3DSHelper.h
  13. 0 0
      code/3DS/3DSLoader.cpp
  14. 0 0
      code/3DS/3DSLoader.h
  15. 0 0
      code/3MF/3MFXmlTags.h
  16. 5 1
      code/3MF/D3MFExporter.cpp
  17. 0 0
      code/3MF/D3MFExporter.h
  18. 5 1
      code/3MF/D3MFImporter.cpp
  19. 0 0
      code/3MF/D3MFImporter.h
  20. 15 1
      code/3MF/D3MFOpcPackage.cpp
  21. 0 0
      code/3MF/D3MFOpcPackage.h
  22. 1 1
      code/AC/ACLoader.cpp
  23. 0 0
      code/AC/ACLoader.h
  24. 0 0
      code/AMF/AMFImporter.cpp
  25. 0 0
      code/AMF/AMFImporter.hpp
  26. 0 0
      code/AMF/AMFImporter_Geometry.cpp
  27. 0 0
      code/AMF/AMFImporter_Macro.hpp
  28. 0 0
      code/AMF/AMFImporter_Material.cpp
  29. 0 0
      code/AMF/AMFImporter_Node.hpp
  30. 0 0
      code/AMF/AMFImporter_Postprocess.cpp
  31. 15 15
      code/ASE/ASELoader.cpp
  32. 0 1
      code/ASE/ASELoader.h
  33. 2 2
      code/ASE/ASEParser.cpp
  34. 1 1
      code/ASE/ASEParser.h
  35. 3 2
      code/Assbin/AssbinExporter.cpp
  36. 0 0
      code/Assbin/AssbinExporter.h
  37. 2 2
      code/Assbin/AssbinLoader.cpp
  38. 0 0
      code/Assbin/AssbinLoader.h
  39. 109 0
      code/Assjson/cencode.c
  40. 31 0
      code/Assjson/cencode.h
  41. 818 0
      code/Assjson/json_exporter.cpp
  42. 320 0
      code/Assjson/mesh_splitter.cpp
  43. 61 0
      code/Assjson/mesh_splitter.h
  44. 4 2
      code/Assxml/AssxmlExporter.cpp
  45. 0 0
      code/Assxml/AssxmlExporter.h
  46. 6 4
      code/B3D/B3DImporter.cpp
  47. 0 0
      code/B3D/B3DImporter.h
  48. 0 0
      code/BVH/BVHLoader.cpp
  49. 0 0
      code/BVH/BVHLoader.h
  50. 0 0
      code/Blender/BlenderBMesh.cpp
  51. 0 0
      code/Blender/BlenderBMesh.h
  52. 0 0
      code/Blender/BlenderCustomData.cpp
  53. 0 0
      code/Blender/BlenderCustomData.h
  54. 0 0
      code/Blender/BlenderDNA.cpp
  55. 0 0
      code/Blender/BlenderDNA.h
  56. 0 0
      code/Blender/BlenderDNA.inl
  57. 0 0
      code/Blender/BlenderIntermediate.h
  58. 27 0
      code/Blender/BlenderLoader.cpp
  59. 0 0
      code/Blender/BlenderLoader.h
  60. 0 0
      code/Blender/BlenderModifier.cpp
  61. 0 0
      code/Blender/BlenderModifier.h
  62. 4 1
      code/Blender/BlenderScene.cpp
  63. 4 0
      code/Blender/BlenderScene.h
  64. 0 0
      code/Blender/BlenderSceneGen.h
  65. 0 0
      code/Blender/BlenderTessellator.cpp
  66. 5 1
      code/Blender/BlenderTessellator.h
  67. 0 0
      code/C4D/C4DImporter.cpp
  68. 0 0
      code/C4D/C4DImporter.h
  69. 1 1
      code/CApi/AssimpCExport.cpp
  70. 0 0
      code/CApi/CInterfaceIOWrapper.cpp
  71. 0 0
      code/CApi/CInterfaceIOWrapper.h
  72. 379 365
      code/CMakeLists.txt
  73. 13 8
      code/COB/COBLoader.cpp
  74. 0 0
      code/COB/COBLoader.h
  75. 0 0
      code/COB/COBScene.h
  76. 0 0
      code/CSM/CSMLoader.cpp
  77. 0 0
      code/CSM/CSMLoader.h
  78. 55 51
      code/Collada/ColladaExporter.cpp
  79. 1 2
      code/Collada/ColladaExporter.h
  80. 0 0
      code/Collada/ColladaHelper.h
  81. 100 136
      code/Collada/ColladaLoader.cpp
  82. 0 0
      code/Collada/ColladaLoader.h
  83. 1 3
      code/Collada/ColladaParser.cpp
  84. 0 0
      code/Collada/ColladaParser.h
  85. 1 1
      code/Common/Assimp.cpp
  86. 5 1
      code/Common/BaseImporter.cpp
  87. 1 1
      code/Common/BaseProcess.cpp
  88. 0 0
      code/Common/BaseProcess.h
  89. 0 0
      code/Common/Bitmap.cpp
  90. 0 4
      code/Common/CreateAnimMesh.cpp
  91. 0 0
      code/Common/DefaultIOStream.cpp
  92. 0 0
      code/Common/DefaultIOSystem.cpp
  93. 0 0
      code/Common/DefaultLogger.cpp
  94. 0 0
      code/Common/DefaultProgressHandler.h
  95. 15 9
      code/Common/Exporter.cpp
  96. 0 0
      code/Common/FileLogStream.h
  97. 0 0
      code/Common/FileSystemFilter.h
  98. 0 0
      code/Common/IFF.h
  99. 11 8
      code/Common/Importer.cpp
  100. 0 0
      code/Common/Importer.h

+ 7 - 0
.gitignore

@@ -7,6 +7,12 @@ build
 *.sln
 *.ncb
 *.vcproj
+*.vcxproj.user
+*.VC.db
+*.VC.db-shm
+*.VC.db-wal
+*.VC.opendb
+*.ipch
 
 # Output
 bin/
@@ -32,6 +38,7 @@ cmake_uninstall.cmake
 *.dir/
 assimp-config.cmake
 assimp-config-version.cmake
+assimpTargets*.cmake
 
 # MakeFile
 Makefile

+ 162 - 74
CMakeLists.txt

@@ -1,7 +1,7 @@
 # Open Asset Import Library (assimp)
 # ----------------------------------------------------------------------
 # Copyright (c) 2006-2019, assimp team
-
+#
 # All rights reserved.
 #
 # Redistribution and use of this software in source and binary forms,
@@ -34,9 +34,24 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #----------------------------------------------------------------------
-SET(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required
-CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )
-PROJECT( Assimp )
+SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW)
+
+CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
+
+# Toggles the use of the hunter package manager
+option(HUNTER_ENABLED "Enable Hunter package manager support" OFF)
+
+include("cmake/HunterGate.cmake")
+HunterGate(
+    URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz"
+    SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a"
+)
+
+IF(HUNTER_ENABLED)
+  add_definitions(-DASSIMP_USE_HUNTER)
+ENDIF(HUNTER_ENABLED)
+
+PROJECT( Assimp VERSION 5.0.0 )
 
 # All supported options ###############################################
 
@@ -67,7 +82,7 @@ OPTION( ASSIMP_NO_EXPORT
 )
 OPTION( ASSIMP_BUILD_ZLIB
   "Build your own zlib"
-  OFF  
+  OFF
 )
 OPTION( ASSIMP_BUILD_ASSIMP_TOOLS
   "If the supplementary tools for Assimp are built in addition to the library."
@@ -115,12 +130,12 @@ OPTION ( IGNORE_GIT_HASH
    OFF
 )
 
-IF (IOS)
+IF (IOS AND NOT HUNTER_ENABLED)
   IF (NOT CMAKE_BUILD_TYPE)
     SET(CMAKE_BUILD_TYPE "Release")
   ENDIF (NOT CMAKE_BUILD_TYPE)
   ADD_DEFINITIONS(-DENABLE_BITCODE)
-ENDIF (IOS)
+ENDIF (IOS AND NOT HUNTER_ENABLED)
 
 # Use subset of Windows.h
 if (WIN32)
@@ -151,17 +166,18 @@ ELSE()
 ENDIF(NOT BUILD_SHARED_LIBS)
 
 # Define here the needed parameters
-SET (ASSIMP_VERSION_MAJOR 4)
-SET (ASSIMP_VERSION_MINOR 1)
-SET (ASSIMP_VERSION_PATCH 0)
+SET (ASSIMP_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
+SET (ASSIMP_VERSION_MINOR ${PROJECT_VERSION_MINOR})
+SET (ASSIMP_VERSION_PATCH ${PROJECT_VERSION_PATCH})
 SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
-SET (ASSIMP_SOVERSION 4)
-SET (PROJECT_VERSION "${ASSIMP_VERSION}")
+SET (ASSIMP_SOVERSION 5)
 
 SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
 
-# Enable C++11 support globally
-set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
+if(NOT HUNTER_ENABLED)
+  # Enable C++11 support globally
+  set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
+endif()
 
 IF(NOT IGNORE_GIT_HASH)
   # Get the current working branch
@@ -203,6 +219,7 @@ CONFIGURE_FILE(
 
 INCLUDE_DIRECTORIES( BEFORE
   ./
+  code/
   include
   ${CMAKE_CURRENT_BINARY_DIR}
   ${CMAKE_CURRENT_BINARY_DIR}/include
@@ -221,9 +238,13 @@ ENDIF( UNIX )
 
 # Grouped compiler settings
 IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
+  IF(NOT HUNTER_ENABLED)
+    SET(CMAKE_CXX_FLAGS "-fPIC -std=c++0x ${CMAKE_CXX_FLAGS}")
+    SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
+  ENDIF()
   # hide all not-exported symbols
-  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -std=c++0x ${CMAKE_CXX_FLAGS}")
-  SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}")
+  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
+  SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
   SET(LIBSTDC++_LIBRARIES -lstdc++)
 ELSEIF(MSVC)
   # enable multi-core compilation with MSVC
@@ -234,20 +255,28 @@ ELSEIF(MSVC)
     ADD_COMPILE_OPTIONS(/wd4351)
   ENDIF()
 ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
-  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 ${CMAKE_CXX_FLAGS}" )
-  SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}")
+  IF(NOT HUNTER_ENABLED)
+    SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
+    SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
+  ENDIF()
+  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
+  SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
 ELSEIF( CMAKE_COMPILER_IS_MINGW )
   IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
     message(FATAL_ERROR "MinGW is too old to be supported. Please update MinGW and try again.")
   ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3)
     message(WARNING "MinGW is old, if you experience errors, update MinGW.")
   ENDIF()
-  SET( CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}" )
-  SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS} ")
+  IF(NOT HUNTER_ENABLED)
+    SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
+    SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
+  ENDIF()
+  SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}")
+  SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
   ADD_DEFINITIONS( -U__STRICT_ANSI__ )
 ENDIF()
 
-IF ( IOS )
+IF ( IOS AND NOT HUNTER_ENABLED)
 
 IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og")
@@ -255,9 +284,10 @@ IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
 ELSE()
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
+  # Experimental for pdb generation
 ENDIF()
 
-ENDIF( IOS )
+ENDIF( IOS AND NOT HUNTER_ENABLED)
 
 IF (ASSIMP_COVERALLS)
   MESSAGE(STATUS "Coveralls enabled")
@@ -324,20 +354,67 @@ IF (NOT TARGET uninstall)
   ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
 ENDIF()
 
-# cmake configuration files
-CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
-CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
-CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in"   "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
-CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
-CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
-#we should generated these scripts after CMake VERSION 3.0.2 using export(EXPORT ...) and write_basic_package_version_file(...)
-INSTALL(FILES 
-  "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake"
-  "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake"
-  "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake"
-  "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake"
-  "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake"
-  DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
+IF(HUNTER_ENABLED)
+  set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
+  set(INCLUDE_INSTALL_DIR "include")
+
+  set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
+
+  # Configuration
+  set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
+  set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
+  set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
+  set(NAMESPACE "${PROJECT_NAME}::")
+
+  # Include module with fuction 'write_basic_package_version_file'
+  include(CMakePackageConfigHelpers)
+
+  # Note: PROJECT_VERSION is used as a VERSION
+  write_basic_package_version_file("${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion)
+
+  # Use variables:
+  #   * TARGETS_EXPORT_NAME
+  #   * PROJECT_NAME
+  configure_package_config_file(
+      "cmake/assimp-hunter-config.cmake.in"
+      "${PROJECT_CONFIG}"
+      INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
+  )
+
+  install(
+      FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
+      DESTINATION "${CONFIG_INSTALL_DIR}"
+  )
+
+  install(
+      EXPORT "${TARGETS_EXPORT_NAME}"
+      NAMESPACE "${NAMESPACE}"
+      DESTINATION "${CONFIG_INSTALL_DIR}"
+  )
+ELSE(HUNTER_ENABLED)
+  # cmake configuration files
+  CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
+  CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
+  IF (is_multi_config)
+    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in"   "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
+    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
+    SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake")
+  ELSEIF (CMAKE_BUILD_TYPE STREQUAL Debug)
+    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in"   "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
+    SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake")
+  ELSE()
+    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
+    SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake")
+  ENDIF()
+  CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
+  #we should generated these scripts after CMake VERSION 3.0.2 using export(EXPORT ...) and write_basic_package_version_file(...)
+  INSTALL(FILES
+    "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake"
+    ${PACKAGE_TARGETS_FILE}
+    DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
+ENDIF(HUNTER_ENABLED)
 
 FIND_PACKAGE( DirectX )
 
@@ -352,48 +429,57 @@ ENDIF( SYSTEM_IRRXML )
 
 # Search for external dependencies, and build them from source if not found
 # Search for zlib
-IF ( NOT ASSIMP_BUILD_ZLIB )
-  FIND_PACKAGE(ZLIB)
-ENDIF( NOT ASSIMP_BUILD_ZLIB )
-
-IF( NOT ZLIB_FOUND )
-  MESSAGE(STATUS "compiling zlib from sources")
-  INCLUDE(CheckIncludeFile)
-  INCLUDE(CheckTypeSize)
-  INCLUDE(CheckFunctionExists)
-
-  # Explicitly turn off ASM686 and AMD64 cmake options.
-  # The AMD64 option causes a build failure on MSVC and the ASM builds seem to have problems:
-  #		https://github.com/madler/zlib/issues/41#issuecomment-125848075
-  # Also prevents these options from "polluting" the cmake options if assimp is being
-  # included as a submodule.
-  set( ASM686 FALSE CACHE INTERNAL "Override ZLIB flag to turn off assembly" FORCE )
-  set( AMD64 FALSE CACHE INTERNAL "Override ZLIB flag to turn off assembly" FORCE )
-
-  # compile from sources
-  ADD_SUBDIRECTORY(contrib/zlib)
-  SET(ZLIB_FOUND 1)
-  SET(ZLIB_LIBRARIES zlibstatic)
-  SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
-  # need to ensure we don't link with system zlib or minizip as well.
-  SET(ASSIMP_BUILD_MINIZIP 1)
-ELSE(NOT ZLIB_FOUND)
-  ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
-  SET(ZLIB_LIBRARIES_LINKED -lz)
-ENDIF(NOT ZLIB_FOUND)
-INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
-
-# Search for unzip
-IF ( NOT IOS )
+IF(HUNTER_ENABLED)
+  hunter_add_package(ZLIB)
+  find_package(ZLIB CONFIG REQUIRED)
+
+  add_definitions(-DASSIMP_BUILD_NO_OWN_ZLIB)
+  set(ZLIB_FOUND TRUE)
+  set(ZLIB_LIBRARIES ZLIB::zlib)
+  set(ASSIMP_BUILD_MINIZIP TRUE)
+ELSE(HUNTER_ENABLED)
+  IF ( NOT ASSIMP_BUILD_ZLIB )
+    FIND_PACKAGE(ZLIB)
+  ENDIF( NOT ASSIMP_BUILD_ZLIB )
+
+  IF( NOT ZLIB_FOUND )
+    MESSAGE(STATUS "compiling zlib from sources")
+    INCLUDE(CheckIncludeFile)
+    INCLUDE(CheckTypeSize)
+    INCLUDE(CheckFunctionExists)
+
+    # Explicitly turn off ASM686 and AMD64 cmake options.
+    # The AMD64 option causes a build failure on MSVC and the ASM builds seem to have problems:
+    #		https://github.com/madler/zlib/issues/41#issuecomment-125848075
+    # Also prevents these options from "polluting" the cmake options if assimp is being
+    # included as a submodule.
+    set( ASM686 FALSE CACHE INTERNAL "Override ZLIB flag to turn off assembly" FORCE )
+    set( AMD64 FALSE CACHE INTERNAL "Override ZLIB flag to turn off assembly" FORCE )
+
+    # compile from sources
+    ADD_SUBDIRECTORY(contrib/zlib)
+    SET(ZLIB_FOUND 1)
+    SET(ZLIB_LIBRARIES zlibstatic)
+    SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
+    # need to ensure we don't link with system zlib or minizip as well.
+    SET(ASSIMP_BUILD_MINIZIP 1)
+  ELSE(NOT ZLIB_FOUND)
+    ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
+    SET(ZLIB_LIBRARIES_LINKED -lz)
+  ENDIF(NOT ZLIB_FOUND)
+  INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
+ENDIF(HUNTER_ENABLED)
+
+IF( NOT IOS )
   IF( NOT ASSIMP_BUILD_MINIZIP )
-	  use_pkgconfig(UNZIP minizip)
+    use_pkgconfig(UNZIP minizip)
   ENDIF( NOT ASSIMP_BUILD_MINIZIP )
 ELSE ( NOT IOS )
-	IF(NOT BUILD_SHARED_LIBS)
+  IF( NOT BUILD_SHARED_LIBS )
     IF( NOT ASSIMP_BUILD_MINIZIP )
-		  use_pkgconfig(UNZIP minizip)
+      use_pkgconfig(UNZIP minizip)
     ENDIF( NOT ASSIMP_BUILD_MINIZIP )
-	ENDIF (NOT BUILD_SHARED_LIBS)
+  ENDIF ( NOT BUILD_SHARED_LIBS )
 ENDIF ( NOT IOS )
 
 IF ( ASSIMP_NO_EXPORT )
@@ -467,7 +553,9 @@ ELSE (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
   ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
 ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
 
-ADD_SUBDIRECTORY(contrib)
+IF(NOT HUNTER_ENABLED)
+  ADD_SUBDIRECTORY(contrib)
+ENDIF(NOT HUNTER_ENABLED)
 
 ADD_SUBDIRECTORY( code/ )
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )

+ 7 - 2
Readme.md

@@ -125,7 +125,7 @@ Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file.
 ### Ports ###
 * [Android](port/AndroidJNI/README.md)
 * [Python](port/PyAssimp/README.md)
-* [.NET](port/AssimpNET/Readme.md)
+* [.NET](https://github.com/kebby/assimp-net)
 * [Pascal](port/AssimpPascal/Readme.md)
 * [Javascript (Alpha)](https://github.com/makc/assimp2json)
 * [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
@@ -136,7 +136,7 @@ Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file.
 [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.
 
 #### Repository structure ####
-Open Asset Import Library is implemented in C++. The directory structure is:
+Open Asset Import Library is implemented in C++. The directory structure looks like:
 
 	/code		Source code
 	/contrib	Third-party libraries
@@ -149,6 +149,11 @@ Open Asset Import Library is implemented in C++. The directory structure is:
 	/samples	A small number of samples to illustrate possible
                         use cases for Assimp
 
+The source code is organized in the following way:
+
+	code/Common		The base implementation for importers and the infrastructure
+	code/PostProcessing	The post-processing steps
+	code/<FormatName>	Implementation for import and export for the format
 
 ### Where to get help ###
 For more information, visit [our website](http://assimp.org/). Or check out the `./doc`- folder, which contains the official documentation in HTML format.

+ 70 - 34
assimpTargets-debug.cmake.in

@@ -5,48 +5,79 @@
 # Commands may need to know the format version.
 set(CMAKE_IMPORT_FILE_VERSION 1)
 
+set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
+
 if(MSVC)
-  if( MSVC70 OR MSVC71 )
-    set(MSVC_PREFIX "vc70")
-  elseif( MSVC80 )
-    set(MSVC_PREFIX "vc80")
-  elseif( MSVC90 )
-    set(MSVC_PREFIX "vc90")
-  elseif( MSVC10 )
-    set(MSVC_PREFIX "vc100")
-  elseif( MSVC11 )
-    set(MSVC_PREFIX "vc110")
-  elseif( MSVC12 )
-    set(MSVC_PREFIX "vc120")
-  elseif( MSVC14 )
-    set(MSVC_PREFIX "vc140")
+  if(MSVC_TOOLSET_VERSION)
+    set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
   else()
-    set(MSVC_PREFIX "vc150")
+    if( MSVC70 OR MSVC71 )
+      set(MSVC_PREFIX "vc70")
+    elseif( MSVC80 )
+      set(MSVC_PREFIX "vc80")
+    elseif( MSVC90 )
+      set(MSVC_PREFIX "vc90")
+    elseif( MSVC10 )
+      set(MSVC_PREFIX "vc100")
+    elseif( MSVC11 )
+      set(MSVC_PREFIX "vc110")
+    elseif( MSVC12 )
+      set(MSVC_PREFIX "vc120")
+    elseif( MSVC_VERSION LESS 1910)
+      set(MSVC_PREFIX "vc140")
+    elseif( MSVC_VERSION LESS 1920)
+      set(MSVC_PREFIX "vc141")
+    elseif( MSVC_VERSION LESS 1930)
+      set(MSVC_PREFIX "vc142")
+    else()
+      set(MSVC_PREFIX "vc150")
+    endif()
   endif()
   set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
 
-  set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
-  set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
+  if(ASSIMP_BUILD_SHARED_LIBS)
+    set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
+    set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
+
+    # Import target "assimp::assimp" for configuration "Debug"
+    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+    set_target_properties(assimp::assimp PROPERTIES
+      IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/${importLibraryName}"
+      IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
+    )
+    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
+  else()
+    set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
 
-  # Import target "assimp::assimp" for configuration "Debug"
-  set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
-  set_target_properties(assimp::assimp PROPERTIES
-    IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/${importLibraryName}"
-    IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
-    ) 
-  list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
-  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
+    # Import target "assimp::assimp" for configuration "Debug"
+    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+    set_target_properties(assimp::assimp PROPERTIES
+      IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
+    )
+    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}")
+  endif()
 
 else()
-  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" )
-  set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
-  set_target_properties(assimp::assimp PROPERTIES
-    IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
-    IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
+  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
+  if(ASSIMP_BUILD_SHARED_LIBS)
+    set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
+    set_target_properties(assimp::assimp PROPERTIES
+      IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
+      IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
     )
-  list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
+    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
+  else()
+    set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
+    set_target_properties(assimp::assimp PROPERTIES
+      IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
+    )
+    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" )
+  endif()
 endif()
 
 
@@ -60,7 +91,11 @@ set( ASSIMP_CXX_FLAGS ) # dynamically linked library
 set( ASSIMP_LINK_FLAGS "" )
 set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
 set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
-set( ASSIMP_LIBRARIES ${sharedLibraryName})
+if(ASSIMP_BUILD_SHARED_LIBS)
+  set( ASSIMP_LIBRARIES ${sharedLibraryName})
+else()
+  set( ASSIMP_LIBRARIES ${staticLibraryName})
+endif()
 
 # for compatibility with pkg-config
 set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
@@ -75,4 +110,5 @@ MARK_AS_ADVANCED(
   ASSIMP_CFLAGS_OTHER
   ASSIMP_LDFLAGS_OTHER
   ASSIMP_LIBRARY_SUFFIX
+  ASSIMP_BUILD_SHARED_LIBS
 )

+ 70 - 33
assimpTargets-release.cmake.in

@@ -5,59 +5,95 @@
 # Commands may need to know the format version.
 set(CMAKE_IMPORT_FILE_VERSION 1)
 
+set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
+
 if(MSVC)
-  if( MSVC70 OR MSVC71 )
-    set(MSVC_PREFIX "vc70")
-  elseif( MSVC80 )
-    set(MSVC_PREFIX "vc80")
-  elseif( MSVC90 )
-    set(MSVC_PREFIX "vc90")
-  elseif( MSVC10 )
-    set(MSVC_PREFIX "vc100")
-  elseif( MSVC11 )
-    set(MSVC_PREFIX "vc110")
-  elseif( MSVC12 )
-    set(MSVC_PREFIX "vc120")
-  elseif( MSVC14 )
-    set(MSVC_PREFIX "vc140")
+  if(MSVC_TOOLSET_VERSION)
+    set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
   else()
-    set(MSVC_PREFIX "vc150")
+    if( MSVC70 OR MSVC71 )
+      set(MSVC_PREFIX "vc70")
+    elseif( MSVC80 )
+      set(MSVC_PREFIX "vc80")
+    elseif( MSVC90 )
+      set(MSVC_PREFIX "vc90")
+    elseif( MSVC10 )
+      set(MSVC_PREFIX "vc100")
+    elseif( MSVC11 )
+      set(MSVC_PREFIX "vc110")
+    elseif( MSVC12 )
+      set(MSVC_PREFIX "vc120")
+    elseif( MSVC_VERSION LESS 1910)
+      set(MSVC_PREFIX "vc140")
+    elseif( MSVC_VERSION LESS 1920)
+      set(MSVC_PREFIX "vc141")
+    elseif( MSVC_VERSION LESS 1930)
+      set(MSVC_PREFIX "vc142")
+    else()
+      set(MSVC_PREFIX "vc150")
+    endif()
   endif()
   set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
 
-  set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
-  set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@")
+  if(ASSIMP_BUILD_SHARED_LIBS)
+    set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
+    set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@")
+
+    # Import target "assimp::assimp" for configuration "Release"
+    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+    set_target_properties(assimp::assimp PROPERTIES
+      IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/${importLibraryName}"
+      IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
+    )
+    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
+  else()
+    set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
 
-  # Import target "assimp::assimp" for configuration "Release"
-  set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
-  set_target_properties(assimp::assimp PROPERTIES
-    IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/${importLibraryName}"
-    IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
+    # Import target "assimp::assimp" for configuration "Release"
+    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+    set_target_properties(assimp::assimp PROPERTIES
+      IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
     )
-  list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
-  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
+    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}")
+  endif()
 
 else()
-  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" )
-  set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
-  set_target_properties(assimp::assimp PROPERTIES
-    IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
-    IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
+  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
+  if(ASSIMP_BUILD_SHARED_LIBS)
+    set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
+    set_target_properties(assimp::assimp PROPERTIES
+      IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
+      IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
     )
-  list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
+    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
+  else()
+    set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
+    set_target_properties(assimp::assimp PROPERTIES
+      IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
+    )
+    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" )
+  endif()
 endif()
 
 # Commands beyond this point should not need to know the version.
 set(CMAKE_IMPORT_FILE_VERSION)
 
 get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
+
 set( ASSIMP_CXX_FLAGS ) # dynamically linked library
 set( ASSIMP_LINK_FLAGS "" )
 set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
 set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
-set( ASSIMP_LIBRARIES ${sharedLibraryName})
+if(ASSIMP_BUILD_SHARED_LIBS)
+  set( ASSIMP_LIBRARIES ${sharedLibraryName})
+else()
+  set( ASSIMP_LIBRARIES ${staticLibraryName})
+endif()
 
 # for compatibility with pkg-config
 set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
@@ -72,4 +108,5 @@ MARK_AS_ADVANCED(
   ASSIMP_CFLAGS_OTHER
   ASSIMP_LDFLAGS_OTHER
   ASSIMP_LIBRARY_SUFFIX
+  ASSIMP_BUILD_SHARED_LIBS
 )

+ 5 - 1
assimpTargets.cmake.in

@@ -51,7 +51,11 @@ if(_IMPORT_PREFIX STREQUAL "/")
 endif()
 
 # Create imported target assimp::assimp
-add_library(assimp::assimp SHARED IMPORTED)
+if(@BUILD_SHARED_LIBS@)
+  add_library(assimp::assimp SHARED IMPORTED)
+else()
+  add_library(assimp::assimp STATIC IMPORTED)
+endif()
 
 set_target_properties(assimp::assimp PROPERTIES
   COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"

+ 540 - 0
cmake/HunterGate.cmake

@@ -0,0 +1,540 @@
+# Copyright (c) 2013-2018, Ruslan Baratov
+# All rights reserved.
+#
+# Redistribution and use 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.
+#
+# 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 HOLDER 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.
+
+# This is a gate file to Hunter package manager.
+# Include this file using `include` command and add package you need, example:
+#
+#     cmake_minimum_required(VERSION 3.2)
+#
+#     include("cmake/HunterGate.cmake")
+#     HunterGate(
+#         URL "https://github.com/path/to/hunter/archive.tar.gz"
+#         SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
+#     )
+#
+#     project(MyProject)
+#
+#     hunter_add_package(Foo)
+#     hunter_add_package(Boo COMPONENTS Bar Baz)
+#
+# Projects:
+#     * https://github.com/hunter-packages/gate/
+#     * https://github.com/ruslo/hunter
+
+option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
+
+if(HUNTER_ENABLED)
+  if(CMAKE_VERSION VERSION_LESS "3.2")
+    message(
+        FATAL_ERROR
+        "At least CMake version 3.2 required for Hunter dependency management."
+        " Update CMake or set HUNTER_ENABLED to OFF."
+    )
+  endif()
+endif()
+
+include(CMakeParseArguments) # cmake_parse_arguments
+
+option(HUNTER_STATUS_PRINT "Print working status" ON)
+option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
+option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
+
+set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki")
+
+function(hunter_gate_status_print)
+  if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
+    foreach(print_message ${ARGV})
+      message(STATUS "[hunter] ${print_message}")
+    endforeach()
+  endif()
+endfunction()
+
+function(hunter_gate_status_debug)
+  if(HUNTER_STATUS_DEBUG)
+    foreach(print_message ${ARGV})
+      string(TIMESTAMP timestamp)
+      message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
+    endforeach()
+  endif()
+endfunction()
+
+function(hunter_gate_wiki wiki_page)
+  message("------------------------------ WIKI -------------------------------")
+  message("    ${HUNTER_WIKI}/${wiki_page}")
+  message("-------------------------------------------------------------------")
+  message("")
+  message(FATAL_ERROR "")
+endfunction()
+
+function(hunter_gate_internal_error)
+  message("")
+  foreach(print_message ${ARGV})
+    message("[hunter ** INTERNAL **] ${print_message}")
+  endforeach()
+  message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
+  message("")
+  hunter_gate_wiki("error.internal")
+endfunction()
+
+function(hunter_gate_fatal_error)
+  cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}")
+  string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki)
+  if(have_no_wiki)
+    hunter_gate_internal_error("Expected wiki")
+  endif()
+  message("")
+  foreach(x ${hunter_UNPARSED_ARGUMENTS})
+    message("[hunter ** FATAL ERROR **] ${x}")
+  endforeach()
+  message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
+  message("")
+  hunter_gate_wiki("${hunter_WIKI}")
+endfunction()
+
+function(hunter_gate_user_error)
+  hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data")
+endfunction()
+
+function(hunter_gate_self root version sha1 result)
+  string(COMPARE EQUAL "${root}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("root is empty")
+  endif()
+
+  string(COMPARE EQUAL "${version}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("version is empty")
+  endif()
+
+  string(COMPARE EQUAL "${sha1}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("sha1 is empty")
+  endif()
+
+  string(SUBSTRING "${sha1}" 0 7 archive_id)
+
+  if(EXISTS "${root}/cmake/Hunter")
+    set(hunter_self "${root}")
+  else()
+    set(
+        hunter_self
+        "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
+    )
+  endif()
+
+  set("${result}" "${hunter_self}" PARENT_SCOPE)
+endfunction()
+
+# Set HUNTER_GATE_ROOT cmake variable to suitable value.
+function(hunter_gate_detect_root)
+  # Check CMake variable
+  string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty)
+  if(not_empty)
+    set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable")
+    return()
+  endif()
+
+  # Check environment variable
+  string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty)
+  if(not_empty)
+    set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT detected by environment variable")
+    return()
+  endif()
+
+  # Check HOME environment variable
+  string(COMPARE NOTEQUAL "$ENV{HOME}" "" result)
+  if(result)
+    set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable")
+    return()
+  endif()
+
+  # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)
+  if(WIN32)
+    string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result)
+    if(result)
+      set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE)
+      hunter_gate_status_debug(
+          "HUNTER_ROOT set using SYSTEMDRIVE environment variable"
+      )
+      return()
+    endif()
+
+    string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result)
+    if(result)
+      set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE)
+      hunter_gate_status_debug(
+          "HUNTER_ROOT set using USERPROFILE environment variable"
+      )
+      return()
+    endif()
+  endif()
+
+  hunter_gate_fatal_error(
+      "Can't detect HUNTER_ROOT"
+      WIKI "error.detect.hunter.root"
+  )
+endfunction()
+
+function(hunter_gate_download dir)
+  string(
+      COMPARE
+      NOTEQUAL
+      "$ENV{HUNTER_DISABLE_AUTOINSTALL}"
+      ""
+      disable_autoinstall
+  )
+  if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)
+    hunter_gate_fatal_error(
+        "Hunter not found in '${dir}'"
+        "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'"
+        "Settings:"
+        "  HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
+        "  HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
+        WIKI "error.run.install"
+    )
+  endif()
+  string(COMPARE EQUAL "${dir}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("Empty 'dir' argument")
+  endif()
+
+  string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("HUNTER_GATE_SHA1 empty")
+  endif()
+
+  string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("HUNTER_GATE_URL empty")
+  endif()
+
+  set(done_location "${dir}/DONE")
+  set(sha1_location "${dir}/SHA1")
+
+  set(build_dir "${dir}/Build")
+  set(cmakelists "${dir}/CMakeLists.txt")
+
+  hunter_gate_status_debug("Locking directory: ${dir}")
+  file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
+  hunter_gate_status_debug("Lock done")
+
+  if(EXISTS "${done_location}")
+    # while waiting for lock other instance can do all the job
+    hunter_gate_status_debug("File '${done_location}' found, skip install")
+    return()
+  endif()
+
+  file(REMOVE_RECURSE "${build_dir}")
+  file(REMOVE_RECURSE "${cmakelists}")
+
+  file(MAKE_DIRECTORY "${build_dir}") # check directory permissions
+
+  # Disabling languages speeds up a little bit, reduces noise in the output
+  # and avoids path too long windows error
+  file(
+      WRITE
+      "${cmakelists}"
+      "cmake_minimum_required(VERSION 3.2)\n"
+      "project(HunterDownload LANGUAGES NONE)\n"
+      "include(ExternalProject)\n"
+      "ExternalProject_Add(\n"
+      "    Hunter\n"
+      "    URL\n"
+      "    \"${HUNTER_GATE_URL}\"\n"
+      "    URL_HASH\n"
+      "    SHA1=${HUNTER_GATE_SHA1}\n"
+      "    DOWNLOAD_DIR\n"
+      "    \"${dir}\"\n"
+      "    TLS_VERIFY\n"
+      "    ${HUNTER_TLS_VERIFY}\n"
+      "    SOURCE_DIR\n"
+      "    \"${dir}/Unpacked\"\n"
+      "    CONFIGURE_COMMAND\n"
+      "    \"\"\n"
+      "    BUILD_COMMAND\n"
+      "    \"\"\n"
+      "    INSTALL_COMMAND\n"
+      "    \"\"\n"
+      ")\n"
+  )
+
+  if(HUNTER_STATUS_DEBUG)
+    set(logging_params "")
+  else()
+    set(logging_params OUTPUT_QUIET)
+  endif()
+
+  hunter_gate_status_debug("Run generate")
+
+  # Need to add toolchain file too.
+  # Otherwise on Visual Studio + MDD this will fail with error:
+  # "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
+  if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
+    get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
+    set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}")
+  else()
+    # 'toolchain_arg' can't be empty
+    set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
+  endif()
+
+  string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make)
+  if(no_make)
+    set(make_arg "")
+  else()
+    # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM
+    set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}")
+  endif()
+
+  execute_process(
+      COMMAND
+      "${CMAKE_COMMAND}"
+      "-H${dir}"
+      "-B${build_dir}"
+      "-G${CMAKE_GENERATOR}"
+      "${toolchain_arg}"
+      ${make_arg}
+      WORKING_DIRECTORY "${dir}"
+      RESULT_VARIABLE download_result
+      ${logging_params}
+  )
+
+  if(NOT download_result EQUAL 0)
+    hunter_gate_internal_error(
+        "Configure project failed."
+        "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}"
+        "In directory ${dir}"
+    )
+  endif()
+
+  hunter_gate_status_print(
+      "Initializing Hunter workspace (${HUNTER_GATE_SHA1})"
+      "  ${HUNTER_GATE_URL}"
+      "  -> ${dir}"
+  )
+  execute_process(
+      COMMAND "${CMAKE_COMMAND}" --build "${build_dir}"
+      WORKING_DIRECTORY "${dir}"
+      RESULT_VARIABLE download_result
+      ${logging_params}
+  )
+
+  if(NOT download_result EQUAL 0)
+    hunter_gate_internal_error("Build project failed")
+  endif()
+
+  file(REMOVE_RECURSE "${build_dir}")
+  file(REMOVE_RECURSE "${cmakelists}")
+
+  file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}")
+  file(WRITE "${done_location}" "DONE")
+
+  hunter_gate_status_debug("Finished")
+endfunction()
+
+# Must be a macro so master file 'cmake/Hunter' can
+# apply all variables easily just by 'include' command
+# (otherwise PARENT_SCOPE magic needed)
+macro(HunterGate)
+  if(HUNTER_GATE_DONE)
+    # variable HUNTER_GATE_DONE set explicitly for external project
+    # (see `hunter_download`)
+    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
+  endif()
+
+  # First HunterGate command will init Hunter, others will be ignored
+  get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)
+
+  if(NOT HUNTER_ENABLED)
+    # Empty function to avoid error "unknown function"
+    function(hunter_add_package)
+    endfunction()
+
+    set(
+        _hunter_gate_disabled_mode_dir
+        "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode"
+    )
+    if(EXISTS "${_hunter_gate_disabled_mode_dir}")
+      hunter_gate_status_debug(
+          "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}"
+      )
+      list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}")
+    endif()
+  elseif(_hunter_gate_done)
+    hunter_gate_status_debug("Secondary HunterGate (use old settings)")
+    hunter_gate_self(
+        "${HUNTER_CACHED_ROOT}"
+        "${HUNTER_VERSION}"
+        "${HUNTER_SHA1}"
+        _hunter_self
+    )
+    include("${_hunter_self}/cmake/Hunter")
+  else()
+    set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
+
+    string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
+    if(_have_project_name)
+      hunter_gate_fatal_error(
+          "Please set HunterGate *before* 'project' command. "
+          "Detected project: ${PROJECT_NAME}"
+          WIKI "error.huntergate.before.project"
+      )
+    endif()
+
+    cmake_parse_arguments(
+        HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV}
+    )
+
+    string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1)
+    string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url)
+    string(
+        COMPARE
+        NOTEQUAL
+        "${HUNTER_GATE_UNPARSED_ARGUMENTS}"
+        ""
+        _have_unparsed
+    )
+    string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global)
+    string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath)
+
+    if(_have_unparsed)
+      hunter_gate_user_error(
+          "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}"
+      )
+    endif()
+    if(_empty_sha1)
+      hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory")
+    endif()
+    if(_empty_url)
+      hunter_gate_user_error("URL suboption of HunterGate is mandatory")
+    endif()
+    if(_have_global)
+      if(HUNTER_GATE_LOCAL)
+        hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)")
+      endif()
+      if(_have_filepath)
+        hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)")
+      endif()
+    endif()
+    if(HUNTER_GATE_LOCAL)
+      if(_have_global)
+        hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)")
+      endif()
+      if(_have_filepath)
+        hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)")
+      endif()
+    endif()
+    if(_have_filepath)
+      if(_have_global)
+        hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)")
+      endif()
+      if(HUNTER_GATE_LOCAL)
+        hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)")
+      endif()
+    endif()
+
+    hunter_gate_detect_root() # set HUNTER_GATE_ROOT
+
+    # Beautify path, fix probable problems with windows path slashes
+    get_filename_component(
+        HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE
+    )
+    hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}")
+    if(NOT HUNTER_ALLOW_SPACES_IN_PATH)
+      string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces)
+      if(NOT _contain_spaces EQUAL -1)
+        hunter_gate_fatal_error(
+            "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
+            "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
+            "(Use at your own risk!)"
+            WIKI "error.spaces.in.hunter.root"
+        )
+      endif()
+    endif()
+
+    string(
+        REGEX
+        MATCH
+        "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*"
+        HUNTER_GATE_VERSION
+        "${HUNTER_GATE_URL}"
+    )
+    string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty)
+    if(_is_empty)
+      set(HUNTER_GATE_VERSION "unknown")
+    endif()
+
+    hunter_gate_self(
+        "${HUNTER_GATE_ROOT}"
+        "${HUNTER_GATE_VERSION}"
+        "${HUNTER_GATE_SHA1}"
+        _hunter_self
+    )
+
+    set(_master_location "${_hunter_self}/cmake/Hunter")
+    if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter")
+      # Hunter downloaded manually (e.g. by 'git clone')
+      set(_unused "xxxxxxxxxx")
+      set(HUNTER_GATE_SHA1 "${_unused}")
+      set(HUNTER_GATE_VERSION "${_unused}")
+    else()
+      get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
+      set(_done_location "${_archive_id_location}/DONE")
+      set(_sha1_location "${_archive_id_location}/SHA1")
+
+      # Check Hunter already downloaded by HunterGate
+      if(NOT EXISTS "${_done_location}")
+        hunter_gate_download("${_archive_id_location}")
+      endif()
+
+      if(NOT EXISTS "${_done_location}")
+        hunter_gate_internal_error("hunter_gate_download failed")
+      endif()
+
+      if(NOT EXISTS "${_sha1_location}")
+        hunter_gate_internal_error("${_sha1_location} not found")
+      endif()
+      file(READ "${_sha1_location}" _sha1_value)
+      string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
+      if(NOT _is_equal)
+        hunter_gate_internal_error(
+            "Short SHA1 collision:"
+            "  ${_sha1_value} (from ${_sha1_location})"
+            "  ${HUNTER_GATE_SHA1} (HunterGate)"
+        )
+      endif()
+      if(NOT EXISTS "${_master_location}")
+        hunter_gate_user_error(
+            "Master file not found:"
+            "  ${_master_location}"
+            "try to update Hunter/HunterGate"
+        )
+      endif()
+    endif()
+    include("${_master_location}")
+    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
+  endif()
+endmacro()

+ 14 - 0
cmake/assimp-hunter-config.cmake.in

@@ -0,0 +1,14 @@
+@PACKAGE_INIT@
+
+find_package(RapidJSON CONFIG REQUIRED)
+find_package(ZLIB CONFIG REQUIRED)
+find_package(utf8 CONFIG REQUIRED)
+find_package(irrXML CONFIG REQUIRED)
+find_package(minizip CONFIG REQUIRED)
+find_package(openddlparser CONFIG REQUIRED)
+find_package(poly2tri CONFIG REQUIRED)
+find_package(polyclipping CONFIG REQUIRED)
+find_package(zip CONFIG REQUIRED)
+
+include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
+check_required_components("@PROJECT_NAME@")

+ 1 - 1
code/3DSConverter.cpp → code/3DS/3DSConverter.cpp

@@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "3DSLoader.h"
-#include "TargetAnimation.h"
+#include "Common/TargetAnimation.h"
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/StringComparison.h>

+ 6 - 4
code/3DSExporter.cpp → code/3DS/3DSExporter.cpp

@@ -43,15 +43,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
 
-#include "3DSExporter.h"
-#include "3DSLoader.h"
-#include "3DSHelper.h"
+#include "3DS/3DSExporter.h"
+#include "3DS/3DSLoader.h"
+#include "3DS/3DSHelper.h"
+#include "PostProcessing/SplitLargeMeshes.h"
+
 #include <assimp/SceneCombiner.h>
-#include "SplitLargeMeshes.h"
 #include <assimp/StringComparison.h>
 #include <assimp/IOSystem.hpp>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Exporter.hpp>
+
 #include <memory>
 
 using namespace Assimp;

+ 0 - 0
code/3DSExporter.h → code/3DS/3DSExporter.h


+ 0 - 0
code/3DSHelper.h → code/3DS/3DSHelper.h


+ 0 - 0
code/3DSLoader.cpp → code/3DS/3DSLoader.cpp


+ 0 - 0
code/3DSLoader.h → code/3DS/3DSLoader.h


+ 0 - 0
code/3MFXmlTags.h → code/3MF/3MFXmlTags.h


+ 5 - 1
code/D3MFExporter.cpp → code/3MF/D3MFExporter.cpp

@@ -55,7 +55,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "3MFXmlTags.h"
 #include "D3MFOpcPackage.h"
 
-#include <contrib/zip/src/zip.h>
+#ifdef ASSIMP_USE_HUNTER
+#  include <zip/zip.h>
+#else
+#  include <contrib/zip/src/zip.h>
+#endif
 
 namespace Assimp {
 

+ 0 - 0
code/D3MFExporter.h → code/3MF/D3MFExporter.h


+ 5 - 1
code/D3MFImporter.cpp → code/3MF/D3MFImporter.cpp

@@ -58,7 +58,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <memory>
 
 #include "D3MFOpcPackage.h"
-#include <unzip.h>
+#ifdef ASSIMP_USE_HUNTER
+#  include <minizip/unzip.h>
+#else
+#  include <unzip.h>
+#endif
 #include <assimp/irrXMLWrapper.h>
 #include "3MFXmlTags.h"
 #include <assimp/fast_atof.h>

+ 0 - 0
code/D3MFImporter.h → code/3MF/D3MFImporter.h


+ 15 - 1
code/D3MFOpcPackage.cpp → code/3MF/D3MFOpcPackage.cpp

@@ -56,7 +56,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <map>
 #include <algorithm>
 #include <cassert>
-#include <unzip.h>
+#ifdef ASSIMP_USE_HUNTER
+#  include <minizip/unzip.h>
+#else
+#  include <unzip.h>
+#endif
 #include "3MFXmlTags.h"
 
 namespace Assimp {
@@ -148,6 +152,15 @@ int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
 zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
     zlib_filefunc_def mapping;
 
+#ifdef ASSIMP_USE_HUNTER
+    mapping.zopen_file = (open_file_func)open;
+    mapping.zread_file = (read_file_func)read;
+    mapping.zwrite_file = (write_file_func)write;
+    mapping.ztell_file = (tell_file_func)tell;
+    mapping.zseek_file = (seek_file_func)seek;
+    mapping.zclose_file = (close_file_func)close;
+    mapping.zerror_file = (error_file_func)testerror;
+#else
     mapping.zopen_file = open;
     mapping.zread_file = read;
     mapping.zwrite_file = write;
@@ -155,6 +168,7 @@ zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
     mapping.zseek_file = seek;
     mapping.zclose_file = close;
     mapping.zerror_file = testerror;
+#endif
     mapping.opaque = reinterpret_cast<voidpf>(pIOHandler);
 
     return mapping;

+ 0 - 0
code/D3MFOpcPackage.h → code/3MF/D3MFOpcPackage.h


+ 1 - 1
code/ACLoader.cpp → code/AC/ACLoader.cpp

@@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/ParsingUtils.h>
 #include <assimp/fast_atof.h>
 #include <assimp/Subdivision.h>
-#include "Importer.h"
+#include "Common/Importer.h"
 #include <assimp/BaseImporter.h>
 #include <assimp/Importer.hpp>
 #include <assimp/light.h>

+ 0 - 0
code/ACLoader.h → code/AC/ACLoader.h


+ 0 - 0
code/AMFImporter.cpp → code/AMF/AMFImporter.cpp


+ 0 - 0
code/AMFImporter.hpp → code/AMF/AMFImporter.hpp


+ 0 - 0
code/AMFImporter_Geometry.cpp → code/AMF/AMFImporter_Geometry.cpp


+ 0 - 0
code/AMFImporter_Macro.hpp → code/AMF/AMFImporter_Macro.hpp


+ 0 - 0
code/AMFImporter_Material.cpp → code/AMF/AMFImporter_Material.cpp


+ 0 - 0
code/AMFImporter_Node.hpp → code/AMF/AMFImporter_Node.hpp


+ 0 - 0
code/AMFImporter_Postprocess.cpp → code/AMF/AMFImporter_Postprocess.cpp


+ 15 - 15
code/ASELoader.cpp → code/ASE/ASELoader.cpp

@@ -53,7 +53,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ASELoader.h"
 #include <assimp/StringComparison.h>
 #include <assimp/SkeletonMeshBuilder.h>
-#include "TargetAnimation.h"
+#include "Common/TargetAnimation.h"
+
 #include <assimp/Importer.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/DefaultLogger.hpp>
@@ -88,23 +89,25 @@ ASEImporter::ASEImporter()
 , mBuffer()
 , pcScene()
 , configRecomputeNormals()
-, noSkeletonMesh()
-{}
+, noSkeletonMesh() {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
-ASEImporter::~ASEImporter()
-{}
+ASEImporter::~ASEImporter() {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
-{
+bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const {
     // check file extension
     const std::string extension = GetExtension(pFile);
 
-    if( extension == "ase" || extension == "ask")
+    if (extension == "ase" || extension == "ask") {
         return true;
+    }
 
     if ((!extension.length() || cs) && pIOHandler) {
         const char* tokens[] = {"*3dsmax_asciiexport"};
@@ -115,15 +118,13 @@ bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
 
 // ------------------------------------------------------------------------------------------------
 // Loader meta information
-const aiImporterDesc* ASEImporter::GetInfo () const
-{
+const aiImporterDesc* ASEImporter::GetInfo () const {
     return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup configuration options
-void ASEImporter::SetupProperties(const Importer* pImp)
-{
+void ASEImporter::SetupProperties(const Importer* pImp) {
     configRecomputeNormals = (pImp->GetPropertyInteger(
         AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false);
 
@@ -133,12 +134,11 @@ void ASEImporter::SetupProperties(const Importer* pImp)
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void ASEImporter::InternReadFile( const std::string& pFile,
-    aiScene* pScene, IOSystem* pIOHandler)
-{
+    aiScene* pScene, IOSystem* pIOHandler) {
     std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
 
     // Check whether we can read from the file
-    if( file.get() == NULL) {
+    if( file.get() == nullptr) {
         throw DeadlyImportError( "Failed to open ASE file " + pFile + ".");
     }
 

+ 0 - 1
code/ASELoader.h → code/ASE/ASELoader.h

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

+ 2 - 2
code/ASEParser.cpp → code/ASE/ASEParser.cpp

@@ -49,15 +49,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
 
 // internal headers
-#include "TextureTransform.h"
+#include "PostProcessing/TextureTransform.h"
 #include "ASELoader.h"
+
 #include <assimp/fast_atof.h>
 #include <assimp/DefaultLogger.hpp>
 
 using namespace Assimp;
 using namespace Assimp::ASE;
 
-
 // ------------------------------------------------------------------------------------------------
 // Begin an ASE parsing function
 

+ 1 - 1
code/ASEParser.h → code/ASE/ASEParser.h

@@ -57,7 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/qnan.h>
 
 // ASE is quite similar to 3ds. We can reuse some structures
-#include "3DSLoader.h"
+#include "3DS/3DSLoader.h"
 
 namespace Assimp    {
 namespace ASE   {

+ 3 - 2
code/AssbinExporter.cpp → code/Assbin/AssbinExporter.cpp

@@ -46,12 +46,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
 
-#include "assbin_chunks.h"
+#include "Common/assbin_chunks.h"
+#include "PostProcessing/ProcessHelper.h"
+
 #include <assimp/version.h>
 #include <assimp/IOStream.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/Exporter.hpp>
-#include "ProcessHelper.h"
 #include <assimp/Exceptional.h>
 
 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB

+ 0 - 0
code/AssbinExporter.h → code/Assbin/AssbinExporter.h


+ 2 - 2
code/AssbinLoader.cpp → code/Assbin/AssbinLoader.cpp

@@ -50,8 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
 
 // internal headers
-#include "AssbinLoader.h"
-#include "assbin_chunks.h"
+#include "Assbin/AssbinLoader.h"
+#include "Common/assbin_chunks.h"
 #include <assimp/MemoryIOWrapper.h>
 #include <assimp/mesh.h>
 #include <assimp/anim.h>

+ 0 - 0
code/AssbinLoader.h → code/Assbin/AssbinLoader.h


+ 109 - 0
code/Assjson/cencode.c

@@ -0,0 +1,109 @@
+/*
+cencoder.c - c source to a base64 encoding algorithm implementation
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#include "cencode.h" // changed from <B64/cencode.h>
+
+const int CHARS_PER_LINE = 72;
+
+void base64_init_encodestate(base64_encodestate* state_in)
+{
+	state_in->step = step_A;
+	state_in->result = 0;
+	state_in->stepcount = 0;
+}
+
+char base64_encode_value(char value_in)
+{
+	static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+	if (value_in > 63) return '=';
+	return encoding[(int)value_in];
+}
+
+int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
+{
+	const char* plainchar = plaintext_in;
+	const char* const plaintextend = plaintext_in + length_in;
+	char* codechar = code_out;
+	char result;
+	char fragment;
+	
+	result = state_in->result;
+	
+	switch (state_in->step)
+	{
+		while (1)
+		{
+	case step_A:
+			if (plainchar == plaintextend)
+			{
+				state_in->result = result;
+				state_in->step = step_A;
+				return codechar - code_out;
+			}
+			fragment = *plainchar++;
+			result = (fragment & 0x0fc) >> 2;
+			*codechar++ = base64_encode_value(result);
+			result = (fragment & 0x003) << 4;
+	case step_B:
+			if (plainchar == plaintextend)
+			{
+				state_in->result = result;
+				state_in->step = step_B;
+				return codechar - code_out;
+			}
+			fragment = *plainchar++;
+			result |= (fragment & 0x0f0) >> 4;
+			*codechar++ = base64_encode_value(result);
+			result = (fragment & 0x00f) << 2;
+	case step_C:
+			if (plainchar == plaintextend)
+			{
+				state_in->result = result;
+				state_in->step = step_C;
+				return codechar - code_out;
+			}
+			fragment = *plainchar++;
+			result |= (fragment & 0x0c0) >> 6;
+			*codechar++ = base64_encode_value(result);
+			result  = (fragment & 0x03f) >> 0;
+			*codechar++ = base64_encode_value(result);
+			
+			++(state_in->stepcount);
+			if (state_in->stepcount == CHARS_PER_LINE/4)
+			{
+				*codechar++ = '\n';
+				state_in->stepcount = 0;
+			}
+		}
+	}
+	/* control should not reach here */
+	return codechar - code_out;
+}
+
+int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
+{
+	char* codechar = code_out;
+	
+	switch (state_in->step)
+	{
+	case step_B:
+		*codechar++ = base64_encode_value(state_in->result);
+		*codechar++ = '=';
+		*codechar++ = '=';
+		break;
+	case step_C:
+		*codechar++ = base64_encode_value(state_in->result);
+		*codechar++ = '=';
+		break;
+	case step_A:
+		break;
+	}
+	*codechar++ = '\n';
+	
+	return codechar - code_out;
+}
+

+ 31 - 0
code/Assjson/cencode.h

@@ -0,0 +1,31 @@
+/*
+cencode.h - c header for a base64 encoding algorithm
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#ifndef BASE64_CENCODE_H
+#define BASE64_CENCODE_H
+
+typedef enum
+{
+	step_A, step_B, step_C
+} base64_encodestep;
+
+typedef struct
+{
+	base64_encodestep step;
+	char result;
+	int stepcount;
+} base64_encodestate;
+
+void base64_init_encodestate(base64_encodestate* state_in);
+
+char base64_encode_value(char value_in);
+
+int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
+
+int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
+
+#endif /* BASE64_CENCODE_H */

+ 818 - 0
code/Assjson/json_exporter.cpp

@@ -0,0 +1,818 @@
+/*
+Assimp2Json
+Copyright (c) 2011, Alexander C. Gessler
+
+Licensed under a 3-clause BSD license. See the LICENSE file for more information.
+
+*/
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
+
+#include <assimp/Importer.hpp>
+#include <assimp/Exporter.hpp>
+#include <assimp/IOStream.hpp>
+#include <assimp/IOSystem.hpp>
+#include <assimp/scene.h>
+
+#include <sstream>
+#include <limits>
+#include <cassert>
+#include <memory>
+
+#define CURRENT_FORMAT_VERSION 100
+
+// grab scoped_ptr from assimp to avoid a dependency on boost. 
+//#include <assimp/../../code/BoostWorkaround/boost/scoped_ptr.hpp>
+
+#include "mesh_splitter.h"
+
+extern "C" {
+    #include "cencode.h"
+}
+namespace Assimp {
+
+void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
+
+Exporter::ExportFormatEntry Assimp2Json_desc = Assimp::Exporter::ExportFormatEntry(
+    "json",
+    "Plain JSON representation of the Assimp scene data structure",
+    "json",
+    &ExportAssimp2Json,
+    0u
+);
+
+
+// small utility class to simplify serializing the aiScene to Json
+class JSONWriter {
+public:
+    enum {
+        Flag_DoNotIndent = 0x1,
+        Flag_WriteSpecialFloats = 0x2,
+    };
+
+    JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u)
+    : out(out)
+    , first()
+    , flags(flags) {
+        // make sure that all formatting happens using the standard, C locale and not the user's current locale
+        buff.imbue(std::locale("C"));
+    }
+
+    ~JSONWriter() {
+        Flush();
+    }
+
+    void Flush() {
+        const std::string s = buff.str();
+        out.Write(s.c_str(), s.length(), 1);
+        buff.clear();
+    }
+
+    void PushIndent() {
+        indent += '\t';
+    }
+
+    void PopIndent() {
+        indent.erase(indent.end() - 1);
+    }
+
+    void Key(const std::string& name) {
+        AddIndentation();
+        Delimit();
+        buff << '\"' + name + "\": ";
+    }
+
+    template<typename Literal>
+    void Element(const Literal& name) {
+        AddIndentation();
+        Delimit();
+
+        LiteralToString(buff, name) << '\n';
+    }
+
+    template<typename Literal>
+    void SimpleValue(const Literal& s) {
+        LiteralToString(buff, s) << '\n';
+    }
+
+    void SimpleValue(const void* buffer, size_t len) {
+        base64_encodestate s;
+        base64_init_encodestate(&s);
+
+        char* const out = new char[std::max(len * 2, static_cast<size_t>(16u))];
+        const int n = base64_encode_block(reinterpret_cast<const char*>(buffer), static_cast<int>(len), out, &s);
+        out[n + base64_encode_blockend(out + n, &s)] = '\0';
+
+        // base64 encoding may add newlines, but JSON strings may not contain 'real' newlines
+        // (only escaped ones). Remove any newlines in out.
+        for (char* cur = out; *cur; ++cur) {
+            if (*cur == '\n') {
+                *cur = ' ';
+            }
+        }
+
+        buff << '\"' << out << "\"\n";
+        delete[] out;
+    }
+
+    void StartObj(bool is_element = false) {
+        // if this appears as a plain array element, we need to insert a delimiter and we should also indent it
+        if (is_element) {
+            AddIndentation();
+            if (!first) {
+                buff << ',';
+            }
+        }
+        first = true;
+        buff << "{\n";
+        PushIndent();
+    }
+
+    void EndObj() {
+        PopIndent();
+        AddIndentation();
+        first = false;
+        buff << "}\n";
+    }
+
+    void StartArray(bool is_element = false) {
+        // if this appears as a plain array element, we need to insert a delimiter and we should also indent it
+        if (is_element) {
+            AddIndentation();
+            if (!first) {
+                buff << ',';
+            }
+        }
+        first = true;
+        buff << "[\n";
+        PushIndent();
+    }
+
+    void EndArray() {
+        PopIndent();
+        AddIndentation();
+        buff << "]\n";
+        first = false;
+    }
+
+    void AddIndentation() {
+        if (!(flags & Flag_DoNotIndent)) {
+            buff << indent;
+        }
+    }
+
+    void Delimit() {
+        if (!first) {
+            buff << ',';
+        }
+        else {
+            buff << ' ';
+            first = false;
+        }
+    }
+
+private:
+    template<typename Literal>
+    std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) {
+        stream << s;
+        return stream;
+    }
+
+    std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) {
+        std::string t;
+
+        // escape backslashes and single quotes, both would render the JSON invalid if left as is
+        t.reserve(s.length);
+        for (size_t i = 0; i < s.length; ++i) {
+
+            if (s.data[i] == '\\' || s.data[i] == '\'' || s.data[i] == '\"') {
+                t.push_back('\\');
+            }
+
+            t.push_back(s.data[i]);
+        }
+        stream << "\"";
+        stream << t;
+        stream << "\"";
+        return stream;
+    }
+
+    std::stringstream& LiteralToString(std::stringstream& stream, float f) {
+        if (!std::numeric_limits<float>::is_iec559) {
+            // on a non IEEE-754 platform, we make no assumptions about the representation or existence
+            // of special floating-point numbers. 
+            stream << f;
+            return stream;
+        }
+
+        // JSON does not support writing Inf/Nan
+        // [RFC 4672: "Numeric values that cannot be represented as sequences of digits
+        // (such as Infinity and NaN) are not permitted."]
+        // Nevertheless, many parsers will accept the special keywords Infinity, -Infinity and NaN
+        if (std::numeric_limits<float>::infinity() == fabs(f)) {
+            if (flags & Flag_WriteSpecialFloats) {
+                stream << (f < 0 ? "\"-" : "\"") + std::string("Infinity\"");
+                return stream;
+            }
+            //  we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr
+            //	std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl;
+            stream << "0.0";
+            return stream;
+        }
+        // f!=f is the most reliable test for NaNs that I know of
+        else if (f != f) {
+            if (flags & Flag_WriteSpecialFloats) {
+                stream << "\"NaN\"";
+                return stream;
+            }
+            //  we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr
+            //	std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl;
+            stream << "0.0";
+            return stream;
+        }
+
+        stream << f;
+        return stream;
+    }
+
+private:
+    Assimp::IOStream& out;
+    std::string indent, newline;
+    std::stringstream buff;
+    bool first;
+
+    unsigned int flags;
+};
+
+void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
+    out.StartArray(is_elem);
+    out.Element(ai.x);
+    out.Element(ai.y);
+    out.Element(ai.z);
+    out.EndArray();
+}
+
+void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
+    out.StartArray(is_elem);
+    out.Element(ai.w);
+    out.Element(ai.x);
+    out.Element(ai.y);
+    out.Element(ai.z);
+    out.EndArray();
+}
+
+void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
+    out.StartArray(is_elem);
+    out.Element(ai.r);
+    out.Element(ai.g);
+    out.Element(ai.b);
+    out.EndArray();
+}
+
+void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
+    out.StartArray(is_elem);
+    for (unsigned int x = 0; x < 4; ++x) {
+        for (unsigned int y = 0; y < 4; ++y) {
+            out.Element(ai[x][y]);
+        }
+    }
+    out.EndArray();
+}
+
+void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
+    out.StartObj(is_elem);
+
+    out.Key("name");
+    out.SimpleValue(ai.mName);
+
+    out.Key("offsetmatrix");
+    Write(out, ai.mOffsetMatrix, false);
+
+    out.Key("weights");
+    out.StartArray();
+    for (unsigned int i = 0; i < ai.mNumWeights; ++i) {
+        out.StartArray(true);
+        out.Element(ai.mWeights[i].mVertexId);
+        out.Element(ai.mWeights[i].mWeight);
+        out.EndArray();
+    }
+    out.EndArray();
+    out.EndObj();
+}
+
+void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
+    out.StartArray(is_elem);
+    for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
+        out.Element(ai.mIndices[i]);
+    }
+    out.EndArray();
+}
+
+void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
+    out.StartObj(is_elem);
+
+    out.Key("name");
+    out.SimpleValue(ai.mName);
+
+    out.Key("materialindex");
+    out.SimpleValue(ai.mMaterialIndex);
+
+    out.Key("primitivetypes");
+    out.SimpleValue(ai.mPrimitiveTypes);
+
+    out.Key("vertices");
+    out.StartArray();
+    for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
+        out.Element(ai.mVertices[i].x);
+        out.Element(ai.mVertices[i].y);
+        out.Element(ai.mVertices[i].z);
+    }
+    out.EndArray();
+
+    if (ai.HasNormals()) {
+        out.Key("normals");
+        out.StartArray();
+        for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
+            out.Element(ai.mNormals[i].x);
+            out.Element(ai.mNormals[i].y);
+            out.Element(ai.mNormals[i].z);
+        }
+        out.EndArray();
+    }
+
+    if (ai.HasTangentsAndBitangents()) {
+        out.Key("tangents");
+        out.StartArray();
+        for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
+            out.Element(ai.mTangents[i].x);
+            out.Element(ai.mTangents[i].y);
+            out.Element(ai.mTangents[i].z);
+        }
+        out.EndArray();
+
+        out.Key("bitangents");
+        out.StartArray();
+        for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
+            out.Element(ai.mBitangents[i].x);
+            out.Element(ai.mBitangents[i].y);
+            out.Element(ai.mBitangents[i].z);
+        }
+        out.EndArray();
+    }
+
+    if (ai.GetNumUVChannels()) {
+        out.Key("numuvcomponents");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) {
+            out.Element(ai.mNumUVComponents[n]);
+        }
+        out.EndArray();
+
+        out.Key("texturecoords");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) {
+            const unsigned int numc = ai.mNumUVComponents[n] ? ai.mNumUVComponents[n] : 2;
+
+            out.StartArray(true);
+            for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
+                for (unsigned int c = 0; c < numc; ++c) {
+                    out.Element(ai.mTextureCoords[n][i][c]);
+                }
+            }
+            out.EndArray();
+        }
+        out.EndArray();
+    }
+
+    if (ai.GetNumColorChannels()) {
+        out.Key("colors");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.GetNumColorChannels(); ++n) {
+            out.StartArray(true);
+            for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
+                out.Element(ai.mColors[n][i].r);
+                out.Element(ai.mColors[n][i].g);
+                out.Element(ai.mColors[n][i].b);
+                out.Element(ai.mColors[n][i].a);
+            }
+            out.EndArray();
+        }
+        out.EndArray();
+    }
+
+    if (ai.mNumBones) {
+        out.Key("bones");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumBones; ++n) {
+            Write(out, *ai.mBones[n]);
+        }
+        out.EndArray();
+    }
+
+    out.Key("faces");
+    out.StartArray();
+    for (unsigned int n = 0; n < ai.mNumFaces; ++n) {
+        Write(out, ai.mFaces[n]);
+    }
+    out.EndArray();
+
+    out.EndObj();
+}
+
+void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
+    out.StartObj(is_elem);
+
+    out.Key("name");
+    out.SimpleValue(ai.mName);
+
+    out.Key("transformation");
+    Write(out, ai.mTransformation, false);
+
+    if (ai.mNumMeshes) {
+        out.Key("meshes");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumMeshes; ++n) {
+            out.Element(ai.mMeshes[n]);
+        }
+        out.EndArray();
+    }
+
+    if (ai.mNumChildren) {
+        out.Key("children");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumChildren; ++n) {
+            Write(out, *ai.mChildren[n]);
+        }
+        out.EndArray();
+    }
+
+    out.EndObj();
+}
+
+void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
+    out.StartObj(is_elem);
+
+    out.Key("properties");
+    out.StartArray();
+    for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
+        const aiMaterialProperty* const prop = ai.mProperties[i];
+        out.StartObj(true);
+        out.Key("key");
+        out.SimpleValue(prop->mKey);
+        out.Key("semantic");
+        out.SimpleValue(prop->mSemantic);
+        out.Key("index");
+        out.SimpleValue(prop->mIndex);
+
+        out.Key("type");
+        out.SimpleValue(prop->mType);
+
+        out.Key("value");
+        switch (prop->mType) {
+            case aiPTI_Float:
+                if (prop->mDataLength / sizeof(float) > 1) {
+                    out.StartArray();
+                    for (unsigned int i = 0; i < prop->mDataLength / sizeof(float); ++i) {
+                        out.Element(reinterpret_cast<float*>(prop->mData)[i]);
+                    }
+                    out.EndArray();
+                }
+                else {
+                    out.SimpleValue(*reinterpret_cast<float*>(prop->mData));
+                }
+                break;
+
+            case aiPTI_Integer:
+                if (prop->mDataLength / sizeof(int) > 1) {
+                    out.StartArray();
+                    for (unsigned int i = 0; i < prop->mDataLength / sizeof(int); ++i) {
+                        out.Element(reinterpret_cast<int*>(prop->mData)[i]);
+                    }
+                    out.EndArray();
+                } else {
+                    out.SimpleValue(*reinterpret_cast<int*>(prop->mData));
+                }
+                break;
+
+            case aiPTI_String:
+                {
+                    aiString s;
+                    aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
+                    out.SimpleValue(s);
+                }
+                break;
+            case aiPTI_Buffer:
+                {
+                    // binary data is written as series of hex-encoded octets
+                    out.SimpleValue(prop->mData, prop->mDataLength);
+                }
+                break;
+            default:
+                assert(false);
+        }
+
+        out.EndObj();
+    }
+
+    out.EndArray();
+    out.EndObj();
+}
+
+void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
+    out.StartObj(is_elem);
+
+    out.Key("width");
+    out.SimpleValue(ai.mWidth);
+
+    out.Key("height");
+    out.SimpleValue(ai.mHeight);
+
+    out.Key("formathint");
+    out.SimpleValue(aiString(ai.achFormatHint));
+
+    out.Key("data");
+    if (!ai.mHeight) {
+        out.SimpleValue(ai.pcData, ai.mWidth);
+    }
+    else {
+        out.StartArray();
+        for (unsigned int y = 0; y < ai.mHeight; ++y) {
+            out.StartArray(true);
+            for (unsigned int x = 0; x < ai.mWidth; ++x) {
+                const aiTexel& tx = ai.pcData[y*ai.mWidth + x];
+                out.StartArray(true);
+                out.Element(static_cast<unsigned int>(tx.r));
+                out.Element(static_cast<unsigned int>(tx.g));
+                out.Element(static_cast<unsigned int>(tx.b));
+                out.Element(static_cast<unsigned int>(tx.a));
+                out.EndArray();
+            }
+            out.EndArray();
+        }
+        out.EndArray();
+    }
+
+    out.EndObj();
+}
+
+void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
+    out.StartObj(is_elem);
+
+    out.Key("name");
+    out.SimpleValue(ai.mName);
+
+    out.Key("type");
+    out.SimpleValue(ai.mType);
+
+    if (ai.mType == aiLightSource_SPOT || ai.mType == aiLightSource_UNDEFINED) {
+        out.Key("angleinnercone");
+        out.SimpleValue(ai.mAngleInnerCone);
+
+        out.Key("angleoutercone");
+        out.SimpleValue(ai.mAngleOuterCone);
+    }
+
+    out.Key("attenuationconstant");
+    out.SimpleValue(ai.mAttenuationConstant);
+
+    out.Key("attenuationlinear");
+    out.SimpleValue(ai.mAttenuationLinear);
+
+    out.Key("attenuationquadratic");
+    out.SimpleValue(ai.mAttenuationQuadratic);
+
+    out.Key("diffusecolor");
+    Write(out, ai.mColorDiffuse, false);
+
+    out.Key("specularcolor");
+    Write(out, ai.mColorSpecular, false);
+
+    out.Key("ambientcolor");
+    Write(out, ai.mColorAmbient, false);
+
+    if (ai.mType != aiLightSource_POINT) {
+        out.Key("direction");
+        Write(out, ai.mDirection, false);
+
+    }
+
+    if (ai.mType != aiLightSource_DIRECTIONAL) {
+        out.Key("position");
+        Write(out, ai.mPosition, false);
+    }
+
+    out.EndObj();
+}
+
+void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
+    out.StartObj(is_elem);
+
+    out.Key("name");
+    out.SimpleValue(ai.mNodeName);
+
+    out.Key("prestate");
+    out.SimpleValue(ai.mPreState);
+
+    out.Key("poststate");
+    out.SimpleValue(ai.mPostState);
+
+    if (ai.mNumPositionKeys) {
+        out.Key("positionkeys");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
+            const aiVectorKey& pos = ai.mPositionKeys[n];
+            out.StartArray(true);
+            out.Element(pos.mTime);
+            Write(out, pos.mValue);
+            out.EndArray();
+        }
+        out.EndArray();
+    }
+
+    if (ai.mNumRotationKeys) {
+        out.Key("rotationkeys");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
+            const aiQuatKey& rot = ai.mRotationKeys[n];
+            out.StartArray(true);
+            out.Element(rot.mTime);
+            Write(out, rot.mValue);
+            out.EndArray();
+        }
+        out.EndArray();
+    }
+
+    if (ai.mNumScalingKeys) {
+        out.Key("scalingkeys");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
+            const aiVectorKey& scl = ai.mScalingKeys[n];
+            out.StartArray(true);
+            out.Element(scl.mTime);
+            Write(out, scl.mValue);
+            out.EndArray();
+        }
+        out.EndArray();
+    }
+    out.EndObj();
+}
+
+void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
+    out.StartObj(is_elem);
+
+    out.Key("name");
+    out.SimpleValue(ai.mName);
+
+    out.Key("tickspersecond");
+    out.SimpleValue(ai.mTicksPerSecond);
+
+    out.Key("duration");
+    out.SimpleValue(ai.mDuration);
+
+    out.Key("channels");
+    out.StartArray();
+    for (unsigned int n = 0; n < ai.mNumChannels; ++n) {
+        Write(out, *ai.mChannels[n]);
+    }
+    out.EndArray();
+    out.EndObj();
+}
+
+void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
+    out.StartObj(is_elem);
+
+    out.Key("name");
+    out.SimpleValue(ai.mName);
+
+    out.Key("aspect");
+    out.SimpleValue(ai.mAspect);
+
+    out.Key("clipplanefar");
+    out.SimpleValue(ai.mClipPlaneFar);
+
+    out.Key("clipplanenear");
+    out.SimpleValue(ai.mClipPlaneNear);
+
+    out.Key("horizontalfov");
+    out.SimpleValue(ai.mHorizontalFOV);
+
+    out.Key("up");
+    Write(out, ai.mUp, false);
+
+    out.Key("lookat");
+    Write(out, ai.mLookAt, false);
+
+    out.EndObj();
+}
+
+void WriteFormatInfo(JSONWriter& out) {
+    out.StartObj();
+    out.Key("format");
+    out.SimpleValue("\"assimp2json\"");
+    out.Key("version");
+    out.SimpleValue(CURRENT_FORMAT_VERSION);
+    out.EndObj();
+}
+
+void Write(JSONWriter& out, const aiScene& ai) {
+    out.StartObj();
+
+    out.Key("__metadata__");
+    WriteFormatInfo(out);
+
+    out.Key("rootnode");
+    Write(out, *ai.mRootNode, false);
+
+    out.Key("flags");
+    out.SimpleValue(ai.mFlags);
+
+    if (ai.HasMeshes()) {
+        out.Key("meshes");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumMeshes; ++n) {
+            Write(out, *ai.mMeshes[n]);
+        }
+        out.EndArray();
+    }
+
+    if (ai.HasMaterials()) {
+        out.Key("materials");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumMaterials; ++n) {
+            Write(out, *ai.mMaterials[n]);
+        }
+        out.EndArray();
+    }
+
+    if (ai.HasAnimations()) {
+        out.Key("animations");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumAnimations; ++n) {
+            Write(out, *ai.mAnimations[n]);
+        }
+        out.EndArray();
+    }
+
+    if (ai.HasLights()) {
+        out.Key("lights");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumLights; ++n) {
+            Write(out, *ai.mLights[n]);
+        }
+        out.EndArray();
+    }
+
+    if (ai.HasCameras()) {
+        out.Key("cameras");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumCameras; ++n) {
+            Write(out, *ai.mCameras[n]);
+        }
+        out.EndArray();
+    }
+
+    if (ai.HasTextures()) {
+        out.Key("textures");
+        out.StartArray();
+        for (unsigned int n = 0; n < ai.mNumTextures; ++n) {
+            Write(out, *ai.mTextures[n]);
+        }
+        out.EndArray();
+    }
+    out.EndObj();
+}
+
+
+void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) {
+    std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
+    if (!str) {
+        //throw Assimp::DeadlyExportError("could not open output file");
+    }
+
+    // get a copy of the scene so we can modify it
+    aiScene* scenecopy_tmp;
+    aiCopyScene(scene, &scenecopy_tmp);
+
+    try {
+        // split meshes so they fit into a 16 bit index buffer
+        MeshSplitter splitter;
+        splitter.SetLimit(1 << 16);
+        splitter.Execute(scenecopy_tmp);
+
+        // XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters
+        JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
+        Write(s, *scenecopy_tmp);
+
+    }
+    catch (...) {
+        aiFreeScene(scenecopy_tmp);
+        throw;
+    }
+    aiFreeScene(scenecopy_tmp);
+}
+
+}
+
+#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 320 - 0
code/Assjson/mesh_splitter.cpp

@@ -0,0 +1,320 @@
+/*
+Assimp2Json
+Copyright (c) 2011, Alexander C. Gessler
+
+Licensed under a 3-clause BSD license. See the LICENSE file for more information.
+
+*/
+
+#include "mesh_splitter.h"
+
+#include <assimp/scene.h>
+
+// ----------------------------------------------------------------------------
+// Note: this is largely based on assimp's SplitLargeMeshes_Vertex process.
+// it is refactored and the coding style is slightly improved, though.
+// ----------------------------------------------------------------------------
+
+// ------------------------------------------------------------------------------------------------
+// Executes the post processing step on the given imported data.
+void MeshSplitter::Execute( aiScene* pScene) {
+	std::vector<std::pair<aiMesh*, unsigned int> > source_mesh_map;
+
+	for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
+		SplitMesh(a, pScene->mMeshes[a],source_mesh_map);
+	}
+
+	const unsigned int size = static_cast<unsigned int>(source_mesh_map.size());
+	if (size != pScene->mNumMeshes) {
+		// it seems something has been split. rebuild the mesh list
+		delete[] pScene->mMeshes;
+		pScene->mNumMeshes = size;
+		pScene->mMeshes = new aiMesh*[size]();
+
+		for (unsigned int i = 0; i < size;++i) {
+			pScene->mMeshes[i] = source_mesh_map[i].first;
+		}
+
+		// now we need to update all nodes
+		UpdateNode(pScene->mRootNode,source_mesh_map);
+	}
+}
+
+
+// ------------------------------------------------------------------------------------------------
+void MeshSplitter::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map) {
+	// TODO: should better use std::(multi)set for source_mesh_map.
+
+	// for every index in out list build a new entry
+	std::vector<unsigned int> aiEntries;
+	aiEntries.reserve(pcNode->mNumMeshes + 1);
+	for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)	{
+		for (unsigned int a = 0, end = static_cast<unsigned int>(source_mesh_map.size()); a < end;++a)	{
+			if (source_mesh_map[a].second == pcNode->mMeshes[i])	{
+				aiEntries.push_back(a);
+			}
+		}
+	}
+
+	// now build the new list
+	delete pcNode->mMeshes;
+	pcNode->mNumMeshes = static_cast<unsigned int>(aiEntries.size());
+	pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
+
+	for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) {
+		pcNode->mMeshes[b] = aiEntries[b];
+	}
+
+	// recursively update children
+	for (unsigned int i = 0, end = pcNode->mNumChildren; i < end;++i)	{
+		UpdateNode ( pcNode->mChildren[i], source_mesh_map );
+	}
+	return;
+}
+
+#define WAS_NOT_COPIED 0xffffffff
+
+typedef std::pair <unsigned int,float> PerVertexWeight;
+typedef std::vector	<PerVertexWeight> VertexWeightTable;
+
+// ------------------------------------------------------------------------------------------------
+VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) {
+	if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) {
+		return nullptr;
+	}
+
+	VertexWeightTable* const avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
+	for (unsigned int i = 0; i < pMesh->mNumBones;++i)	{
+
+		aiBone* bone = pMesh->mBones[i];
+		for (unsigned int a = 0; a < bone->mNumWeights;++a)	{
+			const aiVertexWeight& weight = bone->mWeights[a];
+			avPerVertexWeights[weight.mVertexId].push_back( std::make_pair(i,weight.mWeight) );
+		}
+	}
+	return avPerVertexWeights;
+}
+
+// ------------------------------------------------------------------------------------------------
+void MeshSplitter :: SplitMesh(unsigned int a, aiMesh* in_mesh, std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map) {
+	// TODO: should better use std::(multi)set for source_mesh_map.
+
+	if (in_mesh->mNumVertices <= LIMIT)	{
+		source_mesh_map.push_back(std::make_pair(in_mesh,a));
+		return;
+	}
+
+	// build a per-vertex weight list if necessary
+	VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(in_mesh);
+
+	// we need to split this mesh into sub meshes. Estimate submesh size
+	const unsigned int sub_meshes = (in_mesh->mNumVertices / LIMIT) + 1;
+
+	// create a std::vector<unsigned int> to remember which vertices have already 
+	// been copied and to which position (i.e. output index)
+	std::vector<unsigned int> was_copied_to;
+	was_copied_to.resize(in_mesh->mNumVertices,WAS_NOT_COPIED);
+
+	// Try to find a good estimate for the number of output faces
+	// per mesh. Add 12.5% as buffer
+	unsigned int size_estimated = in_mesh->mNumFaces / sub_meshes;
+	size_estimated += size_estimated / 8;
+
+	// now generate all submeshes
+	unsigned int base = 0;
+	while (true) {
+		const unsigned int out_vertex_index = LIMIT;
+
+		aiMesh* out_mesh = new aiMesh();			
+		out_mesh->mNumVertices = 0;
+		out_mesh->mMaterialIndex = in_mesh->mMaterialIndex;
+
+		// the name carries the adjacency information between the meshes
+		out_mesh->mName = in_mesh->mName;
+
+		typedef std::vector<aiVertexWeight> BoneWeightList;
+		if (in_mesh->HasBones())	{
+			out_mesh->mBones = new aiBone*[in_mesh->mNumBones]();
+		}
+
+		// clear the temporary helper array
+		if (base)	{
+			std::fill(was_copied_to.begin(), was_copied_to.end(), WAS_NOT_COPIED);
+		}
+
+		std::vector<aiFace> vFaces;
+
+		// reserve enough storage for most cases
+		if (in_mesh->HasPositions()) {
+			out_mesh->mVertices = new aiVector3D[out_vertex_index];
+		}
+
+		if (in_mesh->HasNormals()) {
+			out_mesh->mNormals = new aiVector3D[out_vertex_index];
+		}
+
+		if (in_mesh->HasTangentsAndBitangents())	{
+			out_mesh->mTangents = new aiVector3D[out_vertex_index];
+			out_mesh->mBitangents = new aiVector3D[out_vertex_index];
+		}
+
+		for (unsigned int c = 0; in_mesh->HasVertexColors(c);++c)	{
+			out_mesh->mColors[c] = new aiColor4D[out_vertex_index];
+		}
+
+		for (unsigned int c = 0; in_mesh->HasTextureCoords(c);++c)	{
+			out_mesh->mNumUVComponents[c] = in_mesh->mNumUVComponents[c];
+			out_mesh->mTextureCoords[c] = new aiVector3D[out_vertex_index];
+		}
+		vFaces.reserve(size_estimated);
+
+		// (we will also need to copy the array of indices)
+		while (base < in_mesh->mNumFaces) {
+			const unsigned int iNumIndices = in_mesh->mFaces[base].mNumIndices;
+
+			// doesn't catch degenerates but is quite fast
+			unsigned int iNeed = 0;
+			for (unsigned int v = 0; v < iNumIndices;++v)	{
+				unsigned int index = in_mesh->mFaces[base].mIndices[v];
+
+				// check whether we do already have this vertex
+				if (WAS_NOT_COPIED == was_copied_to[index])	{
+					iNeed++; 
+				}
+			}
+			if (out_mesh->mNumVertices + iNeed > out_vertex_index)	{
+				// don't use this face
+				break;
+			}
+
+			vFaces.push_back(aiFace());
+			aiFace& rFace = vFaces.back();
+
+			// setup face type and number of indices
+			rFace.mNumIndices = iNumIndices;
+			rFace.mIndices = new unsigned int[iNumIndices];
+
+			// need to update the output primitive types
+			switch (rFace.mNumIndices)
+			{
+			case 1:
+				out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
+				break;
+			case 2:
+				out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
+				break;
+			case 3:
+				out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+				break;
+			default:
+				out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+			}
+
+			// and copy the contents of the old array, offset them by current base
+			for (unsigned int v = 0; v < iNumIndices;++v) {
+				const unsigned int index = in_mesh->mFaces[base].mIndices[v];
+
+				// check whether we do already have this vertex
+				if (WAS_NOT_COPIED != was_copied_to[index]) {
+					rFace.mIndices[v] = was_copied_to[index];
+					continue;
+				}
+
+				// copy positions
+				out_mesh->mVertices[out_mesh->mNumVertices] = (in_mesh->mVertices[index]);
+
+				// copy normals
+				if (in_mesh->HasNormals()) {
+					out_mesh->mNormals[out_mesh->mNumVertices] = (in_mesh->mNormals[index]);
+				}
+
+				// copy tangents/bi-tangents
+				if (in_mesh->HasTangentsAndBitangents()) {
+					out_mesh->mTangents[out_mesh->mNumVertices] = (in_mesh->mTangents[index]);
+					out_mesh->mBitangents[out_mesh->mNumVertices] = (in_mesh->mBitangents[index]);
+				}
+
+				// texture coordinates
+				for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
+					if (in_mesh->HasTextureCoords( c)) {
+						out_mesh->mTextureCoords[c][out_mesh->mNumVertices] = in_mesh->mTextureCoords[c][index];
+					}
+				}
+				// vertex colors 
+				for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) {
+					if (in_mesh->HasVertexColors( c)) {
+						out_mesh->mColors[c][out_mesh->mNumVertices] = in_mesh->mColors[c][index];
+					}
+				}
+				// check whether we have bone weights assigned to this vertex
+				rFace.mIndices[v] = out_mesh->mNumVertices;
+				if (avPerVertexWeights) {
+					VertexWeightTable& table = avPerVertexWeights[ out_mesh->mNumVertices ];
+					for (VertexWeightTable::const_iterator iter = table.begin(), end = table.end(); iter != end;++iter) {
+						// allocate the bone weight array if necessary and store it in the mBones field (HACK!)
+						BoneWeightList* weight_list = reinterpret_cast<BoneWeightList*>(out_mesh->mBones[(*iter).first]);
+						if (!weight_list) {
+							weight_list = new BoneWeightList();
+							out_mesh->mBones[(*iter).first] = reinterpret_cast<aiBone*>(weight_list);
+						}
+						weight_list->push_back(aiVertexWeight(out_mesh->mNumVertices,(*iter).second));
+					}
+				}
+
+				was_copied_to[index] = out_mesh->mNumVertices;
+				out_mesh->mNumVertices++;
+			}
+			base++;
+			if(out_mesh->mNumVertices == out_vertex_index) {
+				// break here. The face is only added if it was complete
+				break;
+			}
+		}
+
+		// check which bones we'll need to create for this submesh
+		if (in_mesh->HasBones()) {
+			aiBone** ppCurrent = out_mesh->mBones;
+			for (unsigned int k = 0; k < in_mesh->mNumBones;++k) {
+				// check whether the bone exists
+				BoneWeightList* const weight_list = reinterpret_cast<BoneWeightList*>(out_mesh->mBones[k]);
+
+				if (weight_list) {
+					const aiBone* const bone_in = in_mesh->mBones[k];
+					aiBone* const bone_out = new aiBone();
+					*ppCurrent++ = bone_out;
+					bone_out->mName = aiString(bone_in->mName);
+					bone_out->mOffsetMatrix =bone_in->mOffsetMatrix;
+					bone_out->mNumWeights = (unsigned int)weight_list->size();
+					bone_out->mWeights = new aiVertexWeight[bone_out->mNumWeights];
+
+					// copy the vertex weights
+					::memcpy(bone_out->mWeights, &(*weight_list)[0],bone_out->mNumWeights * sizeof(aiVertexWeight));
+
+					delete weight_list;
+					out_mesh->mNumBones++;
+				}
+			}
+		}
+
+		// copy the face list to the mesh
+		out_mesh->mFaces = new aiFace[vFaces.size()];
+		out_mesh->mNumFaces = (unsigned int)vFaces.size();
+
+		for (unsigned int p = 0; p < out_mesh->mNumFaces;++p) {
+			out_mesh->mFaces[p] = vFaces[p];
+		}
+
+		// add the newly created mesh to the list
+		source_mesh_map.push_back(std::make_pair(out_mesh,a));
+
+		if (base == in_mesh->mNumFaces) {
+			break;
+		}
+	}
+
+	// delete the per-vertex weight list again
+	delete[] avPerVertexWeights;
+
+	// now delete the old mesh data
+	delete in_mesh;
+}

+ 61 - 0
code/Assjson/mesh_splitter.h

@@ -0,0 +1,61 @@
+/*
+Assimp2Json
+Copyright (c) 2011, Alexander C. Gessler
+
+Licensed under a 3-clause BSD license. See the LICENSE file for more information.
+
+*/
+
+#ifndef INCLUDED_MESH_SPLITTER
+#define INCLUDED_MESH_SPLITTER
+
+// ----------------------------------------------------------------------------
+// Note: this is largely based on assimp's SplitLargeMeshes_Vertex process.
+// it is refactored and the coding style is slightly improved, though.
+// ----------------------------------------------------------------------------
+
+#include <vector>
+
+struct aiScene;
+struct aiMesh;
+struct aiNode;
+
+// ---------------------------------------------------------------------------
+/** Splits meshes of unique vertices into meshes with no more vertices than
+ *  a given, configurable threshold value. 
+ */
+class MeshSplitter 
+{
+
+public:
+	
+	void SetLimit(unsigned int l) {
+		LIMIT = l;
+	}
+
+	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);
+
+
+private:
+
+	void UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map);
+	void SplitMesh (unsigned int index, aiMesh* mesh, std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map);
+
+public:
+
+	unsigned int LIMIT;
+};
+
+#endif // INCLUDED_MESH_SPLITTER
+

+ 4 - 2
code/AssxmlExporter.cpp → code/Assxml/AssxmlExporter.cpp

@@ -46,13 +46,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
 
-#include <stdarg.h>
+#include "PostProcessing/ProcessHelper.h"
+
 #include <assimp/version.h>
-#include "ProcessHelper.h"
 #include <assimp/IOStream.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/Exporter.hpp>
 
+#include <stdarg.h>
+
 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
 #   include <zlib.h>
 #else

+ 0 - 0
code/AssxmlExporter.h → code/Assxml/AssxmlExporter.h


+ 6 - 4
code/B3DImporter.cpp → code/B3D/B3DImporter.cpp

@@ -49,17 +49,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_B3D_IMPORTER
 
 // internal headers
-#include "B3DImporter.h"
-#include "TextureTransform.h"
-#include "ConvertToLHProcess.h"
+#include "B3D/B3DImporter.h"
+#include "PostProcessing/TextureTransform.h"
+#include "PostProcessing/ConvertToLHProcess.h"
+
 #include <assimp/StringUtils.h>
-#include <memory>
 #include <assimp/IOSystem.hpp>
 #include <assimp/anim.h>
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/importerdesc.h>
 
+#include <memory>
+
 using namespace Assimp;
 using namespace std;
 

+ 0 - 0
code/B3DImporter.h → code/B3D/B3DImporter.h


+ 0 - 0
code/BVHLoader.cpp → code/BVH/BVHLoader.cpp


+ 0 - 0
code/BVHLoader.h → code/BVH/BVHLoader.h


+ 0 - 0
code/BlenderBMesh.cpp → code/Blender/BlenderBMesh.cpp


+ 0 - 0
code/BlenderBMesh.h → code/Blender/BlenderBMesh.h


+ 0 - 0
code/BlenderCustomData.cpp → code/Blender/BlenderCustomData.cpp


+ 0 - 0
code/BlenderCustomData.h → code/Blender/BlenderCustomData.h


+ 0 - 0
code/BlenderDNA.cpp → code/Blender/BlenderDNA.cpp


+ 0 - 0
code/BlenderDNA.h → code/Blender/BlenderDNA.h


+ 0 - 0
code/BlenderDNA.inl → code/Blender/BlenderDNA.inl


+ 0 - 0
code/BlenderIntermediate.h → code/Blender/BlenderIntermediate.h


+ 27 - 0
code/BlenderLoader.cpp → code/Blender/BlenderLoader.cpp

@@ -1225,6 +1225,16 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
         case Lamp::Type_Local:
             out->mType = aiLightSource_POINT;
             break;
+        case Lamp::Type_Spot:
+            out->mType = aiLightSource_SPOT;
+
+            // blender orients directional lights as facing toward -z
+            out->mDirection = aiVector3D(0.f, 0.f, -1.f);
+            out->mUp = aiVector3D(0.f, 1.f, 0.f);
+
+            out->mAngleInnerCone = lamp->spotsize * (1.0f - lamp->spotblend);
+            out->mAngleOuterCone = lamp->spotsize;
+            break;
         case Lamp::Type_Sun:
             out->mType = aiLightSource_DIRECTIONAL;
 
@@ -1255,6 +1265,23 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
     out->mColorAmbient = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
     out->mColorSpecular = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
     out->mColorDiffuse = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
+
+    // If default values are supplied, compute the coefficients from light's max distance
+    // Read this: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
+    //
+    if (lamp->constant_coefficient == 1.0f && lamp->linear_coefficient == 0.0f && lamp->quadratic_coefficient == 0.0f && lamp->dist > 0.0f)
+    {
+        out->mAttenuationConstant = 1.0f;
+        out->mAttenuationLinear = 2.0f / lamp->dist;
+        out->mAttenuationQuadratic = 1.0f / (lamp->dist * lamp->dist);
+    }
+    else
+    {
+        out->mAttenuationConstant = lamp->constant_coefficient;
+        out->mAttenuationLinear = lamp->linear_coefficient;
+        out->mAttenuationQuadratic = lamp->quadratic_coefficient;
+    }
+
     return out.release();
 }
 

+ 0 - 0
code/BlenderLoader.h → code/Blender/BlenderLoader.h


+ 0 - 0
code/BlenderModifier.cpp → code/Blender/BlenderModifier.cpp


+ 0 - 0
code/BlenderModifier.h → code/Blender/BlenderModifier.h


+ 4 - 1
code/BlenderScene.cpp → code/Blender/BlenderScene.cpp

@@ -211,9 +211,12 @@ template <> void Structure :: Convert<Lamp> (
     ReadField<ErrorPolicy_Warn>(dest.b,"b",db);
     ReadField<ErrorPolicy_Warn>(dest.k,"k",db);
     ReadField<ErrorPolicy_Igno>(dest.energy,"energy",db);
-    ReadField<ErrorPolicy_Igno>(dest.dist,"dist",db);
+    ReadField<ErrorPolicy_Warn>(dest.dist,"dist",db);
     ReadField<ErrorPolicy_Igno>(dest.spotsize,"spotsize",db);
     ReadField<ErrorPolicy_Igno>(dest.spotblend,"spotblend",db);
+    ReadField<ErrorPolicy_Warn>(dest.constant_coefficient, "coeff_const", db);
+    ReadField<ErrorPolicy_Warn>(dest.linear_coefficient, "coeff_lin", db);
+    ReadField<ErrorPolicy_Warn>(dest.quadratic_coefficient, "coeff_quad", db);
     ReadField<ErrorPolicy_Igno>(dest.att1,"att1",db);
     ReadField<ErrorPolicy_Igno>(dest.att2,"att2",db);
     ReadField<ErrorPolicy_Igno>(temp,"falloff_type",db);

+ 4 - 0
code/BlenderScene.h → code/Blender/BlenderScene.h

@@ -538,6 +538,10 @@ struct Lamp : ElemBase {
       float energy, dist, spotsize, spotblend;
       //float haint;
 
+      float constant_coefficient;
+      float linear_coefficient;
+      float quadratic_coefficient;
+
       float att1, att2;
       //struct CurveMapping *curfalloff;
       FalloffType falloff_type;

+ 0 - 0
code/BlenderSceneGen.h → code/Blender/BlenderSceneGen.h


+ 0 - 0
code/BlenderTessellator.cpp → code/Blender/BlenderTessellator.cpp


+ 5 - 1
code/BlenderTessellator.h → code/Blender/BlenderTessellator.h

@@ -144,7 +144,11 @@ namespace Assimp
 
 #if ASSIMP_BLEND_WITH_POLY_2_TRI
 
-#include "../contrib/poly2tri/poly2tri/poly2tri.h"
+#ifdef ASSIMP_USE_HUNTER
+#  include <poly2tri/poly2tri.h>
+#else
+#  include "../contrib/poly2tri/poly2tri/poly2tri.h"
+#endif
 
 namespace Assimp
 {

+ 0 - 0
code/C4DImporter.cpp → code/C4D/C4DImporter.cpp


+ 0 - 0
code/C4DImporter.h → code/C4D/C4DImporter.h


+ 1 - 1
code/AssimpCExport.cpp → code/CApi/AssimpCExport.cpp

@@ -49,7 +49,7 @@ Assimp C export interface. See Exporter.cpp for some notes.
 
 #include "CInterfaceIOWrapper.h"
 #include <assimp/SceneCombiner.h>
-#include "ScenePrivate.h"
+#include "Common/ScenePrivate.h"
 #include <assimp/Exporter.hpp>
 
 using namespace Assimp;

+ 0 - 0
code/CInterfaceIOWrapper.cpp → code/CApi/CInterfaceIOWrapper.cpp


+ 0 - 0
code/CInterfaceIOWrapper.h → code/CApi/CInterfaceIOWrapper.h


File diff suppressed because it is too large
+ 379 - 365
code/CMakeLists.txt


+ 13 - 8
code/COBLoader.cpp → code/COB/COBLoader.cpp

@@ -45,20 +45,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #ifndef ASSIMP_BUILD_NO_COB_IMPORTER
-#include "COBLoader.h"
-#include "COBScene.h"
-#include "ConvertToLHProcess.h"
+#include "COB/COBLoader.h"
+#include "COB/COBScene.h"
+#include "PostProcessing/ConvertToLHProcess.h"
+
 #include <assimp/StreamReader.h>
 #include <assimp/ParsingUtils.h>
 #include <assimp/fast_atof.h>
 #include <assimp/LineSplitter.h>
 #include <assimp/TinyFormatter.h>
-#include <memory>
 #include <assimp/IOSystem.hpp>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/scene.h>
 #include <assimp/importerdesc.h>
 
+#include <memory>
+
 using namespace Assimp;
 using namespace Assimp::COB;
 using namespace Assimp::Formatter;
@@ -896,6 +898,7 @@ public:
     : nfo(nfo)
     , reader(reader)
     , cur(reader.GetCurrentPos()) {
+        // empty
     }
 
     ~chunk_guard() {
@@ -903,7 +906,7 @@ public:
         if(nfo.size != static_cast<unsigned int>(-1)) {
             try {
                 reader.IncPtr( static_cast< int >( nfo.size ) - reader.GetCurrentPos() + cur );
-            } catch (const DeadlyImportError& e ) {
+            } catch (const DeadlyImportError& ) {
                 // out of limit so correct the value
                 reader.IncPtr( reader.GetReadLimit() );
             }
@@ -911,15 +914,17 @@ public:
     }
 
 private:
-
     const COB::ChunkInfo& nfo;
     StreamReaderLE& reader;
     long cur;
 };
 
 // ------------------------------------------------------------------------------------------------
-void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader)
-{
+void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
+    if (nullptr == reader) {
+        return;
+    }
+
     while(1) {
         std::string type;
          type += reader -> GetI1()

+ 0 - 0
code/COBLoader.h → code/COB/COBLoader.h


+ 0 - 0
code/COBScene.h → code/COB/COBScene.h


+ 0 - 0
code/CSMLoader.cpp → code/CSM/CSMLoader.cpp


+ 0 - 0
code/CSMLoader.h → code/CSM/CSMLoader.h


+ 55 - 51
code/ColladaExporter.cpp → code/Collada/ColladaExporter.cpp

@@ -64,13 +64,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 
-namespace Assimp
-{
+namespace Assimp {
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
-void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
-{
+void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) {
     std::string path = DefaultIOSystem::absolutePath(std::string(pFile));
     std::string file = DefaultIOSystem::completeBaseName(std::string(pFile));
 
@@ -93,15 +91,15 @@ void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* p
 
 } // end of namespace Assimp
 
-
-
 // ------------------------------------------------------------------------------------------------
 // Constructor for a specific scene to export
-ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file)
-{
+ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) 
+: mIOSystem(pIOSystem)
+, mPath(path)
+, mFile(file) {
     // make sure that all formatting happens using the standard, C locale and not the user's current locale
     mOutput.imbue( std::locale("C") );
-    mOutput.precision(16);
+    mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
 
     mScene = pScene;
     mSceneOwned = false;
@@ -115,17 +113,15 @@ ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, co
 
 // ------------------------------------------------------------------------------------------------
 // Destructor
-ColladaExporter::~ColladaExporter()
-{
-    if(mSceneOwned) {
+ColladaExporter::~ColladaExporter() {
+    if ( mSceneOwned ) {
         delete mScene;
     }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Starts writing the contents
-void ColladaExporter::WriteFile()
-{
+void ColladaExporter::WriteFile() {
     // write the DTD
     mOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>" << endstr;
     // COLLADA element start
@@ -158,8 +154,7 @@ void ColladaExporter::WriteFile()
 
 // ------------------------------------------------------------------------------------------------
 // Writes the asset header
-void ColladaExporter::WriteHeader()
-{
+void ColladaExporter::WriteHeader() {
     static const ai_real epsilon = ai_real( 0.00001 );
     static const aiQuaternion x_rot(aiMatrix3x3(
         0, -1,  0,
@@ -240,51 +235,60 @@ void ColladaExporter::WriteHeader()
 
     // If no Scene metadata, use root node metadata
     aiMetadata* meta = mScene->mMetaData;
-    if (!meta)
+    if (nullptr == meta) {
         meta = mScene->mRootNode->mMetaData;
+    }
 
     aiString value;
-    if (!meta || !meta->Get("Author", value))
+    if (!meta || !meta->Get("Author", value)) {
         mOutput << startstr << "<author>" << "Assimp" << "</author>" << endstr;
-    else
+    } else {
         mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
+    }
 
-    if (!meta || !meta->Get("AuthoringTool", value))
+    if (nullptr == meta || !meta->Get("AuthoringTool", value)) {
         mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
-    else
+    } else {
         mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
+    }
 
-    if (meta)
-    {
-        if (meta->Get("Comments", value))
+    if (meta) {
+        if (meta->Get("Comments", value)) {
             mOutput << startstr << "<comments>" << XMLEscape(value.C_Str()) << "</comments>" << endstr;
-        if (meta->Get("Copyright", value))
+        }
+        if (meta->Get("Copyright", value)) {
             mOutput << startstr << "<copyright>" << XMLEscape(value.C_Str()) << "</copyright>" << endstr;
-        if (meta->Get("SourceData", value))
+        }
+        if (meta->Get("SourceData", value)) {
             mOutput << startstr << "<source_data>" << XMLEscape(value.C_Str()) << "</source_data>" << endstr;
+        }
     }
 
     PopTag();
     mOutput << startstr << "</contributor>" << endstr;
 
-    if (!meta || !meta->Get("Created", value))
+    if (nullptr == meta || !meta->Get("Created", value)) {
         mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
-    else
+    } else {
         mOutput << startstr << "<created>" << XMLEscape(value.C_Str()) << "</created>" << endstr;
+    }
 
     // Modified date is always the date saved
     mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr;
 
-    if (meta)
-    {
-        if (meta->Get("Keywords", value))
+    if (meta) {
+        if (meta->Get("Keywords", value)) {
             mOutput << startstr << "<keywords>" << XMLEscape(value.C_Str()) << "</keywords>" << endstr;
-        if (meta->Get("Revision", value))
+        }
+        if (meta->Get("Revision", value)) {
             mOutput << startstr << "<revision>" << XMLEscape(value.C_Str()) << "</revision>" << endstr;
-        if (meta->Get("Subject", value))
+        }
+        if (meta->Get("Subject", value)) {
             mOutput << startstr << "<subject>" << XMLEscape(value.C_Str()) << "</subject>" << endstr;
-        if (meta->Get("Title", value))
+        }
+        if (meta->Get("Title", value)) {
             mOutput << startstr << "<title>" << XMLEscape(value.C_Str()) << "</title>" << endstr;
+        }
     }
 
     mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr;
@@ -299,12 +303,15 @@ void ColladaExporter::WriteTextures() {
     static const unsigned int buffer_size = 1024;
     char str[buffer_size];
 
-    if(mScene->HasTextures()) {
+    if (mScene->HasTextures()) {
         for(unsigned int i = 0; i < mScene->mNumTextures; i++) {
             // It would be great to be able to create a directory in portable standard C++, but it's not the case,
             // so we just write the textures in the current directory.
 
             aiTexture* texture = mScene->mTextures[i];
+            if ( nullptr == texture ) {
+                continue;
+            }
 
             ASSIMP_itoa10(str, buffer_size, i + 1);
 
@@ -458,6 +465,7 @@ void ColladaExporter::WritePointLight(const aiLight *const light){
     mOutput << startstr << "</point>" << endstr;
 
 }
+
 void ColladaExporter::WriteDirectionalLight(const aiLight *const light){
     const aiColor3D &color=  light->mColorDiffuse;
     mOutput << startstr << "<directional>" << endstr;
@@ -470,6 +478,7 @@ void ColladaExporter::WriteDirectionalLight(const aiLight *const light){
     mOutput << startstr << "</directional>" << endstr;
 
 }
+
 void ColladaExporter::WriteSpotLight(const aiLight *const light){
 
     const aiColor3D &color=  light->mColorDiffuse;
@@ -526,18 +535,16 @@ void ColladaExporter::WriteAmbienttLight(const aiLight *const light){
 
 // ------------------------------------------------------------------------------------------------
 // Reads a single surface entry from the given material keys
-void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex)
-{
-  if( pSrcMat->GetTextureCount( pTexture) > 0 )
-  {
+void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, 
+                                          aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex) {
+  if( pSrcMat->GetTextureCount( pTexture) > 0 ) {
     aiString texfile;
     unsigned int uvChannel = 0;
     pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel);
 
     std::string index_str(texfile.C_Str());
 
-    if(index_str.size() != 0 && index_str[0] == '*')
-    {
+    if(index_str.size() != 0 && index_str[0] == '*') {
         unsigned int index;
 
         index_str = index_str.substr(1, std::string::npos);
@@ -555,15 +562,13 @@ void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial*
         } else {
             throw DeadlyExportError("could not find embedded texture at index " + index_str);
         }
-    } else
-    {
+    } else {
         poSurface.texture = texfile.C_Str();
     }
 
     poSurface.channel = uvChannel;
     poSurface.exist = true;
-  } else
-  {
+  } else {
     if( pKey )
       poSurface.exist = pSrcMat->Get( pKey, static_cast<unsigned int>(pType), static_cast<unsigned int>(pIndex), poSurface.color) == aiReturn_SUCCESS;
   }
@@ -571,15 +576,13 @@ void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial*
 
 // ------------------------------------------------------------------------------------------------
 // Reimplementation of isalnum(,C locale), because AppVeyor does not see standard version.
-static bool isalnum_C(char c)
-{
+static bool isalnum_C(char c) {
   return ( nullptr != strchr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",c) );
 }
 
 // ------------------------------------------------------------------------------------------------
 // Writes an image entry for the given surface
-void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd)
-{
+void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) {
   if( !pSurface.texture.empty() )
   {
     mOutput << startstr << "<image id=\"" << XMLEscape(pNameAdd) << "\">" << endstr;
@@ -833,8 +836,9 @@ void ColladaExporter::WriteControllerLibrary()
     mOutput << startstr << "<library_controllers>" << endstr;
     PushTag();
     
-    for( size_t a = 0; a < mScene->mNumMeshes; ++a)
+    for( size_t a = 0; a < mScene->mNumMeshes; ++a) {
         WriteController( a);
+    }
 
     PopTag();
     mOutput << startstr << "</library_controllers>" << endstr;
@@ -1667,4 +1671,4 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
 }
 
 #endif
-#endif
+#endif

+ 1 - 2
code/ColladaExporter.h → code/Collada/ColladaExporter.h

@@ -150,7 +150,6 @@ public:
     /// Stringstream to write all output into
     std::stringstream mOutput;
 
-protected:
     /// The IOSystem for output
     IOSystem* mIOSystem;
 
@@ -204,7 +203,7 @@ protected:
 
   std::map<unsigned int, std::string> textures;
 
-protected:
+public:
   /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
   /// Reads a single surface entry from the given material keys
   void ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex);

+ 0 - 0
code/ColladaHelper.h → code/Collada/ColladaHelper.h


+ 100 - 136
code/ColladaLoader.cpp → code/Collada/ColladaLoader.cpp

@@ -65,6 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "math.h"
 #include <algorithm>
 #include <numeric>
+#include <memory>
 
 using namespace Assimp;
 using namespace Assimp::Formatter;
@@ -126,7 +127,7 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
         if (!pIOHandler) {
             return true;
         }
-        const char* tokens[] = {"<collada"};
+        static const char* tokens[] = {"<collada"};
         return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
     }
 
@@ -134,8 +135,7 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
 }
 
 // ------------------------------------------------------------------------------------------------
-void ColladaLoader::SetupProperties(const Importer* pImp)
-{
+void ColladaLoader::SetupProperties(const Importer* pImp) {
     noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
     ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0;
     useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES,0) != 0;
@@ -143,8 +143,7 @@ void ColladaLoader::SetupProperties(const Importer* pImp)
 
 // ------------------------------------------------------------------------------------------------
 // Get file extension list
-const aiImporterDesc* ColladaLoader::GetInfo () const
-{
+const aiImporterDesc* ColladaLoader::GetInfo () const {
     return &desc;
 }
 
@@ -246,8 +245,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
 
 // ------------------------------------------------------------------------------------------------
 // Recursively constructs a scene node for the given parser node and returns it.
-aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode)
-{
+aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode) {
     // create a node for it
     aiNode* node = new aiNode();
 
@@ -265,15 +263,13 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla
     node->mNumChildren = static_cast<unsigned int>(pNode->mChildren.size()+instances.size());
     node->mChildren = new aiNode*[node->mNumChildren];
 
-    for( size_t a = 0; a < pNode->mChildren.size(); a++)
-    {
+    for( size_t a = 0; a < pNode->mChildren.size(); ++a) {
         node->mChildren[a] = BuildHierarchy( pParser, pNode->mChildren[a]);
         node->mChildren[a]->mParent = node;
     }
 
     // ... and finally the resolved node instances
-    for( size_t a = 0; a < instances.size(); a++)
-    {
+    for( size_t a = 0; a < instances.size(); ++a) {
         node->mChildren[pNode->mChildren.size() + a] = BuildHierarchy( pParser, instances[a]);
         node->mChildren[pNode->mChildren.size() + a]->mParent = node;
     }
@@ -286,20 +282,19 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla
 
     // construct lights
     BuildLightsForNode(pParser, pNode, node);
+    
     return node;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Resolve node instances
 void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
-    std::vector<const Collada::Node*>& resolved)
-{
+        std::vector<const Collada::Node*>& resolved) {
     // reserve enough storage
     resolved.reserve(pNode->mNodeInstances.size());
 
     // ... and iterate through all nodes to be instanced as children of pNode
-    for (const auto &nodeInst: pNode->mNodeInstances)
-    {
+    for (const auto &nodeInst: pNode->mNodeInstances) {
         // find the corresponding node in the library
         const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find(nodeInst.mNode);
         const Collada::Node* nd = itt == pParser.mNodeLibrary.end() ? NULL : (*itt).second;
@@ -323,12 +318,12 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
 // ------------------------------------------------------------------------------------------------
 // Resolve UV channels
 void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
-     const Collada::SemanticMappingTable& table)
-{
+     const Collada::SemanticMappingTable& table) {
     std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
     if (it != table.mMap.end()) {
-        if (it->second.mType != Collada::IT_Texcoord)
+        if (it->second.mType != Collada::IT_Texcoord) {
             ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
+        }
 
         sampler.mUVId = it->second.mSet;
     }
@@ -336,14 +331,11 @@ void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler
 
 // ------------------------------------------------------------------------------------------------
 // Builds lights for the given node and references them
-void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget)
-{
-    for( const Collada::LightInstance& lid : pNode->mLights)
-    {
+void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) {
+    for( const Collada::LightInstance& lid : pNode->mLights) {
         // find the referred light
         ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find( lid.mLight);
-        if( srcLightIt == pParser.mLightLibrary.end())
-        {
+        if( srcLightIt == pParser.mLightLibrary.end()) {
             ASSIMP_LOG_WARN_F("Collada: Unable to find light for ID \"" , lid.mLight , "\". Skipping.");
             continue;
         }
@@ -365,8 +357,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
         if (out->mType == aiLightSource_AMBIENT) {
             out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0);
             out->mColorAmbient = srcLight->mColor*srcLight->mIntensity;
-        }
-        else {
+        } else {
             // collada doesn't differentiate between these color types
             out->mColorDiffuse = out->mColorSpecular = srcLight->mColor*srcLight->mIntensity;
             out->mColorAmbient = aiColor3D(0, 0, 0);
@@ -374,27 +365,24 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
 
         // convert falloff angle and falloff exponent in our representation, if given
         if (out->mType == aiLightSource_SPOT) {
-
             out->mAngleInnerCone = AI_DEG_TO_RAD( srcLight->mFalloffAngle );
 
             // ... some extension magic.
-            if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f))
-            {
+            if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f)) {
                 // ... some deprecation magic.
-                if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f))
-                {
+                if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f)) {
                     // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
                     // epsilon chosen to be 0.1
                     out->mAngleOuterCone = std::acos(std::pow(0.1f,1.f/srcLight->mFalloffExponent))+
                             out->mAngleInnerCone;
-                }
-                else {
+                } else {
                     out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(  srcLight->mPenumbraAngle );
                     if (out->mAngleOuterCone < out->mAngleInnerCone)
                         std::swap(out->mAngleInnerCone,out->mAngleOuterCone);
                 }
+            } else {
+                out->mAngleOuterCone = AI_DEG_TO_RAD(  srcLight->mOuterAngle );
             }
-            else out->mAngleOuterCone = AI_DEG_TO_RAD(  srcLight->mOuterAngle );
         }
 
         // add to light list
@@ -404,14 +392,11 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
 
 // ------------------------------------------------------------------------------------------------
 // Builds cameras for the given node and references them
-void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget)
-{
-    for( const Collada::CameraInstance& cid : pNode->mCameras)
-    {
+void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) {
+    for( const Collada::CameraInstance& cid : pNode->mCameras) {
         // find the referred light
         ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find( cid.mCamera);
-        if( srcCameraIt == pParser.mCameraLibrary.end())
-        {
+        if( srcCameraIt == pParser.mCameraLibrary.end()) {
             ASSIMP_LOG_WARN_F("Collada: Unable to find camera for ID \"" , cid.mCamera , "\". Skipping.");
             continue;
         }
@@ -435,8 +420,9 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
 
         // ... but for the rest some values are optional
         // and we need to compute the others in any combination.
-         if (srcCamera->mAspect != 10e10f)
+        if (srcCamera->mAspect != 10e10f) {
             out->mAspect = srcCamera->mAspect;
+        }
 
         if (srcCamera->mHorFov != 10e10f) {
             out->mHorizontalFOV = srcCamera->mHorFov;
@@ -461,77 +447,69 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
 
 // ------------------------------------------------------------------------------------------------
 // Builds meshes for the given node and references them
-void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget)
-{
+void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) {
     // accumulated mesh references by this node
     std::vector<size_t> newMeshRefs;
     newMeshRefs.reserve(pNode->mMeshes.size());
 
     // add a mesh for each subgroup in each collada mesh
-    for( const Collada::MeshInstance& mid : pNode->mMeshes)
-    {
-        const Collada::Mesh* srcMesh = NULL;
-        const Collada::Controller* srcController = NULL;
+    for( const Collada::MeshInstance& mid : pNode->mMeshes) {
+        const Collada::Mesh* srcMesh = nullptr;
+        const Collada::Controller* srcController = nullptr;
 
         // find the referred mesh
         ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find( mid.mMeshOrController);
-        if( srcMeshIt == pParser.mMeshLibrary.end())
-        {
+        if( srcMeshIt == pParser.mMeshLibrary.end()) {
             // if not found in the mesh-library, it might also be a controller referring to a mesh
             ColladaParser::ControllerLibrary::const_iterator srcContrIt = pParser.mControllerLibrary.find( mid.mMeshOrController);
-            if( srcContrIt != pParser.mControllerLibrary.end())
-            {
+            if( srcContrIt != pParser.mControllerLibrary.end()) {
                 srcController = &srcContrIt->second;
                 srcMeshIt = pParser.mMeshLibrary.find( srcController->mMeshId);
-                if( srcMeshIt != pParser.mMeshLibrary.end())
+                if( srcMeshIt != pParser.mMeshLibrary.end()) {
                     srcMesh = srcMeshIt->second;
+                }
             }
 
-            if( !srcMesh)
-            {
+            if( !srcMesh) {
                 ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." );
                 continue;
             }
-        } else
-        {
+        } else {
             // ID found in the mesh library -> direct reference to an unskinned mesh
             srcMesh = srcMeshIt->second;
         }
 
         // build a mesh for each of its subgroups
         size_t vertexStart = 0, faceStart = 0;
-        for( size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm)
-        {
+        for( size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm) {
             const Collada::SubMesh& submesh = srcMesh->mSubMeshes[sm];
-            if( submesh.mNumFaces == 0)
+            if( submesh.mNumFaces == 0) {
                 continue;
+            }
 
             // find material assigned to this submesh
             std::string meshMaterial;
             std::map<std::string, Collada::SemanticMappingTable >::const_iterator meshMatIt = mid.mMaterials.find( submesh.mMaterial);
 
-            const Collada::SemanticMappingTable* table = NULL;
-            if( meshMatIt != mid.mMaterials.end())
-            {
+            const Collada::SemanticMappingTable* table = nullptr;
+            if( meshMatIt != mid.mMaterials.end()) {
                 table = &meshMatIt->second;
                 meshMaterial = table->mMatName;
-            }
-            else
-            {
+            } else {
                 ASSIMP_LOG_WARN_F( "Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <",
                     mid.mMeshOrController, ">." );
-                if( !mid.mMaterials.empty() )
+                if( !mid.mMaterials.empty() ) {
                     meshMaterial = mid.mMaterials.begin()->second.mMatName;
+                }
             }
 
             // OK ... here the *real* fun starts ... we have the vertex-input-to-effect-semantic-table
             // given. The only mapping stuff which we do actually support is the UV channel.
             std::map<std::string, size_t>::const_iterator matIt = mMaterialIndexByName.find( meshMaterial);
-            unsigned int matIdx;
-            if( matIt != mMaterialIndexByName.end())
+            unsigned int matIdx = 0;
+            if( matIt != mMaterialIndexByName.end()) {
                 matIdx = static_cast<unsigned int>(matIt->second);
-            else
-                matIdx = 0;
+            }
 
             if (table && !table->mMap.empty() ) {
                 std::pair<Collada::Effect*, aiMaterial*>&  mat = newMats[matIdx];
@@ -553,9 +531,7 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
             std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find( index);
             if( dstMeshIt != mMeshIndexByID.end())  {
                 newMeshRefs.push_back( dstMeshIt->second);
-            }
-            else
-            {
+            } else {
                 // else we have to add the mesh to the collection and store its newly assigned index at the node
                 aiMesh* dstMesh = CreateMesh( pParser, srcMesh, submesh, srcController, vertexStart, faceStart);
 
@@ -567,22 +543,18 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
 
                 // assign the material index
                 dstMesh->mMaterialIndex = matIdx;
-                if(dstMesh->mName.length == 0)
-                {
+                if(dstMesh->mName.length == 0) {
                     dstMesh->mName = mid.mMeshOrController;
                 }
-      }
+            }
         }
     }
 
     // now place all mesh references we gathered in the target node
     pTarget->mNumMeshes = static_cast<unsigned int>(newMeshRefs.size());
-    if( newMeshRefs.size())
-    {
-        struct UIntTypeConverter
-        {
-            unsigned int operator()(const size_t& v) const
-            {
+    if( newMeshRefs.size()) {
+        struct UIntTypeConverter {
+            unsigned int operator()(const size_t& v) const {
                 return static_cast<unsigned int>(v);
             }
         };
@@ -594,25 +566,27 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
 
 // ------------------------------------------------------------------------------------------------
 // Find mesh from either meshes or morph target meshes
-aiMesh *ColladaLoader::findMesh(std::string meshid)
-{
-    for (unsigned int i = 0; i < mMeshes.size(); i++)
-        if (std::string(mMeshes[i]->mName.data) == meshid)
+aiMesh *ColladaLoader::findMesh(std::string meshid) {
+    for (unsigned int i = 0; i < mMeshes.size(); ++i ) {
+        if (std::string(mMeshes[i]->mName.data) == meshid) {
             return mMeshes[i];
+        }
+    }
 
-    for (unsigned int i = 0; i < mTargetMeshes.size(); i++)
-        if (std::string(mTargetMeshes[i]->mName.data) == meshid)
+    for (unsigned int i = 0; i < mTargetMeshes.size(); ++i ) {
+        if (std::string(mTargetMeshes[i]->mName.data) == meshid) {
             return mTargetMeshes[i];
-
-    return NULL;
+        }
+    }
+    
+    return nullptr;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh
 aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
-    const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace)
-{
-    aiMesh* dstMesh = new aiMesh;
+        const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace) {
+    std::unique_ptr<aiMesh> dstMesh(new aiMesh);
 
     dstMesh->mName = pSrcMesh->mName;
 
@@ -629,24 +603,21 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
     // normals, if given. HACK: (thom) Due to the glorious Collada spec we never
     // know if we have the same number of normals as there are positions. So we
     // also ignore any vertex attribute if it has a different count
-    if( pSrcMesh->mNormals.size() >= pStartVertex + numVertices)
-    {
+    if( pSrcMesh->mNormals.size() >= pStartVertex + numVertices) {
         dstMesh->mNormals = new aiVector3D[numVertices];
         std::copy( pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() +
             pStartVertex + numVertices, dstMesh->mNormals);
     }
 
     // tangents, if given.
-    if( pSrcMesh->mTangents.size() >= pStartVertex + numVertices)
-    {
+    if( pSrcMesh->mTangents.size() >= pStartVertex + numVertices) {
         dstMesh->mTangents = new aiVector3D[numVertices];
         std::copy( pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() +
             pStartVertex + numVertices, dstMesh->mTangents);
     }
 
     // bitangents, if given.
-    if( pSrcMesh->mBitangents.size() >= pStartVertex + numVertices)
-    {
+    if( pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) {
         dstMesh->mBitangents = new aiVector3D[numVertices];
         std::copy( pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() +
             pStartVertex + numVertices, dstMesh->mBitangents);
@@ -654,13 +625,12 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
 
     // same for texturecoords, as many as we have
     // empty slots are not allowed, need to pack and adjust UV indexes accordingly
-    for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)
-    {
-        if( pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices)
-        {
+    for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) {
+        if( pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) {
             dstMesh->mTextureCoords[real] = new aiVector3D[numVertices];
-            for( size_t b = 0; b < numVertices; ++b)
+            for( size_t b = 0; b < numVertices; ++b) {
                 dstMesh->mTextureCoords[real][b] = pSrcMesh->mTexCoords[a][pStartVertex+b];
+            }
 
             dstMesh->mNumUVComponents[real] = pSrcMesh->mNumUVComponents[a];
             ++real;
@@ -668,10 +638,8 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
     }
 
     // same for vertex colors, as many as we have. again the same packing to avoid empty slots
-    for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++)
-    {
-        if( pSrcMesh->mColors[a].size() >= pStartVertex + numVertices)
-        {
+    for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) {
+        if( pSrcMesh->mColors[a].size() >= pStartVertex + numVertices) {
             dstMesh->mColors[real] = new aiColor4D[numVertices];
             std::copy( pSrcMesh->mColors[a].begin() + pStartVertex, pSrcMesh->mColors[a].begin() + pStartVertex + numVertices,dstMesh->mColors[real]);
             ++real;
@@ -682,14 +650,14 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
     size_t vertex = 0;
     dstMesh->mNumFaces = static_cast<unsigned int>(pSubMesh.mNumFaces);
     dstMesh->mFaces = new aiFace[dstMesh->mNumFaces];
-    for( size_t a = 0; a < dstMesh->mNumFaces; ++a)
-    {
+    for( size_t a = 0; a < dstMesh->mNumFaces; ++a) {
         size_t s = pSrcMesh->mFaceSize[ pStartFace + a];
         aiFace& face = dstMesh->mFaces[a];
         face.mNumIndices = static_cast<unsigned int>(s);
         face.mIndices = new unsigned int[s];
-        for( size_t b = 0; b < s; ++b)
+        for( size_t b = 0; b < s; ++b) {
             face.mIndices[b] = static_cast<unsigned int>(vertex++);
+        }
     }
 
     // create morph target meshes if any
@@ -697,14 +665,12 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
     std::vector<float> targetWeights;
     Collada::MorphMethod method = Collada::Normalized;
 
-    for(std::map<std::string, Collada::Controller>::const_iterator it = pParser.mControllerLibrary.begin();
-        it != pParser.mControllerLibrary.end(); it++)
-    {
+    for(std::map<std::string, Collada::Controller>::const_iterator it = pParser.mControllerLibrary.begin(); 
+            it != pParser.mControllerLibrary.end(); it++) {
         const Collada::Controller &c = it->second;
         const Collada::Mesh* baseMesh = pParser.ResolveLibraryReference( pParser.mMeshLibrary, c.mMeshId);
 
-        if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName)
-        {
+        if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) {
             const Collada::Accessor& targetAccessor = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, c.mMorphTarget);
             const Collada::Accessor& weightAccessor = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, c.mMorphWeight);
             const Collada::Data& targetData = pParser.ResolveLibraryReference( pParser.mDataLibrary, targetAccessor.mSource);
@@ -713,34 +679,34 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
             // take method
             method = c.mMethod;
 
-            if (!targetData.mIsStringArray)
+            if (!targetData.mIsStringArray) {
                 throw DeadlyImportError( "target data must contain id. ");
-            if (weightData.mIsStringArray)
+            }
+            if (weightData.mIsStringArray) {
                 throw DeadlyImportError( "target weight data must not be textual ");
+            }
 
-            for (unsigned int i = 0; i < targetData.mStrings.size(); ++i)
-            {
+            for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) {
                 const Collada::Mesh* targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i));
 
                 aiMesh *aimesh = findMesh(targetMesh->mName);
-                if (!aimesh)
-                {
-                    if (targetMesh->mSubMeshes.size() > 1)
+                if (!aimesh) {
+                    if (targetMesh->mSubMeshes.size() > 1) {
                         throw DeadlyImportError( "Morhing target mesh must be a single");
+                    }
                     aimesh = CreateMesh(pParser, targetMesh, targetMesh->mSubMeshes.at(0), NULL, 0, 0);
                     mTargetMeshes.push_back(aimesh);
                 }
                 targetMeshes.push_back(aimesh);
             }
-            for (unsigned int i = 0; i < weightData.mValues.size(); ++i)
+            for (unsigned int i = 0; i < weightData.mValues.size(); ++i) {
                 targetWeights.push_back(weightData.mValues.at(i));
+            }
         }
     }
-    if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size())
-    {
+    if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size()) {
         std::vector<aiAnimMesh*> animMeshes;
-        for (unsigned int i = 0; i < targetMeshes.size(); i++)
-        {
+        for (unsigned int i = 0; i < targetMeshes.size(); ++i ) {
             aiMesh* targetMesh = targetMeshes.at(i);
             aiAnimMesh *animMesh = aiCreateAnimMesh(targetMesh);
             float weight = targetWeights[i];
@@ -753,13 +719,13 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
                                 : aiMorphingMethod_MORPH_NORMALIZED;
         dstMesh->mAnimMeshes = new aiAnimMesh*[animMeshes.size()];
         dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size());
-        for (unsigned int i = 0; i < animMeshes.size(); i++)
+        for (unsigned int i = 0; i < animMeshes.size(); ++i ) {
             dstMesh->mAnimMeshes[i] = animMeshes.at(i);
+        }
     }
 
     // create bones if given
-    if( pSrcController && pSrcController->mType == Collada::Skin)
-    {
+    if( pSrcController && pSrcController->mType == Collada::Skin) {
         // resolve references - joint names
         const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointNameSource);
         const Collada::Data& jointNames = pParser.ResolveLibraryReference( pParser.mDataLibrary, jointNamesAcc.mSource);
@@ -790,15 +756,13 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
         weightStartPerVertex.resize(pSrcController->mWeightCounts.size(),pSrcController->mWeights.end());
 
         IndexPairVector::const_iterator pit = pSrcController->mWeights.begin();
-        for( size_t a = 0; a < pSrcController->mWeightCounts.size(); ++a)
-        {
+        for( size_t a = 0; a < pSrcController->mWeightCounts.size(); ++a) {
             weightStartPerVertex[a] = pit;
             pit += pSrcController->mWeightCounts[a];
         }
 
         // now for each vertex put the corresponding vertex weights into each bone's weight collection
-        for( size_t a = pStartVertex; a < pStartVertex + numVertices; ++a)
-        {
+        for( size_t a = pStartVertex; a < pStartVertex + numVertices; ++a) {
             // which position index was responsible for this vertex? that's also the index by which
             // the controller assigns the vertex weights
             size_t orgIndex = pSrcMesh->mFacePosIndices[a];
@@ -898,7 +862,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
         }
     }
 
-    return dstMesh;
+    return dstMesh.release();
 }
 
 // ------------------------------------------------------------------------------------------------

+ 0 - 0
code/ColladaLoader.h → code/Collada/ColladaLoader.h


+ 1 - 3
code/ColladaParser.cpp → code/Collada/ColladaParser.cpp

@@ -323,10 +323,8 @@ void ColladaParser::ReadMetaDataItem(StringMetaData &metadata)
             aiString aistr;
             aistr.Set(value_char);
             metadata.emplace(camel_key_str, aistr);
-            TestClosing(key_str.c_str());
         }
-        else
-            SkipElement();
+        TestClosing(key_str.c_str());
     }
     else
         SkipElement();

+ 0 - 0
code/ColladaParser.h → code/Collada/ColladaParser.h


+ 1 - 1
code/Assimp.cpp → code/Common/Assimp.cpp

@@ -54,7 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Exceptional.h>
 #include <assimp/BaseImporter.h>
 
-#include "CInterfaceIOWrapper.h"
+#include "CApi/CInterfaceIOWrapper.h"
 #include "Importer.h"
 #include "ScenePrivate.h"
 

+ 5 - 1
code/BaseImporter.cpp → code/Common/BaseImporter.cpp

@@ -320,7 +320,11 @@ std::string BaseImporter::GetExtension( const std::string& file ) {
     return false;
 }
 
-#include "../contrib/utf8cpp/source/utf8.h"
+#ifdef ASSIMP_USE_HUNTER
+#  include <utf8/utf8.h>
+#else
+#  include "../contrib/utf8cpp/source/utf8.h"
+#endif
 
 // ------------------------------------------------------------------------------------------------
 // Convert to UTF8 data

+ 1 - 1
code/BaseProcess.cpp → code/Common/BaseProcess.cpp

@@ -89,7 +89,7 @@ void BaseProcess::ExecuteOnScene( Importer* pImp)
 
         // and kill the partially imported data
         delete pImp->Pimpl()->mScene;
-        pImp->Pimpl()->mScene = NULL;
+        pImp->Pimpl()->mScene = nullptr;
     }
 }
 

+ 0 - 0
code/BaseProcess.h → code/Common/BaseProcess.h


+ 0 - 0
code/Bitmap.cpp → code/Common/Bitmap.cpp


+ 0 - 4
code/CreateAnimMesh.cpp → code/Common/CreateAnimMesh.cpp

@@ -47,10 +47,6 @@ namespace Assimp    {
 aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
 {
     aiAnimMesh *animesh = new aiAnimMesh;
-    animesh->mVertices = NULL;
-    animesh->mNormals = NULL;
-    animesh->mTangents = NULL;
-    animesh->mBitangents = NULL;
     animesh->mNumVertices = mesh->mNumVertices;
     if (mesh->mVertices) {
         animesh->mVertices = new aiVector3D[animesh->mNumVertices];

+ 0 - 0
code/DefaultIOStream.cpp → code/Common/DefaultIOStream.cpp


+ 0 - 0
code/DefaultIOSystem.cpp → code/Common/DefaultIOSystem.cpp


+ 0 - 0
code/DefaultLogger.cpp → code/Common/DefaultLogger.cpp


+ 0 - 0
code/DefaultProgressHandler.h → code/Common/DefaultProgressHandler.h


+ 15 - 9
code/Exporter.cpp → code/Common/Exporter.cpp

@@ -61,15 +61,16 @@ Here we implement only the C++ interface (Assimp::Exporter).
 #include <assimp/mesh.h>
 #include <assimp/postprocess.h>
 #include <assimp/scene.h>
-
-#include "DefaultProgressHandler.h"
-#include "BaseProcess.h"
-#include "JoinVerticesProcess.h"
-#include "MakeVerboseFormat.h"
-#include "ConvertToLHProcess.h"
-#include "PretransformVertices.h"
 #include <assimp/Exceptional.h>
-#include "ScenePrivate.h"
+
+#include "Common/DefaultProgressHandler.h"
+#include "Common/BaseProcess.h"
+#include "Common/ScenePrivate.h"
+#include "PostProcessing/CalcTangentsProcess.h"
+#include "PostProcessing/MakeVerboseFormat.h"
+#include "PostProcessing/JoinVerticesProcess.h"
+#include "PostProcessing/ConvertToLHProcess.h"
+#include "PostProcessing/PretransformVertices.h"
 
 #include <memory>
 
@@ -101,6 +102,7 @@ void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperti
 void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
+void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
 
 // ------------------------------------------------------------------------------------------------
 // global array of all export formats which Assimp supports in its current build
@@ -178,7 +180,11 @@ Exporter::ExportFormatEntry gExporters[] =
 #endif
 
 #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
-    Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 )
+    Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ),
+#endif
+
+#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
+    Exporter::ExportFormatEntry("json", "Plain JSON representation of the Assimp scene data structure", "json", &ExportAssimp2Json, 0)
 #endif
 };
 

+ 0 - 0
code/FileLogStream.h → code/Common/FileLogStream.h


+ 0 - 0
code/FileSystemFilter.h → code/Common/FileSystemFilter.h


+ 0 - 0
code/IFF.h → code/Common/IFF.h


+ 11 - 8
code/Importer.cpp → code/Common/Importer.cpp

@@ -64,15 +64,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // ------------------------------------------------------------------------------------------------
 // Internal headers
 // ------------------------------------------------------------------------------------------------
-#include "Importer.h"
-#include <assimp/BaseImporter.h>
-#include "BaseProcess.h"
+#include "Common/Importer.h"
+#include "Common/BaseProcess.h"
+#include "Common/DefaultProgressHandler.h"
+#include "PostProcessing/ProcessHelper.h"
+#include "Common/ScenePreprocessor.h"
+#include "Common/ScenePrivate.h"
 
-#include "DefaultProgressHandler.h"
+#include <assimp/BaseImporter.h>
 #include <assimp/GenericProperty.h>
-#include "ProcessHelper.h"
-#include "ScenePreprocessor.h"
-#include "ScenePrivate.h"
 #include <assimp/MemoryIOWrapper.h>
 #include <assimp/Profiler.h>
 #include <assimp/TinyFormatter.h>
@@ -86,7 +86,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/DefaultIOSystem.h>
 
 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
-#   include "ValidateDataStructure.h"
+#   include "PostProcessing/ValidateDataStructure.h"
 #endif
 
 using namespace Assimp::Profiling;
@@ -590,10 +590,12 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 
         // Find an worker class which can handle the file
         BaseImporter* imp = NULL;
+        SetPropertyInteger("importerIndex", -1);
         for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
 
             if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
                 imp = pimpl->mImporter[a];
+                SetPropertyInteger("importerIndex", a);
                 break;
             }
         }
@@ -606,6 +608,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
                 for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
                     if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
                         imp = pimpl->mImporter[a];
+                        SetPropertyInteger("importerIndex", a);
                         break;
                     }
                 }

+ 0 - 0
code/Importer.h → code/Common/Importer.h


Some files were not shown because too many files changed in this diff