Browse Source

closes https://github.com/assimp/assimp/issues/340: start integrating assimp2json.

kkulling 6 years ago
parent
commit
b463ddd399
100 changed files with 2742 additions and 579 deletions
  1. 7 0
      .gitignore
  2. 161 74
      CMakeLists.txt
  3. 7 2
      Readme.md
  4. 70 34
      assimpTargets-debug.cmake.in
  5. 69 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. 853 0
      code/Assjson/json_exporter.cpp
  42. 327 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. 0 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. 0 0
      code/Blender/BlenderScene.cpp
  63. 0 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. 6 4
      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. 2 2
      code/Collada/ColladaExporter.cpp
  79. 1 2
      code/Collada/ColladaExporter.h
  80. 0 0
      code/Collada/ColladaHelper.h
  81. 0 0
      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 0
      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. 9 8
      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

+ 161 - 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 5)
-SET (ASSIMP_VERSION_MINOR 0)
-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")
@@ -258,7 +287,7 @@ ELSE()
   # Experimental for pdb generation
 ENDIF()
 
-ENDIF( IOS )
+ENDIF( IOS AND NOT HUNTER_ENABLED)
 
 IF (ASSIMP_COVERALLS)
   MESSAGE(STATUS "Coveralls enabled")
@@ -325,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 )
 
@@ -353,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 )
@@ -468,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
 )

+ 69 - 33
assimpTargets-release.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_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}"
+    # 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}" )
+    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_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()
 
 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.
@@ -58,7 +89,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}")
@@ -73,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 */

+ 853 - 0
code/Assjson/json_exporter.cpp

@@ -0,0 +1,853 @@
+/*
+Assimp2Json
+Copyright (c) 2011, Alexander C. Gessler
+
+Licensed under a 3-clause BSD license. See the LICENSE file for more information.
+
+*/
+
+#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 {
+void Assimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
+}
+
+Assimp::Exporter::ExportFormatEntry Assimp2Json_desc = Assimp::Exporter::ExportFormatEntry(
+	"assimp.json",
+	"Plain JSON representation of the Assimp scene data structure",
+	"assimp.json",
+	Assimp2Json,
+	0u);
+
+namespace {
+
+
+	// small utility class to simplify serializing the aiScene to Json
+class JSONWriter
+{
+
+public:
+
+	enum {
+		Flag_DoNotIndent = 0x1,
+		Flag_WriteSpecialFloats = 0x2,
+	};
+
+public:
+
+	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();
+	}
+
+public:
+
+	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 Assimp2Json(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);
+}
+
+} // 

+ 327 - 0
code/Assjson/mesh_splitter.cpp

@@ -0,0 +1,327 @@
+/*
+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 NULL;
+	}
+
+	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


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


+ 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


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


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


+ 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


+ 6 - 4
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;

+ 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


+ 2 - 2
code/ColladaExporter.cpp → code/Collada/ColladaExporter.cpp

@@ -99,7 +99,7 @@ ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, co
 , 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;
@@ -1671,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


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


+ 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 - 0
code/CreateAnimMesh.cpp → code/Common/CreateAnimMesh.cpp


+ 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


+ 9 - 8
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>
 

+ 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