Browse Source

Merge branch 'master' into export_3mf

Kim Kulling 7 years ago
parent
commit
9ca7b00280
100 changed files with 3488 additions and 464 deletions
  1. 15 0
      .travis.sh
  2. 12 6
      .travis.yml
  3. 5 2
      CMakeLists.txt
  4. 2 2
      cmake-modules/CoverallsGenerateGcov.cmake
  5. 2 2
      code/AMFImporter.hpp
  6. 1 1
      code/AMFImporter_Node.hpp
  7. 5 2
      code/AMFImporter_Postprocess.cpp
  8. 1 0
      code/ASELoader.cpp
  9. 1 0
      code/AssbinExporter.cpp
  10. 2 2
      code/Bitmap.cpp
  11. 6 0
      code/BlenderDNA.h
  12. 31 12
      code/BlenderScene.cpp
  13. 8 0
      code/BlenderScene.h
  14. 254 6
      code/ColladaExporter.cpp
  15. 8 1
      code/ColladaExporter.h
  16. 1 1
      code/ColladaHelper.h
  17. 1 1
      code/ColladaLoader.cpp
  18. 1 1
      code/ColladaParser.cpp
  19. 1 1
      code/ColladaParser.h
  20. 0 1
      code/DefaultIOSystem.cpp
  21. 0 1
      code/FBXBinaryTokenizer.cpp
  22. 10 5
      code/FBXConverter.cpp
  23. 19 13
      code/FIReader.cpp
  24. 17 4
      code/FIReader.hpp
  25. 76 36
      code/FindDegenerates.cpp
  26. 40 19
      code/FindDegenerates.h
  27. 1 40
      code/IFCOpenings.cpp
  28. 1 1
      code/IRRLoader.cpp
  29. 0 4
      code/Importer.cpp
  30. 1 0
      code/ImproveCacheLocality.cpp
  31. 1 3
      code/LWOAnimation.cpp
  32. 1 1
      code/LWOMaterial.cpp
  33. 1 1
      code/LWSLoader.cpp
  34. 3 5
      code/MD2Loader.cpp
  35. 3 1
      code/MDLMaterialLoader.cpp
  36. 11 8
      code/NFFLoader.cpp
  37. 5 4
      code/ObjExporter.cpp
  38. 1 1
      code/OgreMaterial.cpp
  39. 2 0
      code/OpenGEXImporter.cpp
  40. 6 4
      code/OptimizeGraph.cpp
  41. 1 2
      code/PlyParser.cpp
  42. 1 1
      code/RawLoader.cpp
  43. 3 0
      code/RemoveRedundantMaterials.cpp
  44. 2 0
      code/SIBImporter.cpp
  45. 1 1
      code/STEPFileEncoding.cpp
  46. 53 39
      code/STLLoader.cpp
  47. 34 26
      code/STLLoader.h
  48. 10 9
      code/Subdivision.h
  49. 1 4
      code/TerragenLoader.cpp
  50. 1 1
      code/TextureTransform.cpp
  51. 4 4
      code/ValidateDataStructure.cpp
  52. 1 1
      code/ValidateDataStructure.h
  53. 6 2
      code/X3DExporter.cpp
  54. 2 2
      code/X3DExporter.hpp
  55. 3 3
      code/X3DImporter.hpp
  56. 7 0
      code/X3DImporter_Postprocess.cpp
  57. 1 4
      code/XFileImporter.h
  58. 3 3
      code/fast_atof.h
  59. 31 6
      code/glTF2Asset.h
  60. 140 13
      code/glTF2Asset.inl
  61. 3 4
      code/glTF2AssetWriter.inl
  62. 29 5
      code/glTF2Exporter.cpp
  63. 4 4
      code/glTF2Importer.cpp
  64. 1 1
      code/glTFAsset.inl
  65. 1 1
      code/glTFExporter.cpp
  66. 2 0
      contrib/Open3DGC/o3dgcArithmeticCodec.cpp
  67. 6 3
      contrib/Open3DGC/o3dgcBinaryStream.h
  68. 96 0
      contrib/android-cmake/AndroidNdkGdb.cmake
  69. 58 0
      contrib/android-cmake/AndroidNdkModules.cmake
  70. 240 0
      contrib/android-cmake/README.md
  71. 1693 0
      contrib/android-cmake/android.toolchain.cmake
  72. 211 0
      contrib/android-cmake/ndk_links.md
  73. 3 0
      contrib/clipper/clipper.cpp
  74. 2 4
      contrib/openddlparser/code/OpenDDLExport.cpp
  75. 14 12
      contrib/openddlparser/code/OpenDDLParser.cpp
  76. 4 8
      contrib/unzip/unzip.c
  77. 2 0
      contrib/zlib/zconf.h.included
  78. 1 1
      doc/Doxyfile.in
  79. 5 5
      doc/dox.h
  80. 10 1
      include/assimp/config.h.in
  81. 4 5
      include/assimp/vector3.h
  82. 1 1
      port/PyAssimp/pyassimp/structs.py
  83. 1 1
      port/PyAssimp/scripts/3d_viewer.py
  84. 1 1
      port/PyAssimp/scripts/3d_viewer_py3.py
  85. 1 1
      port/PyAssimp/scripts/transformations.py
  86. 1 1
      port/dAssimp/assimp/mesh.d
  87. 1 1
      port/jassimp/jassimp-native/src/jassimp.cpp
  88. 1 1
      port/swig/assimp.i
  89. 1 1
      samples/SimpleAssimpViewX/MyDocument.mm
  90. 2 2
      samples/glut/GL/glut.h
  91. 28 0
      scripts/android_crosscompile/make_android.bat
  92. 76 62
      test/CMakeLists.txt
  93. 1 1
      test/models-nonbsd/BLEND/fleurOptonl.source.txt
  94. 1 1
      test/models/AMF/README
  95. 18 0
      test/models/STL/triangle_with_two_solids.stl
  96. 12 11
      test/unit/utFindDegenerates.cpp
  97. 8 8
      test/unit/utObjImportExport.cpp
  98. 68 0
      test/unit/utSTLImportExport.cpp
  99. 15 3
      tools/assimp_cmd/WriteDumb.cpp
  100. 1 1
      tools/assimp_qt_viewer/glview.cpp

+ 15 - 0
.travis.sh

@@ -43,9 +43,24 @@ if [ $ANDROID ]; then
     ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
 fi
 if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+  if [ $ANALYZE = "ON" ] ; then
+    if [ "$CC" = "clang" ]; then
+        scan-build cmake -G "Unix Makefiles" -DBUILD_SHARED_LIBS=OFF -DASSIMP_BUILD_TESTS=OFF
+        scan-build --status-bugs make -j2
+    else
+        cppcheck --version
+        generate \
+        && cppcheck --error-exitcode=1 -j2 -Iinclude -Icode code 2> cppcheck.txt
+        if [ -s cppcheck.txt ]; then
+            cat cppcheck.txt
+            exit 1
+        fi
+    fi
+  else
     generate \
     && make -j4 \
     && sudo make install \
     && sudo ldconfig \
     && (cd test/unit; ../../bin/unit)
+  fi
 fi

+ 12 - 6
.travis.yml

@@ -4,7 +4,7 @@ language: cpp
 cache: ccache
 
 before_install:
-  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake cppcheck && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi
   - 'if [ "$TRAVIS_OS_NAME" = "osx" ];  then
        if brew ls --versions cmake > /dev/null; then
          echo cmake already installed.;
@@ -34,11 +34,8 @@ env:
 matrix:
   include:
     - os: linux
-      compiler: gcc
-      env: DISABLE_EXPORTERS=YES ENABLE_COVERALLS=ON
-    - os: linux
-      compiler: gcc
-      env: SHARED_BUILD=ON
+      compiler: clang
+      env: ANALYZE=ON
     - os: linux
       compiler: clang
       env: ASAN=ON
@@ -48,6 +45,15 @@ matrix:
     - os: linux
       compiler: clang
       env: SHARED_BUILD=ON
+    - os: linux
+      compiler: gcc
+      env: ANALYZE=ON
+    - os: linux
+      compiler: gcc
+      env: DISABLE_EXPORTERS=YES ENABLE_COVERALLS=ON
+    - os: linux
+      compiler: gcc
+      env: SHARED_BUILD=ON
 
 install:
   - if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi

+ 5 - 2
CMakeLists.txt

@@ -183,8 +183,11 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
 
 IF( UNIX )
   # Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
-  IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
-    ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
+  IF( ${OPERATING_SYSTEM} MATCHES "Android")
+  ELSE()
+    IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
+      #ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
+    ENDIF()
   ENDIF()
 
   # Use GNUInstallDirs for Unix predefined directories

+ 2 - 2
cmake-modules/CoverallsGenerateGcov.cmake

@@ -310,7 +310,7 @@ foreach (GCOV_FILE ${GCOV_FILES})
 	message("MD5: ${GCOV_SRC_PATH} = ${GCOV_CONTENTS_MD5}")
 
 	# Loads the gcov file as a list of lines.
-	# (We first open the file and replace all occurences of [] with _
+	# (We first open the file and replace all occurrences of [] with _
 	#  because CMake will fail to parse a line containing unmatched brackets...
 	#  also the \ to escaped \n in macros screws up things.)
 	# https://public.kitware.com/Bug/view.php?id=15369
@@ -329,7 +329,7 @@ foreach (GCOV_FILE ${GCOV_FILES})
 	# Instead of trying to parse the source from the
 	# gcov file, simply read the file contents from the source file.
 	# (Parsing it from the gcov is hard because C-code uses ; in many places
-	#  which also happens to be the same as the CMake list delimeter).
+	#  which also happens to be the same as the CMake list delimiter).
 	file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE)
 
 	string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")

+ 2 - 2
code/AMFImporter.hpp

@@ -249,7 +249,7 @@ private:
 
 	/// \fn size_t PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A)
 	/// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new
-	/// converted texture will be returned. Convertion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
+	/// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
 	/// to converted textures list.
 	/// Any of source ID's can be absent(empty string) or even one ID only specified. But at least one ID must be specified.
 	/// \param [in] pID_R - ID of source "red" texture.
@@ -378,7 +378,7 @@ private:
 	void XML_CheckNode_MustHaveChildren();
 
 	/// \fn bool XML_CheckNode_NameEqual(const std::string& pNodeName)
-	/// Chek if current node name is equal to pNodeName.
+	/// Check if current node name is equal to pNodeName.
 	/// \param [in] pNodeName - name for checking.
 	/// return true if current node name is equal to pNodeName, else - false.
 	bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }

+ 1 - 1
code/AMFImporter_Node.hpp

@@ -137,7 +137,7 @@ struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement
 {
 	/****************** Variables ******************/
 
-	std::string ObjectID;///< ID of object for instanciation.
+	std::string ObjectID;///< ID of object for instantiation.
 	/// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to
 	/// create an instance of the object in the current constellation.
 	aiVector3D Delta;

+ 5 - 2
code/AMFImporter_Postprocess.cpp

@@ -281,8 +281,11 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string&
 	{
 		if(!pID.empty())
 		{
-			for(size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++)
-				converted_texture.Data[idx_target] = src_texture[pSrcTexNum]->Data.at(idx_src);
+			for(size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) {
+				CAMFImporter_NodeElement_Texture* tex = src_texture[pSrcTexNum];
+				ai_assert(tex);
+				converted_texture.Data[idx_target] = tex->Data.at(idx_src);
+			}
 		}
 	};// auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
 

+ 1 - 0
code/ASELoader.cpp

@@ -1021,6 +1021,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 
                             // convert bones, if existing
                             if (!mesh.mBones.empty()) {
+                                ai_assert(avOutputBones);
                                 // check whether there is a vertex weight for this vertex index
                                 if (iIndex2 < mesh.mBoneVertices.size())    {
 

+ 1 - 0
code/AssbinExporter.cpp

@@ -171,6 +171,7 @@ inline size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v)
     t += Write<float>(stream,v.x);
     t += Write<float>(stream,v.y);
     t += Write<float>(stream,v.z);
+    ai_assert(t == 16);
     return 16;
 }
 

+ 2 - 2
code/Bitmap.cpp

@@ -102,7 +102,7 @@ namespace Assimp {
         offset += Copy(&data[offset], header.size);
         offset += Copy(&data[offset], header.reserved1);
         offset += Copy(&data[offset], header.reserved2);
-        offset += Copy(&data[offset], header.offset);
+                  Copy(&data[offset], header.offset);
 
         file->Write(data, Header::header_size, 1);
     }
@@ -122,7 +122,7 @@ namespace Assimp {
         offset += Copy(&data[offset], dib.x_resolution);
         offset += Copy(&data[offset], dib.y_resolution);
         offset += Copy(&data[offset], dib.nb_colors);
-        offset += Copy(&data[offset], dib.nb_important_colors);
+                  Copy(&data[offset], dib.nb_important_colors);
 
         file->Write(data, DIB::dib_size, 1);
     }

+ 6 - 0
code/BlenderDNA.h

@@ -92,6 +92,12 @@ struct Error : DeadlyImportError {
  *  descendents. It serves as base class for all data structure fields. */
 // -------------------------------------------------------------------------------
 struct ElemBase {
+    ElemBase()
+    : dna_type(nullptr)
+    {
+        // empty
+    }
+
     virtual ~ElemBase() {
         // empty
     }

+ 31 - 12
code/BlenderScene.cpp

@@ -59,7 +59,9 @@ template <> void Structure :: Convert<Object> (
 {
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
-    ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
+    int temp = 0;
+    ReadField<ErrorPolicy_Fail>(temp,"type",db);
+    dest.type = static_cast<Assimp::Blender::Object::Type>(temp);
     ReadFieldArray2<ErrorPolicy_Warn>(dest.obmat,"obmat",db);
     ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv,"parentinv",db);
     ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr,"parsubstr",db);
@@ -100,14 +102,21 @@ template <> void Structure :: Convert<MTex> (
     ) const
 {
 
-    ReadField<ErrorPolicy_Igno>((short&)dest.mapto,"mapto",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.blendtype,"blendtype",db);
+    int temp_short = 0;
+    ReadField<ErrorPolicy_Igno>(temp_short,"mapto",db);
+    dest.mapto = static_cast<Assimp::Blender::MTex::MapType>(temp_short);
+    int temp = 0;
+    ReadField<ErrorPolicy_Igno>(temp,"blendtype",db);
+    dest.blendtype = static_cast<Assimp::Blender::MTex::BlendType>(temp);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.object,"*object",db);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.tex,"*tex",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.uvname,"uvname",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.projx,"projx",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.projy,"projy",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.projz,"projz",db);
+    ReadField<ErrorPolicy_Igno>(temp,"projx",db);
+    dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
+    ReadField<ErrorPolicy_Igno>(temp,"projy",db);
+    dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
+    ReadField<ErrorPolicy_Igno>(temp,"projz",db);
+    dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
     ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);
@@ -190,7 +199,9 @@ template <> void Structure :: Convert<Lamp> (
 {
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
-    ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
+    int temp = 0;
+    ReadField<ErrorPolicy_Fail>(temp,"type",db);
+    dest.type = static_cast<Assimp::Blender::Lamp::Type>(temp);
     ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db);
     ReadField<ErrorPolicy_Igno>(dest.colormodel,"colormodel",db);
     ReadField<ErrorPolicy_Igno>(dest.totex,"totex",db);
@@ -204,7 +215,8 @@ template <> void Structure :: Convert<Lamp> (
     ReadField<ErrorPolicy_Igno>(dest.spotblend,"spotblend",db);
     ReadField<ErrorPolicy_Igno>(dest.att1,"att1",db);
     ReadField<ErrorPolicy_Igno>(dest.att2,"att2",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.falloff_type,"falloff_type",db);
+    ReadField<ErrorPolicy_Igno>(temp,"falloff_type",db);
+    dest.falloff_type = static_cast<Assimp::Blender::Lamp::FalloffType>(temp);
     ReadField<ErrorPolicy_Igno>(dest.sun_brightness,"sun_brightness",db);
     ReadField<ErrorPolicy_Igno>(dest.area_size,"area_size",db);
     ReadField<ErrorPolicy_Igno>(dest.area_sizey,"area_sizey",db);
@@ -693,8 +705,12 @@ template <> void Structure :: Convert<Tex> (
     const FileDatabase& db
     ) const
 {
-    ReadField<ErrorPolicy_Igno>((short&)dest.imaflag,"imaflag",db);
-    ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
+    short temp_short = 0;
+    ReadField<ErrorPolicy_Igno>(temp_short,"imaflag",db);
+    dest.imaflag = static_cast<Assimp::Blender::Tex::ImageFlags>(temp_short);
+    int temp = 0;
+    ReadField<ErrorPolicy_Fail>(temp,"type",db);
+    dest.type = static_cast<Assimp::Blender::Tex::Type>(temp);
     ReadFieldPtr<ErrorPolicy_Warn>(dest.ima,"*ima",db);
 
     db.reader->IncPtr(size);
@@ -708,8 +724,11 @@ template <> void Structure :: Convert<Camera> (
 {
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
-    ReadField<ErrorPolicy_Warn>((int&)dest.type,"type",db);
-    ReadField<ErrorPolicy_Warn>((int&)dest.flag,"flag",db);
+    int temp = 0;
+    ReadField<ErrorPolicy_Warn>(temp,"type",db);
+    dest.type = static_cast<Assimp::Blender::Camera::Type>(temp);
+    ReadField<ErrorPolicy_Warn>(temp,"flag",db);
+    dest.flag = static_cast<Assimp::Blender::Camera::Type>(temp);
     ReadField<ErrorPolicy_Warn>(dest.lens,"lens",db);
     ReadField<ErrorPolicy_Warn>(dest.sensor_x,"sensor_x",db);
     ReadField<ErrorPolicy_Igno>(dest.clipsta,"clipsta",db);

+ 8 - 0
code/BlenderScene.h

@@ -225,6 +225,14 @@ struct TFace : ElemBase {
 
 // -------------------------------------------------------------------------------
 struct MTFace : ElemBase {
+	MTFace()
+	: flag(0)
+	, mode(0)
+	, tile(0)
+	, unwrap(0)
+	{
+	}
+
     float uv[4][2] FAIL;
     char flag;
     short mode;

+ 254 - 6
code/ColladaExporter.cpp

@@ -141,6 +141,9 @@ void ColladaExporter::WriteFile()
     WriteControllerLibrary();
 
     WriteSceneLibrary();
+	
+	// customized, Writes the animation library
+	WriteAnimationsLibrary();
 
     // useless Collada fu at the end, just in case we haven't had enough indirections, yet.
     mOutput << startstr << "<scene>" << endstr;
@@ -1129,6 +1132,7 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
         case FloatType_Color: floatsPerElement = 3; break;
         case FloatType_Mat4x4: floatsPerElement = 16; break;
         case FloatType_Weight: floatsPerElement = 1; break;
+		case FloatType_Time: floatsPerElement = 1; break;
         default:
             return;
     }
@@ -1205,7 +1209,13 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
         case FloatType_Weight:
             mOutput << startstr << "<param name=\"WEIGHT\" type=\"float\" />" << endstr;
             break;
-    }
+
+		// customized, add animation related
+		case FloatType_Time:
+			mOutput << startstr << "<param name=\"TIME\" type=\"float\" />" << endstr;
+			break;
+
+	}
 
     PopTag();
     mOutput << startstr << "</accessor>" << endstr;
@@ -1235,7 +1245,172 @@ void ColladaExporter::WriteSceneLibrary()
     PopTag();
     mOutput << startstr << "</library_visual_scenes>" << endstr;
 }
-
+// ------------------------------------------------------------------------------------------------
+void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
+{
+	const aiAnimation * anim = mScene->mAnimations[pIndex];
+	
+	if ( anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels ==0 )
+		return;
+	
+	const std::string animation_name_escaped = XMLEscape( anim->mName.C_Str() );
+	std::string idstr = anim->mName.C_Str();
+	std::string ending = std::string( "AnimId" ) + to_string(pIndex);
+	if (idstr.length() >= ending.length()) {
+		if (0 != idstr.compare (idstr.length() - ending.length(), ending.length(), ending)) {
+			idstr = idstr + ending;
+		}
+	} else {
+		idstr = idstr + ending;
+	}
+
+	const std::string idstrEscaped = XMLEscape(idstr);
+	
+	mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr;
+	PushTag();
+	
+	for (size_t a = 0; a < anim->mNumChannels; ++a) {
+		const aiNodeAnim * nodeAnim = anim->mChannels[a];
+		
+		// sanity check
+		if ( nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys ||  nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys ) continue;
+		
+		{
+			const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-input");
+
+			std::vector<ai_real> frames;
+			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
+				frames.push_back(nodeAnim->mPositionKeys[i].mTime);
+			}
+			
+			WriteFloatArray( node_idstr , FloatType_Time, (const ai_real*) frames.data(), frames.size());
+			frames.clear();
+		}
+		
+		{
+			const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-output");
+			
+			std::vector<ai_real> keyframes;
+			keyframes.reserve(nodeAnim->mNumPositionKeys * 16);
+			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
+				
+				aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue;
+				aiMatrix4x4 ScalingM;  // identity
+				ScalingM[0][0] = Scaling.x; ScalingM[1][1] = Scaling.y; ScalingM[2][2] = Scaling.z;
+				
+				aiQuaternion RotationQ = nodeAnim->mRotationKeys[i].mValue;
+				aiMatrix4x4 s = aiMatrix4x4( RotationQ.GetMatrix() );
+				aiMatrix4x4 RotationM(s.a1, s.a2, s.a3, 0, s.b1, s.b2, s.b3, 0, s.c1, s.c2, s.c3, 0, 0, 0, 0, 1);
+				
+				aiVector3D Translation = nodeAnim->mPositionKeys[i].mValue;
+				aiMatrix4x4 TranslationM;	// identity
+				TranslationM[0][3] = Translation.x; TranslationM[1][3] = Translation.y; TranslationM[2][3] = Translation.z;
+				
+				// Combine the above transformations
+				aiMatrix4x4 mat = TranslationM * RotationM * ScalingM;
+				
+				for( size_t j = 0; j < 4; ++j) {
+					keyframes.insert(keyframes.end(), mat[j], mat[j] + 4);
+                }
+			}
+			
+			WriteFloatArray( node_idstr, FloatType_Mat4x4, (const ai_real*) keyframes.data(), keyframes.size() / 16);
+		}
+		
+		{
+			std::vector<std::string> names;
+			for ( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
+				if ( nodeAnim->mPreState == aiAnimBehaviour_DEFAULT
+					|| nodeAnim->mPreState == aiAnimBehaviour_LINEAR
+					|| nodeAnim->mPreState == aiAnimBehaviour_REPEAT
+					) {
+					names.push_back( "LINEAR" );
+				} else if (nodeAnim->mPostState == aiAnimBehaviour_CONSTANT) {
+					names.push_back( "STEP" );
+				}
+			}
+			
+			const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-interpolation");
+			std::string arrayId = node_idstr + "-array";
+			
+			mOutput << startstr << "<source id=\"" << XMLEscape(node_idstr) << "\">" << endstr;
+			PushTag();
+			
+			// source array
+			mOutput << startstr << "<Name_array id=\"" << XMLEscape(arrayId) << "\" count=\"" << names.size() << "\"> ";
+			for( size_t a = 0; a < names.size(); ++a ) {
+				mOutput << names[a] << " ";
+            }
+			mOutput << "</Name_array>" << endstr;
+			
+			mOutput << startstr << "<technique_common>" << endstr;
+			PushTag();
+
+			mOutput << startstr << "<accessor source=\"#" << XMLEscape(arrayId) << "\" count=\"" << names.size() << "\" stride=\"" << 1 << "\">" << endstr;
+			PushTag();
+			
+			mOutput << startstr << "<param name=\"INTERPOLATION\" type=\"name\"></param>" << endstr;
+			
+			PopTag();
+			mOutput << startstr << "</accessor>" << endstr;
+			
+			PopTag();
+			mOutput << startstr << "</technique_common>" << endstr;
+
+			PopTag();
+			mOutput << startstr << "</source>" << endstr;
+		}
+		
+	}
+	
+	for (size_t a = 0; a < anim->mNumChannels; ++a) {
+		const aiNodeAnim * nodeAnim = anim->mChannels[a];
+		
+		{
+		// samplers
+			const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-sampler");
+			mOutput << startstr << "<sampler id=\"" << XMLEscape(node_idstr) << "\">" << endstr;
+			PushTag();
+			
+			mOutput << startstr << "<input semantic=\"INPUT\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-input") ) << "\"/>" << endstr;
+			mOutput << startstr << "<input semantic=\"OUTPUT\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-output") ) << "\"/>" << endstr;
+			mOutput << startstr << "<input semantic=\"INTERPOLATION\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-interpolation") ) << "\"/>" << endstr;
+			
+			PopTag();
+			mOutput << startstr << "</sampler>" << endstr;
+		}
+	}
+	
+	for (size_t a = 0; a < anim->mNumChannels; ++a) {
+		const aiNodeAnim * nodeAnim = anim->mChannels[a];
+		
+		{
+		// channels
+			mOutput << startstr << "<channel source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-sampler") ) << "\" target=\"" << XMLEscape(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr;
+		}
+	}
+	
+	PopTag();
+	mOutput << startstr << "</animation>" << endstr;
+	
+}
+// ------------------------------------------------------------------------------------------------
+void ColladaExporter::WriteAnimationsLibrary()
+{
+	const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str());
+	
+	if ( mScene->mNumAnimations > 0 ) {
+		mOutput << startstr << "<library_animations>" << endstr;
+		PushTag();
+		
+		// start recursive write at the root node
+		for( size_t a = 0; a < mScene->mNumAnimations; ++a)
+			WriteAnimationLibrary( a );
+
+		PopTag();
+		mOutput << startstr << "</library_animations>" << endstr;
+	}
+}
 // ------------------------------------------------------------------------------------------------
 // Helper to find a bone by name in the scene
 aiBone* findBone( const aiScene* scene, const char * name) {
@@ -1251,6 +1426,59 @@ aiBone* findBone( const aiScene* scene, const char * name) {
     return NULL;
 }
 
+// ------------------------------------------------------------------------------------------------
+const aiNode * findBoneNode( const aiNode* aNode, const aiBone* bone)
+{
+	if ( aNode && bone && aNode->mName == bone->mName ) {
+		return aNode;
+	}
+	
+	if ( aNode && bone ) {
+		for (unsigned int i=0; i < aNode->mNumChildren; ++i) {
+			aiNode * aChild = aNode->mChildren[i];
+			const aiNode * foundFromChild = 0;
+			if ( aChild ) {
+				foundFromChild = findBoneNode( aChild, bone );
+				if ( foundFromChild ) return foundFromChild;
+			}
+		}
+	}
+	
+	return NULL;
+}
+
+const aiNode * findSkeletonRootNode( const aiScene* scene, const aiMesh * mesh)
+{
+	std::set<const aiNode*> topParentBoneNodes;
+	if ( mesh && mesh->mNumBones > 0 ) {
+		for (unsigned int i=0; i < mesh->mNumBones; ++i) {
+			aiBone * bone = mesh->mBones[i];
+
+			const aiNode * node = findBoneNode( scene->mRootNode, bone);
+			if ( node ) {
+				while ( node->mParent && findBone(scene, node->mParent->mName.C_Str() ) != 0 ) {
+					node = node->mParent;
+				}
+				topParentBoneNodes.insert( node );
+			}
+		}
+	}
+	
+	if ( !topParentBoneNodes.empty() ) {
+		const aiNode * parentBoneNode = *topParentBoneNodes.begin();
+		if ( topParentBoneNodes.size() == 1 ) {
+			return parentBoneNode;
+		} else {
+			for (auto it : topParentBoneNodes) {
+				if ( it->mParent ) return it->mParent;
+			}
+			return parentBoneNode;
+		}
+	}
+	
+	return NULL;
+}
+
 // ------------------------------------------------------------------------------------------------
 // Recursively writes the given node
 void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
@@ -1278,12 +1506,22 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
     }
 
     const std::string node_name_escaped = XMLEscape(pNode->mName.data);
+	/* // customized, Note! the id field is crucial for inter-xml look up, it cannot be replaced with sid ?!
     mOutput << startstr
             << "<node ";
     if(is_skeleton_root)
         mOutput << "id=\"" << "skeleton_root" << "\" "; // For now, only support one skeleton in a scene.
     mOutput << (is_joint ? "s" : "") << "id=\"" << node_name_escaped;
-    mOutput << "\" name=\"" << node_name_escaped
+	 */
+	mOutput << startstr << "<node ";
+	if(is_skeleton_root) {
+		mOutput << "id=\"" << node_name_escaped << "\" " << (is_joint ? "sid=\"" + node_name_escaped +"\"" : "") ; // For now, only support one skeleton in a scene.
+		mFoundSkeletonRootNodeID = node_name_escaped;
+	} else {
+		mOutput << "id=\"" << node_name_escaped << "\" " << (is_joint ? "sid=\"" + node_name_escaped +"\"": "") ;
+	}
+	
+    mOutput << " name=\"" << node_name_escaped
             << "\" type=\"" << node_type
             << "\">" << endstr;
     PushTag();
@@ -1291,7 +1529,11 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
     // write transformation - we can directly put the matrix there
     // TODO: (thom) decompose into scale - rot - quad to allow addressing it by animations afterwards
     const aiMatrix4x4& mat = pNode->mTransformation;
-    mOutput << startstr << "<matrix sid=\"transform\">";
+	
+	// customized, sid should be 'matrix' to match with loader code.
+    //mOutput << startstr << "<matrix sid=\"transform\">";
+	mOutput << startstr << "<matrix sid=\"matrix\">";
+	
     mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
     mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " ";
     mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " ";
@@ -1319,7 +1561,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
     for( size_t a = 0; a < pNode->mNumMeshes; ++a )
     {
         const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]];
-        // do not instanciate mesh if empty. I wonder how this could happen
+        // do not instantiate mesh if empty. I wonder how this could happen
         if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
             continue;
 
@@ -1335,7 +1577,13 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
                     << endstr;
             PushTag();
 
-            mOutput << startstr << "<skeleton>#skeleton_root</skeleton>" << endstr;
+			// note! this mFoundSkeletonRootNodeID some how affects animation, it makes the mesh attaches to armature skeleton root node.
+			// use the first bone to find skeleton root
+			const aiNode * skeletonRootBoneNode = findSkeletonRootNode( pScene, mesh );
+			if ( skeletonRootBoneNode ) {
+				mFoundSkeletonRootNodeID = XMLEscape( skeletonRootBoneNode->mName.C_Str() );
+			}
+            mOutput << startstr << "<skeleton>#" << mFoundSkeletonRootNodeID << "</skeleton>" << endstr;
         }
         mOutput << startstr << "<bind_material>" << endstr;
         PushTag();

+ 8 - 1
code/ColladaExporter.h

@@ -114,7 +114,9 @@ protected:
     /// Writes the given mesh
     void WriteGeometry( size_t pIndex);
 
-    enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight };
+    //enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight };
+    // customized to add animation related type
+	enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight, FloatType_Time };
 
     /// Writes a float array of the given type
     void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const ai_real* pData, size_t pElementCount);
@@ -122,6 +124,11 @@ protected:
     /// Writes the scene library
     void WriteSceneLibrary();
 
+	// customized, Writes the animation library
+	void WriteAnimationsLibrary();
+	void WriteAnimationLibrary( size_t pIndex);
+	std::string mFoundSkeletonRootNodeID = "skeleton_root";	 	// will be replaced by found node id in the WriteNode call.
+	
     /// Recursively writes the given node
     void WriteNode( const aiScene* scene, aiNode* pNode);
 

+ 1 - 1
code/ColladaHelper.h

@@ -302,7 +302,7 @@ struct Accessor
     size_t mOffset;  // in number of values
     size_t mStride;  // Stride in number of values
     std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
-    size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
+    size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on.
                           // For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
     std::string mSource;   // URL of the source array
     mutable const Data* mData; // Pointer to the source array, if resolved. NULL else

+ 1 - 1
code/ColladaLoader.cpp

@@ -1619,7 +1619,7 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
         mat.AddProperty( &effect.mRefractIndex, 1, AI_MATKEY_REFRACTI);
 
         // transparency, a very hard one. seemingly not all files are following the
-        // specification here (1.0 transparency => completly opaque)...
+        // specification here (1.0 transparency => completely opaque)...
         // therefore, we let the opportunity for the user to manually invert
         // the transparency if necessary and we add preliminary support for RGB_ZERO mode
         if(effect.mTransparency >= 0.f && effect.mTransparency <= 1.f) {

+ 1 - 1
code/ColladaParser.cpp

@@ -224,7 +224,7 @@ void ColladaParser::ReadStructure()
 }
 
 // ------------------------------------------------------------------------------------------------
-// Reads asset informations such as coordinate system informations and legal blah
+// Reads asset information such as coordinate system information and legal blah
 void ColladaParser::ReadAssetInfo()
 {
     if( mReader->isEmptyElement())

+ 1 - 1
code/ColladaParser.h

@@ -77,7 +77,7 @@ namespace Assimp
         /** Reads the structure of the file */
         void ReadStructure();
 
-        /** Reads asset informations such as coordinate system informations and legal blah */
+        /** Reads asset information such as coordinate system information and legal blah */
         void ReadAssetInfo();
 
         /** Reads the animation library */

+ 0 - 1
code/DefaultIOSystem.cpp

@@ -49,7 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/ai_assert.h>
 #include <stdlib.h>
 
-
 #ifdef __unix__
 #include <sys/param.h>
 #include <stdlib.h>

+ 0 - 1
code/FBXBinaryTokenizer.cpp

@@ -422,7 +422,6 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
     return true;
 }
 
-
 }
 
 // ------------------------------------------------------------------------------------------------

+ 10 - 5
code/FBXConverter.cpp

@@ -566,7 +566,6 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
 
                 if ( !name_carrier ) {
                     nodes_chain.push_back( new aiNode( original_name ) );
-                    name_carrier = nodes_chain.back();
                 }
 
                 //setup metadata on newest node
@@ -645,7 +644,6 @@ void Converter::ConvertCameras( const Model& model )
     }
 }
 
-
 void Converter::ConvertLight( const Model& model, const Light& light )
 {
     lights.push_back( new aiLight() );
@@ -783,7 +781,6 @@ const char* Converter::NameTransformationComp( TransformationComp comp )
     return NULL;
 }
 
-
 const char* Converter::NameTransformationCompProperty( TransformationComp comp )
 {
     switch ( comp )
@@ -2239,9 +2236,17 @@ void Converter::ConvertAnimations()
     }
 }
 
+void Converter::RenameNode( const std::string& fixed_name, const std::string& new_name ) {
+    if ( node_names.find( fixed_name ) == node_names.end() ) {
+        FBXImporter::LogError( "Cannot rename node " + fixed_name + ", not existing.");
+        return;
+    }
+
+    if ( node_names.find( new_name ) != node_names.end() ) {
+        FBXImporter::LogError( "Cannot rename node " + fixed_name + " to " + new_name +", name already existing." );
+        return;
+    }
 
-void Converter::RenameNode( const std::string& fixed_name, const std::string& new_name )
-{
     ai_assert( node_names.find( fixed_name ) != node_names.end() );
     ai_assert( node_names.find( new_name ) == node_names.end() );
 

+ 19 - 13
code/FIReader.cpp

@@ -45,13 +45,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
 
+#include "FIReader.hpp"
+#include "StringUtils.h"
+
 // Workaround for issue #1361
 // https://github.com/assimp/assimp/issues/1361
 #ifdef __ANDROID__
-#define _GLIBCXX_USE_C99 1
+#  define _GLIBCXX_USE_C99 1
 #endif
 
-#include "FIReader.hpp"
 #include "Exceptional.h"
 #include <assimp/IOStream.hpp>
 #include <assimp/types.h>
@@ -485,7 +487,9 @@ struct FIFloatDecoder: public FIDecoder {
         value.reserve(numFloats);
         for (size_t i = 0; i < numFloats; ++i) {
             int v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
-            value.push_back(*(float*)&v);
+            float f;
+            memcpy(&f, &v, 4);
+            value.push_back(f);
             data += 4;
         }
         return FIFloatValue::create(std::move(value));
@@ -503,7 +507,9 @@ struct FIDoubleDecoder: public FIDecoder {
         for (size_t i = 0; i < numDoubles; ++i) {
             long long b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7];
             long long v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
-            value.push_back(*(double*)&v);
+            double f;
+            memcpy(&f, &v, 8);
+            value.push_back(f);
             data += 8;
         }
         return FIDoubleValue::create(std::move(value));
@@ -685,7 +691,7 @@ public:
         if (intValue) {
             return intValue->value.size() == 1 ? intValue->value.front() : 0;
         }
-        return stoi(attr->value->toString());
+        return atoi(attr->value->toString().c_str());
     }
 
     virtual int getAttributeValueAsInt(int idx) const /*override*/ {
@@ -696,7 +702,7 @@ public:
         if (intValue) {
             return intValue->value.size() == 1 ? intValue->value.front() : 0;
         }
-        return stoi(attributes[idx].value->toString());
+        return atoi(attributes[idx].value->toString().c_str());
     }
 
     virtual float getAttributeValueAsFloat(const char* name) const /*override*/ {
@@ -708,7 +714,7 @@ public:
         if (floatValue) {
             return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
         }
-        return stof(attr->value->toString());
+        return atof(attr->value->toString().c_str());
     }
 
     virtual float getAttributeValueAsFloat(int idx) const /*override*/ {
@@ -719,7 +725,7 @@ public:
         if (floatValue) {
             return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
         }
-        return stof(attributes[idx].value->toString());
+        return atof(attributes[idx].value->toString().c_str());
     }
 
     virtual const char* getNodeName() const /*override*/ {
@@ -984,13 +990,13 @@ private:
         if (index < 32) {
             FIDecoder *decoder = defaultDecoder[index];
             if (!decoder) {
-                throw DeadlyImportError("Invalid encoding algorithm index " + std::to_string(index));
+                throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index));
             }
             return decoder->decode(dataP, len);
         }
         else {
             if (index - 32 >= vocabulary.encodingAlgorithmTable.size()) {
-                throw DeadlyImportError("Invalid encoding algorithm index " + std::to_string(index));
+                throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index));
             }
             std::string uri = vocabulary.encodingAlgorithmTable[index - 32];
             auto it = decoderMap.find(uri);
@@ -1014,12 +1020,12 @@ private:
                 alphabet = "0123456789-:TZ ";
                 break;
             default:
-                throw DeadlyImportError("Invalid restricted alphabet index " + std::to_string(index));
+                throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index));
             }
         }
         else {
             if (index - 16 >= vocabulary.restrictedAlphabetTable.size()) {
-                throw DeadlyImportError("Invalid restricted alphabet index " + std::to_string(index));
+                throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index));
             }
             alphabet = vocabulary.restrictedAlphabetTable[index - 16];
         }
@@ -1027,7 +1033,7 @@ private:
         utf8::utf8to32(alphabet.begin(), alphabet.end(), back_inserter(alphabetUTF32));
         std::string::size_type alphabetLength = alphabetUTF32.size();
         if (alphabetLength < 2) {
-            throw DeadlyImportError("Invalid restricted alphabet length " + std::to_string(alphabetLength));
+            throw DeadlyImportError("Invalid restricted alphabet length " + to_string(alphabetLength));
         }
         std::string::size_type bitsPerCharacter = 1;
         while ((1ull << bitsPerCharacter) <= alphabetLength) {

+ 17 - 4
code/FIReader.hpp

@@ -46,11 +46,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_FI_READER_H
 #define INCLUDED_AI_FI_READER_H
 
-#include <irrXML.h>
-#include <memory>
+#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
+
+//#include <wchar.h>
 #include <string>
+#include <memory>
+#include <cerrno>
+#include <cwchar>
 #include <vector>
-#include <cstdint>
+//#include <stdio.h>
+//#include <cstdint>
+#include <irrXML.h>
 
 namespace Assimp {
 
@@ -154,7 +160,7 @@ class IOStream;
 
 class FIReader: public irr::io::IIrrXMLReader<char, irr::io::IXMLBase> {
 public:
-
+	virtual ~FIReader();
     virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int idx) const = 0;
 
     virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char *name) const = 0;
@@ -167,6 +173,13 @@ public:
 
 };// class IFIReader
 
+inline
+FIReader::~FIReader() {
+	// empty
+}
+
 }// namespace Assimp
 
+#endif // #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
+
 #endif // INCLUDED_AI_FI_READER_H

+ 76 - 36
code/FindDegenerates.cpp

@@ -56,98 +56,138 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 FindDegeneratesProcess::FindDegeneratesProcess()
-: configRemoveDegenerates (false)
-{}
+: mConfigRemoveDegenerates( false )
+, mConfigCheckAreaOfTriangle( false ){
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
-FindDegeneratesProcess::~FindDegeneratesProcess()
-{
+FindDegeneratesProcess::~FindDegeneratesProcess() {
     // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const
-{
+bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const {
     return 0 != (pFlags & aiProcess_FindDegenerates);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup import configuration
-void FindDegeneratesProcess::SetupProperties(const Importer* pImp)
-{
+void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
     // Get the current value of AI_CONFIG_PP_FD_REMOVE
-    configRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0));
+    mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0));
+    mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) );
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void FindDegeneratesProcess::Execute( aiScene* pScene)
-{
+void FindDegeneratesProcess::Execute( aiScene* pScene) {
     DefaultLogger::get()->debug("FindDegeneratesProcess begin");
     for (unsigned int i = 0; i < pScene->mNumMeshes;++i){
-        ExecuteOnMesh( pScene->mMeshes[i]);
+        ExecuteOnMesh( pScene->mMeshes[ i ] );
     }
     DefaultLogger::get()->debug("FindDegeneratesProcess finished");
 }
 
+static ai_real heron( ai_real a, ai_real b, ai_real c ) {
+    ai_real s = (a + b + c) / 2;
+    ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), 0.5 );
+    return area;
+}
+
+static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB ) {
+    const ai_real lx = ( vB.x - vA.x );
+    const ai_real ly = ( vB.y - vA.y );
+    const ai_real lz = ( vB.z - vA.z );
+    ai_real a = lx*lx + ly*ly + lz*lz;
+    ai_real d = pow( a, 0.5 );
+
+    return d;
+}
+
+static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
+    ai_real area = 0;
+
+    aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
+    aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
+    aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
+
+    ai_real a( distance3D( vA, vB ) );
+    ai_real b( distance3D( vB, vC ) );
+    ai_real c( distance3D( vC, vA ) );
+    area = heron( a, b, c );
+
+    return area;
+}
+
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported mesh
-void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh)
-{
+void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
     mesh->mPrimitiveTypes = 0;
 
     std::vector<bool> remove_me;
-    if (configRemoveDegenerates)
-        remove_me.resize(mesh->mNumFaces,false);
+    if (mConfigRemoveDegenerates) {
+        remove_me.resize( mesh->mNumFaces, false );
+    }
 
     unsigned int deg = 0, limit;
-    for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
-    {
+    for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) {
         aiFace& face = mesh->mFaces[a];
         bool first = true;
 
         // check whether the face contains degenerated entries
-        for (unsigned int i = 0; i < face.mNumIndices; ++i)
-        {
+        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
             // Polygons with more than 4 points are allowed to have double points, that is
             // simulating polygons with holes just with concave polygons. However,
             // double points may not come directly after another.
             limit = face.mNumIndices;
-            if (face.mNumIndices > 4)
-                limit = std::min(limit,i+2);
+            if (face.mNumIndices > 4) {
+                limit = std::min( limit, i+2 );
+            }
 
-            for (unsigned int t = i+1; t < limit; ++t)
-            {
-                if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]])
-                {
+            for (unsigned int t = i+1; t < limit; ++t) {
+                if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) {
                     // we have found a matching vertex position
                     // remove the corresponding index from the array
-                    --face.mNumIndices;--limit;
-                    for (unsigned int m = t; m < face.mNumIndices; ++m)
-                    {
-                        face.mIndices[m] = face.mIndices[m+1];
+                    --face.mNumIndices;
+                    --limit;
+                    for (unsigned int m = t; m < face.mNumIndices; ++m) {
+                        face.mIndices[ m ] = face.mIndices[ m+1 ];
                     }
                     --t;
 
                     // NOTE: we set the removed vertex index to an unique value
                     // to make sure the developer gets notified when his
                     // application attemps to access this data.
-                    face.mIndices[face.mNumIndices] = 0xdeadbeef;
+                    face.mIndices[ face.mNumIndices ] = 0xdeadbeef;
 
-                    if(first)
-                    {
+                    if(first) {
                         ++deg;
                         first = false;
                     }
 
-                    if (configRemoveDegenerates) {
-                        remove_me[a] = true;
+                    if ( mConfigRemoveDegenerates ) {
+                        remove_me[ a ] = true;
                         goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
                     }
                 }
             }
+
+            if ( mConfigCheckAreaOfTriangle ) {
+                if ( face.mNumIndices == 3 ) {
+                    ai_real area = calculateAreaOfTriangle( face, mesh );
+                    if ( area < 1e-6 ) {
+                        if ( mConfigRemoveDegenerates ) {
+                            remove_me[ a ] = true;
+                            goto evil_jump_outside;
+                        }
+
+                        // todo: check for index which is corrupt.
+                    }
+                }
+            }
         }
 
         // We need to update the primitive flags array of the mesh.
@@ -171,7 +211,7 @@ evil_jump_outside:
     }
 
     // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
-    if (configRemoveDegenerates && deg) {
+    if (mConfigRemoveDegenerates && deg) {
         unsigned int n = 0;
         for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
         {

+ 40 - 19
code/FindDegenerates.h

@@ -54,15 +54,11 @@ namespace Assimp    {
 // ---------------------------------------------------------------------------
 /** FindDegeneratesProcess: Searches a mesh for degenerated triangles.
 */
-class ASSIMP_API FindDegeneratesProcess : public BaseProcess
-{
+class ASSIMP_API FindDegeneratesProcess : public BaseProcess {
 public:
-
     FindDegeneratesProcess();
     ~FindDegeneratesProcess();
 
-public:
-
     // -------------------------------------------------------------------
     // Check whether step is active
     bool IsActive( unsigned int pFlags) const;
@@ -79,28 +75,53 @@ public:
     // Execute step on a given mesh
     void ExecuteOnMesh( aiMesh* mesh);
 
+    // -------------------------------------------------------------------
+    /// @brief Enable the instant removal of degenerated primitives
+    /// @param enabled  true for enabled.
+    void EnableInstantRemoval(bool enabled);
+
+    // -------------------------------------------------------------------
+    /// @brief Check whether instant removal is currently enabled
+    /// @return The instant removal state.
+    bool IsInstantRemoval() const;
 
     // -------------------------------------------------------------------
-    /** @brief Enable the instant removal of degenerated primitives
-     *  @param d hm ... difficult to guess what this means, hu!?
-     */
-    void EnableInstantRemoval(bool d) {
-        configRemoveDegenerates = d;
-    }
+    /// @brief Enable the area check for triangles.
+    /// @param enabled  true for enabled.
+    void EnableAreaCheck( bool enabled );
 
     // -------------------------------------------------------------------
-    /** @brief Check whether instant removal is currently enabled
-     *  @return ...
-     */
-    bool IsInstantRemoval() const {
-        return configRemoveDegenerates;
-    }
+    /// @brief Check whether the area check is enabled.
+    /// @return The area check state.
+    bool isAreaCheckEnabled() const;
 
 private:
-
     //! Configuration option: remove degenerates faces immediately
-    bool configRemoveDegenerates;
+    bool mConfigRemoveDegenerates;
+    //! Configuration option: check for area
+    bool mConfigCheckAreaOfTriangle;
 };
+
+inline
+void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) {
+    mConfigRemoveDegenerates = enabled;
 }
 
+inline
+bool FindDegeneratesProcess::IsInstantRemoval() const {
+    return mConfigRemoveDegenerates;
+}
+
+inline
+void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) {
+    mConfigCheckAreaOfTriangle = enabled;
+}
+
+inline
+bool FindDegeneratesProcess::isAreaCheckEnabled() const {
+    return mConfigCheckAreaOfTriangle;
+}
+
+} // Namespace Assimp
+
 #endif // !! AI_FINDDEGENERATESPROCESS_H_INC

+ 1 - 40
code/IFCOpenings.cpp

@@ -1499,7 +1499,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
 
 
     IfcVector3 wall_extrusion;
-    bool do_connections = false, first = true;
+    bool first = true;
 
     try {
 
@@ -1527,7 +1527,6 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
                 if (first) {
                     first = false;
                     if (dot > 0.f) {
-                        do_connections = true;
                         wall_extrusion = t.extrusionDir;
                         if (is_extruded_side) {
                             wall_extrusion = - wall_extrusion;
@@ -1607,44 +1606,6 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
     old_verts.swap(curmesh.verts);
     old_vertcnt.swap(curmesh.vertcnt);
 
-
-    // add connection geometry to close the adjacent 'holes' for the openings
-    // this should only be done from one side of the wall or the polygons
-    // would be emitted twice.
-    if (false && do_connections) {
-
-        std::vector<IfcVector3> tmpvec;
-        for(ClipperLib::Polygon& opening : holes_union) {
-
-            ai_assert(ClipperLib::Orientation(opening));
-
-            tmpvec.clear();
-
-            for(ClipperLib::IntPoint& point : opening) {
-
-                tmpvec.push_back( minv * IfcVector3(
-                    vmin.x + from_int64(point.X) * vmax.x,
-                    vmin.y + from_int64(point.Y) * vmax.y,
-                    coord));
-            }
-
-            for(size_t i = 0, size = tmpvec.size(); i < size; ++i) {
-                const size_t next = (i+1)%size;
-
-                curmesh.vertcnt.push_back(4);
-
-                const IfcVector3& in_world = tmpvec[i];
-                const IfcVector3& next_world = tmpvec[next];
-
-                // Assumptions: no 'partial' openings, wall thickness roughly the same across the wall
-                curmesh.verts.push_back(in_world);
-                curmesh.verts.push_back(in_world+wall_extrusion);
-                curmesh.verts.push_back(next_world+wall_extrusion);
-                curmesh.verts.push_back(next_world);
-            }
-        }
-    }
-
     std::vector< std::vector<p2t::Point*> > contours;
     for(ClipperLib::ExPolygon& clip : clipped) {
 

+ 1 - 1
code/IRRLoader.cpp

@@ -394,7 +394,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
                 angles[1] %= 360;
                 angles[2] %= 360;
 
-                if ( bool(angles[0]*angles[1]) && bool(angles[1]*angles[2]) )
+                if ( (angles[0]*angles[1]) != 0 && (angles[1]*angles[2]) != 0 )
                 {
                     FindSuitableMultiple(angles[0]);
                     FindSuitableMultiple(angles[1]);

+ 0 - 4
code/Importer.cpp

@@ -274,10 +274,6 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
 
     if (it != pimpl->mImporter.end())   {
         pimpl->mImporter.erase(it);
-
-        std::set<std::string> st;
-        pImp->GetExtensionList(st);
-
         DefaultLogger::get()->info("Unregistering custom importer: ");
         return AI_SUCCESS;
     }

+ 1 - 0
code/ImproveCacheLocality.cpp

@@ -223,6 +223,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh
             iMaxRefTris = std::max(iMaxRefTris,*piCur);
         }
     }
+    ai_assert(iMaxRefTris > 0);
     unsigned int* piCandidates = new unsigned int[iMaxRefTris*3];
     unsigned int iCacheMisses = 0;
 

+ 1 - 3
code/LWOAnimation.cpp

@@ -446,8 +446,6 @@ void AnimResolver::GetKeys(std::vector<aiVectorKey>& out,
 
     // Iterate through all three arrays at once - it's tricky, but
     // rather interesting to implement.
-    double lasttime = std::min(envl_x->keys[0].time,std::min(envl_y->keys[0].time,envl_z->keys[0].time));
-
     cur_x = envl_x->keys.begin();
     cur_y = envl_y->keys.begin();
     cur_z = envl_z->keys.begin();
@@ -503,7 +501,7 @@ void AnimResolver::GetKeys(std::vector<aiVectorKey>& out,
                 InterpolateTrack(out,fill,(end_y ? (*cur_x) : (*cur_y)).time);
             }
         }
-        lasttime = fill.mTime;
+        double lasttime = fill.mTime;
         out.push_back(fill);
 
         if (lasttime >= (*cur_x).time) {

+ 1 - 1
code/LWOMaterial.cpp

@@ -483,7 +483,7 @@ void LWOImporter::FindVCChannels(const LWO::Surface& surf, LWO::SortedRep& sorte
         const LWO::VColorChannel& vc = layer.mVColorChannels[i];
 
         if (surf.mVCMap == vc.name) {
-            // The vertex color map is explicitely requested by the surface so we need to take special care of it
+            // The vertex color map is explicitly requested by the surface so we need to take special care of it
             for (unsigned int a = 0; a < std::min(next,AI_MAX_NUMBER_OF_COLOR_SETS-1u); ++a) {
                 out[a+1] = out[a];
             }

+ 1 - 1
code/LWSLoader.cpp

@@ -471,7 +471,7 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
 // Determine the exact location of a LWO file
 std::string LWSImporter::FindLWOFile(const std::string& in)
 {
-    // insert missing directory seperator if necessary
+    // insert missing directory separator if necessary
     std::string tmp;
     if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/')
     {

+ 3 - 5
code/MD2Loader.cpp

@@ -274,11 +274,9 @@ void MD2Importer::InternReadFile( const std::string& pFile,
     aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh();
     pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
 
-    // navigate to the begin of the frame data
-    BE_NCONST MD2::Frame* pcFrame = (BE_NCONST MD2::Frame*) ((uint8_t*)
-        m_pcHeader + m_pcHeader->offsetFrames);
-
-    pcFrame += configFrameID;
+    // navigate to the begin of the current frame data
+	BE_NCONST MD2::Frame* pcFrame = (BE_NCONST MD2::Frame*) ((uint8_t*)
+		m_pcHeader + m_pcHeader->offsetFrames + (m_pcHeader->frameSize * configFrameID));
 
     // navigate to the begin of the triangle data
     MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)

+ 3 - 1
code/MDLMaterialLoader.cpp

@@ -665,7 +665,9 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
         if (0.0f != pcMatIn->Power)
         {
             iShadingMode = (int)aiShadingMode_Phong;
-            pcMatOut->AddProperty<float>(&pcMatIn->Power,1,AI_MATKEY_SHININESS);
+            // pcMatIn is packed, we can't form pointers to its members
+            float power = pcMatIn->Power;
+            pcMatOut->AddProperty<float>(&power,1,AI_MATKEY_SHININESS);
         }
         pcMatOut->AddProperty<int>(&iShadingMode,1,AI_MATKEY_SHADING_MODEL);
     }

+ 11 - 8
code/NFFLoader.cpp

@@ -243,8 +243,6 @@ void NFFImporter::InternReadFile( const std::string& pFile,
     if( !file.get())
         throw DeadlyImportError( "Failed to open NFF file " + pFile + ".");
 
-    unsigned int m = (unsigned int)file->FileSize();
-
     // allocate storage and copy the contents of the file to a memory buffer
     // (terminate it with zero)
     std::vector<char> mBuffer2;
@@ -469,7 +467,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
                         for (unsigned int a = 0; a < numIdx;++a)
                         {
                             SkipSpaces(sz,&sz);
-                            m = ::strtoul10(sz,&sz);
+                            unsigned int m = ::strtoul10(sz,&sz);
                             if (m >= (unsigned int)tempPositions.size())
                             {
                                 DefaultLogger::get()->error("NFF2: Vertex index overflow");
@@ -635,7 +633,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
                         for (std::vector<unsigned int>::const_iterator it = tempIdx.begin(), end = tempIdx.end();
                             it != end;++it)
                         {
-                            m = *it;
+                            unsigned int m = *it;
 
                             // copy colors -vertex color specifications override polygon color specifications
                             if (hasColor)
@@ -735,7 +733,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
                     sz = &line[1];out = currentMesh;
                 }
                 SkipSpaces(sz,&sz);
-                m = strtoul10(sz);
+                unsigned int m = strtoul10(sz);
 
                 // ---- flip the face order
                 out->vertices.resize(out->vertices.size()+m);
@@ -1081,7 +1079,9 @@ void NFFImporter::InternReadFile( const std::string& pFile,
     // generate the camera
     if (hasCam)
     {
-        aiNode* nd = *ppcChildren = new aiNode();
+        ai_assert(ppcChildren);
+        aiNode* nd = new aiNode();
+        *ppcChildren = nd;
         nd->mName.Set("<NFF_Camera>");
         nd->mParent = root;
 
@@ -1105,13 +1105,15 @@ void NFFImporter::InternReadFile( const std::string& pFile,
     // generate light sources
     if (!lights.empty())
     {
+        ai_assert(ppcChildren);
         pScene->mNumLights = (unsigned int)lights.size();
         pScene->mLights = new aiLight*[pScene->mNumLights];
         for (unsigned int i = 0; i < pScene->mNumLights;++i,++ppcChildren)
         {
             const Light& l = lights[i];
 
-            aiNode* nd = *ppcChildren  = new aiNode();
+            aiNode* nd = new aiNode();
+            *ppcChildren = nd;
             nd->mParent = root;
 
             nd->mName.length = ::ai_snprintf(nd->mName.data,1024,"<NFF_Light%u>",i);
@@ -1128,7 +1130,8 @@ void NFFImporter::InternReadFile( const std::string& pFile,
     if (!pScene->mNumMeshes)throw DeadlyImportError("NFF: No meshes loaded");
     pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
     pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes];
-    for (it = meshes.begin(), m = 0; it != end;++it)
+    unsigned int m = 0;
+    for (it = meshes.begin(); it != end;++it)
     {
         if ((*it).faces.empty())continue;
 

+ 5 - 4
code/ObjExporter.cpp

@@ -155,7 +155,7 @@ std::string ObjExporter :: GetMaterialLibName()
 
 // ------------------------------------------------------------------------------------------------
 std::string ObjExporter::GetMaterialLibFileName() {
-    // Remove existing .obj file extention so that the final material file name will be fileName.mtl and not fileName.obj.mtl
+    // Remove existing .obj file extension so that the final material file name will be fileName.mtl and not fileName.obj.mtl
     size_t lastdot = filename.find_last_of('.');
     if (lastdot != std::string::npos)
         return filename.substr(0, lastdot) + MaterialExt;
@@ -258,7 +258,6 @@ void ObjExporter::WriteMaterialFile()
     }
 }
 
-// ------------------------------------------------------------------------------------------------
 void ObjExporter::WriteGeometryFile(bool noMtl) {
     WriteHeader(mOutput);
     if (!noMtl)
@@ -280,8 +279,10 @@ void ObjExporter::WriteGeometryFile(bool noMtl) {
         mOutput << "# " << vp.size() << " vertex positions and colors" << endl;
         size_t colIdx = 0;
         for ( const aiVector3D& v : vp ) {
-            mOutput << "v  " << v.x << " " << v.y << " " << v.z << " " << vc[ colIdx ].r << " " << vc[ colIdx ].g << " " << vc[ colIdx ].b << endl;
-            colIdx++;
+            if ( colIdx < vc.size() ) {
+                mOutput << "v  " << v.x << " " << v.y << " " << v.z << " " << vc[ colIdx ].r << " " << vc[ colIdx ].g << " " << vc[ colIdx ].b << endl;
+            }
+            ++colIdx;
         }
     }
     mOutput << endl;

+ 1 - 1
code/OgreMaterial.cpp

@@ -258,7 +258,7 @@ aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSyste
                 ReadTechnique(Trim(techniqueName), ss, material);
             }
 
-            // Read informations from a custom material
+            // Read information from a custom material
             /** @todo This "set $x y" does not seem to be a official Ogre material system feature.
                 Materials can inherit other materials and override texture units by using the (unique)
                 parent texture unit name in your cloned material.

+ 2 - 0
code/OpenGEXImporter.cpp

@@ -652,6 +652,8 @@ static void setMatrix( aiNode *node, DataArrayList *transformData ) {
         i++;
     }
 
+    ai_assert(i == 16);
+
     node->mTransformation.a1 = m[ 0 ];
     node->mTransformation.a2 = m[ 4 ];
     node->mTransformation.a3 = m[ 8 ];

+ 6 - 4
code/OptimizeGraph.cpp

@@ -233,10 +233,12 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
 
     nd->mNumChildren = static_cast<unsigned int>(child_nodes.size());
 
-    aiNode** tmp = nd->mChildren;
-    for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
-        aiNode* node = *tmp++ = *it;
-        node->mParent = nd;
+    if (nd->mChildren) {
+        aiNode** tmp = nd->mChildren;
+        for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
+            aiNode* node = *tmp++ = *it;
+            node->mParent = nd;
+        }
     }
 
     nodes_out += static_cast<unsigned int>(child_nodes.size());

+ 1 - 2
code/PlyParser.cpp

@@ -671,7 +671,6 @@ bool PLY::ElementInstanceList::ParseInstanceList(
   PLYImporter* loader)
 {
   ai_assert(NULL != pcElement);
-  const char* pCur = (const char*)&buffer[0];
 
   // parse all elements
   if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty())
@@ -683,11 +682,11 @@ bool PLY::ElementInstanceList::ParseInstanceList(
       PLY::DOM::SkipComments(buffer);
       PLY::DOM::SkipLine(buffer);
       streamBuffer.getNextLine(buffer);
-      pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0];
     }
   }
   else
   {
+    const char* pCur = (const char*)&buffer[0];
     // be sure to have enough storage
     for (unsigned int i = 0; i < pcElement->NumOccur; ++i)
     {

+ 1 - 1
code/RawLoader.cpp

@@ -260,7 +260,7 @@ void RAWImporter::InternReadFile( const std::string& pFile,
             node = *cc = new aiNode();
             node->mParent = pScene->mRootNode;
         }
-        else node = *cc;++cc;
+        else node = *cc;
         node->mName.Set(outGroup.name);
 
         // add all meshes

+ 3 - 0
code/RemoveRedundantMaterials.cpp

@@ -145,6 +145,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
             if (!abReferenced[i]) {
                 ++unreferencedRemoved;
                 delete pScene->mMaterials[i];
+                pScene->mMaterials[i] = nullptr;
                 continue;
             }
 
@@ -158,6 +159,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
                     me = 0;
                     aiMappingTable[i] = aiMappingTable[a];
                     delete pScene->mMaterials[i];
+                    pScene->mMaterials[i] = nullptr;
                     break;
                 }
             }
@@ -169,6 +171,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
         // If the new material count differs from the original,
         // we need to rebuild the material list and remap mesh material indexes.
         if (iNewNum != pScene->mNumMaterials) {
+            ai_assert(iNewNum > 0);
             aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
             ::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
             for (unsigned int p = 0; p < pScene->mNumMaterials;++p)

+ 2 - 0
code/SIBImporter.cpp

@@ -902,6 +902,7 @@ void SIBImporter::InternReadFile(const std::string& pFile,
     // Add nodes for each object.
     for (size_t n=0;n<sib.objs.size();n++)
     {
+        ai_assert(root->mChildren);
         SIBObject& obj = sib.objs[n];
         aiNode* node = new aiNode;
         root->mChildren[childIdx++] = node;
@@ -926,6 +927,7 @@ void SIBImporter::InternReadFile(const std::string& pFile,
     // (no transformation as the light is already in world space)
     for (size_t n=0;n<sib.lights.size();n++)
     {
+        ai_assert(root->mChildren);
         aiLight* light = sib.lights[n];
         if ( nullptr != light ) {
             aiNode* node = new aiNode;

+ 1 - 1
code/STEPFileEncoding.cpp

@@ -334,7 +334,7 @@ bool STEP::StringToUTF8(std::string& s)
                         size_t j = basei, jend = s.size()-3;
 
                         for (; j < jend; ++j) {
-                            if (s[j] == '\\' && s[j] == 'X' && s[j] == '0' && s[j] == '\\') {
+                            if (s[j] == '\\' && s[j+1] == 'X' && s[j+2] == '0' && s[j+3] == '\\') {
                                 break;
                             }
                         }

+ 53 - 39
code/STLLoader.cpp

@@ -80,7 +80,9 @@ static bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
         return false;
     }
 
-    const uint32_t faceCount = *reinterpret_cast<const uint32_t*>(buffer + 80);
+    const char *facecount_pos = buffer + 80;
+    uint32_t faceCount( 0 );
+    ::memcpy( &faceCount, facecount_pos, sizeof( uint32_t ) );
     const uint32_t expectedBinaryFileSize = faceCount * 50 + 84;
 
     return expectedBinaryFileSize == fileSize;
@@ -200,17 +202,11 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
     if (IsBinarySTL(mBuffer, fileSize)) {
         bMatClr = LoadBinaryFile();
     } else if (IsAsciiSTL(mBuffer, fileSize)) {
-        LoadASCIIFile();
+        LoadASCIIFile( pScene->mRootNode );
     } else {
         throw DeadlyImportError( "Failed to determine STL storage representation for " + pFile + ".");
     }
 
-    // add all created meshes to the single node
-    pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
-    pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
-    for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
-        pScene->mRootNode->mMeshes[i] = i;
-
     // create a single default material, using a white diffuse color for consistency with
     // other geometric types (e.g., PLY).
     aiMaterial* pcMat = new aiMaterial();
@@ -231,11 +227,12 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
     pScene->mMaterials = new aiMaterial*[1];
     pScene->mMaterials[0] = pcMat;
 }
+
 // ------------------------------------------------------------------------------------------------
 // Read an ASCII STL file
-void STLImporter::LoadASCIIFile()
-{
+void STLImporter::LoadASCIIFile( aiNode *root ) {
     std::vector<aiMesh*> meshes;
+    std::vector<aiNode*> nodes;
     const char* sz = mBuffer;
     const char* bufferEnd = mBuffer + fileSize;
     std::vector<aiVector3D> positionBuffer;
@@ -247,12 +244,15 @@ void STLImporter::LoadASCIIFile()
     positionBuffer.reserve(sizeEstimate);
     normalBuffer.reserve(sizeEstimate);
 
-    while (IsAsciiSTL(sz, static_cast<unsigned int>(bufferEnd - sz)))
-    {
+    while (IsAsciiSTL(sz, static_cast<unsigned int>(bufferEnd - sz))) {
+        std::vector<unsigned int> meshIndices;
         aiMesh* pMesh = new aiMesh();
         pMesh->mMaterialIndex = 0;
+        meshIndices.push_back( meshes.size() );
         meshes.push_back(pMesh);
-
+        aiNode *node = new aiNode;
+        node->mParent = root;
+        nodes.push_back( node );
         SkipSpaces(&sz);
         ai_assert(!IsLineEnd(sz));
 
@@ -265,20 +265,21 @@ void STLImporter::LoadASCIIFile()
 
         size_t temp;
         // setup the name of the node
-        if ((temp = (size_t)(sz-szMe)))    {
+        if ((temp = (size_t)(sz-szMe))) {
             if (temp >= MAXLEN) {
                 throw DeadlyImportError( "STL: Node name too long" );
             }
-
-            pScene->mRootNode->mName.length = temp;
-            memcpy(pScene->mRootNode->mName.data,szMe,temp);
-            pScene->mRootNode->mName.data[temp] = '\0';
+            std::string name( szMe, temp );
+            node->mName.Set( name.c_str() );
+            //pScene->mRootNode->mName.length = temp;
+            //memcpy(pScene->mRootNode->mName.data,szMe,temp);
+            //pScene->mRootNode->mName.data[temp] = '\0';
+        } else {
+            pScene->mRootNode->mName.Set("<STL_ASCII>");
         }
-        else pScene->mRootNode->mName.Set("<STL_ASCII>");
 
         unsigned int faceVertexCounter = 3;
-        for ( ;; )
-        {
+        for ( ;; ) {
             // go to the next token
             if(!SkipSpacesAndLineEnd(&sz))
             {
@@ -300,9 +301,7 @@ void STLImporter::LoadASCIIFile()
                 SkipSpaces(&sz);
                 if (strncmp(sz,"normal",6))    {
                     DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found");
-                }
-                else
-                {
+                } else {
                     if (sz[6] == '\0') {
                         throw DeadlyImportError("STL: unexpected EOF while parsing facet");
                     }
@@ -316,16 +315,11 @@ void STLImporter::LoadASCIIFile()
                     normalBuffer.push_back(*vn);
                     normalBuffer.push_back(*vn);
                 }
-            }
-            // vertex 1.50000 1.50000 0.00000
-            else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6)))
-            {
+            } else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6))) { // vertex 1.50000 1.50000 0.00000
                 if (faceVertexCounter >= 3) {
                     DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found");
                     ++sz;
-                }
-                else
-                {
+                } else {
                     if (sz[6] == '\0') {
                         throw DeadlyImportError("STL: unexpected EOF while parsing facet");
                     }
@@ -340,17 +334,14 @@ void STLImporter::LoadASCIIFile()
                     sz = fast_atoreal_move<ai_real>(sz, (ai_real&)vn->z );
                     faceVertexCounter++;
                 }
-            }
-            else if (!::strncmp(sz,"endsolid",8))    {
+            } else if (!::strncmp(sz,"endsolid",8))    {
                 do {
                     ++sz;
                 } while (!::IsLineEnd(*sz));
                 SkipSpacesAndLineEnd(&sz);
                 // finished!
                 break;
-            }
-            // else skip the whole identifier
-            else {
+            } else { // else skip the whole identifier
                 do {
                     ++sz;
                 } while (!::IsSpaceOrNewLine(*sz));
@@ -380,13 +371,22 @@ void STLImporter::LoadASCIIFile()
 
         // now copy faces
         addFacesToMesh(pMesh);
+
+        // assign the meshes to the current node
+        pushMeshesToNode( meshIndices, node );
     }
+
     // now add the loaded meshes
     pScene->mNumMeshes = (unsigned int)meshes.size();
     pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
-    for (size_t i = 0; i < meshes.size(); i++)
-    {
-        pScene->mMeshes[i] = meshes[i];
+    for (size_t i = 0; i < meshes.size(); i++) {
+        pScene->mMeshes[ i ] = meshes[i];
+    }
+
+    root->mNumChildren = nodes.size();
+    root->mChildren = new aiNode*[ root->mNumChildren ];
+    for ( size_t i=0; i<nodes.size(); ++i ) {
+        root->mChildren[ i ] = nodes[ i ];
     }
 }
 
@@ -513,4 +513,18 @@ bool STLImporter::LoadBinaryFile()
     return false;
 }
 
+void STLImporter::pushMeshesToNode( std::vector<unsigned int> &meshIndices, aiNode *node ) {
+    ai_assert( nullptr != node );
+    if ( meshIndices.empty() ) {
+        return;
+    }
+
+    node->mNumMeshes = static_cast<unsigned int>( meshIndices.size() );
+    node->mMeshes = new unsigned int[ meshIndices.size() ];
+    for ( size_t i=0; i<meshIndices.size(); ++i ) {
+        node->mMeshes[ i ] = meshIndices[ i ];
+    }
+    meshIndices.clear();
+}
+
 #endif // !! ASSIMP_BUILD_NO_STL_IMPORTER

+ 34 - 26
code/STLLoader.h

@@ -48,53 +48,61 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BaseImporter.h"
 #include <assimp/types.h>
 
-namespace Assimp    {
+// Forward declarations
+struct aiNode;
+
+namespace Assimp {
+
 
 // ---------------------------------------------------------------------------
-/** Importer class for the sterolithography STL file format
-*/
-class STLImporter : public BaseImporter
-{
+/**
+ * @brief   Importer class for the sterolithography STL file format.
+ */
+class STLImporter : public BaseImporter {
 public:
+    /**
+     * @brief STLImporter, the class default constructor.
+     */
     STLImporter();
-    ~STLImporter();
 
+    /**
+     * @brief   The class destructor.
+     */
+    ~STLImporter();
 
-public:
-
-    // -------------------------------------------------------------------
-    /** Returns whether the class can handle the format of the given file.
-     * See BaseImporter::CanRead() for details.
+    /**
+     * @brief   Returns whether the class can handle the format of the given file.
+     *  See BaseImporter::CanRead() for details.
      */
-    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-        bool checkSig) const;
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
 
 protected:
 
-    // -------------------------------------------------------------------
-    /** Return importer meta information.
-     * See #BaseImporter::GetInfo for the details
+    /**
+     * @brief   Return importer meta information.
+     *  See #BaseImporter::GetInfo for the details
      */
     const aiImporterDesc* GetInfo () const;
 
-    // -------------------------------------------------------------------
-    /** Imports the given file into the given scene structure.
+    /**
+     * @brief   Imports the given file into the given scene structure.
     * See BaseImporter::InternReadFile() for details
     */
     void InternReadFile( const std::string& pFile, aiScene* pScene,
         IOSystem* pIOHandler);
 
-
-    // -------------------------------------------------------------------
-    /** Loads a binary .stl file
+    /**
+     * @brief   Loads a binary .stl file
      * @return true if the default vertex color must be used as material color
-    */
+     */
     bool LoadBinaryFile();
 
-    // -------------------------------------------------------------------
-    /** Loads a ASCII text .stl file
-    */
-    void LoadASCIIFile();
+    /**
+     * @brief   Loads a ASCII text .stl file
+     */
+    void LoadASCIIFile( aiNode *root );
+
+    void pushMeshesToNode( std::vector<unsigned int> &meshIndices, aiNode *node );
 
 protected:
 

+ 10 - 9
code/Subdivision.h

@@ -40,10 +40,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 /** @file Defines a helper class to evaluate subdivision surfaces.*/
+#pragma once
 #ifndef AI_SUBDISIVION_H_INC
 #define AI_SUBDISIVION_H_INC
 
 #include <cstddef>
+#include <assimp/types.h>
+
 struct aiMesh;
 
 namespace Assimp    {
@@ -52,8 +55,7 @@ namespace Assimp    {
 /** Helper class to evaluate subdivision surfaces. Different algorithms
  *  are provided for choice. */
 // ------------------------------------------------------------------------------
-class Subdivider
-{
+class ASSIMP_API Subdivider {
 public:
 
     /** Enumerates all supported subvidision algorithms */
@@ -61,12 +63,7 @@ public:
         CATMULL_CLARKE = 0x1
     };
 
-public:
-
-    virtual ~Subdivider() {
-    }
-
-public:
+    virtual ~Subdivider();
 
     // ---------------------------------------------------------------
     /** Create a subdivider of a specific type
@@ -119,9 +116,13 @@ public:
         unsigned int num,
         bool discard_input = false) = 0;
 
-private:
 };
 
+inline
+Subdivider::~Subdivider() {
+    // empty
+}
+
 } // end namespace Assimp
 
 

+ 1 - 4
code/TerragenLoader.cpp

@@ -141,9 +141,6 @@ void TerragenImporter::InternReadFile( const std::string& pFile,
         throw DeadlyImportError( "TER: Magic string \'TERRAIN\' not found" );
 
     unsigned int x = 0,y = 0,mode = 0;
-    float rad  = 6370.f;
-    (void)rad;
-
 
     aiNode* root = pScene->mRootNode = new aiNode();
     root->mName.Set("<TERRAGEN.TERRAIN>");
@@ -187,7 +184,7 @@ void TerragenImporter::InternReadFile( const std::string& pFile,
         // mapping == 1: earth radius
         else if (!::strncmp(head,AI_TERR_CHUNK_CRAD,4))
         {
-            rad = reader.GetF4();
+            reader.GetF4();
         }
         // mapping mode
         else if (!::strncmp(head,AI_TERR_CHUNK_CRVM,4))

+ 1 - 1
code/TextureTransform.cpp

@@ -317,7 +317,7 @@ void TextureTransformStep::Execute( aiScene* pScene)
                     info.lockedPos = AI_TT_UV_IDX_LOCK_TBD;
                 }
 
-                // Get all coresponding meshes
+                // Get all corresponding meshes
                 for (unsigned int n = 0; n < pScene->mNumMeshes;++n)    {
                     aiMesh* mesh = pScene->mMeshes[n];
                     if (mesh->mMaterialIndex != i || !mesh->mTextureCoords[0])

+ 4 - 4
code/ValidateDataStructure.cpp

@@ -334,28 +334,28 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
             case 1:
                 if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT))
                 {
-                    ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimtiveTypes "
+                    ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimitiveTypes "
                         "does not report the POINT flag",i);
                 }
                 break;
             case 2:
                 if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE))
                 {
-                    ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimtiveTypes "
+                    ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimitiveTypes "
                         "does not report the LINE flag",i);
                 }
                 break;
             case 3:
                 if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE))
                 {
-                    ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimtiveTypes "
+                    ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimitiveTypes "
                         "does not report the TRIANGLE flag",i);
                 }
                 break;
             default:
                 if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON))
                 {
-                    this->ReportError("aiMesh::mFaces[%i] is a POLYGON but aiMesh::mPrimtiveTypes "
+                    this->ReportError("aiMesh::mFaces[%i] is a POLYGON but aiMesh::mPrimitiveTypes "
                         "does not report the POLYGON flag",i);
                 }
                 break;

+ 1 - 1
code/ValidateDataStructure.h

@@ -91,7 +91,7 @@ protected:
 
     // -------------------------------------------------------------------
     /** Report a validation warning. This won't throw an exception,
-     *  control will return to the callera.
+     *  control will return to the caller.
      * @param msg Format string for sprintf().*/
     void ReportWarning(const char* msg,...);
 

+ 6 - 2
code/X3DExporter.cpp

@@ -240,8 +240,12 @@ list<SAttribute> attr_list;
 		if((rotate_angle != 0) && (rotate_axis.Length() > 0))
 			attr_list.push_back({"rotation", Rotation2String(rotate_axis, rotate_angle)});
 
-		if(!scale.Equal({1, 1, 1})) attr_list.push_back({"scale", Vector2String(scale)});
-		if(translate.Length() > 0) attr_list.push_back({"translation", Vector2String(translate)});
+        if(!scale.Equal({1.0,1.0,1.0})) {
+            attr_list.push_back({"scale", Vector2String(scale)});
+        }
+        if(translate.Length() > 0) {
+            attr_list.push_back({"translation", Vector2String(translate)});
+        }
 	}
 
 	// Begin node if need.

+ 2 - 2
code/X3DExporter.hpp

@@ -27,7 +27,7 @@ namespace Assimp
 ///
 /// Pay attention that X3D is format for interactive graphic and simulations for web browsers. aiScene can not contain all features of the X3D format.
 /// Also, aiScene contain rasterized-like data. For example, X3D can describe circle all cylinder with one tag, but aiScene contain result of tesselation:
-/// vertices, faces etc. Yes, you can use algorithm for detecting figures or shapes, but thats not good idea at all.
+/// vertices, faces etc. Yes, you can use algorithm for detecting figures or shapes, but that's not a good idea at all.
 ///
 /// Supported nodes:
 ///		Core component:
@@ -96,7 +96,7 @@ private:
 	aiMatrix4x4 Matrix_GlobalToCurrent(const aiNode& pNode) const;
 
 	/// \fn void AttrHelper_CommaToPoint(std::string& pStringWithComma)
-	/// Convert commas in string to points. Thats need because "std::to_string" result depend on locale (regional settings).
+	/// Convert commas in string to points. That's needed because "std::to_string" result depends on locale (regional settings).
 	/// \param [in, out] pStringWithComma - reference to string, which must be modified.
 	void AttrHelper_CommaToPoint(std::string& pStringWithComma) { for(char& c: pStringWithComma) { if(c == ',') c = '.'; } }
 

+ 3 - 3
code/X3DImporter.hpp

@@ -176,7 +176,7 @@ namespace Assimp {
 /// Ignored attributes: "creaseAngle", "convex", "solid".
 ///
 /// Texture coordinates generating: only for Sphere, Cone, Cylinder. In all other case used PLANE mapping.
-///		It's better that Assimp main code has powerfull texture coordinates generator. Then is not needed to
+///		It's better that Assimp main code has powerful texture coordinates generator. Then is not needed to
 ///		duplicate this code in every importer.
 ///
 /// Lighting limitations.
@@ -401,10 +401,10 @@ private:
 	/************** Functions: XML set *************/
 	/***********************************************/
 
-	/// Chek if current node is empty: <node />. If not then exception will throwed.
+	/// Check if current node is empty: <node />. If not then exception will throwed.
 	void XML_CheckNode_MustBeEmpty();
 
-	/// Chek if current node name is equal to pNodeName.
+	/// Check if current node name is equal to pNodeName.
 	/// \param [in] pNodeName - name for checking.
 	/// return true if current node name is equal to pNodeName, else - false.
 	bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }

+ 7 - 0
code/X3DImporter_Postprocess.cpp

@@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "X3DImporter.hpp"
 
 // Header files, Assimp.
+#include <assimp/ai_assert.h>
 #include "StandardShapes.h"
 #include "StringUtils.h"
 
@@ -357,6 +358,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
 		// copy additional information from children
 		for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
 		{
+			ai_assert(*pMesh);
 			if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
 				MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
 			else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
@@ -389,6 +391,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
 		// copy additional information from children
 		for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
 		{
+			ai_assert(*pMesh);
 			if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
 				MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
 			else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
@@ -446,6 +449,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
 		// copy additional information from children
 		for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
 		{
+			ai_assert(*pMesh);
 			if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
 				MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, true);
 			else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
@@ -475,6 +479,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
 		// copy additional information from children
 		for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
 		{
+			ai_assert(*pMesh);
 			if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
 				MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, true);
 			else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
@@ -550,6 +555,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
 		// copy additional information from children
 		for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
 		{
+			ai_assert(*pMesh);
 			if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
 				MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
 			else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
@@ -584,6 +590,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
 		// copy additional information from children
 		for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
 		{
+			ai_assert(*pMesh);
 			if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
 				MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
 			else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)

+ 1 - 4
code/XFileImporter.h

@@ -65,14 +65,11 @@ struct Node;
 /** The XFileImporter is a worker class capable of importing a scene from a
  * DirectX file .x
  */
-class XFileImporter : public BaseImporter
-{
+class XFileImporter : public BaseImporter {
 public:
     XFileImporter();
     ~XFileImporter();
 
-
-public:
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.
      * See BaseImporter::CanRead() for details. */

+ 3 - 3
code/fast_atof.h

@@ -360,7 +360,7 @@ inline const char* fast_atoreal_move(const char* c, Real& out, bool check_comma
 // The same but more human.
 inline ai_real fast_atof(const char* c)
 {
-    ai_real ret;
+    ai_real ret(0.0);
     fast_atoreal_move<ai_real>(c, ret);
     return ret;
 }
@@ -368,7 +368,7 @@ inline ai_real fast_atof(const char* c)
 
 inline ai_real fast_atof( const char* c, const char** cout)
 {
-    ai_real ret;
+    ai_real ret(0.0);
     *cout = fast_atoreal_move<ai_real>(c, ret);
 
     return ret;
@@ -376,7 +376,7 @@ inline ai_real fast_atof( const char* c, const char** cout)
 
 inline ai_real fast_atof( const char** inout)
 {
-    ai_real ret;
+    ai_real ret(0.0);
     *inout = fast_atoreal_move<ai_real>(*inout, ret);
 
     return ret;

+ 31 - 6
code/glTF2Asset.h

@@ -88,6 +88,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #   endif
 #endif
 
+#include "StringUtils.h"
+
 namespace glTF2
 {
 #ifdef ASSIMP_API
@@ -190,15 +192,31 @@ namespace glTF2
         #include "./../include/assimp/Compiler/pushpack1.h"
     #endif
 
+    //! For binary .glb files
+    //! 12-byte header (+ the JSON + a "body" data section)
+    struct GLB_Header
+    {
+        uint8_t magic[4];     //!< Magic number: "glTF"
+        uint32_t version;     //!< Version number (always 2 as of the last update)
+        uint32_t length;      //!< Total length of the Binary glTF, including header, scene, and body, in bytes
+    } PACK_STRUCT;
+
+    struct GLB_Chunk
+    {
+        uint32_t chunkLength;
+        uint32_t chunkType;
+    } PACK_STRUCT;
+
     #ifdef ASSIMP_API
         #include "./../include/assimp/Compiler/poppack1.h"
     #endif
 
 
-    //! Values for the GLB_Header::sceneFormat field
-    enum SceneFormat
+    //! Values for the GLB_Chunk::chunkType field
+    enum ChunkType
     {
-        SceneFormat_JSON = 0
+        ChunkType_JSON = 0x4E4F534A,
+        ChunkType_BIN  = 0x004E4942
     };
 
     //! Values for the mesh primitive modes
@@ -239,7 +257,7 @@ namespace glTF2
             case ComponentType_UNSIGNED_BYTE:
                 return 1;
             default:
-                throw DeadlyImportError("GLTF: Unsupported Component Type " + std::to_string(t));
+                throw DeadlyImportError("GLTF: Unsupported Component Type " + to_string(t));
         }
     }
 
@@ -418,7 +436,6 @@ namespace glTF2
     {
         Ref<BufferView> bufferView;  //!< The ID of the bufferView. (required)
         unsigned int byteOffset;     //!< The offset relative to the start of the bufferView in bytes. (required)
-        unsigned int byteStride;     //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0)
         ComponentType componentType; //!< The datatype of components in the attribute. (required)
         unsigned int count;          //!< The number of attributes referenced by this accessor. (required)
         AttribType::Value type;      //!< Specifies if the attribute is a scalar, vector, or matrix. (required)
@@ -609,6 +626,7 @@ namespace glTF2
         Ref<Buffer> buffer; //! The ID of the buffer. (required)
         size_t byteOffset; //! The offset into the buffer in bytes. (required)
         size_t byteLength; //! The length of the bufferView in bytes. (default: 0)
+        unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0)
 
         BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
 
@@ -971,6 +989,8 @@ namespace glTF2
         Ref<T> Create(const std::string& id)
             { return Create(id.c_str()); }
 
+        unsigned int Remove(const char* id);
+
         inline unsigned int Size() const
             { return unsigned(mObjs.size()); }
 
@@ -1082,7 +1102,10 @@ namespace glTF2
         }
 
         //! Main function
-        void Load(const std::string& file);
+        void Load(const std::string& file, bool isBinary = false);
+
+        //! Enables binary encoding on the asset
+        void SetAsBinary();
 
         //! Search for an available name, starting from the given strings
         std::string FindUniqueID(const std::string& str, const char* suffix);
@@ -1091,6 +1114,8 @@ namespace glTF2
             { return mBodyBuffer; }
 
     private:
+        void ReadBinaryHeader(IOStream& stream, std::vector<char>& sceneData);
+
         void ReadExtensionsUsed(Document& doc);
 
         IOStream* OpenFile(std::string path, const char* mode, bool absolute = false);

+ 140 - 13
code/glTF2Asset.inl

@@ -193,6 +193,50 @@ inline void LazyDict<T>::DetachFromDocument()
     mDict = 0;
 }
 
+template<class T>
+unsigned int LazyDict<T>::Remove(const char* id)
+{
+    id = T::TranslateId(mAsset, id);
+
+    typename IdDict::iterator it = mObjsById.find(id);
+
+    if (it == mObjsById.end()) {
+        throw DeadlyExportError("GLTF: Object with id \"" + std::string(id) + "\" is not found");
+    }
+
+    const unsigned int index = it->second;
+
+    mAsset.mUsedIds[id] = false;
+    mObjsById.erase(id);
+    mObjsByOIndex.erase(index);
+    mObjs.erase(mObjs.begin() + index);
+
+    //update index of object in mObjs;
+    for (size_t i = index; i < mObjs.size(); ++i) {
+        T *obj = mObjs[i];
+
+        obj->index = i;
+    }
+
+    for (IdDict::iterator it = mObjsById.begin(); it != mObjsById.end(); ++it) {
+        if (it->second <= index) {
+            continue;
+        }
+
+        mObjsById[it->first] = it->second - 1;
+    }
+
+    for (Dict::iterator it = mObjsByOIndex.begin(); it != mObjsByOIndex.end(); ++it) {
+        if (it->second <= index) {
+            continue;
+        }
+
+        mObjsByOIndex[it->first] = it->second - 1;
+    }
+
+    return index;
+}
+
 template<class T>
 Ref<T> LazyDict<T>::Retrieve(unsigned int i)
 {
@@ -214,11 +258,11 @@ Ref<T> LazyDict<T>::Retrieve(unsigned int i)
     Value &obj = (*mDict)[i];
 
     if (!obj.IsObject()) {
-        throw DeadlyImportError("GLTF: Object at index \"" + std::to_string(i) + "\" is not a JSON object");
+        throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object");
     }
 
     T* inst = new T();
-    inst->id = std::string(mDictId) + "_" + std::to_string(i);
+    inst->id = std::string(mDictId) + "_" + to_string(i);
     inst->oIndex = i;
     ReadMember(obj, "name", inst->name);
     inst->Read(obj, mAsset);
@@ -468,6 +512,7 @@ inline void BufferView::Read(Value& obj, Asset& r)
 
     byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
     byteLength = MemberOrDefault(obj, "byteLength", 0u);
+    byteStride = MemberOrDefault(obj, "byteStride", 0u);
 }
 
 //
@@ -482,7 +527,6 @@ inline void Accessor::Read(Value& obj, Asset& r)
     }
 
     byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
-    byteStride = MemberOrDefault(obj, "byteStride", 0u);
     componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
     count = MemberOrDefault(obj, "count", 0u);
 
@@ -557,7 +601,7 @@ bool Accessor::ExtractData(T*& outData)
     const size_t elemSize = GetElementSize();
     const size_t totalSize = elemSize * count;
 
-    const size_t stride = byteStride ? byteStride : elemSize;
+    const size_t stride = bufferView && bufferView->byteStride ? bufferView->byteStride : elemSize;
 
     const size_t targetElemSize = sizeof(T);
     ai_assert(elemSize <= targetElemSize);
@@ -597,7 +641,7 @@ inline Accessor::Indexer::Indexer(Accessor& acc)
     : accessor(acc)
     , data(acc.GetPointer())
     , elemSize(acc.GetElementSize())
-    , stride(acc.byteStride ? acc.byteStride : elemSize)
+    , stride(acc.bufferView && acc.bufferView->byteStride ? acc.bufferView->byteStride : elemSize)
 {
 
 }
@@ -993,7 +1037,72 @@ inline void AssetMetadata::Read(Document& doc)
 // Asset methods implementation
 //
 
-inline void Asset::Load(const std::string& pFile)
+inline void Asset::ReadBinaryHeader(IOStream& stream, std::vector<char>& sceneData)
+{
+    GLB_Header header;
+    if (stream.Read(&header, sizeof(header), 1) != 1) {
+        throw DeadlyImportError("GLTF: Unable to read the file header");
+    }
+
+    if (strncmp((char*)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
+        throw DeadlyImportError("GLTF: Invalid binary glTF file");
+    }
+
+    AI_SWAP4(header.version);
+    asset.version = to_string(header.version);
+    if (header.version != 2) {
+        throw DeadlyImportError("GLTF: Unsupported binary glTF version");
+    }
+
+    GLB_Chunk chunk;
+    if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
+        throw DeadlyImportError("GLTF: Unable to read JSON chunk");
+    }
+
+    AI_SWAP4(chunk.chunkLength);
+    AI_SWAP4(chunk.chunkType);
+
+    if (chunk.chunkType != ChunkType_JSON) {
+        throw DeadlyImportError("GLTF: JSON chunk missing");
+    }
+
+    // read the scene data
+
+    mSceneLength = chunk.chunkLength;
+    sceneData.resize(mSceneLength + 1);
+    sceneData[mSceneLength] = '\0';
+
+    if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
+        throw DeadlyImportError("GLTF: Could not read the file contents");
+    }
+
+    uint32_t padding = ((chunk.chunkLength + 3) & ~3) - chunk.chunkLength;
+    if (padding > 0) {
+        stream.Seek(padding, aiOrigin_CUR);
+    }
+
+    AI_SWAP4(header.length);
+    mBodyOffset = 12 + 8 + chunk.chunkLength + padding + 8;
+    if (header.length >= mBodyOffset) {
+        if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
+            throw DeadlyImportError("GLTF: Unable to read BIN chunk");
+        }
+
+        AI_SWAP4(chunk.chunkLength);
+        AI_SWAP4(chunk.chunkType);
+
+        if (chunk.chunkType != ChunkType_BIN) {
+            throw DeadlyImportError("GLTF: BIN chunk missing");
+        }
+
+        mBodyLength = chunk.chunkLength;
+    }
+    else {
+        mBodyOffset = mBodyLength = 0;
+    }
+}
+
+inline void Asset::Load(const std::string& pFile, bool isBinary)
 {
     mCurrentAssetDir.clear();
     int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
@@ -1004,16 +1113,25 @@ inline void Asset::Load(const std::string& pFile)
         throw DeadlyImportError("GLTF: Could not open file for reading");
     }
 
-    mSceneLength = stream->FileSize();
-    mBodyLength = 0;
+    // is binary? then read the header
+    std::vector<char> sceneData;
+    if (isBinary) {
+        SetAsBinary(); // also creates the body buffer
+        ReadBinaryHeader(*stream, sceneData);
+    }
+    else {
+        mSceneLength = stream->FileSize();
+        mBodyLength = 0;
 
-    // read the scene data
 
-    std::vector<char> sceneData(mSceneLength + 1);
-    sceneData[mSceneLength] = '\0';
+        // read the scene data
 
-    if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
-        throw DeadlyImportError("GLTF: Could not read the file contents");
+        sceneData.resize(mSceneLength + 1);
+        sceneData[mSceneLength] = '\0';
+
+        if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
+            throw DeadlyImportError("GLTF: Could not read the file contents");
+        }
     }
 
 
@@ -1066,6 +1184,15 @@ inline void Asset::Load(const std::string& pFile)
     }
 }
 
+inline void Asset::SetAsBinary()
+{
+    if (!mBodyBuffer) {
+        mBodyBuffer = buffers.Create("binary_glTF");
+        mBodyBuffer->MarkAsSpecial();
+    }
+}
+
+
 inline void Asset::ReadExtensionsUsed(Document& doc)
 {
     Value* extsUsed = FindArray(doc, "extensionsUsed");

+ 3 - 4
code/glTF2AssetWriter.inl

@@ -98,10 +98,6 @@ namespace glTF2 {
         obj.AddMember("bufferView", a.bufferView->index, w.mAl);
         obj.AddMember("byteOffset", a.byteOffset, w.mAl);
 
-        if (a.byteStride != 0) {
-            obj.AddMember("byteStride", a.byteStride, w.mAl);
-        }
-
         obj.AddMember("componentType", int(a.componentType), w.mAl);
         obj.AddMember("count", a.count, w.mAl);
         obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
@@ -168,6 +164,9 @@ namespace glTF2 {
         obj.AddMember("buffer", bv.buffer->index, w.mAl);
         obj.AddMember("byteOffset", static_cast<uint64_t>(bv.byteOffset), w.mAl);
         obj.AddMember("byteLength", static_cast<uint64_t>(bv.byteLength), w.mAl);
+        if (bv.byteStride != 0) {
+            obj.AddMember("byteStride", bv.byteStride, w.mAl);
+        }
         obj.AddMember("target", int(bv.target), w.mAl);
     }
 

+ 29 - 5
code/glTF2Exporter.cpp

@@ -56,7 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/material.h>
 #include <assimp/scene.h>
 
-// Header files, standart library.
+// Header files, standard library.
 #include <memory>
 #include <inttypes.h>
 
@@ -170,13 +170,13 @@ inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& bu
     bv->buffer = buffer;
     bv->byteOffset = unsigned(offset);
     bv->byteLength = length; //! The target that the WebGL buffer should be bound to.
+    bv->byteStride = 0;
     bv->target = isIndices ? BufferViewTarget_ELEMENT_ARRAY_BUFFER : BufferViewTarget_ARRAY_BUFFER;
 
     // accessor
     Ref<Accessor> acc = a.accessors.Create(a.FindUniqueID(meshName, "accessor"));
     acc->bufferView = bv;
     acc->byteOffset = 0;
-    acc->byteStride = 0;
     acc->componentType = compType;
     acc->count = count;
     acc->type = typeOut;
@@ -402,7 +402,7 @@ void glTF2Exporter::ExportMaterials()
     for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
         const aiMaterial* mat = mScene->mMaterials[i];
 
-        std::string id = "material_" + std::to_string(i);
+        std::string id = "material_" + to_string(i);
 
         Ref<Material> m = mAsset->materials.Create(id);
 
@@ -800,9 +800,33 @@ void glTF2Exporter::MergeMeshes()
             for (unsigned int m = nMeshes - 1; m >= 1; --m) {
                 Ref<Mesh> mesh = node->meshes.at(m);
 
-                firstMesh->primitives.insert(firstMesh->primitives.end(), mesh->primitives.begin(), mesh->primitives.end());
+                //append this mesh's primitives to the first mesh's primitives
+                firstMesh->primitives.insert(
+                    firstMesh->primitives.end(),
+                    mesh->primitives.begin(),
+                    mesh->primitives.end()
+                );
 
-                node->meshes.erase(node->meshes.begin() + m);
+                //remove the mesh from the list of meshes
+                unsigned int removedIndex = mAsset->meshes.Remove(mesh->id.c_str());
+
+                //find the presence of the removed mesh in other nodes
+                for (unsigned int nn = 0; nn < mAsset->nodes.Size(); ++nn) {
+                    Ref<Node> node = mAsset->nodes.Get(nn);
+
+                    for (unsigned int mm = 0; mm < node->meshes.size(); ++mm) {
+                        Ref<Mesh>& meshRef = node->meshes.at(mm);
+                        unsigned int meshIndex = meshRef.GetIndex();
+
+                        if (meshIndex == removedIndex) {
+                            node->meshes.erase(node->meshes.begin() + mm);
+                        } else if (meshIndex > removedIndex) {
+                            Ref<Mesh> newMeshRef = mAsset->meshes.Get(meshIndex - 1);
+
+                            meshRef = newMeshRef;
+                        }
+                    }
+                }
             }
 
             //since we were looping backwards, reverse the order of merged primitives to their original order

+ 4 - 4
code/glTF2Importer.cpp

@@ -74,7 +74,7 @@ static const aiImporterDesc desc = {
     "",
     "",
     "",
-    aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
+    aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
     0,
     0,
     0,
@@ -103,13 +103,13 @@ bool glTF2Importer::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool
 {
     const std::string &extension = GetExtension(pFile);
 
-    if (extension != "gltf") // We currently can't read glTF2 binary files (.glb), yet
+    if (extension != "gltf" && extension != "glb")
         return false;
 
     if (checkSig && pIOHandler) {
         glTF2::Asset asset(pIOHandler);
         try {
-            asset.Load(pFile);
+            asset.Load(pFile, extension == "glb");
             std::string version = asset.asset.version;
             return !version.empty() && version[0] == '2';
         } catch (...) {
@@ -639,7 +639,7 @@ void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IO
 
     // read the asset file
     glTF2::Asset asset(pIOHandler);
-    asset.Load(pFile);
+    asset.Load(pFile, GetExtension(pFile) == "glb");
 
     //
     // Copy the data out

+ 1 - 1
code/glTFAsset.inl

@@ -1282,7 +1282,7 @@ inline void Asset::ReadBinaryHeader(IOStream& stream)
     }
 
     AI_SWAP4(header.version);
-    asset.version = std::to_string(header.version);
+    asset.version = to_string(header.version);
     if (header.version != 1) {
         throw DeadlyImportError("GLTF: Unsupported binary glTF version");
     }

+ 1 - 1
code/glTFExporter.cpp

@@ -56,7 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/material.h>
 #include <assimp/scene.h>
 
-// Header files, standart library.
+// Header files, standard library.
 #include <memory>
 #include <inttypes.h>
 

+ 2 - 0
contrib/Open3DGC/o3dgcArithmeticCodec.cpp

@@ -820,6 +820,7 @@ namespace o3dgc
         for (unsigned n = 0; n < data_symbols; n++)
           total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1);
       }
+      assert(total_count > 0);
                                  // compute cumulative distribution, decoder table
       unsigned k, sum = 0, s = 0;
       unsigned scale = 0x80000000U / total_count;
@@ -830,6 +831,7 @@ namespace o3dgc
           sum += symbol_count[k];
         }
       else {
+        assert(decoder_table);
         for (k = 0; k < data_symbols; k++) {
           distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
           sum += symbol_count[k];

+ 6 - 3
contrib/Open3DGC/o3dgcBinaryStream.h

@@ -231,7 +231,8 @@ namespace o3dgc
         float                   ReadFloat32Bin(unsigned long & position) const
                                 {
                                     unsigned long value = ReadUInt32Bin(position);
-                                    float fvalue = *((float *)(&value));
+                                    float fvalue;
+                                    memcpy(&fvalue, &value, 4);
                                     return fvalue;
                                 }
         unsigned long           ReadUInt32Bin(unsigned long & position)  const
@@ -261,7 +262,8 @@ namespace o3dgc
 
         void                    WriteFloat32ASCII(float value) 
                                 {
-                                    unsigned long uiValue = *((unsigned long *)(&value));
+                                    unsigned long uiValue;
+                                    memcpy(&uiValue, &value, 4);
                                     WriteUInt32ASCII(uiValue);
                                 }
         void                    WriteUInt32ASCII(unsigned long position, unsigned long value) 
@@ -314,7 +316,8 @@ namespace o3dgc
         float                   ReadFloat32ASCII(unsigned long & position) const
                                 {
                                     unsigned long value = ReadUInt32ASCII(position);
-                                    float fvalue = *((float *)(&value));
+                                    float fvalue;
+                                    memcpy(&fvalue, &value, 4);
                                     return fvalue;
                                 }
         unsigned long           ReadUInt32ASCII(unsigned long & position)  const

+ 96 - 0
contrib/android-cmake/AndroidNdkGdb.cmake

@@ -0,0 +1,96 @@
+# Copyright (c) 2014, Pavel Rojtberg
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. 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.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# 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.
+
+# ------------------------------------------------------------------------------
+# Usage:
+# 1. place AndroidNdkGdb.cmake somewhere inside ${CMAKE_MODULE_PATH}
+# 2. inside your project add
+#
+#    include(AndroidNdkGdb)
+#    android_ndk_gdb_enable()
+#    # for each target
+#    add_library(MyLibrary ...)
+#    android_ndk_gdb_debuggable(MyLibrary)    
+
+
+# add gdbserver and general gdb configuration to project
+# also create a mininal NDK skeleton so ndk-gdb finds the paths
+#
+# the optional parameter defines the path to the android project.
+# uses PROJECT_SOURCE_DIR by default.
+macro(android_ndk_gdb_enable)
+    if(ANDROID)
+        # create custom target that depends on the real target so it gets executed afterwards
+        add_custom_target(NDK_GDB ALL)
+        
+        if(${ARGC})
+            set(ANDROID_PROJECT_DIR ${ARGV0})
+        else()
+            set(ANDROID_PROJECT_DIR ${PROJECT_SOURCE_DIR})
+        endif()
+
+        set(NDK_GDB_SOLIB_PATH ${ANDROID_PROJECT_DIR}/obj/local/${ANDROID_NDK_ABI_NAME}/)
+        file(MAKE_DIRECTORY ${NDK_GDB_SOLIB_PATH})
+        
+        # 1. generate essential Android Makefiles
+        file(MAKE_DIRECTORY ${ANDROID_PROJECT_DIR}/jni)
+        if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Android.mk)
+            file(WRITE ${ANDROID_PROJECT_DIR}/jni/Android.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n")
+        endif()
+        if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Application.mk)
+            file(WRITE ${ANDROID_PROJECT_DIR}/jni/Application.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n")
+        endif()
+    
+        # 2. generate gdb.setup
+        get_directory_property(PROJECT_INCLUDES DIRECTORY ${PROJECT_SOURCE_DIR} INCLUDE_DIRECTORIES)
+        string(REGEX REPLACE ";" " " PROJECT_INCLUDES "${PROJECT_INCLUDES}")
+        file(WRITE ${LIBRARY_OUTPUT_PATH}/gdb.setup "set solib-search-path ${NDK_GDB_SOLIB_PATH}\n")
+        file(APPEND ${LIBRARY_OUTPUT_PATH}/gdb.setup "directory ${PROJECT_INCLUDES}\n")
+    
+        # 3. copy gdbserver executable
+        file(COPY ${ANDROID_NDK}/prebuilt/android-${ANDROID_ARCH_NAME}/gdbserver/gdbserver DESTINATION ${LIBRARY_OUTPUT_PATH})
+    endif()
+endmacro()
+
+# register a target for remote debugging
+# copies the debug version to NDK_GDB_SOLIB_PATH then strips symbols of original
+macro(android_ndk_gdb_debuggable TARGET_NAME)
+    if(ANDROID)
+        get_property(TARGET_LOCATION TARGET ${TARGET_NAME} PROPERTY LOCATION)
+        
+        # create custom target that depends on the real target so it gets executed afterwards
+        add_dependencies(NDK_GDB ${TARGET_NAME})
+    
+        # 4. copy lib to obj
+        add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${TARGET_LOCATION} ${NDK_GDB_SOLIB_PATH})
+    
+        # 5. strip symbols
+        add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_STRIP} ${TARGET_LOCATION})
+    endif()
+endmacro()

+ 58 - 0
contrib/android-cmake/AndroidNdkModules.cmake

@@ -0,0 +1,58 @@
+# Copyright (c) 2014, Pavel Rojtberg
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. 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.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# 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.
+
+macro(android_ndk_import_module_cpufeatures)
+    if(ANDROID)
+        include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
+        add_library(cpufeatures ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
+        target_link_libraries(cpufeatures dl)
+    endif()
+endmacro()
+
+macro(android_ndk_import_module_native_app_glue)
+    if(ANDROID)
+        include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
+        add_library(native_app_glue ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
+        target_link_libraries(native_app_glue log)
+    endif()
+endmacro()
+
+macro(android_ndk_import_module_ndk_helper)
+    if(ANDROID)
+        android_ndk_import_module_cpufeatures()
+        android_ndk_import_module_native_app_glue()
+        
+        include_directories(${ANDROID_NDK}/sources/android/ndk_helper)
+        file(GLOB _NDK_HELPER_SRCS ${ANDROID_NDK}/sources/android/ndk_helper/*.cpp ${ANDROID_NDK}/sources/android/ndk_helper/gl3stub.c)
+        add_library(ndk_helper ${_NDK_HELPER_SRCS})
+        target_link_libraries(ndk_helper log android EGL GLESv2 cpufeatures native_app_glue)
+        
+        unset(_NDK_HELPER_SRCS)
+    endif()
+endmacro()

+ 240 - 0
contrib/android-cmake/README.md

@@ -0,0 +1,240 @@
+# android-cmake
+
+CMake is great, and so is Android. This is a collection of CMake scripts that may be useful to the Android NDK community. It is based on experience from porting OpenCV library to Android: http://opencv.org/platforms/android.html
+
+Main goal is to share these scripts so that devs that use CMake as their build system may easily compile native code for Android.
+
+## TL;DR
+
+    cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake \
+          -DANDROID_NDK=<ndk_path>                       \
+          -DCMAKE_BUILD_TYPE=Release                     \
+          -DANDROID_ABI="armeabi-v7a with NEON"          \
+          <source_path>
+    cmake --build .
+
+One-liner:
+
+    cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake -DANDROID_NDK=<ndk_path> -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="armeabi-v7a with NEON" <source_path> && cmake --build .
+
+_android-cmake_ will search for your NDK install in the following order:
+
+1. Value of `ANDROID_NDK` CMake variable;
+1. Value of `ANDROID_NDK` environment variable;
+1. Search under paths from `ANDROID_NDK_SEARCH_PATHS` CMake variable;
+1. Search platform specific locations (home folder, Windows "Program Files", etc).
+
+So if you have installed the NDK as `~/android-ndk-r10d` then _android-cmake_ will locate it automatically.
+
+## Getting started
+
+To build a cmake-based C/C++ project for Android you need:
+
+* Android NDK (>= r5) http://developer.android.com/tools/sdk/ndk/index.html
+* CMake (>= v2.6.3, >= v2.8.9 recommended) http://www.cmake.org/download
+
+The _android-cmake_ is also capable to build with NDK from AOSP or Linaro Android source tree, but you may be required to manually specify path to `libm` binary to link with.
+
+## Difference from traditional CMake
+
+Folowing the _ndk-build_ the _android-cmake_ supports **only two build targets**:
+
+* `-DCMAKE_BUILD_TYPE=Release`
+* `-DCMAKE_BUILD_TYPE=Debug`
+
+So don't even try other targets that can be found in CMake documentation and don't forget to explicitly specify `Release` or `Debug` because CMake builds without a build configuration by default.
+
+## Difference from _ndk-build_
+
+* Latest GCC available in NDK is used as the default compiler;
+* `Release` builds with `-O3` instead of `-Os`;
+* `Release` builds without debug info (without `-g`) (because _ndk-build_ always creates a stripped version but cmake delays this for `install/strip` target);
+* `-fsigned-char` is added to compiler flags to make `char` signed by default as it is on x86/x86_64;
+* GCC's stack protector is not used neither in `Debug` nor `Release` configurations;
+* No builds for multiple platforms (e.g. building for both arm and x86 require to run cmake twice with different parameters);
+* No file level Neon via `.neon` suffix;
+
+The following features of _ndk-build_ are not supported by the _android-cmake_ yet:
+
+* `armeabi-v7a-hard` ABI
+* `libc++_static`/`libc++_shared` STL runtime
+
+## Basic options
+
+Similarly to the NDK build system _android-cmake_ allows to select between several compiler toolchains and target platforms. Most of the options can be set either as cmake arguments: `-D<NAME>=<VALUE>` or as environment variables:
+
+* **ANDROID_NDK** - path to the Android NDK. If not set then _android-cmake_ will search for the most recent version of supported NDK in commonly used locations;
+* **ANDROID_ABI** - specifies the target Application Binary Interface (ABI). This option nearly matches to the APP_ABI variable used by ndk-build tool from Android NDK. If not specified then set to `armeabi-v7a`. Possible target names are:
+    * `armeabi` - ARMv5TE based CPU with software floating point operations;
+    * **`armeabi-v7a`** - ARMv7 based devices with hardware FPU instructions (VFPv3_D16);
+    * `armeabi-v7a with NEON` - same as armeabi-v7a, but sets NEON as floating-point unit;
+    * `armeabi-v7a with VFPV3` - same as armeabi-v7a, but sets VFPv3_D32 as floating-point unit;
+    * `armeabi-v6 with VFP` - tuned for ARMv6 processors having VFP;
+    * `x86` - IA-32 instruction set
+    * `mips` - MIPS32 instruction set
+    * `arm64-v8a` - ARMv8 AArch64 instruction set - only for NDK r10 and newer
+    * `x86_64` - Intel64 instruction set (r1) - only for NDK r10 and newer
+    * `mips64` - MIPS64 instruction set (r6) - only for NDK r10 and newer
+* **ANDROID_NATIVE_API_LEVEL** - level of android API to build for. Can be set either to full name (example: `android-8`) or a numeric value (example: `17`). The default API level depends on the target ABI:
+    * `android-8` for ARM;
+    * `android-9` for x86 and MIPS;
+    * `android-21` for 64-bit ABIs.
+
+    Building for `android-L` is possible only when it is explicitly selected.
+* **ANDROID_TOOLCHAIN_NAME** - the name of compiler toolchain to be used. This option allows to select between different GCC and Clang versions. The list of possible values depends on the NDK version and will be printed by toolchain file if an invalid value is set. By default _android-cmake_ selects the most recent version of GCC which can build for specified `ANDROID_ABI`.
+
+    Example values are:
+    * `aarch64-linux-android-4.9`
+    * `aarch64-linux-android-clang3.5`
+    * `arm-linux-androideabi-4.8`
+    * `arm-linux-androideabi-4.9`
+    * `arm-linux-androideabi-clang3.5`
+    * `mips64el-linux-android-4.9`
+    * `mipsel-linux-android-4.8`
+    * `x86-4.9`
+    * `x86_64-4.9`
+    * etc.
+* **ANDROID_STL** - the name of C++ runtime to use. The default is `gnustl_static`.
+    * `none` - do not configure the runtime.
+    * `system` - use the default minimal system C++ runtime library.
+        * Implies `-fno-rtti -fno-exceptions`.
+    * `system_re` - use the default minimal system C++ runtime library.
+        * Implies `-frtti -fexceptions`.
+    * `gabi++_static` - use the GAbi++ runtime as a static library.
+        * Implies `-frtti -fno-exceptions`.
+        * Available for NDK r7 and newer.
+    * `gabi++_shared` - use the GAbi++ runtime as a shared library.
+        * Implies `-frtti -fno-exceptions`.
+        * Available for NDK r7 and newer.
+    * `stlport_static` - use the STLport runtime as a static library.
+        * Implies `-fno-rtti -fno-exceptions` for NDK before r7.
+        * Implies `-frtti -fno-exceptions` for NDK r7 and newer.
+    * `stlport_shared` - use the STLport runtime as a shared library.
+        * Implies `-fno-rtti -fno-exceptions` for NDK before r7.
+        * Implies `-frtti -fno-exceptions` for NDK r7 and newer.
+    * **`gnustl_static`** - use the GNU STL as a static library.
+        * Implies `-frtti -fexceptions`.
+    * `gnustl_shared` - use the GNU STL as a shared library.
+        * Implies `-frtti -fno-exceptions`.
+        * Available for NDK r7b and newer.
+        * Silently degrades to `gnustl_static` if not available.
+* **NDK_CCACHE** - path to `ccache` executable. If not set then initialized from `NDK_CCACHE` environment variable.
+
+## Advanced _android-cmake_ options
+
+Normally _android-cmake_ users are not supposed to touch these variables but they might be useful to workaround some build issues:
+
+* **ANDROID_FORCE_ARM_BUILD** = `OFF` - generate 32-bit ARM instructions instead of Thumb. Applicable only for arm ABIs and is forced to be `ON` for `armeabi-v6 with VFP`;
+* **ANDROID_NO_UNDEFINED** = `ON` - show all undefined symbols as linker errors;
+* **ANDROID_SO_UNDEFINED** = `OFF` - allow undefined symbols in shared libraries;
+    * actually it is turned `ON` by default for NDK older than `r7`
+* **ANDROID_STL_FORCE_FEATURES** = `ON` - automatically configure rtti and exceptions support based on C++ runtime;
+* **ANDROID_NDK_LAYOUT** = `RELEASE` - inner layout of Android NDK, should be detected automatically. Possible values are:
+    * `RELEASE` - public releases from Google;
+    * `LINARO` - NDK from Linaro project;
+    * `ANDROID` - NDK from AOSP.
+* **ANDROID_FUNCTION_LEVEL_LINKING** = `ON` - enables saparate putting each function and data items into separate sections and enable garbage collection of unused input sections at link time (`-fdata-sections -ffunction-sections -Wl,--gc-sections`);
+* **ANDROID_GOLD_LINKER** = `ON` - use gold linker with GCC 4.6 for NDK r8b and newer (only for ARM and x86);
+* **ANDROID_NOEXECSTACK** = `ON` - enables or disables stack execution protection code (`-Wl,-z,noexecstack`);
+* **ANDROID_RELRO** = `ON` - Enables RELRO - a memory corruption mitigation technique (`-Wl,-z,relro -Wl,-z,now`);
+* **ANDROID_LIBM_PATH** - path to `libm.so` (set to something like `$(TOP)/out/target/product/<product_name>/obj/lib/libm.so`) to workaround unresolved `sincos`.
+
+## Fine-tuning `CMakeLists.txt` for _android-cmake_
+
+### Recognizing Android build
+
+_android-cmake_ defines `ANDROID` CMake variable which can be used to add Android-specific stuff:
+
+    if (ANDROID)
+        message(STATUS "Hello from Android build!")
+    endif()
+
+The recommended way to identify ARM/MIPS/x86 architecture is examining `CMAKE_SYSTEM_PROCESSOR` which is set to the appropriate value:
+
+* `armv5te` - for `armeabi` ABI
+* `armv6` - for `armeabi-v6 with VFP` ABI
+* `armv7-a` - for `armeabi-v7a`, `armeabi-v7a with VFPV3` and `armeabi-v7a with NEON` ABIs
+* `aarch64` - for `arm64-v8a` ABI
+* `i686` - for `x86` ABI
+* `x86_64` - for `x86_64` ABI
+* `mips` - for `mips` ABI
+* `mips64` - for `mips64` ABI
+
+Other variables that are set by _android-cmake_ and can be used for the fine-grained build configuration are:
+
+* `NEON` - set if target ABI supports Neon;
+* `ANDROID_NATIVE_API_LEVEL` - native Android API level we are building for (note: Java part of Andoid application can be built for another API level)
+* `ANDROID_NDK_RELEASE` - version of the Android NDK
+* `ANDROID_NDK_HOST_SYSTEM_NAME` - "windows", "linux-x86" or "darwin-x86" depending on the host platform
+* `ANDROID_RTTI` - set if rtti is enabled by the runtime
+* `ANDROID_EXCEPTIONS` - set if exceptions are enabled by the runtime
+
+### Finding packages
+
+When crosscompiling CMake `find_*` commands are normally expected to find libraries and packages belonging to the same build target. So _android-cmake_ configures CMake to search in Android-specific paths only and ignore your host system locations. So
+
+    find_package(ZLIB)
+
+will surely find libz.so within the Android NDK.
+
+However sometimes you need to locate a host package even when cross-compiling. For example you can be searching for your documentation generator. The _android-cmake_ recommends you to use `find_host_package` and `find_host_program` macro defined in the `android.toolchain.cmake`:
+
+    find_host_package(Doxygen)
+    find_host_program(PDFLATEX pdflatex)
+
+However this will break regular builds so instead of wrapping package search into platform-specific logic you can copy the following snippet into your project (put it after your top-level `project()` command):
+
+    # Search packages for host system instead of packages for target system
+    # in case of cross compilation these macro should be defined by toolchain file
+    if(NOT COMMAND find_host_package)
+      macro(find_host_package)
+        find_package(${ARGN})
+      endmacro()
+    endif()
+    if(NOT COMMAND find_host_program)
+      macro(find_host_program)
+        find_program(${ARGN})
+      endmacro()
+    endif()
+
+### Compiler flags recycling
+
+Make sure to do the following in your scripts:
+
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}")
+
+The flags will be prepopulated with critical flags, so don't loose them. Also be aware that _android-cmake_ also sets configuration-specific compiler and linker flags.
+
+## Troubleshooting
+
+### Building on Windows
+
+First of all `cygwin` builds are **NOT supported** and will not be supported by _android-cmake_. To build natively on Windows you need a port of make but I recommend http://martine.github.io/ninja/ instead.
+
+To build with Ninja you need:
+
+* Ensure you are using CMake newer than 2.8.9;
+* Download the latest Ninja from https://github.com/martine/ninja/releases;
+* Put the `ninja.exe` into your PATH (or add path to `ninja.exe` to your PATH environment variable);
+* Pass `-GNinja` to `cmake` alongside with other arguments (or choose Ninja generator in `cmake-gui`).
+* Enjoy the fast native multithreaded build :)
+
+But if you still want to stick to old make then:
+
+* Get a Windows port of GNU Make:
+    * Android NDK r7 (and newer) already has `make.exe` on board;
+    * `mingw-make` should work as fine;
+    * Download some other port. For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm.
+* Add path to your `make.exe` to system PATH or always use full path;
+* Pass `-G"MinGW Makefiles"` and `-DCMAKE_MAKE_PROGRAM="<full/path/to/>make.exe"`
+    * It must be `MinGW Makefiles` and not `Unix Makefiles` even if your `make.exe` is not a MinGW's make.
+* Run `make.exe` or `cmake --build .` for single-threaded build.
+
+### Projects with assembler files
+
+The _android-cmake_ should correctly handle projects with assembler sources (`*.s` or `*.S`). But if you still facing problems with assembler then try to upgrade your CMake to version newer than 2.8.5
+
+## Copying
+
+_android-cmake_ is distributed under the terms of [BSD 3-Clause License](http://opensource.org/licenses/BSD-3-Clause)

+ 1693 - 0
contrib/android-cmake/android.toolchain.cmake

@@ -0,0 +1,1693 @@
+# Copyright (c) 2010-2011, Ethan Rublee
+# Copyright (c) 2011-2014, Andrey Kamaev
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1.  Redistributions of source code must retain the above copyright notice,
+#     this list of conditions and the following disclaimer.
+#
+# 2.  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.
+#
+# 3.  Neither the name of the copyright holder nor the names of its
+#     contributors may be used to endorse or promote products derived from this
+#     software without specific prior written permission.
+#
+# 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.
+
+# ------------------------------------------------------------------------------
+#  Android CMake toolchain file, for use with the Android NDK r5-r10d
+#  Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended).
+#  See home page: https://github.com/taka-no-me/android-cmake
+#
+#  Usage Linux:
+#   $ export ANDROID_NDK=/absolute/path/to/the/android-ndk
+#   $ mkdir build && cd build
+#   $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
+#   $ make -j8
+#
+#  Usage Windows:
+#     You need native port of make to build your project.
+#     Android NDK r7 (and newer) already has make.exe on board.
+#     For older NDK you have to install it separately.
+#     For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm
+#
+#   $ SET ANDROID_NDK=C:\absolute\path\to\the\android-ndk
+#   $ mkdir build && cd build
+#   $ cmake.exe -G"MinGW Makefiles"
+#       -DCMAKE_TOOLCHAIN_FILE=path\to\the\android.toolchain.cmake
+#       -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows\bin\make.exe" ..
+#   $ cmake.exe --build .
+#
+#
+#  Options (can be set as cmake parameters: -D<option_name>=<value>):
+#    ANDROID_NDK=/opt/android-ndk - path to the NDK root.
+#      Can be set as environment variable. Can be set only at first cmake run.
+#
+#    ANDROID_ABI=armeabi-v7a - specifies the target Application Binary
+#      Interface (ABI). This option nearly matches to the APP_ABI variable
+#      used by ndk-build tool from Android NDK.
+#
+#      Possible targets are:
+#        "armeabi" - ARMv5TE based CPU with software floating point operations
+#        "armeabi-v7a" - ARMv7 based devices with hardware FPU instructions
+#            this ABI target is used by default
+#        "armeabi-v7a with NEON" - same as armeabi-v7a, but
+#            sets NEON as floating-point unit
+#        "armeabi-v7a with VFPV3" - same as armeabi-v7a, but
+#            sets VFPV3 as floating-point unit (has 32 registers instead of 16)
+#        "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP
+#        "x86" - IA-32 instruction set
+#        "mips" - MIPS32 instruction set
+#
+#      64-bit ABIs for NDK r10 and newer:
+#        "arm64-v8a" - ARMv8 AArch64 instruction set
+#        "x86_64" - Intel64 instruction set (r1)
+#        "mips64" - MIPS64 instruction set (r6)
+#
+#    ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for.
+#      Option is read-only when standalone toolchain is used.
+#      Note: building for "android-L" requires explicit configuration.
+#
+#    ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 - the name of compiler
+#      toolchain to be used. The list of possible values depends on the NDK
+#      version. For NDK r10c the possible values are:
+#
+#        * aarch64-linux-android-4.9
+#        * aarch64-linux-android-clang3.4
+#        * aarch64-linux-android-clang3.5
+#        * arm-linux-androideabi-4.6
+#        * arm-linux-androideabi-4.8
+#        * arm-linux-androideabi-4.9 (default)
+#        * arm-linux-androideabi-clang3.4
+#        * arm-linux-androideabi-clang3.5
+#        * mips64el-linux-android-4.9
+#        * mips64el-linux-android-clang3.4
+#        * mips64el-linux-android-clang3.5
+#        * mipsel-linux-android-4.6
+#        * mipsel-linux-android-4.8
+#        * mipsel-linux-android-4.9
+#        * mipsel-linux-android-clang3.4
+#        * mipsel-linux-android-clang3.5
+#        * x86-4.6
+#        * x86-4.8
+#        * x86-4.9
+#        * x86-clang3.4
+#        * x86-clang3.5
+#        * x86_64-4.9
+#        * x86_64-clang3.4
+#        * x86_64-clang3.5
+#
+#    ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions
+#      instead of Thumb. Is not available for "armeabi-v6 with VFP"
+#      (is forced to be ON) ABI.
+#
+#    ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker
+#      errors even if they are not used.
+#
+#    ANDROID_SO_UNDEFINED=OFF - set ON to allow undefined symbols in shared
+#      libraries. Automatically turned for NDK r5x and r6x due to GLESv2
+#      problems.
+#
+#    ANDROID_STL=gnustl_static - specify the runtime to use.
+#
+#      Possible values are:
+#        none           -> Do not configure the runtime.
+#        system         -> Use the default minimal system C++ runtime library.
+#                          Implies -fno-rtti -fno-exceptions.
+#                          Is not available for standalone toolchain.
+#        system_re      -> Use the default minimal system C++ runtime library.
+#                          Implies -frtti -fexceptions.
+#                          Is not available for standalone toolchain.
+#        gabi++_static  -> Use the GAbi++ runtime as a static library.
+#                          Implies -frtti -fno-exceptions.
+#                          Available for NDK r7 and newer.
+#                          Is not available for standalone toolchain.
+#        gabi++_shared  -> Use the GAbi++ runtime as a shared library.
+#                          Implies -frtti -fno-exceptions.
+#                          Available for NDK r7 and newer.
+#                          Is not available for standalone toolchain.
+#        stlport_static -> Use the STLport runtime as a static library.
+#                          Implies -fno-rtti -fno-exceptions for NDK before r7.
+#                          Implies -frtti -fno-exceptions for NDK r7 and newer.
+#                          Is not available for standalone toolchain.
+#        stlport_shared -> Use the STLport runtime as a shared library.
+#                          Implies -fno-rtti -fno-exceptions for NDK before r7.
+#                          Implies -frtti -fno-exceptions for NDK r7 and newer.
+#                          Is not available for standalone toolchain.
+#        gnustl_static  -> Use the GNU STL as a static library.
+#                          Implies -frtti -fexceptions.
+#        gnustl_shared  -> Use the GNU STL as a shared library.
+#                          Implies -frtti -fno-exceptions.
+#                          Available for NDK r7b and newer.
+#                          Silently degrades to gnustl_static if not available.
+#
+#    ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on
+#      chosen runtime. If disabled, then the user is responsible for settings
+#      these options.
+#
+#  What?:
+#    android-cmake toolchain searches for NDK/toolchain in the following order:
+#      ANDROID_NDK - cmake parameter
+#      ANDROID_NDK - environment variable
+#      ANDROID_STANDALONE_TOOLCHAIN - cmake parameter
+#      ANDROID_STANDALONE_TOOLCHAIN - environment variable
+#      ANDROID_NDK - default locations
+#      ANDROID_STANDALONE_TOOLCHAIN - default locations
+#
+#    Make sure to do the following in your scripts:
+#      SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" )
+#      SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" )
+#    The flags will be prepopulated with critical flags, so don't loose them.
+#    Also be aware that toolchain also sets configuration-specific compiler
+#    flags and linker flags.
+#
+#    ANDROID and BUILD_ANDROID will be set to true, you may test any of these
+#    variables to make necessary Android-specific configuration changes.
+#
+#    Also ARMEABI or ARMEABI_V7A or X86 or MIPS or ARM64_V8A or X86_64 or MIPS64
+#    will be set true, mutually exclusive. NEON option will be set true
+#    if VFP is set to NEON.
+#
+# ------------------------------------------------------------------------------
+
+cmake_minimum_required( VERSION 2.6.3 )
+
+if( DEFINED CMAKE_CROSSCOMPILING )
+ # subsequent toolchain loading is not really needed
+ return()
+endif()
+
+if( CMAKE_TOOLCHAIN_FILE )
+ # touch toolchain variable to suppress "unused variable" warning
+endif()
+
+# inherit settings in recursive loads
+get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE )
+if( _CMAKE_IN_TRY_COMPILE )
+ include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL )
+endif()
+
+# this one is important
+if( CMAKE_VERSION VERSION_GREATER "3.0.99" )
+ set( CMAKE_SYSTEM_NAME Android )
+else()
+ set( CMAKE_SYSTEM_NAME Linux )
+endif()
+
+# this one not so much
+set( CMAKE_SYSTEM_VERSION 1 )
+
+# rpath makes low sense for Android
+set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" )
+set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." )
+
+# NDK search paths
+set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
+if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS )
+ if( CMAKE_HOST_WIN32 )
+  file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS )
+  set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" )
+ else()
+  file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS )
+  set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" )
+ endif()
+endif()
+if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH )
+ set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain )
+endif()
+
+# known ABIs
+set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" )
+set( ANDROID_SUPPORTED_ABIS_arm64 "arm64-v8a" )
+set( ANDROID_SUPPORTED_ABIS_x86 "x86" )
+set( ANDROID_SUPPORTED_ABIS_x86_64 "x86_64" )
+set( ANDROID_SUPPORTED_ABIS_mips "mips" )
+set( ANDROID_SUPPORTED_ABIS_mips64 "mips64" )
+
+# API level defaults
+set( ANDROID_DEFAULT_NDK_API_LEVEL 8 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 21 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 21 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 )
+
+
+macro( __LIST_FILTER listvar regex )
+  if( ${listvar} )
+    foreach( __val ${${listvar}} )
+      if( __val MATCHES "${regex}" )
+        list( REMOVE_ITEM ${listvar} "${__val}" )
+      endif()
+    endforeach()
+  endif()
+endmacro()
+
+macro( __INIT_VARIABLE var_name )
+  set( __test_path 0 )
+  foreach( __var ${ARGN} )
+    if( __var STREQUAL "PATH" )
+      set( __test_path 1 )
+      break()
+    endif()
+  endforeach()
+
+  if( __test_path AND NOT EXISTS "${${var_name}}" )
+    unset( ${var_name} CACHE )
+  endif()
+
+  if( " ${${var_name}}" STREQUAL " " )
+    set( __values 0 )
+    foreach( __var ${ARGN} )
+      if( __var STREQUAL "VALUES" )
+        set( __values 1 )
+      elseif( NOT __var STREQUAL "PATH" )
+        if( __var MATCHES "^ENV_.*$" )
+          string( REPLACE "ENV_" "" __var "${__var}" )
+          set( __value "$ENV{${__var}}" )
+        elseif( DEFINED ${__var} )
+          set( __value "${${__var}}" )
+        elseif( __values )
+          set( __value "${__var}" )
+        else()
+          set( __value "" )
+        endif()
+
+        if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") )
+          set( ${var_name} "${__value}" )
+          break()
+        endif()
+      endif()
+    endforeach()
+    unset( __value )
+    unset( __values )
+  endif()
+
+  if( __test_path )
+    file( TO_CMAKE_PATH "${${var_name}}" ${var_name} )
+  endif()
+  unset( __test_path )
+endmacro()
+
+macro( __DETECT_NATIVE_API_LEVEL _var _path )
+  set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" )
+  file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" )
+  if( NOT __apiFileContent )
+    message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." )
+  endif()
+  string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" )
+  unset( __apiFileContent )
+  unset( __ndkApiLevelRegex )
+endmacro()
+
+macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root )
+ if( EXISTS "${_root}" )
+    file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" )
+    __LIST_FILTER( __gccExePath "^[.].*" )
+    list( LENGTH __gccExePath __gccExePathsCount )
+    if( NOT __gccExePathsCount EQUAL 1  AND NOT _CMAKE_IN_TRY_COMPILE )
+      message( WARNING "Could not determine machine name for compiler from ${_root}" )
+      set( ${_var} "" )
+    else()
+      get_filename_component( __gccExeName "${__gccExePath}" NAME_WE )
+      string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" )
+    endif()
+    unset( __gccExePath )
+    unset( __gccExePathsCount )
+    unset( __gccExeName )
+  else()
+    set( ${_var} "" )
+  endif()
+endmacro()
+
+
+# fight against cygwin
+set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools")
+mark_as_advanced( ANDROID_FORBID_SYGWIN )
+if( ANDROID_FORBID_SYGWIN )
+ if( CYGWIN )
+  message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." )
+ endif()
+
+ if( CMAKE_HOST_WIN32 )
+  # remove cygwin from PATH
+  set( __new_path "$ENV{PATH}")
+  __LIST_FILTER( __new_path "cygwin" )
+  set(ENV{PATH} "${__new_path}")
+  unset(__new_path)
+ endif()
+endif()
+
+
+# detect current host platform
+if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) )
+ set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" )
+ mark_as_advanced( ANDROID_NDK_HOST_X64 )
+endif()
+
+set( TOOL_OS_SUFFIX "" )
+if( CMAKE_HOST_APPLE )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" )
+elseif( CMAKE_HOST_WIN32 )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" )
+ set( TOOL_OS_SUFFIX ".exe" )
+elseif( CMAKE_HOST_UNIX )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" )
+else()
+ message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" )
+endif()
+
+if( NOT ANDROID_NDK_HOST_X64 )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} )
+endif()
+
+# see if we have path to Android NDK
+if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN )
+  __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK )
+endif()
+if( NOT ANDROID_NDK )
+ # see if we have path to Android standalone toolchain
+ __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN )
+
+ if( NOT ANDROID_STANDALONE_TOOLCHAIN )
+  #try to find Android NDK in one of the the default locations
+  set( __ndkSearchPaths )
+  foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} )
+   foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} )
+    list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" )
+   endforeach()
+  endforeach()
+  __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} )
+  unset( __ndkSearchPaths )
+
+  if( ANDROID_NDK )
+   message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" )
+   message( STATUS "  If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" )
+  else()
+   #try to find Android standalone toolchain in one of the the default locations
+   __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH )
+
+   if( ANDROID_STANDALONE_TOOLCHAIN )
+    message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" )
+    message( STATUS "  If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" )
+   endif( ANDROID_STANDALONE_TOOLCHAIN )
+  endif( ANDROID_NDK )
+ endif( NOT ANDROID_STANDALONE_TOOLCHAIN )
+endif( NOT ANDROID_NDK )
+
+# remember found paths
+if( ANDROID_NDK )
+ get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE )
+ set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE )
+ set( BUILD_WITH_ANDROID_NDK True )
+ if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" )
+  file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX "r[0-9]+[a-z]?" )
+  string( REGEX MATCH "r([0-9]+)([a-z]?)" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" )
+ else()
+  set( ANDROID_NDK_RELEASE "r1x" )
+  set( ANDROID_NDK_RELEASE_FULL "unreleased" )
+ endif()
+ string( REGEX REPLACE "r([0-9]+)([a-z]?)" "\\1*1000" ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE}" )
+ string( FIND " abcdefghijklmnopqastuvwxyz" "${CMAKE_MATCH_2}" __ndkReleaseLetterNum )
+ math( EXPR ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE_NUM}+${__ndkReleaseLetterNum}" )
+elseif( ANDROID_STANDALONE_TOOLCHAIN )
+ get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE )
+ # try to detect change
+ if( CMAKE_AR )
+  string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length )
+  string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath )
+  if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN )
+   message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." )
+  endif()
+  unset( __androidStandaloneToolchainPreviousPath )
+  unset( __length )
+ endif()
+ set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" FORCE )
+ set( BUILD_WITH_STANDALONE_TOOLCHAIN True )
+else()
+ list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH)
+ message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolchain.
+    You should either set an environment variable:
+      export ANDROID_NDK=~/my-android-ndk
+    or
+      export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain
+    or put the toolchain or NDK in the default path:
+      sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk
+      sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" )
+endif()
+
+# android NDK layout
+if( BUILD_WITH_ANDROID_NDK )
+ if( NOT DEFINED ANDROID_NDK_LAYOUT )
+  # try to automatically detect the layout
+  if( EXISTS "${ANDROID_NDK}/RELEASE.TXT")
+   set( ANDROID_NDK_LAYOUT "RELEASE" )
+  elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" )
+   set( ANDROID_NDK_LAYOUT "LINARO" )
+  elseif( EXISTS "${ANDROID_NDK}/../../gcc/" )
+   set( ANDROID_NDK_LAYOUT "ANDROID" )
+  endif()
+ endif()
+ set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" )
+ mark_as_advanced( ANDROID_NDK_LAYOUT )
+ if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" )
+  set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment
+  set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" )
+  set( ANDROID_NDK_TOOLCHAINS_SUBPATH  "" )
+  set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" )
+ elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" )
+  set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment
+  set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" )
+  set( ANDROID_NDK_TOOLCHAINS_SUBPATH  "" )
+  set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" )
+ else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE"
+  set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" )
+  set( ANDROID_NDK_TOOLCHAINS_SUBPATH  "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" )
+  set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" )
+ endif()
+ get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE )
+
+ # try to detect change of NDK
+ if( CMAKE_AR )
+  string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length )
+  string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath )
+  if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH )
+   message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first.
+   " )
+  endif()
+  unset( __androidNdkPreviousPath )
+  unset( __length )
+ endif()
+endif()
+
+
+# get all the details about standalone toolchain
+if( BUILD_WITH_STANDALONE_TOOLCHAIN )
+ __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" )
+ set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
+ set( __availableToolchains "standalone" )
+ __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" )
+ if( NOT __availableToolchainMachines )
+  message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." )
+ endif()
+ if( __availableToolchainMachines MATCHES x86_64 )
+  set( __availableToolchainArchs "x86_64" )
+ elseif( __availableToolchainMachines MATCHES i686 )
+  set( __availableToolchainArchs "x86" )
+ elseif( __availableToolchainMachines MATCHES aarch64 )
+  set( __availableToolchainArchs "arm64" )
+ elseif( __availableToolchainMachines MATCHES arm )
+  set( __availableToolchainArchs "arm" )
+ elseif( __availableToolchainMachines MATCHES mips64el )
+  set( __availableToolchainArchs "mips64" )
+ elseif( __availableToolchainMachines MATCHES mipsel )
+  set( __availableToolchainArchs "mips" )
+ endif()
+ execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion
+                  OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE )
+ string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" )
+ if( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${TOOL_OS_SUFFIX}" )
+  list( APPEND __availableToolchains "standalone-clang" )
+  list( APPEND __availableToolchainMachines ${__availableToolchainMachines} )
+  list( APPEND __availableToolchainArchs ${__availableToolchainArchs} )
+  list( APPEND __availableToolchainCompilerVersions ${__availableToolchainCompilerVersions} )
+ endif()
+endif()
+
+macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath )
+ foreach( __toolchain ${${__availableToolchainsLst}} )
+  if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" )
+   SET( __toolchainVersionRegex "^TOOLCHAIN_VERSION[\t ]+:=[\t ]+(.*)$" )
+   FILE( STRINGS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}/setup.mk" __toolchainVersionStr REGEX "${__toolchainVersionRegex}" )
+   if( __toolchainVersionStr )
+    string( REGEX REPLACE "${__toolchainVersionRegex}" "\\1" __toolchainVersionStr "${__toolchainVersionStr}" )
+    string( REGEX REPLACE "-clang3[.][0-9]$" "-${__toolchainVersionStr}" __gcc_toolchain "${__toolchain}" )
+   else()
+    string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" )
+   endif()
+   unset( __toolchainVersionStr )
+   unset( __toolchainVersionRegex )
+  else()
+   set( __gcc_toolchain "${__toolchain}" )
+  endif()
+  __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" )
+  if( __machine )
+   string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" )
+   if( __machine MATCHES x86_64 )
+    set( __arch "x86_64" )
+   elseif( __machine MATCHES i686 )
+    set( __arch "x86" )
+   elseif( __machine MATCHES aarch64 )
+    set( __arch "arm64" )
+   elseif( __machine MATCHES arm )
+    set( __arch "arm" )
+   elseif( __machine MATCHES mips64el )
+    set( __arch "mips64" )
+   elseif( __machine MATCHES mipsel )
+    set( __arch "mips" )
+   else()
+    set( __arch "" )
+   endif()
+   #message("machine: !${__machine}!\narch: !${__arch}!\nversion: !${__version}!\ntoolchain: !${__toolchain}!\n")
+   if (__arch)
+    list( APPEND __availableToolchainMachines "${__machine}" )
+    list( APPEND __availableToolchainArchs "${__arch}" )
+    list( APPEND __availableToolchainCompilerVersions "${__version}" )
+    list( APPEND ${__availableToolchainsVar} "${__toolchain}" )
+   endif()
+  endif()
+  unset( __gcc_toolchain )
+ endforeach()
+endmacro()
+
+# get all the details about NDK
+if( BUILD_WITH_ANDROID_NDK )
+ file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" )
+ string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" )
+ set( __availableToolchains "" )
+ set( __availableToolchainMachines "" )
+ set( __availableToolchainArchs "" )
+ set( __availableToolchainCompilerVersions "" )
+ if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" )
+  # do not go through all toolchains if we know the name
+  set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" )
+  __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
+  if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 )
+   __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" )
+   if( __availableToolchains )
+    set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} )
+   endif()
+  endif()
+ endif()
+ if( NOT __availableToolchains )
+  file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" )
+  if( __availableToolchainsLst )
+   list(SORT __availableToolchainsLst) # we need clang to go after gcc
+  endif()
+  __LIST_FILTER( __availableToolchainsLst "^[.]" )
+  __LIST_FILTER( __availableToolchainsLst "llvm" )
+  __LIST_FILTER( __availableToolchainsLst "renderscript" )
+  __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
+  if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 )
+   __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" )
+   if( __availableToolchains )
+    set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} )
+   endif()
+  endif()
+ endif()
+ if( NOT __availableToolchains )
+  message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." )
+ endif()
+endif()
+
+# build list of available ABIs
+set( ANDROID_SUPPORTED_ABIS "" )
+set( __uniqToolchainArchNames ${__availableToolchainArchs} )
+list( REMOVE_DUPLICATES __uniqToolchainArchNames )
+list( SORT __uniqToolchainArchNames )
+foreach( __arch ${__uniqToolchainArchNames} )
+ list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} )
+endforeach()
+unset( __uniqToolchainArchNames )
+if( NOT ANDROID_SUPPORTED_ABIS )
+ message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." )
+endif()
+
+# choose target ABI
+__INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} )
+# verify that target ABI is supported
+list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx )
+if( __androidAbiIdx EQUAL -1 )
+ string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS  "${ANDROID_SUPPORTED_ABIS}" )
+ message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain.
+   Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\"
+   " )
+endif()
+unset( __androidAbiIdx )
+
+# set target ABI options
+if( ANDROID_ABI STREQUAL "x86" )
+ set( X86 true )
+ set( ANDROID_NDK_ABI_NAME "x86" )
+ set( ANDROID_ARCH_NAME "x86" )
+ set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" )
+ set( CMAKE_SYSTEM_PROCESSOR "i686" )
+elseif( ANDROID_ABI STREQUAL "x86_64" )
+ set( X86 true )
+ set( X86_64 true )
+ set( ANDROID_NDK_ABI_NAME "x86_64" )
+ set( ANDROID_ARCH_NAME "x86_64" )
+ set( CMAKE_SYSTEM_PROCESSOR "x86_64" )
+ set( ANDROID_LLVM_TRIPLE "x86_64-none-linux-android" )
+elseif( ANDROID_ABI STREQUAL "mips64" )
+ set( MIPS64 true )
+ set( ANDROID_NDK_ABI_NAME "mips64" )
+ set( ANDROID_ARCH_NAME "mips64" )
+ set( ANDROID_LLVM_TRIPLE "mips64el-none-linux-android" )
+ set( CMAKE_SYSTEM_PROCESSOR "mips64" )
+elseif( ANDROID_ABI STREQUAL "mips" )
+ set( MIPS true )
+ set( ANDROID_NDK_ABI_NAME "mips" )
+ set( ANDROID_ARCH_NAME "mips" )
+ set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" )
+ set( CMAKE_SYSTEM_PROCESSOR "mips" )
+elseif( ANDROID_ABI STREQUAL "arm64-v8a" )
+ set( ARM64_V8A true )
+ set( ANDROID_NDK_ABI_NAME "arm64-v8a" )
+ set( ANDROID_ARCH_NAME "arm64" )
+ set( ANDROID_LLVM_TRIPLE "aarch64-none-linux-android" )
+ set( CMAKE_SYSTEM_PROCESSOR "aarch64" )
+ set( VFPV3 true )
+ set( NEON true )
+elseif( ANDROID_ABI STREQUAL "armeabi" )
+ set( ARMEABI true )
+ set( ANDROID_NDK_ABI_NAME "armeabi" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv5te" )
+elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" )
+ set( ARMEABI_V6 true )
+ set( ANDROID_NDK_ABI_NAME "armeabi" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv6" )
+ # need always fallback to older platform
+ set( ARMEABI true )
+elseif( ANDROID_ABI STREQUAL "armeabi-v7a")
+ set( ARMEABI_V7A true )
+ set( ANDROID_NDK_ABI_NAME "armeabi-v7a" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv7-a" )
+elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" )
+ set( ARMEABI_V7A true )
+ set( ANDROID_NDK_ABI_NAME "armeabi-v7a" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv7-a" )
+ set( VFPV3 true )
+elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" )
+ set( ARMEABI_V7A true )
+ set( ANDROID_NDK_ABI_NAME "armeabi-v7a" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv7-a" )
+ set( VFPV3 true )
+ set( NEON true )
+else()
+ message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." )
+endif()
+
+if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" )
+ # really dirty hack
+ # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run...
+ file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" )
+endif()
+
+if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 )
+ __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF )
+ set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE )
+ mark_as_advanced( ANDROID_FORCE_ARM_BUILD )
+else()
+ unset( ANDROID_FORCE_ARM_BUILD CACHE )
+endif()
+
+# choose toolchain
+if( ANDROID_TOOLCHAIN_NAME )
+ list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx )
+ if( __toolchainIdx EQUAL -1 )
+  list( SORT __availableToolchains )
+  string( REPLACE ";" "\n  * " toolchains_list "${__availableToolchains}" )
+  set( toolchains_list "  * ${toolchains_list}")
+  message( FATAL_ERROR "Specified toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing in your NDK or broken. Please verify that your NDK is working or select another compiler toolchain.
+To configure the toolchain set CMake variable ANDROID_TOOLCHAIN_NAME to one of the following values:\n${toolchains_list}\n" )
+ endif()
+ list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch )
+ if( NOT __toolchainArch STREQUAL ANDROID_ARCH_NAME )
+  message( SEND_ERROR "Selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." )
+ endif()
+else()
+ set( __toolchainIdx -1 )
+ set( __applicableToolchains "" )
+ set( __toolchainMaxVersion "0.0.0" )
+ list( LENGTH __availableToolchains __availableToolchainsCount )
+ math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" )
+ foreach( __idx RANGE ${__availableToolchainsCount} )
+  list( GET __availableToolchainArchs ${__idx} __toolchainArch )
+  if( __toolchainArch STREQUAL ANDROID_ARCH_NAME )
+   list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion )
+   string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}")
+   if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion )
+    set( __toolchainMaxVersion "${__toolchainVersion}" )
+    set( __toolchainIdx ${__idx} )
+   endif()
+  endif()
+ endforeach()
+ unset( __availableToolchainsCount )
+ unset( __toolchainMaxVersion )
+ unset( __toolchainVersion )
+endif()
+unset( __toolchainArch )
+if( __toolchainIdx EQUAL -1 )
+ message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." )
+endif()
+list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME )
+list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME )
+list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION )
+
+unset( __toolchainIdx )
+unset( __availableToolchains )
+unset( __availableToolchainMachines )
+unset( __availableToolchainArchs )
+unset( __availableToolchainCompilerVersions )
+
+# choose native API level
+__INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL )
+string( REPLACE "android-" "" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" )
+string( STRIP "${ANDROID_NATIVE_API_LEVEL}" ANDROID_NATIVE_API_LEVEL )
+# adjust API level
+set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} )
+foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
+ if( (__level LESS ANDROID_NATIVE_API_LEVEL OR __level STREQUAL ANDROID_NATIVE_API_LEVEL) AND NOT __level LESS __real_api_level )
+  set( __real_api_level ${__level} )
+ endif()
+endforeach()
+if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL STREQUAL __real_api_level )
+ message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'")
+ set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} )
+endif()
+unset(__real_api_level)
+# validate
+list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx )
+if( __levelIdx EQUAL -1 )
+ message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." )
+else()
+ if( BUILD_WITH_ANDROID_NDK )
+  __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" )
+  if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL AND NOT __realApiLevel GREATER 9000 )
+   message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." )
+  endif()
+  unset( __realApiLevel )
+ endif()
+ set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE )
+ set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} )
+ if( CMAKE_VERSION VERSION_GREATER "2.8" )
+  list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS )
+  set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
+ endif()
+endif()
+unset( __levelIdx )
+
+
+# remember target ABI
+set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE )
+if( CMAKE_VERSION VERSION_GREATER "2.8" )
+ list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME} )
+ set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME}} )
+endif()
+
+
+# runtime choice (STL, rtti, exceptions)
+if( NOT ANDROID_STL )
+  set( ANDROID_STL gnustl_static )
+endif()
+set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" )
+set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" )
+mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES )
+
+if( BUILD_WITH_ANDROID_NDK )
+ if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$")
+  message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\".
+The possible values are:
+  none           -> Do not configure the runtime.
+  system         -> Use the default minimal system C++ runtime library.
+  system_re      -> Same as system but with rtti and exceptions.
+  gabi++_static  -> Use the GAbi++ runtime as a static library.
+  gabi++_shared  -> Use the GAbi++ runtime as a shared library.
+  stlport_static -> Use the STLport runtime as a static library.
+  stlport_shared -> Use the STLport runtime as a shared library.
+  gnustl_static  -> (default) Use the GNU STL as a static library.
+  gnustl_shared  -> Use the GNU STL as a shared library.
+" )
+ endif()
+elseif( BUILD_WITH_STANDALONE_TOOLCHAIN )
+ if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$")
+  message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\".
+The possible values are:
+  none           -> Do not configure the runtime.
+  gnustl_static  -> (default) Use the GNU STL as a static library.
+  gnustl_shared  -> Use the GNU STL as a shared library.
+" )
+ endif()
+endif()
+
+unset( ANDROID_RTTI )
+unset( ANDROID_EXCEPTIONS )
+unset( ANDROID_STL_INCLUDE_DIRS )
+unset( __libstl )
+unset( __libsupcxx )
+
+if( NOT _CMAKE_IN_TRY_COMPILE AND ANDROID_NDK_RELEASE STREQUAL "r7b" AND ARMEABI_V7A AND NOT VFPV3 AND ANDROID_STL MATCHES "gnustl" )
+ message( WARNING  "The GNU STL armeabi-v7a binaries from NDK r7b can crash non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf).
+You are strongly recommended to switch to another NDK release.
+" )
+endif()
+
+if( NOT _CMAKE_IN_TRY_COMPILE AND X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" )
+  message( WARNING  "The x86 system header file from NDK r6 has incorrect definition for ptrdiff_t. You are recommended to upgrade to a newer NDK release or manually patch the header:
+See https://android.googlesource.com/platform/development.git f907f4f9d4e56ccc8093df6fee54454b8bcab6c2
+  diff --git a/ndk/platforms/android-9/arch-x86/include/machine/_types.h b/ndk/platforms/android-9/arch-x86/include/machine/_types.h
+  index 5e28c64..65892a1 100644
+  --- a/ndk/platforms/android-9/arch-x86/include/machine/_types.h
+  +++ b/ndk/platforms/android-9/arch-x86/include/machine/_types.h
+  @@ -51,7 +51,11 @@ typedef long int       ssize_t;
+   #endif
+   #ifndef _PTRDIFF_T
+   #define _PTRDIFF_T
+  -typedef long           ptrdiff_t;
+  +#  ifdef __ANDROID__
+  +     typedef int            ptrdiff_t;
+  +#  else
+  +     typedef long           ptrdiff_t;
+  +#  endif
+   #endif
+" )
+endif()
+
+
+# setup paths and STL for standalone toolchain
+if( BUILD_WITH_STANDALONE_TOOLCHAIN )
+ set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" )
+ set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" )
+ set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" )
+
+ if( NOT ANDROID_STL STREQUAL "none" )
+  set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" )
+  if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" )
+   # old location ( pre r8c )
+   set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" )
+  endif()
+  if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" )
+   list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" )
+  elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" )
+   list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" )
+  else()
+   list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" )
+  endif()
+  # always search static GNU STL to get the location of libsupc++.a
+  if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" )
+   set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" )
+  elseif( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" )
+   set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}" )
+  elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" )
+   set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" )
+  elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" )
+   set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" )
+  endif()
+  if( __libstl )
+   set( __libsupcxx "${__libstl}/libsupc++.a" )
+   set( __libstl    "${__libstl}/libstdc++.a" )
+  endif()
+  if( NOT EXISTS "${__libsupcxx}" )
+   message( FATAL_ERROR "The required libstdsupc++.a is missing in your standalone toolchain.
+ Usually it happens because of bug in make-standalone-toolchain.sh script from NDK r7, r7b and r7c.
+ You need to either upgrade to newer NDK or manually copy
+     $ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a
+ to
+     ${__libsupcxx}
+   " )
+  endif()
+  if( ANDROID_STL STREQUAL "gnustl_shared" )
+   if( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" )
+    set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" )
+   elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" )
+    set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" )
+   elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" )
+    set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" )
+   endif()
+  endif()
+ endif()
+endif()
+
+# clang
+if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" )
+ set( ANDROID_COMPILER_IS_CLANG 1 )
+ execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE )
+ string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}")
+elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" )
+ string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}")
+ string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-${ANDROID_COMPILER_VERSION}" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" )
+ if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" )
+  message( FATAL_ERROR "Could not find the Clang compiler driver" )
+ endif()
+ set( ANDROID_COMPILER_IS_CLANG 1 )
+ set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
+else()
+ set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" )
+ unset( ANDROID_COMPILER_IS_CLANG CACHE )
+endif()
+
+string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" )
+if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" )
+ set( _clang_name "clang" )
+endif()
+
+
+# setup paths and STL for NDK
+if( BUILD_WITH_ANDROID_NDK )
+ set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
+ set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" )
+
+ if( ANDROID_STL STREQUAL "none" )
+  # do nothing
+ elseif( ANDROID_STL STREQUAL "system" )
+  set( ANDROID_RTTI             OFF )
+  set( ANDROID_EXCEPTIONS       OFF )
+  set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" )
+ elseif( ANDROID_STL STREQUAL "system_re" )
+  set( ANDROID_RTTI             ON )
+  set( ANDROID_EXCEPTIONS       ON )
+  set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" )
+ elseif( ANDROID_STL MATCHES "gabi" )
+  if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
+   message( FATAL_ERROR "gabi++ is not available in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.")
+  endif()
+  set( ANDROID_RTTI             ON )
+  set( ANDROID_EXCEPTIONS       OFF )
+  set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/gabi++/include" )
+  set( __libstl                 "${ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${ANDROID_NDK_ABI_NAME}/libgabi++_static.a" )
+ elseif( ANDROID_STL MATCHES "stlport" )
+  if( NOT ANDROID_NDK_RELEASE_NUM LESS 8004 ) # before r8d
+   set( ANDROID_EXCEPTIONS       ON )
+  else()
+   set( ANDROID_EXCEPTIONS       OFF )
+  endif()
+  if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
+   set( ANDROID_RTTI            OFF )
+  else()
+   set( ANDROID_RTTI            ON )
+  endif()
+  set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" )
+  set( __libstl                 "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}/libstlport_static.a" )
+ elseif( ANDROID_STL MATCHES "gnustl" )
+  set( ANDROID_EXCEPTIONS       ON )
+  set( ANDROID_RTTI             ON )
+  if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" )
+   if( ARMEABI_V7A AND ANDROID_COMPILER_VERSION VERSION_EQUAL "4.7" AND ANDROID_NDK_RELEASE STREQUAL "r8d" )
+    # gnustl binary for 4.7 compiler is buggy :(
+    # TODO: look for right fix
+    set( __libstl                "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.6" )
+   else()
+    set( __libstl                "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" )
+   endif()
+  else()
+   set( __libstl                "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" )
+  endif()
+  set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" )
+  if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
+   set( __libstl                "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
+  else()
+   set( __libstl                "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" )
+  endif()
+ else()
+  message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" )
+ endif()
+ # find libsupc++.a - rtti & exceptions
+ if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" )
+  set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer
+  if( NOT EXISTS "${__libsupcxx}" )
+   set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8
+  endif()
+  if( NOT EXISTS "${__libsupcxx}" ) # before r7
+   if( ARMEABI_V7A )
+    if( ANDROID_FORCE_ARM_BUILD )
+     set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" )
+    else()
+     set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" )
+    endif()
+   elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD )
+    set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" )
+   else()
+    set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" )
+   endif()
+  endif()
+  if( NOT EXISTS "${__libsupcxx}")
+   message( ERROR "Could not find libsupc++.a for a chosen platform. Either your NDK is not supported or is broken.")
+  endif()
+ endif()
+endif()
+
+
+# case of shared STL linkage
+if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl )
+ string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" )
+ # TODO: check if .so file exists before the renaming
+endif()
+
+
+# ccache support
+__INIT_VARIABLE( _ndk_ccache NDK_CCACHE ENV_NDK_CCACHE )
+if( _ndk_ccache )
+ if( DEFINED NDK_CCACHE AND NOT EXISTS NDK_CCACHE )
+  unset( NDK_CCACHE CACHE )
+ endif()
+ find_program( NDK_CCACHE "${_ndk_ccache}" DOC "The path to ccache binary")
+else()
+ unset( NDK_CCACHE CACHE )
+endif()
+unset( _ndk_ccache )
+
+
+# setup the cross-compiler
+if( NOT CMAKE_C_COMPILER )
+ if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" )
+  set( CMAKE_C_COMPILER   "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" )
+  set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" )
+  if( ANDROID_COMPILER_IS_CLANG )
+   set( CMAKE_C_COMPILER_ARG1   "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}"   CACHE PATH "C compiler")
+   set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler")
+  else()
+   set( CMAKE_C_COMPILER_ARG1   "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler")
+   set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler")
+  endif()
+ else()
+  if( ANDROID_COMPILER_IS_CLANG )
+   set( CMAKE_C_COMPILER   "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}"   CACHE PATH "C compiler")
+   set( CMAKE_CXX_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler")
+  else()
+   set( CMAKE_C_COMPILER   "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}"    CACHE PATH "C compiler" )
+   set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}"    CACHE PATH "C++ compiler" )
+  endif()
+ endif()
+ set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}"     CACHE PATH "assembler" )
+ set( CMAKE_STRIP        "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}"   CACHE PATH "strip" )
+ if( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" )
+  # Use gcc-ar if we have it for better LTO support.
+  set( CMAKE_AR           "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}"      CACHE PATH "archive" )
+ else()
+  set( CMAKE_AR           "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}"      CACHE PATH "archive" )
+ endif()
+ set( CMAKE_LINKER       "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}"      CACHE PATH "linker" )
+ set( CMAKE_NM           "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}"      CACHE PATH "nm" )
+ set( CMAKE_OBJCOPY      "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" )
+ set( CMAKE_OBJDUMP      "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" )
+ set( CMAKE_RANLIB       "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}"  CACHE PATH "ranlib" )
+endif()
+
+set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" )
+if( CMAKE_VERSION VERSION_LESS 2.8.5 )
+ set( CMAKE_ASM_COMPILER_ARG1 "-c" )
+endif()
+if( APPLE )
+ find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool )
+ if( NOT CMAKE_INSTALL_NAME_TOOL )
+  message( FATAL_ERROR "Could not find install_name_tool, please check your installation." )
+ endif()
+ mark_as_advanced( CMAKE_INSTALL_NAME_TOOL )
+endif()
+
+# Force set compilers because standard identification works badly for us
+include( CMakeForceCompiler )
+CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU )
+if( ANDROID_COMPILER_IS_CLANG )
+ set( CMAKE_C_COMPILER_ID Clang )
+endif()
+set( CMAKE_C_PLATFORM_ID Linux )
+if( X86_64 OR MIPS64 OR ARM64_V8A )
+ set( CMAKE_C_SIZEOF_DATA_PTR 8 )
+else()
+ set( CMAKE_C_SIZEOF_DATA_PTR 4 )
+endif()
+set( CMAKE_C_HAS_ISYSROOT 1 )
+set( CMAKE_C_COMPILER_ABI ELF )
+CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU )
+if( ANDROID_COMPILER_IS_CLANG )
+ set( CMAKE_CXX_COMPILER_ID Clang)
+endif()
+set( CMAKE_CXX_PLATFORM_ID Linux )
+set( CMAKE_CXX_SIZEOF_DATA_PTR ${CMAKE_C_SIZEOF_DATA_PTR} )
+set( CMAKE_CXX_HAS_ISYSROOT 1 )
+set( CMAKE_CXX_COMPILER_ABI ELF )
+set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C )
+# force ASM compiler (required for CMake < 2.8.5)
+set( CMAKE_ASM_COMPILER_ID_RUN TRUE )
+set( CMAKE_ASM_COMPILER_ID GNU )
+set( CMAKE_ASM_COMPILER_WORKS TRUE )
+set( CMAKE_ASM_COMPILER_FORCED TRUE )
+set( CMAKE_COMPILER_IS_GNUASM 1)
+set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm )
+
+foreach( lang C CXX ASM )
+ if( ANDROID_COMPILER_IS_CLANG )
+  set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} )
+ else()
+  set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} )
+ endif()
+endforeach()
+
+# flags and definitions
+remove_definitions( -DANDROID )
+add_definitions( -DANDROID )
+
+if( ANDROID_SYSROOT MATCHES "[ ;\"]" )
+ if( CMAKE_HOST_WIN32 )
+  # try to convert path to 8.3 form
+  file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" )
+  execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}"
+                   OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE
+                   RESULT_VARIABLE __result ERROR_QUIET )
+  if( __result EQUAL 0 )
+   file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT )
+   set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" )
+  else()
+   set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" )
+  endif()
+ else()
+  set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" )
+ endif()
+ if( NOT _CMAKE_IN_TRY_COMPILE )
+  # quotes can break try_compile and compiler identification
+  message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n")
+ endif()
+else()
+ set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" )
+endif()
+
+# NDK flags
+if (ARM64_V8A )
+ set( ANDROID_CXX_FLAGS         "${ANDROID_CXX_FLAGS} -funwind-tables" )
+ set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
+ set( ANDROID_CXX_FLAGS_DEBUG   "-fno-omit-frame-pointer -fno-strict-aliasing" )
+ if( NOT ANDROID_COMPILER_IS_CLANG )
+  set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" )
+ endif()
+elseif( ARMEABI OR ARMEABI_V7A)
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
+ if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 )
+  set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" )
+  set( ANDROID_CXX_FLAGS_DEBUG   "-marm -fno-omit-frame-pointer -fno-strict-aliasing" )
+  if( NOT ANDROID_COMPILER_IS_CLANG )
+   set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" )
+  endif()
+ else()
+  # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI
+  set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" )
+  set( ANDROID_CXX_FLAGS_DEBUG   "-marm -fno-omit-frame-pointer -fno-strict-aliasing" )
+  if( NOT ANDROID_COMPILER_IS_CLANG )
+   set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" )
+  endif()
+ endif()
+elseif( X86 OR X86_64 )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
+ if( NOT ANDROID_COMPILER_IS_CLANG )
+  set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" )
+ endif()
+ set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
+ set( ANDROID_CXX_FLAGS_DEBUG   "-fno-omit-frame-pointer -fno-strict-aliasing" )
+elseif( MIPS OR MIPS64 )
+ set( ANDROID_CXX_FLAGS         "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" )
+ set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" )
+ set( ANDROID_CXX_FLAGS_DEBUG   "-fno-omit-frame-pointer" )
+ if( NOT ANDROID_COMPILER_IS_CLANG )
+  set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" )
+  set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" )
+ endif()
+elseif()
+ set( ANDROID_CXX_FLAGS_RELEASE "" )
+ set( ANDROID_CXX_FLAGS_DEBUG   "" )
+endif()
+
+set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries
+
+if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" )
+endif()
+
+if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/
+endif()
+
+# ABI-specific flags
+if( ARMEABI_V7A )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" )
+ if( NEON )
+  set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" )
+ elseif( VFPV3 )
+  set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" )
+ else()
+  set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3-d16" )
+ endif()
+elseif( ARMEABI_V6 )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2
+elseif( ARMEABI )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" )
+endif()
+
+if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") )
+ set( CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_CXX_CREATE_SHARED_MODULE  "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_CXX_LINK_EXECUTABLE       "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" )
+else()
+ set( CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_CXX_CREATE_SHARED_MODULE  "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_CXX_LINK_EXECUTABLE       "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" )
+endif()
+
+# STL
+if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" )
+ if( EXISTS "${__libstl}" )
+  set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" )
+  set( CMAKE_CXX_CREATE_SHARED_MODULE  "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" )
+  set( CMAKE_CXX_LINK_EXECUTABLE       "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libstl}\"" )
+ endif()
+ if( EXISTS "${__libsupcxx}" )
+  set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" )
+  set( CMAKE_CXX_CREATE_SHARED_MODULE  "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" )
+  set( CMAKE_CXX_LINK_EXECUTABLE       "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libsupcxx}\"" )
+  # C objects:
+  set( CMAKE_C_CREATE_SHARED_LIBRARY "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_C_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_C_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+  set( CMAKE_C_CREATE_SHARED_MODULE  "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_C_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_C_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+  set( CMAKE_C_LINK_EXECUTABLE       "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" )
+  set( CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" )
+  set( CMAKE_C_CREATE_SHARED_MODULE  "${CMAKE_C_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" )
+  set( CMAKE_C_LINK_EXECUTABLE       "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" )
+ endif()
+ if( ANDROID_STL MATCHES "gnustl" )
+  if( NOT EXISTS "${ANDROID_LIBM_PATH}" )
+   set( ANDROID_LIBM_PATH -lm )
+  endif()
+  set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" )
+  set( CMAKE_CXX_CREATE_SHARED_MODULE  "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" )
+  set( CMAKE_CXX_LINK_EXECUTABLE       "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" )
+ endif()
+endif()
+
+# variables controlling optional build flags
+if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
+ # libGLESv2.so in NDK's prior to r7 refers to missing external symbols.
+ # So this flag option is required for all projects using OpenGL from native.
+ __INIT_VARIABLE( ANDROID_SO_UNDEFINED                      VALUES ON )
+else()
+ __INIT_VARIABLE( ANDROID_SO_UNDEFINED                      VALUES OFF )
+endif()
+__INIT_VARIABLE( ANDROID_NO_UNDEFINED                       VALUES ON )
+__INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING             VALUES ON )
+__INIT_VARIABLE( ANDROID_GOLD_LINKER                        VALUES ON )
+__INIT_VARIABLE( ANDROID_NOEXECSTACK                        VALUES ON )
+__INIT_VARIABLE( ANDROID_RELRO                              VALUES ON )
+
+set( ANDROID_NO_UNDEFINED           ${ANDROID_NO_UNDEFINED}           CACHE BOOL "Show all undefined symbols as linker errors" )
+set( ANDROID_SO_UNDEFINED           ${ANDROID_SO_UNDEFINED}           CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
+set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" )
+set( ANDROID_GOLD_LINKER            ${ANDROID_GOLD_LINKER}            CACHE BOOL "Enables gold linker" )
+set( ANDROID_NOEXECSTACK            ${ANDROID_NOEXECSTACK}            CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
+set( ANDROID_RELRO                  ${ANDROID_RELRO}                  CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" )
+mark_as_advanced( ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO )
+
+# linker flags
+set( ANDROID_LINKER_FLAGS "" )
+
+if( ARMEABI_V7A )
+ # this is *required* to use the following linker flags that routes around
+ # a CPU bug in some Cortex-A8 implementations:
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--fix-cortex-a8" )
+endif()
+
+if( ANDROID_NO_UNDEFINED )
+ if( MIPS )
+  # there is some sysroot-related problem in mips linker...
+  if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" )
+   set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" )
+  endif()
+ else()
+  set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" )
+ endif()
+endif()
+
+if( ANDROID_SO_UNDEFINED )
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" )
+endif()
+
+if( ANDROID_FUNCTION_LEVEL_LINKING )
+ set( ANDROID_CXX_FLAGS    "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" )
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--gc-sections" )
+endif()
+
+if( ANDROID_COMPILER_VERSION VERSION_EQUAL "4.6" )
+ if( ANDROID_GOLD_LINKER AND (CMAKE_HOST_UNIX OR ANDROID_NDK_RELEASE_NUM GREATER 8002) AND (ARMEABI OR ARMEABI_V7A OR X86) )
+  set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=gold" )
+ elseif( ANDROID_NDK_RELEASE_NUM GREATER 8002 ) # after r8b
+  set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=bfd" )
+ elseif( ANDROID_NDK_RELEASE STREQUAL "r8b" AND ARMEABI AND NOT _CMAKE_IN_TRY_COMPILE )
+  message( WARNING "The default bfd linker from arm GCC 4.6 toolchain can fail with 'unresolvable R_ARM_THM_CALL relocation' error message. See https://code.google.com/p/android/issues/detail?id=35342
+  On Linux and OS X host platform you can workaround this problem using gold linker (default).
+  Rerun cmake with -DANDROID_GOLD_LINKER=ON option in case of problems.
+" )
+ endif()
+endif() # version 4.6
+
+if( ANDROID_NOEXECSTACK )
+ if( ANDROID_COMPILER_IS_CLANG )
+  set( ANDROID_CXX_FLAGS    "${ANDROID_CXX_FLAGS} -Xclang -mnoexecstack" )
+ else()
+  set( ANDROID_CXX_FLAGS    "${ANDROID_CXX_FLAGS} -Wa,--noexecstack" )
+ endif()
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,noexecstack" )
+endif()
+
+if( ANDROID_RELRO )
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now" )
+endif()
+
+if( ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} -Qunused-arguments ${ANDROID_CXX_FLAGS}" )
+ if( BUILD_WITH_ANDROID_NDK )
+  set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" )
+ endif()
+endif()
+
+# cache flags
+set( CMAKE_CXX_FLAGS           ""                        CACHE STRING "c++ flags" )
+set( CMAKE_C_FLAGS             ""                        CACHE STRING "c flags" )
+set( CMAKE_CXX_FLAGS_RELEASE   "-O3 -DNDEBUG"            CACHE STRING "c++ Release flags" )
+set( CMAKE_C_FLAGS_RELEASE     "-O3 -DNDEBUG"            CACHE STRING "c Release flags" )
+set( CMAKE_CXX_FLAGS_DEBUG     "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" )
+set( CMAKE_C_FLAGS_DEBUG       "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" )
+set( CMAKE_SHARED_LINKER_FLAGS ""                        CACHE STRING "shared linker flags" )
+set( CMAKE_MODULE_LINKER_FLAGS ""                        CACHE STRING "module linker flags" )
+set( CMAKE_EXE_LINKER_FLAGS    "-Wl,-z,nocopyreloc"      CACHE STRING "executable linker flags" )
+
+# put flags to cache (for debug purpose only)
+set( ANDROID_CXX_FLAGS         "${ANDROID_CXX_FLAGS}"         CACHE INTERNAL "Android specific c/c++ flags" )
+set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" )
+set( ANDROID_CXX_FLAGS_DEBUG   "${ANDROID_CXX_FLAGS_DEBUG}"   CACHE INTERNAL "Android specific c/c++ Debug flags" )
+set( ANDROID_LINKER_FLAGS      "${ANDROID_LINKER_FLAGS}"      CACHE INTERNAL "Android specific c/c++ linker flags" )
+
+# finish flags
+set( CMAKE_CXX_FLAGS           "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" )
+set( CMAKE_C_FLAGS             "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" )
+set( CMAKE_CXX_FLAGS_RELEASE   "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}" )
+set( CMAKE_C_FLAGS_RELEASE     "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}" )
+set( CMAKE_CXX_FLAGS_DEBUG     "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}" )
+set( CMAKE_C_FLAGS_DEBUG       "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}" )
+set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" )
+set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" )
+set( CMAKE_EXE_LINKER_FLAGS    "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" )
+
+if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" )
+ set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" )
+ set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" )
+ set( CMAKE_EXE_LINKER_FLAGS    "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" )
+endif()
+
+# pie/pic
+if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8) )
+ set( CMAKE_POSITION_INDEPENDENT_CODE TRUE )
+ set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie")
+else()
+ set( CMAKE_POSITION_INDEPENDENT_CODE FALSE )
+ set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" )
+ set( CMAKE_C_FLAGS   "-fpic ${CMAKE_C_FLAGS}" )
+endif()
+
+# configure rtti
+if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES )
+ if( ANDROID_RTTI )
+  set( CMAKE_CXX_FLAGS "-frtti ${CMAKE_CXX_FLAGS}" )
+ else()
+  set( CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}" )
+ endif()
+endif()
+
+# configure exceptios
+if( DEFINED ANDROID_EXCEPTIONS AND ANDROID_STL_FORCE_FEATURES )
+ if( ANDROID_EXCEPTIONS )
+  set( CMAKE_CXX_FLAGS "-fexceptions ${CMAKE_CXX_FLAGS}" )
+  set( CMAKE_C_FLAGS "-fexceptions ${CMAKE_C_FLAGS}" )
+ else()
+  set( CMAKE_CXX_FLAGS "-fno-exceptions ${CMAKE_CXX_FLAGS}" )
+  set( CMAKE_C_FLAGS "-fno-exceptions ${CMAKE_C_FLAGS}" )
+ endif()
+endif()
+
+# global includes and link directories
+include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} )
+get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning
+link_directories( "${__android_install_path}" )
+
+# detect if need link crtbegin_so.o explicitly
+if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK )
+ set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" )
+ string( REPLACE "<CMAKE_CXX_COMPILER>" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" )
+ string( REPLACE "<CMAKE_C_COMPILER>"   "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}"   __cmd "${__cmd}" )
+ string( REPLACE "<CMAKE_SHARED_LIBRARY_CXX_FLAGS>" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" )
+ string( REPLACE "<LANGUAGE_COMPILE_FLAGS>" "" __cmd "${__cmd}" )
+ string( REPLACE "<LINK_FLAGS>" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" )
+ string( REPLACE "<CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS>" "-shared" __cmd "${__cmd}" )
+ string( REPLACE "<CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG>" "" __cmd "${__cmd}" )
+ string( REPLACE "<TARGET_SONAME>" "" __cmd "${__cmd}" )
+ string( REPLACE "<TARGET>" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" )
+ string( REPLACE "<OBJECTS>" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" )
+ string( REPLACE "<LINK_LIBRARIES>" "" __cmd "${__cmd}" )
+ separate_arguments( __cmd )
+ foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN )
+  if( ${__var} )
+   set( __tmp "${${__var}}" )
+   separate_arguments( __tmp )
+   string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}")
+  endif()
+ endforeach()
+ string( REPLACE "'" "" __cmd "${__cmd}" )
+ string( REPLACE "\"" "" __cmd "${__cmd}" )
+ execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET )
+ if( __cmd_result EQUAL 0 )
+  set( ANDROID_EXPLICIT_CRT_LINK ON )
+ else()
+  set( ANDROID_EXPLICIT_CRT_LINK OFF )
+ endif()
+endif()
+
+if( ANDROID_EXPLICIT_CRT_LINK )
+ set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" )
+ set( CMAKE_CXX_CREATE_SHARED_MODULE  "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" )
+endif()
+
+# setup output directories
+set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" )
+
+if( DEFINED LIBRARY_OUTPUT_PATH_ROOT
+      OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml"
+      OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") )
+  set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" )
+  if( NOT _CMAKE_IN_TRY_COMPILE )
+    if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" )
+      set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" )
+    else()
+      set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" )
+    endif()
+    set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" )
+  endif()
+endif()
+
+# copy shaed stl library to build directory
+if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH )
+  get_filename_component( __libstlname "${__libstl}" NAME )
+  execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
+  if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
+    message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
+  endif()
+  unset( __fileCopyProcess )
+  unset( __libstlname )
+endif()
+
+
+# set these global flags for cmake client scripts to change behavior
+set( ANDROID True )
+set( BUILD_ANDROID True )
+
+# where is the target environment
+set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" )
+
+# only search for libraries and includes in the ndk toolchain
+set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
+set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
+set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
+
+
+# macro to find packages on the host OS
+macro( find_host_package )
+ set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
+ set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER )
+ set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER )
+ if( CMAKE_HOST_WIN32 )
+  SET( WIN32 1 )
+  SET( UNIX )
+ elseif( CMAKE_HOST_APPLE )
+  SET( APPLE 1 )
+  SET( UNIX )
+ endif()
+ find_package( ${ARGN} )
+ SET( WIN32 )
+ SET( APPLE )
+ SET( UNIX 1 )
+ set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
+ set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
+ set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
+endmacro()
+
+
+# macro to find programs on the host OS
+macro( find_host_program )
+ set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
+ set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER )
+ set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER )
+ if( CMAKE_HOST_WIN32 )
+  SET( WIN32 1 )
+  SET( UNIX )
+ elseif( CMAKE_HOST_APPLE )
+  SET( APPLE 1 )
+  SET( UNIX )
+ endif()
+ find_program( ${ARGN} )
+ SET( WIN32 )
+ SET( APPLE )
+ SET( UNIX 1 )
+ set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
+ set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
+ set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
+endmacro()
+
+
+# export toolchain settings for the try_compile() command
+if( NOT _CMAKE_IN_TRY_COMPILE )
+ set( __toolchain_config "")
+ foreach( __var NDK_CCACHE  LIBRARY_OUTPUT_PATH_ROOT  ANDROID_FORBID_SYGWIN
+                ANDROID_NDK_HOST_X64
+                ANDROID_NDK
+                ANDROID_NDK_LAYOUT
+                ANDROID_STANDALONE_TOOLCHAIN
+                ANDROID_TOOLCHAIN_NAME
+                ANDROID_ABI
+                ANDROID_NATIVE_API_LEVEL
+                ANDROID_STL
+                ANDROID_STL_FORCE_FEATURES
+                ANDROID_FORCE_ARM_BUILD
+                ANDROID_NO_UNDEFINED
+                ANDROID_SO_UNDEFINED
+                ANDROID_FUNCTION_LEVEL_LINKING
+                ANDROID_GOLD_LINKER
+                ANDROID_NOEXECSTACK
+                ANDROID_RELRO
+                ANDROID_LIBM_PATH
+                ANDROID_EXPLICIT_CRT_LINK
+                ANDROID_APP_PIE
+                )
+  if( DEFINED ${__var} )
+   if( ${__var} MATCHES " ")
+    set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" )
+   else()
+    set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" )
+   endif()
+  endif()
+ endforeach()
+ file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" )
+ unset( __toolchain_config )
+endif()
+
+
+# force cmake to produce / instead of \ in build commands for Ninja generator
+if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 )
+ # it is a bad hack after all
+ # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW
+ set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW
+ set( CMAKE_CROSSCOMPILING TRUE )    # stop recursion
+ enable_language( C )
+ enable_language( CXX )
+ # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it
+ unset( MINGW )
+endif()
+
+
+# Variables controlling behavior or set by cmake toolchain:
+#   ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64"
+#   ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version)
+#   ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none
+#   ANDROID_FORBID_SYGWIN : ON/OFF
+#   ANDROID_NO_UNDEFINED : ON/OFF
+#   ANDROID_SO_UNDEFINED : OFF/ON  (default depends on NDK version)
+#   ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF
+#   ANDROID_GOLD_LINKER : ON/OFF
+#   ANDROID_NOEXECSTACK : ON/OFF
+#   ANDROID_RELRO : ON/OFF
+#   ANDROID_FORCE_ARM_BUILD : ON/OFF
+#   ANDROID_STL_FORCE_FEATURES : ON/OFF
+#   ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product/<product_name>/obj/lib/libm.so) to workaround unresolved `sincos`
+# Can be set only at the first run:
+#   ANDROID_NDK : path to your NDK install
+#   NDK_CCACHE : path to your ccache executable
+#   ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain
+#   ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems)
+#   ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID)
+#   LIBRARY_OUTPUT_PATH_ROOT : <any valid path>
+#   ANDROID_STANDALONE_TOOLCHAIN
+#
+# Primary read-only variables:
+#   ANDROID : always TRUE
+#   ARMEABI : TRUE for arm v6 and older devices
+#   ARMEABI_V6 : TRUE for arm v6
+#   ARMEABI_V7A : TRUE for arm v7a
+#   ARM64_V8A : TRUE for arm64-v8a
+#   NEON : TRUE if NEON unit is enabled
+#   VFPV3 : TRUE if VFP version 3 is enabled
+#   X86 : TRUE if configured for x86
+#   X86_64 : TRUE if configured for x86_64
+#   MIPS : TRUE if configured for mips
+#   MIPS64 : TRUE if configured for mips64
+#   BUILD_WITH_ANDROID_NDK : TRUE if NDK is used
+#   BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used
+#   ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform
+#   ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI
+#   ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK
+#   ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor)
+#   ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI
+#   ANDROID_SYSROOT : path to the compiler sysroot
+#   TOOL_OS_SUFFIX : "" or ".exe" depending on host platform
+#   ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used
+#
+# Secondary (less stable) read-only variables:
+#   ANDROID_COMPILER_VERSION : GCC version used (not Clang version)
+#   ANDROID_CLANG_VERSION : version of clang compiler if clang is used
+#   ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform
+#   ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI
+#   ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux"
+#   ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK)
+#   ANDROID_CLANG_TOOLCHAIN_ROOT : path to clang tools
+#   ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK
+#   ANDROID_STL_INCLUDE_DIRS : stl include paths
+#   ANDROID_RTTI : if rtti is enabled by the runtime
+#   ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime
+#   ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used
+#
+# Defaults:
+#   ANDROID_DEFAULT_NDK_API_LEVEL
+#   ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH}
+#   ANDROID_NDK_SEARCH_PATHS
+#   ANDROID_SUPPORTED_ABIS_${ARCH}
+#   ANDROID_SUPPORTED_NDK_VERSIONS

+ 211 - 0
contrib/android-cmake/ndk_links.md

@@ -0,0 +1,211 @@
+
+============== r1 ============== (dead links)
+
+* http://dl.google.com/android/ndk/android-ndk-1.5_r1-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-1.5_r1-darwin-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-1.5_r1-linux-x86.zip
+
+============== r2 ==============
+
+* http://dl.google.com/android/ndk/android-ndk-1.6_r1-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-1.6_r1-darwin-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-1.6_r1-linux-x86.zip
+
+============== r3 ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r3-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r3-darwin-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-r3-linux-x86.zip
+
+============== r4 ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r4-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r4-darwin-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-r4-linux-x86.zip
+
+============== r4b ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r4b-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r4b-darwin-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-r4b-linux-x86.zip
+
+============== r5 ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r5-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r5-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r5-linux-x86.tar.bz2
+
+============== r5b ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r5b-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r5b-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r5b-linux-x86.tar.bz2
+
+============== r5c ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r5c-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r5c-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r5c-linux-x86.tar.bz2
+
+============== r6 ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r6-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r6-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r6-linux-x86.tar.bz2
+
+============== r6b ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r6b-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r6b-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r6b-linux-x86.tar.bz2
+
+============== r7 ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r7-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r7-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r7-linux-x86.tar.bz2
+
+============== r7b ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r7b-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r7b-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r7b-linux-x86.tar.bz2
+
+============== r7c ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r7c-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r7c-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r7c-linux-x86.tar.bz2
+
+============== r8 ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r8-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r8-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r8-linux-x86.tar.bz2
+
+============== r8b ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r8b-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r8b-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2
+
+============== r8c ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r8c-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r8c-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r8c-linux-x86.tar.bz2
+
+============== r8d ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r8d-windows.zip
+* http://dl.google.com/android/ndk/android-ndk-r8d-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r8d-linux-x86.tar.bz2
+
+============== r8e ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86_64.zip
+* http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86_64.tar.bz2
+
+============== r9 ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86-legacy-toolchains.zip
+* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64.zip
+* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64-legacy-toolchains.zip
+* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86-legacy-toolchains.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64-legacy-toolchains.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86-legacy-toolchains.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64-legacy-toolchains.tar.bz2
+
+============== r9b ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86-legacy-toolchains.zip
+* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64.zip
+* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64-legacy-toolchains.zip
+* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86-legacy-toolchains.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64-legacy-toolchains.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86-legacy-toolchains.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64-legacy-toolchains.tar.bz2
+
+============== r9c ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86_64.zip
+* http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9c-cxx-stl-libs-with-debugging-info.zip
+
+============== r9d ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86.zip
+* http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86_64.zip
+* http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r9d-cxx-stl-libs-with-debug-info.zip
+
+============== r10 ==============
+
+* http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86.zip
+* http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86_64.zip
+* http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86.zip
+* http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86_64.zip
+* http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r10-cxx-stl-libs-with-debug-info.zip
+
+============== r10b ==============
+
+* http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86.zip
+* http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86_64.zip
+* http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86.zip
+* http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86_64.zip
+* http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86_64.tar.bz2
+* http://dl.google.com/android/ndk/android-ndk-r10b-cxx-stl-libs-with-debug-info.zip
+
+============== r10c ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86.exe
+* http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86_64.exe
+* http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86.bin
+* http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86_64.bin
+* http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86.bin
+* http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin
+
+============== r10d ==============
+
+* http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86.exe
+* http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86_64.exe
+* http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86.bin
+* http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86_64.bin
+* http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86.bin
+* http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86_64.bin

+ 3 - 0
contrib/clipper/clipper.cpp

@@ -43,6 +43,7 @@
 #include <vector>
 #include <algorithm>
 #include <stdexcept>
+#include <cassert>
 #include <cstring>
 #include <cstdlib>
 #include <ostream>
@@ -2365,6 +2366,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
       //ok, so far it looks like we're still in range of the horizontal edge
       if ( e->xcurr == horzEdge->xtop && !eMaxPair )
       {
+        assert(horzEdge->nextInLML);
         if (SlopesEqual(*e, *horzEdge->nextInLML, m_UseFullRange))
         {
           //if output polygons share an edge, they'll need joining later ...
@@ -2429,6 +2431,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
     if ( horzEdge->outIdx >= 0 )
       IntersectEdges( horzEdge, eMaxPair,
       IntPoint(horzEdge->xtop, horzEdge->ycurr), ipBoth);
+    assert(eMaxPair);
     if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error");
     DeleteFromAEL(eMaxPair);
     DeleteFromAEL(horzEdge);

+ 2 - 4
contrib/openddlparser/code/OpenDDLExport.cpp

@@ -135,10 +135,9 @@ bool OpenDDLExport::writeToStream( const std::string &statement ) {
 }
 
 bool OpenDDLExport::writeNode( DDLNode *node, std::string &statement ) {
-    bool success( true );
     writeNodeHeader( node, statement );
     if (node->hasProperties()) {
-        success |= writeProperties( node, statement );
+        writeProperties( node, statement );
     }
     writeLineEnd( statement );
 
@@ -360,11 +359,10 @@ bool OpenDDLExport::writeValueArray( DataArrayList *al, std::string &statement )
     }
 
     DataArrayList *nextDataArrayList = al ;
-    Value *nextValue( nextDataArrayList->m_dataList );
     while (ddl_nullptr != nextDataArrayList) {
         if (ddl_nullptr != nextDataArrayList) {
             statement += "{ ";
-            nextValue = nextDataArrayList->m_dataList;
+            Value *nextValue( nextDataArrayList->m_dataList );
             size_t idx( 0 );
             while (ddl_nullptr != nextValue) {
                 if (idx > 0) {

+ 14 - 12
contrib/openddlparser/code/OpenDDLParser.cpp

@@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <iostream>
 #include <sstream>
 #include <algorithm>
+#include <memory>
 #include <math.h>
 
 #ifdef _WIN32
@@ -275,22 +276,24 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) {
         }
         delete id;
 
-		Name *name(ddl_nullptr);
-		in = OpenDDLParser::parseName(in, end, &name);
+		Name *name_(ddl_nullptr);
+		in = OpenDDLParser::parseName(in, end, &name_);
+		std::unique_ptr<Name> name(name_);
         if( ddl_nullptr != name && ddl_nullptr != node ) {
             const std::string nodeName( name->m_id->m_buffer );
             node->setName( nodeName );
-            delete name;
         }
 
 
-		Property *first(ddl_nullptr);
+		std::unique_ptr<Property> first;
 		in = lookForNextToken(in, end);
 		if (*in == Grammar::OpenPropertyToken[0]) {
 			in++;
-			Property *prop(ddl_nullptr), *prev(ddl_nullptr);
+			std::unique_ptr<Property> prop, prev;
 			while (*in != Grammar::ClosePropertyToken[0] && in != end) {
-				in = OpenDDLParser::parseProperty(in, end, &prop);
+				Property *prop_(ddl_nullptr);
+				in = OpenDDLParser::parseProperty(in, end, &prop_);
+				prop.reset(prop_);
 				in = lookForNextToken(in, end);
 
 				if (*in != Grammar::CommaSeparator[0] && *in != Grammar::ClosePropertyToken[0]) {
@@ -300,20 +303,20 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) {
 
 				if (ddl_nullptr != prop && *in != Grammar::CommaSeparator[0]) {
 					if (ddl_nullptr == first) {
-						first = prop;
+						first = std::move(prop);
 					}
 					if (ddl_nullptr != prev) {
-						prev->m_next = prop;
+						prev->m_next = prop.release();
 					}
-					prev = prop;
+					prev = std::move(prop);
 				}
 			}
 			++in;
 		}
 
 		// set the properties
-		if (ddl_nullptr != first && ddl_nullptr != node) {
-			node->setProperties(first);
+		if (first && ddl_nullptr != node) {
+			node->setProperties(first.release());
 		}
     }
 
@@ -339,7 +342,6 @@ char *OpenDDLParser::parseStructure( char *in, char *end ) {
     } else {
         ++in;
         logInvalidTokenError( in, std::string( Grammar::OpenBracketToken ), m_logCallback );
-        error = true;
         return ddl_nullptr;
     }
     in = lookForNextToken( in, end );

+ 4 - 8
contrib/unzip/unzip.c

@@ -204,7 +204,7 @@ local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX)
     uLong *pX;
 {
     uLong x ;
-    int i;
+    int i = 0;
     int err;
 
     err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
@@ -232,7 +232,7 @@ local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX)
     uLong *pX;
 {
     uLong x ;
-    int i;
+    int i = 0;
     int err;
 
     err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
@@ -725,19 +725,15 @@ local int unzlocal_GetCurrentFileInfoInternal (file,
 
         if (lSeek!=0)
         {
-            if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
-                lSeek=0;
-            else
+            if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)!=0)
                 err=UNZ_ERRNO;
         }
         if ((file_info.size_file_comment>0) && (commentBufferSize>0))
             if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
                 err=UNZ_ERRNO;
-        lSeek+=file_info.size_file_comment - uSizeRead;
     }
     else
     {
-        lSeek+=file_info.size_file_comment;
     }
 
     if ((err==UNZ_OK) && (pfile_info!=NULL))
@@ -1129,7 +1125,7 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password)
 
     if ((s->cur_file_info.compression_method!=0) &&
         (s->cur_file_info.compression_method!=Z_DEFLATED))
-        err=UNZ_BADZIPFILE;
+        return UNZ_BADZIPFILE;
 
     pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
     pfile_in_zip_read_info->crc32=0;

+ 2 - 0
contrib/zlib/zconf.h.included

@@ -7,6 +7,8 @@
 
 #ifndef ZCONF_H
 #define ZCONF_H
+/* #undef Z_PREFIX */
+/* #undef Z_HAVE_UNISTD_H */
 
 /*
  * If you *really* need a unique prefix for all types and library functions,

+ 1 - 1
doc/Doxyfile.in

@@ -1742,7 +1742,7 @@ UML_LOOK               = NO
 # the class node. If there are many fields or methods and many nodes the 
 # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 
 # threshold limits the number of items for each type to make the size more 
-# managable. Set this to 0 for no limit. Note that the threshold may be 
+# manageable. Set this to 0 for no limit. Note that the threshold may be 
 # exceeded by 50% before the limit is enforced.
 
 UML_LIMIT_NUM_FIELDS   = 10

+ 5 - 5
doc/dox.h

@@ -60,7 +60,7 @@ that it has not been implemented yet and some (most ...) formats lack proper spe
 <b>Stanford Ply</b> ( <i>*.ply</i> )<br>
 <b>TrueSpace</b> ( <i>*.cob, *.scn</i> )<sup>2</sup><br><br>
 </tt>
-See the @link importer_notes Importer Notes Page @endlink for informations, what a specific importer can do and what not.
+See the @link importer_notes Importer Notes Page @endlink for information, what a specific importer can do and what not.
 Note that although this paper claims to be the official documentation,
 http://assimp.sourceforge.net/main_features_formats.html
 <br>is usually the most up-to-date list of file formats supported by the library. <br>
@@ -81,7 +81,7 @@ formats handle the required endian conversion correctly, so large parts of the l
 
 The assimp linker library and viewer application are provided under the BSD 3-clause license. This basically means
 that you are free to use it in open- or closed-source projects, for commercial or non-commercial purposes as you like
-as long as you retain the license informations and take own responsibility for what you do with it. For details see
+as long as you retain the license information and take own responsibility for what you do with it. For details see
 the LICENSE file.
 
 You can find test models for almost all formats in the <assimp_root>/test/models directory. Beware, they're *free*,
@@ -1420,7 +1420,7 @@ IFC file properties (IfcPropertySet) are kept as per-node metadata, see aiNode::
 
 This section contains implementations notes for the OgreXML importer.
 @subsection overview Overview
-Ogre importer is currently optimized for the Blender Ogre exporter, because thats the only one that I use. You can find the Blender Ogre exporter at: http://www.ogre3d.org/forums/viewtopic.php?f=8&t=45922
+Ogre importer is currently optimized for the Blender Ogre exporter, because that's the only one that I use. You can find the Blender Ogre exporter at: http://www.ogre3d.org/forums/viewtopic.php?f=8&t=45922
 
 @subsection what What will be loaded?
 
@@ -1434,7 +1434,7 @@ Skeleton: Skeleton with Bone hierarchy (Position and Rotation, but no Scaling in
 animations with rotation, translation and scaling keys.
 
 @subsection export_Blender How to export Files from Blender
-You can find informations about how to use the Ogreexporter by your own, so here are just some options that you need, so the assimp
+You can find information about how to use the Ogreexporter by your own, so here are just some options that you need, so the assimp
 importer will load everything correctly:
 - Use either "Rendering Material" or "Custom Material" see @ref material
 - do not use "Flip Up Axies to Y"
@@ -1543,7 +1543,7 @@ Done! Please, share your loader that everyone can profit from it!
 
 @section properties Properties
 
-You can use properties to chance the behavior of you importer. In order to do so, you have to overide BaseImporter::SetupProperties, and specify
+You can use properties to chance the behavior of you importer. In order to do so, you have to override BaseImporter::SetupProperties, and specify
 you custom properties in config.h. Just have a look to the other AI_CONFIG_IMPORT_* defines and you will understand, how it works.
 
 The properties can be set with Importer::SetProperty***() and can be accessed in your SetupProperties function with Importer::GetProperty***(). You can

+ 10 - 1
include/assimp/config.h.in

@@ -266,6 +266,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_CONFIG_PP_FD_REMOVE \
     "PP_FD_REMOVE"
 
+// ---------------------------------------------------------------------------
+/**
+ *  @brief  Configures the #aiProcess_FindDegenerates to check the area of a
+ *  trinagle to be greates than e-6. If this is not the case the triangle will
+ *  be removed if #AI_CONFIG_PP_FD_REMOVE is set to true.
+ */
+#define AI_CONFIG_PP_FD_CHECKAREA \
+    "PP_FD_CHECKAREA"
+
 // ---------------------------------------------------------------------------
 /** @brief Configures the #aiProcess_OptimizeGraph step to preserve nodes
  * matching a name in a given list.
@@ -903,7 +912,7 @@ enum aiComponent
 /** @brief  Set the tessellation for IFC cylindrical shapes.
  *
  * This is used by the IFC importer to determine the tessellation parameter
- * for cylindrical shapes, i.e. the number of segments used to aproximate a circle.
+ * for cylindrical shapes, i.e. the number of segments used to approximate a circle.
  * @note The default value is AI_IMPORT_IFC_DEFAULT_CYLINDRICAL_TESSELLATION and the
  * accepted values are in range [3, 180].
  * Property type: Integer.

+ 4 - 5
include/assimp/vector3.h

@@ -65,11 +65,10 @@ template <typename TReal>
 class aiVector3t
 {
 public:
-
-    aiVector3t () : x(), y(), z() {}
-    aiVector3t (TReal _x, TReal _y, TReal _z) : x(_x), y(_y), z(_z) {}
-    explicit aiVector3t (TReal _xyz) : x(_xyz), y(_xyz), z(_xyz) {}
-    aiVector3t (const aiVector3t& o) : x(o.x), y(o.y), z(o.z) {}
+    aiVector3t() : x(), y(), z() {}
+    aiVector3t(TReal _x, TReal _y, TReal _z) : x(_x), y(_y), z(_z) {}
+    explicit aiVector3t (TReal _xyz ) : x(_xyz), y(_xyz), z(_xyz) {}
+    aiVector3t( const aiVector3t& o ) : x(o.x), y(o.y), z(o.z) {}
 
 public:
 

+ 1 - 1
port/PyAssimp/pyassimp/structs.py

@@ -206,7 +206,7 @@ class MeshKey(Structure):
             ("mTime", c_double),
             
             # Index into the aiMesh::mAnimMeshes array of the
-            #  mesh coresponding to the
+            #  mesh corresponding to the
             #aiMeshAnim hosting this
             #  key frame. The referenced anim mesh is evaluated
             #  according to the rules defined in the docs for

+ 1 - 1
port/PyAssimp/scripts/3d_viewer.py

@@ -895,7 +895,7 @@ class PyAssimp3DViewer:
         aspect = camera.aspect
 
         u = 0.1  # unit size (in m)
-        l = 3 * u  # lenght of the camera cone
+        l = 3 * u  # length of the camera cone
         f = 3 * u  # aperture of the camera cone
 
         glPushMatrix()

+ 1 - 1
port/PyAssimp/scripts/3d_viewer_py3.py

@@ -897,7 +897,7 @@ class PyAssimp3DViewer:
         aspect = camera.aspect
 
         u = 0.1  # unit size (in m)
-        l = 3 * u  # lenght of the camera cone
+        l = 3 * u  # length of the camera cone
         f = 3 * u  # aperture of the camera cone
 
         glPushMatrix()

+ 1 - 1
port/PyAssimp/scripts/transformations.py

@@ -583,7 +583,7 @@ def clip_matrix(left, right, bottom, top, near, far, perspective=False):
     orthographic canonical view volume (a box).
 
     Homogeneous coordinates transformed by the perspective clip matrix
-    need to be dehomogenized (devided by w coordinate).
+    need to be dehomogenized (divided by w coordinate).
 
     >>> frustrum = numpy.random.rand(6)
     >>> frustrum[1] += frustrum[0]

+ 1 - 1
port/dAssimp/assimp/mesh.d

@@ -51,7 +51,7 @@ import assimp.types;
 extern ( C ) {
    /*
     * These limits are required to match the settings Assimp was compiled
-    * against. Therfore, do not redefine them unless you build the library
+    * against. Therefore, do not redefine them unless you build the library
     * from source using the same definitions.
     */
 

+ 1 - 1
port/jassimp/jassimp-native/src/jassimp.cpp

@@ -1951,7 +1951,7 @@ error:
 
 	if (NULL == exception)
 	{
-		/* thats really a problem because we cannot throw in this case */
+		/* that's really a problem because we cannot throw in this case */
 		env->FatalError("could not throw java.io.IOException");
 	}
 	gLastErrorString = imp.GetErrorString();

+ 1 - 1
port/swig/assimp.i

@@ -114,7 +114,7 @@
 %include "interface/IOSystem.i"
 
 
-// We have to "instanciate" the templates used by the ASSSIMP_*_ARRAY macros
+// We have to "instantiate" the templates used by the ASSSIMP_*_ARRAY macros
 // here at the end to avoid running into forward reference issues (SWIG would
 // spit out the helper functions before the header includes for the element
 // types otherwise).

+ 1 - 1
samples/SimpleAssimpViewX/MyDocument.mm

@@ -641,7 +641,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink,const CVTimeS
 {
     for(MeshHelper* helper in modelMeshes)
     {
-        // Set up meterial state.
+        // Set up material state.
         glCallList(helper.displayList);  
     }
 }

+ 2 - 2
samples/glut/GL/glut.h

@@ -179,7 +179,7 @@ extern void exit(int);
  glutSpecialUpFunc, glutIgnoreKeyRepeat, glutSetKeyRepeat,
  glutJoystickFunc, glutForceJoystickFunc (NOT FINALIZED!).
 **/
-#ifndef GLUT_API_VERSION  /* allow this to be overriden */
+#ifndef GLUT_API_VERSION  /* allow this to be overridden */
 #define GLUT_API_VERSION		3
 #endif
 
@@ -219,7 +219,7 @@ extern void exit(int);
 
  GLUT_XLIB_IMPLEMENTATION=15 mjk's GLUT 3.7 beta sync'ed with Mesa <GL/glut.h>
 **/
-#ifndef GLUT_XLIB_IMPLEMENTATION  /* Allow this to be overriden. */
+#ifndef GLUT_XLIB_IMPLEMENTATION  /* Allow this to be overridden. */
 #define GLUT_XLIB_IMPLEMENTATION	15
 #endif
 

+ 28 - 0
scripts/android_crosscompile/make_android.bat

@@ -0,0 +1,28 @@
+@echo off
+
+set ASSIMP_PATH=D:\projects\asset-importer-lib\assimp
+set CMAKE_PATH="C:\Program Files\CMake\bin\cmake.exe"
+set ANDROID_NDK_PATH=C:\Users\kimkulling\AppData\Local\Android\Sdk\ndk-bundle
+set ANDROID_CMAKE_PATH=contrib\android-cmake
+
+pushd %ASSIMP_PATH%
+
+rmdir /s /q build
+mkdir build
+cd build
+
+%CMAKE_PATH% .. ^
+  -G"MinGW Makefiles" ^
+  -DCMAKE_BUILD_TYPE=Release ^
+  -DCMAKE_TOOLCHAIN_FILE=%ANDROID_CMAKE_PATH%\android.toolchain.cmake ^
+  -DCMAKE_MAKE_PROGRAM=%ANDROID_NDK_PATH%\prebuilt\windows-x86_64\bin\make.exe ^
+  -DANDROID_NDK=%ANDROID_NDK_PATH% ^
+  -DANDROID_NATIVE_API_LEVEL=android-9 ^
+  -DASSIMP_ANDROID_JNIIOSYSTEM=ON ^
+  -DANDROID_ABI=arm64-v8a ^
+  -DASSIMP_BUILD_ZLIB=ON ^
+  -DASSIMP_BUILD_TESTS=OFF
+
+%CMAKE_PATH% --build .
+
+popd

+ 76 - 62
test/CMakeLists.txt

@@ -52,24 +52,55 @@ INCLUDE_DIRECTORIES(
 # Assimp library can be found, even if it is not installed system-wide yet.
 LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${AssetImporter_BINARY_DIR}/lib )
 
-SOURCE_GROUP( unit FILES
-  unit/CCompilerTest.c
-)
-
-SET( TEST_SRCS
+SET( COMMON
+  unit/utIOSystem.cpp
+  unit/utIOStreamBuffer.cpp
+  unit/utIssues.cpp
+  unit/utAnim.cpp
+  unit/AssimpAPITest.cpp
+  unit/utBatchLoader.cpp
+  unit/utDefaultIOStream.cpp
+  unit/utFastAtof.cpp
+  unit/utMetadata.cpp
+  unit/SceneDiffer.h
+  unit/SceneDiffer.cpp
   unit/UTLogStream.h
   unit/AbstractImportExportBase.cpp
   unit/TestIOSystem.h
   unit/TestModelFactory.h
+  unit/utTypes.cpp
+  unit/utVersion.cpp
+  unit/utProfiler.cpp
+  unit/utSharedPPData.cpp
+  unit/utStringUtils.cpp
+)
+
+SET( IMPORTERS
+  unit/utLWSImportExport.cpp
+  unit/utSMDImportExport.cpp
+  unit/utglTFImportExport.cpp
+  unit/utglTF2ImportExport.cpp
+  unit/utHMPImportExport.cpp
+  unit/utIFCImportExport.cpp
+  unit/utFBXImporterExporter.cpp
+  unit/utImporter.cpp
   unit/ut3DImportExport.cpp
   unit/ut3DSImportExport.cpp
   unit/utACImportExport.cpp
   unit/utAMFImportExport.cpp
   unit/utASEImportExport.cpp
-  unit/utAnim.cpp
-  unit/AssimpAPITest.cpp
-  unit/utB3DImportExport.cpp
-  unit/utBatchLoader.cpp
+  unit/utD3MFImportExport.cpp
+  unit/utQ3DImportExport.cpp
+  unit/utSTLImportExport.cpp
+  unit/utXImporterExporter.cpp
+  unit/utX3DImportExport.cpp
+  unit/utDXFImporterExporter.cpp
+  unit/utPMXImporter.cpp
+  unit/utPLYImportExport.cpp
+  unit/utObjImportExport.cpp
+  unit/utObjTools.cpp
+  unit/utOpenGEXImportExport.cpp
+  unit/utSIBImporter.cpp
   unit/utBlenderIntermediate.cpp
   unit/utBlendImportAreaLight.cpp
   unit/utBlenderImportExport.cpp
@@ -79,77 +110,60 @@ SET( TEST_SRCS
   unit/utColladaExportLight.cpp
   unit/utColladaImportExport.cpp
   unit/utCSMImportExport.cpp
-  unit/utDefaultIOStream.cpp
-  unit/utDXFImporterExporter.cpp
-  unit/utFastAtof.cpp
-  unit/utFBXImporterExporter.cpp
-  unit/utFindDegenerates.cpp
-  unit/utFindInvalidData.cpp
-  unit/utFixInfacingNormals.cpp
-  unit/utGenNormals.cpp
-  unit/utglTFImportExport.cpp
-  unit/utglTF2ImportExport.cpp
-  unit/utHMPImportExport.cpp
-  unit/utIFCImportExport.cpp
-  unit/utImporter.cpp
-  unit/utImproveCacheLocality.cpp
-  unit/utIOSystem.cpp
-  unit/utIOStreamBuffer.cpp
-  unit/utIssues.cpp
-  unit/utJoinVertices.cpp
-  unit/utLimitBoneWeights.cpp
-  unit/utLWSImportExport.cpp
+  unit/utB3DImportExport.cpp
+)
+
+SET( MATERIAL
   unit/utMaterialSystem.cpp
+)
+
+SET( MATH
   unit/utMatrix3x3.cpp
   unit/utMatrix4x4.cpp
-  unit/utMetadata.cpp
-  unit/SceneDiffer.h
-  unit/SceneDiffer.cpp
-  unit/utSIBImporter.cpp
-  unit/utObjImportExport.cpp
-  unit/utObjTools.cpp
-  unit/utOpenGEXImportExport.cpp
-  unit/utPretransformVertices.cpp
-  unit/utPLYImportExport.cpp
-  unit/utPMXImporter.cpp
-  unit/utRemoveComments.cpp
-  unit/utRemoveComponent.cpp
-  unit/utScenePreprocessor.cpp
-  unit/utSceneCombiner.cpp
-  unit/utSharedPPData.cpp
-  unit/utStringUtils.cpp
-  unit/utSMDImportExport.cpp
-  unit/utSortByPType.cpp
-  unit/utSplitLargeMeshes.cpp
-  unit/utTargetAnimation.cpp
-  unit/utTextureTransform.cpp
-  unit/utTriangulate.cpp
-  unit/utTypes.cpp
-  unit/utVertexTriangleAdjacency.cpp
-  unit/utVersion.cpp
   unit/utVector3.cpp
-  unit/utXImporterExporter.cpp
-  unit/utX3DImportExport.cpp
-  unit/utD3MFImportExport.cpp
-  unit/utQ3DImportExport.cpp
-  unit/utProfiler.cpp
 )
+
 SET( POST_PROCESSES
+  unit/utImproveCacheLocality.cpp
+  unit/utFixInfacingNormals.cpp
+  unit/utGenNormals.cpp
+  unit/utTriangulate.cpp
+  unit/utTextureTransform.cpp
   unit/utRemoveRedundantMaterials.cpp
   unit/utRemoveVCProcess.cpp
   unit/utScaleProcess.cpp
   unit/utJoinVertices.cpp
+  unit/utRemoveComments.cpp
+  unit/utRemoveComponent.cpp
+  unit/utVertexTriangleAdjacency.cpp
+  unit/utJoinVertices.cpp
+  unit/utSplitLargeMeshes.cpp
+  unit/utFindDegenerates.cpp
+  unit/utFindInvalidData.cpp
+  unit/utLimitBoneWeights.cpp
+  unit/utPretransformVertices.cpp
+  unit/utScenePreprocessor.cpp
+  unit/utTargetAnimation.cpp
+  unit/utSortByPType.cpp
+  unit/utSceneCombiner.cpp
 )
 
-SOURCE_GROUP( tests             FILES  ${TEST_SRCS} )
-SOURCE_GROUP( tests/PostProcess FILES  ${POST_PROCESSES})
+SOURCE_GROUP( UnitTests\\Compiler     FILES  unit/CCompilerTest.c )
+SOURCE_GROUP( UnitTests\\Common      FILES  ${COMMON} )
+SOURCE_GROUP( UnitTests\\Importers   FILES  ${IMPORTERS} )
+SOURCE_GROUP( UnitTests\\Material    FILES  ${MATERIAL} )
+SOURCE_GROUP( UnitTests\\Math        FILES  ${MATH} )
+SOURCE_GROUP( UnitTests\\PostProcess FILES  ${POST_PROCESSES})
 
 add_executable( unit
     ../contrib/gtest/src/gtest-all.cc
     unit/CCompilerTest.c
     unit/Main.cpp
     ../code/Version.cpp
-    ${TEST_SRCS}
+	${COMMON}
+	${IMPORTERS}
+	${MATERIAL}
+	${MATH}
     ${POST_PROCESSES}
 )
 

+ 1 - 1
test/models-nonbsd/BLEND/fleurOptonl.source.txt

@@ -32,7 +32,7 @@ L'utilizzo della Creative Commons non influisce su questo diritto.
 ************************************************
 
 This model is released under Creative Commons Licence, Attribution 2.0
-for informations see:
+for information see:
 http://creativecommons.org
 http://creativecommons.org/licenses/by/2.0/
 feel free to use and improve it.

+ 1 - 1
test/models/AMF/README

@@ -1 +1 @@
-Simple models for testing importer. No desription because models are simple and created by hands.
+Simple models for testing importer. No description because models are simple and created by hand.

+ 18 - 0
test/models/STL/triangle_with_two_solids.stl

@@ -0,0 +1,18 @@
+solid testTriangle_1
+  facet normal 0.0 0.0 1.0 
+    outer loop 
+      vertex 1.0 1.0 0.0 
+      vertex -1.0 1.0 0.0 
+      vertex 0.0 -1.0 0.0 
+    endloop 
+  endfacet 
+endsolid
+solid testTriangle_2
+  facet normal 0.0 0.0 1.0 
+    outer loop 
+      vertex 3.0 3.0 0.0 
+      vertex 2.0 3.0 0.0 
+      vertex 0.0 2.0 0.0 
+    endloop 
+  endfacet 
+endsolid

+ 12 - 11
test/unit/utFindDegenerates.cpp

@@ -58,8 +58,7 @@ protected:
 };
 
 // ------------------------------------------------------------------------------------------------
-void FindDegeneratesProcessTest::SetUp()
-{
+void FindDegeneratesProcessTest::SetUp() {
     mesh = new aiMesh();
     process = new FindDegeneratesProcess();
 
@@ -107,16 +106,12 @@ void FindDegeneratesProcessTest::SetUp()
     mesh->mNumUVComponents[1] = numFaces;
 }
 
-// ------------------------------------------------------------------------------------------------
-void FindDegeneratesProcessTest::TearDown()
-{
+void FindDegeneratesProcessTest::TearDown() {
     delete mesh;
     delete process;
 }
 
-// ------------------------------------------------------------------------------------------------
-TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection)
-{
+TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection) {
     process->EnableInstantRemoval(false);
     process->ExecuteOnMesh(mesh);
 
@@ -135,12 +130,18 @@ TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection)
               mesh->mPrimitiveTypes);
 }
 
-// ------------------------------------------------------------------------------------------------
-TEST_F(FindDegeneratesProcessTest, testDegeneratesRemoval)
-{
+TEST_F(FindDegeneratesProcessTest, testDegeneratesRemoval) {
+    process->EnableAreaCheck(false);
     process->EnableInstantRemoval(true);
     process->ExecuteOnMesh(mesh);
 
     EXPECT_EQ(mesh->mNumUVComponents[1], mesh->mNumFaces);
 }
 
+TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) {
+    process->EnableAreaCheck(true);
+    process->EnableInstantRemoval(true);
+    process->ExecuteOnMesh(mesh);
+
+    EXPECT_EQ(mesh->mNumUVComponents[1]-100, mesh->mNumFaces);
+}

+ 8 - 8
test/unit/utObjImportExport.cpp

@@ -294,12 +294,12 @@ TEST_F(utObjImportExport, relative_indices_Test) {
     const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel.c_str(), ObjModel.size(), aiProcess_ValidateDataStructure);
     EXPECT_NE(nullptr, scene);
 
-    EXPECT_EQ(scene->mNumMeshes, 1);
+    EXPECT_EQ(scene->mNumMeshes, 1U);
     const aiMesh *mesh = scene->mMeshes[0];
-    EXPECT_EQ(mesh->mNumVertices, 4);
-    EXPECT_EQ(mesh->mNumFaces, 1);
+    EXPECT_EQ(mesh->mNumVertices, 4U);
+    EXPECT_EQ(mesh->mNumFaces, 1U);
     const aiFace face = mesh->mFaces[0];
-    EXPECT_EQ(face.mNumIndices, 4);
+    EXPECT_EQ(face.mNumIndices, 4U);
     for (unsigned int i = 0; i < face.mNumIndices; ++i)
     {
         EXPECT_EQ(face.mIndices[i], i);
@@ -318,12 +318,12 @@ TEST_F(utObjImportExport, homogeneous_coordinates_Test) {
     const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel.c_str(), ObjModel.size(), aiProcess_ValidateDataStructure);
     EXPECT_NE(nullptr, scene);
 
-    EXPECT_EQ(scene->mNumMeshes, 1);
+    EXPECT_EQ(scene->mNumMeshes, 1U);
     const aiMesh *mesh = scene->mMeshes[0];
-    EXPECT_EQ(mesh->mNumVertices, 3);
-    EXPECT_EQ(mesh->mNumFaces, 1);
+    EXPECT_EQ(mesh->mNumVertices, 3U);
+    EXPECT_EQ(mesh->mNumFaces, 1U);
     const aiFace face = mesh->mFaces[0];
-    EXPECT_EQ(face.mNumIndices, 3);
+    EXPECT_EQ(face.mNumIndices, 3U);
     const aiVector3D vertice = mesh->mVertices[0];
     EXPECT_EQ(vertice.x, -1.0f);
     EXPECT_EQ(vertice.y, 0.0f);

+ 68 - 0
test/unit/utSTLImportExport.cpp

@@ -0,0 +1,68 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#include "UnitTestPCH.h"
+#include "SceneDiffer.h"
+#include "AbstractImportExportBase.h"
+
+#include <assimp/Importer.hpp>
+
+using namespace Assimp;
+
+class utSTLImporterExporter : public AbstractImportExportBase {
+public:
+    virtual bool importerTest() {
+        Assimp::Importer importer;
+        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/STL/Spider_ascii.stl", 0 );
+        return nullptr != scene;
+    }
+};
+
+TEST_F( utSTLImporterExporter, importXFromFileTest ) {
+    EXPECT_TRUE( importerTest() );
+}
+
+TEST_F( utSTLImporterExporter, test_with_two_solids ) {
+    Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/STL/triangle_with_two_solids.stl", 0 );
+    EXPECT_NE( nullptr, scene );
+}

+ 15 - 3
tools/assimp_cmd/WriteDumb.cpp

@@ -177,6 +177,17 @@ inline uint32_t Write<aiVector3D>(const aiVector3D& v)
 	return t;
 }
 
+// -----------------------------------------------------------------------------------
+// Serialize a color value
+template <>
+inline uint32_t Write<aiColor3D>(const aiColor3D& v)
+{
+	uint32_t t = Write<float>(v.r);
+	t += Write<float>(v.g);
+	t += Write<float>(v.b);
+	return t;
+}
+
 // -----------------------------------------------------------------------------------
 // Serialize a color value
 template <>
@@ -198,6 +209,7 @@ inline uint32_t Write<aiQuaternion>(const aiQuaternion& v)
 	t += Write<float>(v.x);
 	t += Write<float>(v.y);
 	t += Write<float>(v.z);
+	ai_assert(t == 16);
 	return 16;
 }
 
@@ -565,9 +577,9 @@ uint32_t WriteBinaryLight(const aiLight* l)
 		len += Write<float>(l->mAttenuationQuadratic);
 	}
 
-	len += Write<aiVector3D>((const aiVector3D&)l->mColorDiffuse);
-	len += Write<aiVector3D>((const aiVector3D&)l->mColorSpecular);
-	len += Write<aiVector3D>((const aiVector3D&)l->mColorAmbient);
+	len += Write<aiColor3D>(l->mColorDiffuse);
+	len += Write<aiColor3D>(l->mColorSpecular);
+	len += Write<aiColor3D>(l->mColorAmbient);
 
 	if (l->mType == aiLightSource_SPOT) {
 		len += Write<float>(l->mAngleInnerCone);

+ 1 - 1
tools/assimp_qt_viewer/glview.cpp

@@ -561,7 +561,7 @@ void CGLView::Enable_Textures(const bool pEnable)
 }
 
 /********************************************************************/
-/*********************** Overrided functions ************************/
+/*********************** Override functions ************************/
 /********************************************************************/
 
 void CGLView::initializeGL()

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