Parcourir la source

Merge remote-tracking branch 'official/master' into contrib

Léo Terziman il y a 10 ans
Parent
commit
3303f97f13

+ 19 - 0
.gitignore

@@ -32,3 +32,22 @@ test/results
 
 # Python
 __pycache__
+*.log
+*.vcxproj
+*.filters
+*.tlog
+Assimp.sdf
+test/gtest/tmp/gtest-gitupdate.cmake
+test/gtest/tmp/gtest-gitclone.cmake
+test/gtest/tmp/gtest-cfgcmd.txt.in
+test/gtest/tmp/gtest-cfgcmd.txt
+test/gtest/src/gtest-stamp/gtest-download.cmake
+test/gtest/src/gtest-stamp/gtest-configure.cmake
+test/gtest/src/gtest-stamp/gtest-build.cmake
+test/gtest/src/gtest-stamp/Debug/gtest-patch
+*.cache
+test/gtest/src/gtest-stamp/Debug/gtest-build
+*.suo
+*.lib
+test/gtest/src/gtest-stamp/Debug/
+tools/assimp_view/assimp_viewer.vcxproj.user

+ 10 - 11
CMakeLists.txt

@@ -78,21 +78,11 @@ SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE PATH
 	"Path the header files are installed to." )
 SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE PATH
 	"Path the tool executables are installed to." )
-option (ASSIMP_BUILD_STATIC_LIB "Build a static (.a) version of the library" OFF)
 
 SET(ASSIMP_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfitx for lib, samples and tools")
 
-# Allow the user to build a static library
+# Allow the user to build a shared or static library
 option ( BUILD_SHARED_LIBS "Build a shared version of the library" ON )
-IF ( ASSIMP_BUILD_STATIC_LIB )
-    option ( BUILD_SHARED_LIBS "Build a shared version of the library" OFF )
-ELSE ( ASSIMP_BUILD_STATIC_LIB )
-    option ( BUILD_SHARED_LIBS "Build a shared version of the library" ON )
-ENDIF ( ASSIMP_BUILD_STATIC_LIB )
-
-# Generate a pkg-config .pc for the Assimp library.
-CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
-INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
 
 # Only generate this target if no higher-level project already has
 IF (NOT TARGET uninstall)
@@ -136,6 +126,10 @@ option ( ASSIMP_NO_EXPORT
 	OFF
 )
 
+if( CMAKE_COMPILER_IS_GNUCXX )
+  set(LIBSTDC++_LIBRARIES -lstdc++)
+endif( CMAKE_COMPILER_IS_GNUCXX )
+
 # Search for external dependencies, and build them from source if not found
 # Search for zlib
 find_package(ZLIB)
@@ -151,6 +145,7 @@ if( NOT ZLIB_FOUND )
   set(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
 else(NOT ZLIB_FOUND)
   ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
+  set(ZLIB_LIBRARIES_LINKED -lz)
 endif(NOT ZLIB_FOUND)
 INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
 
@@ -228,6 +223,10 @@ IF(MSVC)
 	)
 ENDIF(MSVC)
 
+# Generate a pkg-config .pc for the Assimp library.
+CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
+INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
+
 if(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
   # Packing information
   set(CPACK_PACKAGE_NAME                    "assimp{ASSIMP_VERSION_MAJOR}")

+ 1 - 0
assimp.pc.in

@@ -7,4 +7,5 @@ Name: @CMAKE_PROJECT_NAME@
 Description: Import various well-known 3D model formats in an uniform manner.
 Version: @PROJECT_VERSION@
 Libs: -L${libdir} -lassimp@ASSIMP_LIBRARY_SUFFIX@
+Libs.private: @LIBSTDC++_LIBRARIES@ @ZLIB_LIBRARIES_LINKED@
 Cflags: -I${includedir}

+ 24 - 1
code/Assimp.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "GenericProperty.h"
 #include "CInterfaceIOWrapper.h"
+#include "../include/assimp/importerdesc.h"
 #include "Importer.h"
 
 // ------------------------------------------------------------------------------------------------
@@ -84,7 +85,11 @@ namespace Assimp
 
 	/** Verbose logging active or not? */
 	static aiBool gVerboseLogging = false;
-}
+
+    /** will return all registered importers. */
+    void GetImporterInstanceList(std::vector< BaseImporter* >& out);
+
+} // namespace assimp
 
 
 #ifndef ASSIMP_BUILD_SINGLETHREADED
@@ -606,4 +611,22 @@ ASSIMP_API void aiIdentityMatrix4(
 	*mat = aiMatrix4x4();
 }
 
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) {
+    if( NULL == extension ) {
+        return NULL;
+    }
+    const aiImporterDesc *desc( NULL );
+    std::vector< BaseImporter* > out;
+    GetImporterInstanceList( out );
+    for( size_t i = 0; i < out.size(); ++i ) {
+        if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) {
+            desc = out[ i ]->GetInfo();
+            break;
+        }
+    }
 
+    return desc;
+}
+
+// ------------------------------------------------------------------------------------------------

+ 5 - 0
code/BaseImporter.h

@@ -90,6 +90,11 @@ struct ScopeGuard
 	}
 
 private:
+    // no copying allowed.
+    ScopeGuard();
+    ScopeGuard( const ScopeGuard & );
+    ScopeGuard &operator = ( const ScopeGuard & );
+
 	T* obj;
 	bool mdismiss;
 };

+ 74 - 37
code/ColladaParser.cpp

@@ -1867,14 +1867,15 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
 	// read primitive count from the attribute
 	int attrCount = GetAttribute( "count");
 	size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount);
+	// some mesh types (e.g. tristrips) don't specify primitive count upfront,
+	// so we need to sum up the actual number of primitives while we read the <p>-tags
+	size_t actualPrimitives = 0;
 
-	// material subgroup 
+	// material subgroup
 	int attrMaterial = TestAttribute( "material");
 	SubMesh subgroup;
 	if( attrMaterial > -1)
 		subgroup.mMaterial = mReader->getAttributeValue( attrMaterial);
-	subgroup.mNumFaces = numPrimitives;
-	pMesh->mSubMeshes.push_back( subgroup);
 
 	// distinguish between polys and triangles
 	std::string elementName = mReader->getNodeName();
@@ -1933,7 +1934,7 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
 				if( !mReader->isEmptyElement())
 				{
 					// now here the actual fun starts - these are the indices to construct the mesh data from
-					ReadPrimitives( pMesh, perIndexData, numPrimitives, vcount, primType);
+					actualPrimitives += ReadPrimitives(pMesh, perIndexData, numPrimitives, vcount, primType);
 				}
 			} else
 			{
@@ -1948,6 +1949,14 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
 			break;
 		}
 	}
+
+	// small sanity check
+	if (primType != Prim_TriFans && primType != Prim_TriStrips)
+		ai_assert(actualPrimitives == numPrimitives);
+
+	// only when we're done reading all <p> tags (and thus know the final vertex count) can we commit the submesh
+	subgroup.mNumFaces = actualPrimitives;
+	pMesh->mSubMeshes.push_back(subgroup);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -1995,7 +2004,7 @@ void ColladaParser::ReadInputChannel( std::vector<InputChannel>& poChannels)
 
 // ------------------------------------------------------------------------------------------------
 // Reads a <p> primitive index list and assembles the mesh data into the given mesh
-void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels, 
+size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels,
 	size_t pNumPrimitives, const std::vector<size_t>& pVCount, PrimitiveType pPrimType)
 {
 	// determine number of indices coming per vertex 
@@ -2093,70 +2102,98 @@ void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPer
 			acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
 	}
 
-
-	// now assemble vertex data according to those indices
-	std::vector<size_t>::const_iterator idx = indices.begin();
-
 	// For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
 	size_t numPrimitives = pNumPrimitives;
 	if( pPrimType == Prim_TriFans || pPrimType == Prim_Polygon)
 		numPrimitives = 1;
+	// For continued primitives, the given count is actually the number of <p>'s inside the parent tag
+	if ( pPrimType == Prim_TriStrips){
+		size_t numberOfVertices = indices.size() / numOffsets;
+		numPrimitives = numberOfVertices - 2;
+	}
 
 	pMesh->mFaceSize.reserve( numPrimitives);
 	pMesh->mFacePosIndices.reserve( indices.size() / numOffsets);
 
-	for( size_t a = 0; a < numPrimitives; a++)
+	size_t polylistStartVertex = 0;
+	for (size_t currentPrimitive = 0; currentPrimitive < numPrimitives; currentPrimitive++)
 	{
 		// determine number of points for this primitive
 		size_t numPoints = 0;
 		switch( pPrimType)
 		{
 			case Prim_Lines:
-				numPoints = 2; 
+				numPoints = 2;
+				for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
+					CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 				break;
-			case Prim_Triangles: 
-				numPoints = 3; 
+			case Prim_Triangles:
+				numPoints = 3;
+				for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
+					CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+				break;
+			case Prim_TriStrips:
+				numPoints = 3;
+				ReadPrimTriStrips(numOffsets, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 				break;
 			case Prim_Polylist: 
-				numPoints = pVCount[a];
+				numPoints = pVCount[currentPrimitive];
+				for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
+					CopyVertex(polylistStartVertex + currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, 0, indices);
+				polylistStartVertex += numPoints;
 				break;
 			case Prim_TriFans: 
 			case Prim_Polygon:
-				numPoints = indices.size() / numOffsets; 
+				numPoints = indices.size() / numOffsets;
+				for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
+					CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 				break;
 			default:
-				// LineStrip and TriStrip not supported due to expected index unmangling
+				// LineStrip is not supported due to expected index unmangling
 				ThrowException( "Unsupported primitive type.");
 				break;
 		}
 
 		// store the face size to later reconstruct the face from
 		pMesh->mFaceSize.push_back( numPoints);
-
-		// gather that number of vertices
-		for( size_t b = 0; b < numPoints; b++)
-		{
-			// read all indices for this vertex. Yes, in a hacky local array
-			ai_assert( numOffsets < 20 && perVertexOffset < 20);
-			size_t vindex[20];
-			for( size_t offsets = 0; offsets < numOffsets; ++offsets)
-				vindex[offsets] = *idx++;
-
-			// extract per-vertex channels using the global per-vertex offset
-      for( std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
-        ExtractDataObjectFromChannel( *it, vindex[perVertexOffset], pMesh);
-			// and extract per-index channels using there specified offset
-      for( std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it)
-				ExtractDataObjectFromChannel( *it, vindex[it->mOffset], pMesh);
-
-			// store the vertex-data index for later assignment of bone vertex weights
-			pMesh->mFacePosIndices.push_back( vindex[perVertexOffset]);
-		}
 	}
 
-
 	// if I ever get my hands on that guy who invented this steaming pile of indirection...
 	TestClosing( "p");
+	return numPrimitives;
+}
+
+void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices){
+	// calculate the base offset of the vertex whose attributes we ant to copy
+	size_t baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets;
+
+	// don't overrun the boundaries of the index list
+	size_t maxIndexRequested = baseOffset + numOffsets - 1;
+	ai_assert(maxIndexRequested < indices.size());
+
+	// extract per-vertex channels using the global per-vertex offset
+	for (std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
+		ExtractDataObjectFromChannel(*it, indices[baseOffset + perVertexOffset], pMesh);
+	// and extract per-index channels using there specified offset
+	for (std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it)
+		ExtractDataObjectFromChannel(*it, indices[baseOffset + it->mOffset], pMesh);
+
+	// store the vertex-data index for later assignment of bone vertex weights
+	pMesh->mFacePosIndices.push_back(indices[baseOffset + perVertexOffset]);
+}
+
+void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices){
+	if (currentPrimitive % 2 != 0){
+		//odd tristrip triangles need their indices mangled, to preserve winding direction
+		CopyVertex(1, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+		CopyVertex(0, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+		CopyVertex(2, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+	}
+	else {//for non tristrips or even tristrip triangles
+		CopyVertex(0, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+		CopyVertex(1, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+		CopyVertex(2, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+	}
 }
 
 // ------------------------------------------------------------------------------------------------

+ 10 - 1
code/ColladaParser.h

@@ -177,9 +177,18 @@ protected:
 	void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
 
 	/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
-	void ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels, 
+	size_t ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
 		size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType);
 
+	/** Copies the data for a single primitive into the mesh, based on the InputChannels */
+	void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
+		Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
+		size_t currentPrimitive, const std::vector<size_t>& indices);
+
+	/** Reads one triangle of a tristrip into the mesh */
+	void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh* pMesh,
+		std::vector<Collada::InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices);
+
 	/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
 	void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
 

+ 18 - 14
code/DefaultIOStream.h

@@ -56,55 +56,59 @@ namespace Assimp	{
 class DefaultIOStream : public IOStream
 {
 	friend class DefaultIOSystem;
-#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
-	friend class AndroidJNIIOSystem;
-#endif //__ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
+#if __ANDROID__ 
+#if __ANDROID_API__ > 9
+#if defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
+    friend class AndroidJNIIOSystem;
+#endif // defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
+#endif // __ANDROID_API__ > 9
+#endif // __ANDROID__ 
 
 protected:
-	DefaultIOStream ();
-	DefaultIOStream (FILE* pFile, const std::string &strFilename);
+	DefaultIOStream();
+	DefaultIOStream(FILE* pFile, const std::string &strFilename);
 
 public:
 	/** Destructor public to allow simple deletion to close the file. */
 	~DefaultIOStream ();
 
 	// -------------------------------------------------------------------
-	// Read from stream
+	/// Read from stream
     size_t Read(void* pvBuffer, 
 		size_t pSize, 
 		size_t pCount);
 
 
 	// -------------------------------------------------------------------
-	// Write to stream
+	/// Write to stream
     size_t Write(const void* pvBuffer, 
 		size_t pSize,
 		size_t pCount);
 
 	// -------------------------------------------------------------------
-	// Seek specific position
+	/// Seek specific position
 	aiReturn Seek(size_t pOffset,
 		aiOrigin pOrigin);
 
 	// -------------------------------------------------------------------
-	// Get current seek position
+	/// Get current seek position
     size_t Tell() const;
 
 	// -------------------------------------------------------------------
-	// Get size of file
+	/// Get size of file
 	size_t FileSize() const;
 
 	// -------------------------------------------------------------------
-	// Flush file contents
+	/// Flush file contents
 	void Flush();
 
 private:
-	//!	File datastructure, using clib
+	//	File datastructure, using clib
 	FILE* mFile;
-	//!	Filename
+	//	Filename
 	std::string	mFilename;
 
-	//! Cached file size
+	// Cached file size
 	mutable size_t cachedSize;
 };
 

+ 4 - 0
code/Exporter.cpp

@@ -78,6 +78,7 @@ void ExportSceneObj(const char*,IOSystem*, const aiScene*);
 void ExportSceneSTL(const char*,IOSystem*, const aiScene*);
 void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*);
 void ExportScenePly(const char*,IOSystem*, const aiScene*);
+void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*);
 void ExportScene3DS(const char*, IOSystem*, const aiScene*);
 void ExportSceneAssbin(const char*, IOSystem*, const aiScene*);
 void ExportSceneAssxml(const char*, IOSystem*, const aiScene*);
@@ -113,6 +114,9 @@ Exporter::ExportFormatEntry gExporters[] =
 	Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly, 
 		aiProcess_PreTransformVertices
 	),
+	Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
+		aiProcess_PreTransformVertices
+	),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER

+ 1 - 1
code/FBXParser.cpp

@@ -376,7 +376,7 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out)
 			return SafeParse<float>(data+1, t.end());
 		}
 		else {
-			return SafeParse<double>(data+1, t.end());
+			return static_cast<float>( SafeParse<double>(data+1, t.end()) );
 		}
 	}
 

+ 8 - 13
code/ObjFileMtlImporter.cpp

@@ -166,25 +166,27 @@ void ObjFileMtlImporter::load()
 			}
 			break;
 
-		case 'N':	// Shineness
+		case 'N':
+		case 'n':
 			{
 				++m_DataIt;
-				switch(*m_DataIt) 
+				switch(*m_DataIt)
 				{
-				case 's':
+				case 's':	// Specular exponent
 					++m_DataIt;
 					getFloatValue(m_pModel->m_pCurrentMaterial->shineness);
 					break;
-				case 'i': //Index Of refraction 
+				case 'i':	// Index Of refraction
 					++m_DataIt;
 					getFloatValue(m_pModel->m_pCurrentMaterial->ior);
 					break;
+				case 'e':	// New material
+					createMaterial();
+					break;
 				}
 				m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
-				break;
 			}
 			break;
-		
 
 		case 'm':	// Texture
 		case 'b':   // quick'n'dirty - for 'bump' sections
@@ -194,13 +196,6 @@ void ObjFileMtlImporter::load()
 			}
 			break;
 
-		case 'n':	// New material name
-			{
-				createMaterial();
-				m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
-			}
-			break;
-
 		case 'i':	// Illumination model
 			{
 				m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);

+ 103 - 6
code/PlyExporter.cpp

@@ -64,6 +64,20 @@ void ExportScenePly(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene
 	outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
 }
 
+void ExportScenePlyBinary(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+{
+	// invoke the exporter 
+	PlyExporter exporter(pFile, pScene, true);
+
+	// we're still here - export successfully completed. Write the file.
+	boost::scoped_ptr<IOStream> outfile(pIOSystem->Open(pFile, "wb"));
+	if (outfile == NULL) {
+		throw DeadlyExportError("could not open output .ply file: " + std::string(pFile));
+	}
+
+	outfile->Write(exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()), 1);
+}
+
 } // end of namespace Assimp
 
 #define PLY_EXPORT_HAS_NORMALS 0x1
@@ -72,7 +86,7 @@ void ExportScenePly(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene
 #define PLY_EXPORT_HAS_COLORS (PLY_EXPORT_HAS_TEXCOORDS << AI_MAX_NUMBER_OF_TEXTURECOORDS)
 
 // ------------------------------------------------------------------------------------------------
-PlyExporter :: PlyExporter(const char* _filename, const aiScene* pScene)
+PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool binary)
 : filename(_filename)
 , pScene(pScene)
 , endl("\n") 
@@ -102,7 +116,16 @@ PlyExporter :: PlyExporter(const char* _filename, const aiScene* pScene)
 	}
 
 	mOutput << "ply" << endl;
-	mOutput << "format ascii 1.0" << endl;
+	if (binary) {
+#if (defined AI_BUILD_BIG_ENDIAN)
+		mOutput << "format binary_big_endian 1.0" << endl;
+#else
+		mOutput << "format binary_little_endian 1.0" << endl;
+#endif
+	}
+	else {
+		mOutput << "format ascii 1.0" << endl;
+	}
 	mOutput << "comment Created by Open Asset Import Library - http://assimp.sf.net (v"
 		<< aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' 
 		<< aiGetVersionRevision() << ")" << endl;
@@ -163,17 +186,29 @@ PlyExporter :: PlyExporter(const char* _filename, const aiScene* pScene)
 	mOutput << "end_header" << endl;
 
 	for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
-		WriteMeshVerts(pScene->mMeshes[i],components);
+		if (binary) {
+			WriteMeshVertsBinary(pScene->mMeshes[i], components);
+		}
+		else {
+			WriteMeshVerts(pScene->mMeshes[i], components);
+		}
 	}
 	for (unsigned int i = 0, ofs = 0; i < pScene->mNumMeshes; ++i) {
-		WriteMeshIndices(pScene->mMeshes[i],ofs);
+		if (binary) {
+			WriteMeshIndicesBinary(pScene->mMeshes[i], ofs);
+		}
+		else {
+			WriteMeshIndices(pScene->mMeshes[i], ofs);
+		}
 		ofs += pScene->mMeshes[i]->mNumVertices;
 	}
 }
 
 // ------------------------------------------------------------------------------------------------
-void PlyExporter :: WriteMeshVerts(const aiMesh* m, unsigned int components)
+void PlyExporter::WriteMeshVerts(const aiMesh* m, unsigned int components)
 {
+	// If a component (for instance normal vectors) is present in at least one mesh in the scene,
+	// then default values are written for meshes that do not contain this component.
 	for (unsigned int i = 0; i < m->mNumVertices; ++i) {
 		mOutput << 
 			m->mVertices[i].x << " " << 
@@ -237,7 +272,57 @@ void PlyExporter :: WriteMeshVerts(const aiMesh* m, unsigned int components)
 }
 
 // ------------------------------------------------------------------------------------------------
-void PlyExporter :: WriteMeshIndices(const aiMesh* m, unsigned int offset)
+void PlyExporter::WriteMeshVertsBinary(const aiMesh* m, unsigned int components)
+{
+	// If a component (for instance normal vectors) is present in at least one mesh in the scene,
+	// then default values are written for meshes that do not contain this component.
+	aiVector3D defaultNormal(0, 0, 0);
+	aiVector2D defaultUV(-1, -1);
+	aiColor4D defaultColor(-1, -1, -1, -1);
+	for (unsigned int i = 0; i < m->mNumVertices; ++i) {
+		mOutput.write(reinterpret_cast<const char*>(&m->mVertices[i].x), 12);
+		if (components & PLY_EXPORT_HAS_NORMALS) {
+			if (m->HasNormals()) {
+				mOutput.write(reinterpret_cast<const char*>(&m->mNormals[i].x), 12);
+			}
+			else {
+				mOutput.write(reinterpret_cast<const char*>(&defaultNormal.x), 12);
+			}
+		}
+
+		for (unsigned int n = PLY_EXPORT_HAS_TEXCOORDS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_TEXTURECOORDS; n <<= 1, ++c) {
+			if (m->HasTextureCoords(c)) {
+				mOutput.write(reinterpret_cast<const char*>(&m->mTextureCoords[c][i].x), 6);
+			}
+			else {
+				mOutput.write(reinterpret_cast<const char*>(&defaultUV.x), 6);
+			}
+		}
+
+		for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) {
+			if (m->HasVertexColors(c)) {
+				mOutput.write(reinterpret_cast<const char*>(&m->mColors[c][i].r), 16);
+			}
+			else {
+				mOutput.write(reinterpret_cast<const char*>(&defaultColor.r), 16);
+			}
+		}
+
+		if (components & PLY_EXPORT_HAS_TANGENTS_BITANGENTS) {
+			if (m->HasTangentsAndBitangents()) {
+				mOutput.write(reinterpret_cast<const char*>(&m->mTangents[i].x), 12);
+				mOutput.write(reinterpret_cast<const char*>(&m->mBitangents[i].x), 12);
+			}
+			else {
+				mOutput.write(reinterpret_cast<const char*>(&defaultNormal.x), 12);
+				mOutput.write(reinterpret_cast<const char*>(&defaultNormal.x), 12);
+			}
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+void PlyExporter::WriteMeshIndices(const aiMesh* m, unsigned int offset)
 {
 	for (unsigned int i = 0; i < m->mNumFaces; ++i) {
 		const aiFace& f = m->mFaces[i];
@@ -248,4 +333,16 @@ void PlyExporter :: WriteMeshIndices(const aiMesh* m, unsigned int offset)
 	}
 }
 
+void PlyExporter::WriteMeshIndicesBinary(const aiMesh* m, unsigned int offset)
+{
+	for (unsigned int i = 0; i < m->mNumFaces; ++i) {
+		const aiFace& f = m->mFaces[i];
+		mOutput.write(reinterpret_cast<const char*>(&f.mNumIndices), 4);
+		for (unsigned int c = 0; c < f.mNumIndices; ++c) {
+			unsigned int index = f.mIndices[c] + offset;
+			mOutput.write(reinterpret_cast<const char*>(&index), 4);
+		}
+	}
+}
+
 #endif

+ 4 - 1
code/PlyExporter.h

@@ -59,7 +59,7 @@ class PlyExporter
 {
 public:
 	/// Constructor for a specific scene to export
-	PlyExporter(const char* filename, const aiScene* pScene);
+	PlyExporter(const char* filename, const aiScene* pScene, bool binary = false);
 
 public:
 
@@ -71,6 +71,9 @@ private:
 	void WriteMeshVerts(const aiMesh* m, unsigned int components);
 	void WriteMeshIndices(const aiMesh* m, unsigned int ofs);
 
+	void WriteMeshVertsBinary(const aiMesh* m, unsigned int components);
+	void WriteMeshIndicesBinary(const aiMesh* m, unsigned int offset);
+
 private:
 
 	const std::string filename;

+ 1 - 1
include/assimp/cimport.h

@@ -247,7 +247,7 @@ ASSIMP_API C_STRUCT aiLogStream aiGetPredefinedLogStream(
  *  Attaching a log stream can slightly reduce Assimp's overall import
  *  performance. Multiple log-streams can be attached. 
  *  @param stream Describes the new log stream.
- *  @note To ensure proepr destruction of the logging system, you need to manually
+ *  @note To ensure proper destruction of the logging system, you need to manually
  *    call aiDetachLogStream() on every single log stream you attach. 
  *    Alternatively (for the lazy folks) #aiDetachAllLogStreams is provided.
  */

+ 8 - 0
include/assimp/importerdesc.h

@@ -133,4 +133,12 @@ struct aiImporterDesc
 	const char* mFileExtensions;
 };
 
+/** \brief  Returns the Importer description for a given extension.
+
+Will return a NULL-pointer if no assigned importer desc. was found for the given extension
+    \param  extension   [in] The extension to look for
+    \return A pointer showing to the ImporterDesc, \see aiImporterDesc.
+*/
+ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension );
+
 #endif 

+ 1 - 0
port/AssimpPascal/Readme.md

@@ -0,0 +1 @@
+See the [AssimpPascal headers here](https://github.com/ev1313/Pascal-Assimp-Headers) (by Tim Blume / ev1313).

+ 2 - 2
port/PyAssimp/pyassimp/core.py

@@ -50,7 +50,7 @@ def make_tuple(ai_obj, type = None):
 
 # It is faster and more correct to have an init function for each assimp class
 def _init_face(aiFace):
-    aiFace.indices = [aiFace.mIndices[i] for i in xrange(aiFace.mNumIndices)]
+    aiFace.indices = [aiFace.mIndices[i] for i in range(aiFace.mNumIndices)]
     
 assimp_struct_inits =  { structs.Face : _init_face }
     
@@ -177,7 +177,7 @@ def _init(self, target = None, parent = None):
                                      "and quads. Try to load your mesh with"
                                      " a post-processing to triangulate your"
                                      " faces.")
-                    sys.exit(1)
+                    raise e
 
 
             else: # starts with 'm' but not iterable

+ 22 - 17
port/PyAssimp/scripts/quicktest.py

@@ -9,40 +9,45 @@ data structures in detail. It just verifies whether basic
 loading and querying of 3d models using pyassimp works.
 """
 
+import os
+import sys
+
+# Make the development (ie. GIT repo) version of PyAssimp available for import.
+sys.path.insert(0, '..')
 
-import sys,os
 import sample
 from pyassimp import errors
 
-# paths to be walkd recursively
-basepaths = [os.path.join('..','..','..','test','models'), os.path.join('..','..','..','test','models-nonbsd')]
+# Paths to model files.
+basepaths = [os.path.join('..', '..', '..', 'test', 'models'),
+             os.path.join('..', '..', '..', 'test', 'models-nonbsd')]
+
+# Valid extensions for 3D model files.
+extensions = ['.3ds', '.x', '.lwo', '.obj', '.md5mesh', '.dxf', '.ply', '.stl',
+              '.dae', '.md5anim', '.lws', '.irrmesh', '.nff', '.off', '.blend']
 
-# file extensions to be considered
-extensions = ['.3ds','.x','.lwo','.obj','.md5mesh','.dxf','.ply','.stl','.dae','.md5anim','.lws','.irrmesh','.nff','.off','.blend']
 
 def run_tests():
-    ok,err = 0,0
+    ok, err = 0, 0
     for path in basepaths:
         print("Looking for models in %s..." % path)
         for root, dirs, files in os.walk(path):
             for afile in files:
-                base,ext = os.path.splitext(afile)
+                base, ext = os.path.splitext(afile)
                 if ext in extensions:
                     try:
-                        sample.main(os.path.join(root,afile))
+                        sample.main(os.path.join(root, afile))
                         ok += 1
                     except errors.AssimpError as error:
-                        # assimp error is fine, this is a controlled case
-                        print error
+                        # Assimp error is fine; this is a controlled case.
+                        print(error)
                         err += 1
                     except Exception:
-                        print("Error encountered while loading <%s>"%os.path.join(root,afile))
-    print('** Loaded %s models, got controlled errors for %s files' % (ok,err))
+                        print("Error encountered while loading <%s>"
+                              % os.path.join(root, afile))
+    print('** Loaded %s models, got controlled errors for %s files'
+          % (ok, err))
 
 
 if __name__ == '__main__':
-	run_tests()
-
-
-
-
+    run_tests()

+ 10 - 1
port/iOS/README.md

@@ -1,4 +1,4 @@
-# assimp for iOS-SDK 7.1 
+# assimp for iOS
 (deployment target 6.0+, 32/64bit)
 
 Builds assimp libraries for several iOS CPU architectures at once, and outputs a fat binary from the result.
@@ -28,3 +28,12 @@ Supported architectures/devices:
 - ARMv7
 - ARMv7-s
 - ARM64
+
+### Building with older iOS SDK versions
+The script should work out of the box for the iOS 8.x SDKs and probably newer releases as well.
+If you are using SDK version 7.x or older, you need to specify the exact SDK version inside **build.sh**, for example:
+```
+IOS_SDK_VERSION=7.1
+```
+### Optimization
+By default, no compiler optimizations are specified inside the build script. For an optimized build, add the corresponding flags to the CFLAGS definition inside **build.sh**.

+ 2 - 2
port/iOS/build.sh

@@ -6,7 +6,7 @@
 
 BUILD_DIR="./lib/iOS"
 
-IOS_SDK_VERSION=7.1
+IOS_SDK_VERSION=
 IOS_SDK_TARGET=6.0
 #(iPhoneOS iPhoneSimulator) -- determined from arch
 IOS_SDK_DEVICE=
@@ -50,7 +50,7 @@ build_arch()
 
     rm CMakeCache.txt
 
-    cmake  -G 'Unix Makefiles' -DCMAKE_TOOLCHAIN_FILE=./port/iOS/IPHONEOS_$(echo $1 | tr '[:lower:]' '[:upper:]')_TOOLCHAIN.cmake -DENABLE_BOOST_WORKAROUND=ON -DASSIMP_BUILD_STATIC_LIB=ON
+    cmake  -G 'Unix Makefiles' -DCMAKE_TOOLCHAIN_FILE=./port/iOS/IPHONEOS_$(echo $1 | tr '[:lower:]' '[:upper:]')_TOOLCHAIN.cmake -DENABLE_BOOST_WORKAROUND=ON -DBUILD_SHARED_LIBS=OFF
 
     echo "[!] Building $1 library"
 

+ 6 - 1
port/jassimp/README

@@ -15,7 +15,12 @@ application examples using this wrapper
 How To Build
 ------------
 
- I) native library
+ I) native library, for example by issuing this command in jassimp-native/src:
+
+    $ gcc jassimp.cpp -I/usr/lib/jvm/default/include/ \
+      -I/usr/lib/jvm/default/include/linux -lassimp -shared -fPIC -o libjassimp.so
+
+    libjassimp.so is required at runtime and must be located in java.library.path.
 
 II) Java binding
     The java library is built using ant. Executing "ant" in the port/jassimp

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

@@ -1379,6 +1379,7 @@ JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile
 	goto end;
 
 error:
+	{
 	jclass exception = env->FindClass("java/io/IOException");
 
 	if (NULL == exception)
@@ -1390,6 +1391,7 @@ error:
 	env->ThrowNew(exception, aiGetErrorString());
 
 	lprintf("problem detected\n");
+	}
 
 end:
 	/* 
@@ -1405,4 +1407,4 @@ end:
 	lprintf("return from native\n");
 
 	return jScene;
-}
+}

+ 0 - 2
port/jassimp/jassimp-native/src/jassimp.h

@@ -7,8 +7,6 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
-/* Inaccessible static: BUILTIN */
-/* Inaccessible static: s_wrapperProvider */
 /*
  * Class:     jassimp_Jassimp
  * Method:    getErrorString

+ 3 - 3
port/jassimp/jassimp/src/jassimp/JaiDebug.java

@@ -67,7 +67,7 @@ public final class JaiDebug {
             return;
         }
         
-        for (int i = 0; i < mesh.getNumVertives(); i++) {
+        for (int i = 0; i < mesh.getNumVertices(); i++) {
             System.out.println("[" +
                     mesh.getPositionX(i) + ", " + 
                     mesh.getPositionY(i) + ", " + 
@@ -119,7 +119,7 @@ public final class JaiDebug {
             return;
         }
         
-        for (int i = 0; i < mesh.getNumVertives(); i++) {
+        for (int i = 0; i < mesh.getNumVertices(); i++) {
             System.out.println("[" + 
                     mesh.getColorR(i, colorset) + ", " + 
                     mesh.getColorG(i, colorset) + ", " + 
@@ -142,7 +142,7 @@ public final class JaiDebug {
             return;
         }
         
-        for (int i = 0; i < mesh.getNumVertives(); i++) {
+        for (int i = 0; i < mesh.getNumVertices(); i++) {
             int numComponents = mesh.getNumUVComponents(coords);
             System.out.print("[" + mesh.getTexCoordU(i, coords));
             

+ 29 - 28
test/CMakeLists.txt

@@ -16,39 +16,40 @@ SOURCE_GROUP( unit FILES
 )
 
 SET( TEST_SRCS
-	unit/utFastAtof.cpp
-	unit/utFindDegenerates.cpp
-	unit/utFindInvalidData.cpp
-	unit/utFixInfacingNormals.cpp
-	unit/utGenNormals.cpp
-	unit/utImporter.cpp
-	unit/utImproveCacheLocality.cpp
-	unit/utJoinVertices.cpp
-	unit/utLimitBoneWeights.cpp
-	unit/utMaterialSystem.cpp
-	unit/utPretransformVertices.cpp
-	unit/utRemoveComments.cpp
-	unit/utRemoveComponent.cpp
-	unit/utRemoveRedundantMaterials.cpp
-	unit/utScenePreprocessor.cpp
-	unit/utSharedPPData.cpp
-	unit/utSortByPType.cpp
-	unit/utSplitLargeMeshes.cpp
-	unit/utTargetAnimation.cpp
-	unit/utTextureTransform.cpp
-	unit/utTriangulate.cpp
-	unit/utVertexTriangleAdjacency.cpp
-	unit/utNoBoostTest.cpp
+    unit/AssimpAPITest.cpp
+    unit/utFastAtof.cpp
+    unit/utFindDegenerates.cpp
+    unit/utFindInvalidData.cpp
+    unit/utFixInfacingNormals.cpp
+    unit/utGenNormals.cpp
+    unit/utImporter.cpp
+    unit/utImproveCacheLocality.cpp
+    unit/utJoinVertices.cpp
+    unit/utLimitBoneWeights.cpp
+    unit/utMaterialSystem.cpp
+    unit/utPretransformVertices.cpp
+    unit/utRemoveComments.cpp
+    unit/utRemoveComponent.cpp
+    unit/utRemoveRedundantMaterials.cpp
+    unit/utScenePreprocessor.cpp
+    unit/utSharedPPData.cpp
+    unit/utSortByPType.cpp
+    unit/utSplitLargeMeshes.cpp
+    unit/utTargetAnimation.cpp
+    unit/utTextureTransform.cpp
+    unit/utTriangulate.cpp
+    unit/utVertexTriangleAdjacency.cpp
+    unit/utNoBoostTest.cpp
 )
 
 SOURCE_GROUP( tests FILES  ${TEST_SRCS} )
 
 add_executable( unit
-	unit/CCompilerTest.c
-	unit/Main.cpp
-	unit/UnitTestPCH.cpp
-	unit/UnitTestPCH.h
-	${TEST_SRCS}
+    unit/CCompilerTest.c
+    unit/Main.cpp
+    unit/UnitTestPCH.cpp
+    unit/UnitTestPCH.h
+    ${TEST_SRCS}
 )
 
 SET_PROPERTY( TARGET assimp PROPERTY DEBUG_POSTFIX ${ASSIMP_DEBUG_POSTFIX} )

+ 167 - 0
test/models/Collada/cube_tristrips.dae

@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
+	<asset>
+		<contributor/>
+		<created>2014-12-01T18:05:27Z</created>
+		<modified>2014-12-01T18:05:27Z</modified>
+		<unit/>
+		<up_axis>Z_UP</up_axis>
+	</asset>
+	<library_visual_scenes>
+		<visual_scene id="defaultScene">
+			<node id="sceneRoot">
+				<node id="Collada visual scene group">
+					<rotate sid="rotate">1 0 0 90</rotate>
+					<node id="Camera">
+						<matrix sid="Camera_matrix">0.838671 0.205746 -0.504282 -427.749 0 0.925901 0.377766 333.855 0.544639 -0.316822 0.776526 655.017 0 0 0 1</matrix>
+						<instance_camera url="#PerspCamera"/>
+					</node>
+					<node id="Light">
+						<matrix sid="Light_matrix">1 0 0 -500 0 1 0 1000 0 0 1 400 0 0 0 1</matrix>
+						<instance_light url="#light"/>
+					</node>
+					<node id="Box">
+						<matrix sid="Box_matrix">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
+						<instance_geometry url="#BlueSG">
+							<bind_material>
+								<technique_common>
+									<instance_material symbol="BlueSG_material" target="#material"/>
+								</technique_common>
+							</bind_material>
+						</instance_geometry>
+					</node>
+					<node id="testCamera">
+						<matrix sid="testCamera_matrix">0.838671 0.205746 -0.504282 -427.749 0 0.925901 0.377766 333.855 0.544639 -0.316822 0.776526 655.017 0 0 0 1</matrix>
+						<instance_camera url="#testCameraShape"/>
+					</node>
+					<node id="pointLight1">
+						<matrix sid="pointLight1_matrix">1 0 0 3 0 1 0 4 0 0 1 10 0 0 0 1</matrix>
+						<instance_light url="#pointLightShape1"/>
+					</node>
+				</node>
+			</node>
+		</visual_scene>
+	</library_visual_scenes>
+	<library_cameras>
+		<camera id="PerspCamera">
+			<optics>
+				<technique_common>
+					<perspective>
+						<yfov>37.8493</yfov>
+						<aspect_ratio>1</aspect_ratio>
+						<znear>1</znear>
+						<zfar>1000</zfar>
+					</perspective>
+				</technique_common>
+			</optics>
+		</camera>
+		<camera id="testCameraShape">
+			<optics>
+				<technique_common>
+					<perspective>
+						<yfov>37.8501</yfov>
+						<aspect_ratio>1</aspect_ratio>
+						<znear>1</znear>
+						<zfar>1000</zfar>
+					</perspective>
+				</technique_common>
+			</optics>
+		</camera>
+	</library_cameras>
+	<library_lights>
+		<light id="light"/>
+		<light id="light">
+			<technique_common>
+				<point>
+					<color>1 1 1</color>
+					<constant_attenuation>1</constant_attenuation>
+					<linear_attenuation>0</linear_attenuation>
+					<quadratic_attenuation>0</quadratic_attenuation>
+				</point>
+			</technique_common>
+		</light>
+		<light id="pointLightShape1"/>
+		<light id="pointLightShape1">
+			<technique_common>
+				<point>
+					<color>1 1 1</color>
+					<constant_attenuation>1</constant_attenuation>
+					<linear_attenuation>0</linear_attenuation>
+					<quadratic_attenuation>0</quadratic_attenuation>
+				</point>
+			</technique_common>
+		</light>
+	</library_lights>
+	<library_geometries>
+		<geometry id="BlueSG">
+			<mesh>
+				<source id="BlueSG-positions">
+					<float_array id="BlueSG-positions-array" count="72">-50 50 50 -50 50 50 -50 50 50 50 50 50 50 50 50 50 50 50 -50 -50 50 -50 -50 50 -50 -50 50 50 -50 50 50 -50 50 50 -50 50 -50 50 -50 -50 50 -50 -50 50 -50 50 50 -50 50 50 -50 50 50 -50 -50 -50 -50 -50 -50 -50 -50 -50 -50 50 -50 -50 50 -50 -50 50 -50 -50</float_array>
+					<technique_common>
+						<accessor count="24" source="#BlueSG-positions-array" stride="3">
+							<param name="X" type="float"/>
+							<param name="Y" type="float"/>
+							<param name="Z" type="float"/>
+						</accessor>
+					</technique_common>
+				</source>
+				<source id="BlueSG-normals">
+					<float_array id="BlueSG-normals-array" count="72">0 0 1 0 1 0 -1 0 0 0 0 1 0 1 0 1 0 0 0 0 1 0 -1 0 -1 0 0 0 0 1 0 -1 0 1 0 0 0 1 0 -1 0 0 0 0 -1 0 1 0 1 0 0 0 0 -1 0 -1 0 -1 0 0 0 0 -1 0 -1 0 1 0 0 0 0 -1</float_array>
+					<technique_common>
+						<accessor count="24" source="#BlueSG-normals-array" stride="3">
+							<param name="X" type="float"/>
+							<param name="Y" type="float"/>
+							<param name="Z" type="float"/>
+						</accessor>
+					</technique_common>
+				</source>
+				<vertices id="BlueSG-vertices">
+					<input semantic="POSITION" source="#BlueSG-positions"/>
+				</vertices>
+				<tristrips count="6" material="BlueSG_material">
+					<input offset="0" semantic="VERTEX" source="#BlueSG-vertices" set="0"/>
+					<input offset="1" semantic="NORMAL" source="#BlueSG-normals" set="0"/>
+					<p>6 6 9 9 0 0 3 3</p>
+					<p>12 12 1 1 15 15 4 4</p>
+					<p>14 14 17 17 20 20 23 23</p>
+					<p>5 5 11 11 16 16 22 22</p>
+					<p>13 13 19 19 2 2 8 8</p>
+					<p>21 21 10 10 18 18 7 7</p>
+				</tristrips>
+			</mesh>
+		</geometry>
+	</library_geometries>
+	<library_materials>
+		<material id="material">
+			<instance_effect url="#material_effect"/>
+		</material>
+	</library_materials>
+	<library_effects>
+		<effect id="material_effect">
+			<profile_COMMON>
+				<technique sid="t0">
+					<phong>
+						<emission>
+							<color>0 0 0 1</color>
+						</emission>
+						<ambient>
+							<color>0 0 0 1</color>
+						</ambient>
+						<diffuse>
+							<color>0.137255 0.403922 0.870588 1</color>
+						</diffuse>
+						<specular>
+							<color>0.5 0.5 0.5 1</color>
+						</specular>
+						<shininess>
+							<float>16</float>
+						</shininess>
+					</phong>
+				</technique>
+			</profile_COMMON>
+		</effect>
+	</library_effects>
+	<scene>
+		<instance_visual_scene url="#defaultScene"/>
+	</scene>
+</COLLADA>

+ 57 - 0
test/unit/AssimpAPITest.cpp

@@ -0,0 +1,57 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2014, 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 <assimp/importerdesc.h>
+
+using namespace Assimp;
+
+class AssimpAPITest : public ::testing::Test {
+
+};
+
+TEST_F( AssimpAPITest, aiGetImporterDescTest ) {
+    const aiImporterDesc *desc( NULL );
+    desc = aiGetImporterDesc( NULL );
+    EXPECT_EQ( NULL, desc );
+
+    desc = aiGetImporterDesc( "obj" );
+    EXPECT_TRUE( NULL != desc );
+}

+ 1 - 1
test/unit/utFastAtof.cpp

@@ -22,7 +22,7 @@ protected:
 	template <typename Real, typename AtofFunc>
 	static void RunTest(AtofFunc atof_func)
 	{
-		const Real kEps = 1e-5;
+		const Real kEps = 1e-5f;
 
 #define TEST_CASE(NUM) EXPECT_NEAR(static_cast<Real>(NUM), atof_func(#NUM), kEps)
 #define TEST_CASE_NAN(NUM) EXPECT_TRUE(IsNan(atof_func(#NUM)))

+ 1 - 0
test/unit/utNoBoostTest.cpp

@@ -40,6 +40,7 @@ TEST(NoBoostTest, Tuple) {
 	bool b = second.get<3>();
 	EXPECT_FALSE(b);
 
+    // check empty tuple, ignore compile warning
 	boost::tuple<> third;
 
 	// FIXME: Explicit conversion not really required yet

+ 2 - 0
test/unit/utRemoveComponent.cpp

@@ -68,6 +68,8 @@ void RemoveVCProcessTest::SetUp()
 	// so we don't need a virtual destructor
 	char check[sizeof(aiMaterial) == sizeof(aiMaterial) ? 10 : -1];
 	check[0] = 0;
+	// to remove compiler warning
+	EXPECT_TRUE( check );
 }
 
 // ------------------------------------------------------------------------------------------------