Browse Source

Merge pull request #261 from terziman/master

Improvement of collada exporter & bug fixes
Kim Kulling 11 years ago
parent
commit
562dd01655
80 changed files with 2298 additions and 749 deletions
  1. 2 0
      .gitignore
  2. 1 1
      CMakeLists.txt
  3. 22 6
      code/Assimp.cpp
  4. 16 16
      code/AssimpPCH.cpp
  5. 1 1
      code/AssimpPCH.h
  6. 39 1
      code/BaseImporter.cpp
  7. 9 0
      code/BaseImporter.h
  8. 145 0
      code/Bitmap.cpp
  9. 139 0
      code/Bitmap.h
  10. 1 1
      code/BlenderDNA.h
  11. 17 5
      code/CMakeLists.txt
  12. 263 55
      code/ColladaExporter.cpp
  13. 36 7
      code/ColladaExporter.h
  14. 4 4
      code/DefaultLogger.cpp
  15. 2 0
      code/Exporter.cpp
  16. 1 1
      code/FBXConverter.cpp
  17. 1 1
      code/FBXParser.cpp
  18. 2 2
      code/IFCBoolean.cpp
  19. 1 1
      code/IFCCurve.cpp
  20. 3 17
      code/IFCLoader.cpp
  21. 2 2
      code/IFCOpenings.cpp
  22. 1 1
      code/IFCUtil.cpp
  23. 1 1
      code/IFCUtil.h
  24. 26 7
      code/Importer.cpp
  25. 8 3
      code/Importer.h
  26. 1 1
      code/LWOLoader.cpp
  27. 238 242
      code/LineSplitter.h
  28. 12 0
      code/MaterialSystem.cpp
  29. 5 5
      code/ParsingUtils.h
  30. 9 9
      code/PostStepRegistry.cpp
  31. 12 2
      code/PretransformVertices.cpp
  32. 4 2
      code/PretransformVertices.h
  33. 2 2
      code/Q3BSPFileImporter.cpp
  34. 213 97
      code/Q3BSPZipArchive.cpp
  35. 89 108
      code/Q3BSPZipArchive.h
  36. 1 0
      code/RemoveRedundantMaterials.cpp
  37. 13 13
      code/STEPFile.h
  38. 4 18
      code/STEPFileReader.cpp
  39. 0 4
      code/STEPFileReader.h
  40. 57 0
      code/SceneCombiner.cpp
  41. 14 0
      code/SceneCombiner.h
  42. 1 1
      code/ScenePreprocessor.cpp
  43. 1 1
      code/SmoothingGroups.h
  44. 1 1
      code/SpatialSort.cpp
  45. 3 3
      code/Subdivision.cpp
  46. 1 1
      code/ValidateDataStructure.cpp
  47. 24 21
      code/fast_atof.h
  48. 11 1
      code/irrXMLWrapper.h
  49. 1 1
      contrib/irrXML/CXMLReaderImpl.h
  50. 513 0
      contrib/zlib/zconf.h.included
  51. 4 1
      include/assimp/IOStream.hpp
  52. 4 1
      include/assimp/IOSystem.hpp
  53. 17 1
      include/assimp/Importer.hpp
  54. 5 2
      include/assimp/LogStream.hpp
  55. 5 2
      include/assimp/Logger.hpp
  56. 5 2
      include/assimp/ProgressHandler.hpp
  57. 1 1
      include/assimp/ai_assert.h
  58. 18 0
      include/assimp/cimport.h
  59. 1 0
      include/assimp/color4.h
  60. 17 0
      include/assimp/color4.inl
  61. 19 0
      include/assimp/config.h
  62. 1 5
      include/assimp/defs.h
  63. 12 0
      include/assimp/material.h
  64. 6 0
      include/assimp/material.inl
  65. 4 2
      include/assimp/matrix3x3.h
  66. 18 2
      include/assimp/matrix3x3.inl
  67. 12 2
      include/assimp/matrix4x4.h
  68. 81 31
      include/assimp/matrix4x4.inl
  69. 1 1
      include/assimp/mesh.h
  70. 2 0
      include/assimp/metadata.h
  71. 2 0
      include/assimp/quaternion.h
  72. 11 1
      include/assimp/quaternion.inl
  73. 17 17
      include/assimp/scene.h
  74. 12 2
      include/assimp/types.h
  75. 4 2
      include/assimp/vector2.h
  76. 10 0
      include/assimp/vector2.inl
  77. 4 2
      include/assimp/vector3.h
  78. 10 0
      include/assimp/vector3.inl
  79. 1 1
      tools/assimp_cmd/Main.cpp
  80. 21 5
      tools/assimp_view/MessageProc.cpp

+ 2 - 0
.gitignore

@@ -1 +1,3 @@
 build
+.project
+*.kdev4*

+ 1 - 1
CMakeLists.txt

@@ -18,7 +18,7 @@ set(LIBASSIMP-DEV_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_M
 set(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-dev)
 set(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
 
-if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW )
+if((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT CMAKE_COMPILER_IS_MINGW)
   add_definitions(-fPIC) # this is a very important switch and some libraries seem now to have it....
   # hide all not-exported symbols
   add_definitions( -fvisibility=hidden -Wall )

+ 22 - 6
code/Assimp.cpp

@@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "Importer.h"
 
 // ------------------------------------------------------------------------------------------------
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 #	include <boost/thread/thread.hpp>
 #	include <boost/thread/mutex.hpp>
 #endif
@@ -87,7 +87,7 @@ namespace Assimp
 }
 
 
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 /** Global mutex to manage the access to the logstream map */
 static boost::mutex gLogStreamMutex;
 #endif
@@ -104,7 +104,7 @@ public:
 	}
 
 	~LogToCallbackRedirector()	{
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 		boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 		// (HACK) Check whether the 'stream.user' pointer points to a
@@ -172,6 +172,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl
 		pimpl->mIntProperties = pp->ints;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mStringProperties = pp->strings;
+		pimpl->mMatrixProperties = pp->matrices;
 	}
 	// setup a custom IO system if necessary
 	if (pFS)	{
@@ -230,6 +231,7 @@ const aiScene* aiImportFileFromMemoryWithProperties(
 		pimpl->mIntProperties = pp->ints;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mStringProperties = pp->strings;
+		pimpl->mMatrixProperties = pp->matrices;
 	}
 
 	// and have it read the file from the memory buffer
@@ -337,7 +339,7 @@ ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
 {
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 
@@ -356,7 +358,7 @@ ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
 {
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 	// find the logstream associated with this data
@@ -381,7 +383,7 @@ ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
 ASSIMP_API void aiDetachAllLogStreams(void)
 {
 	ASSIMP_BEGIN_EXCEPTION_REGION();
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 	for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
@@ -504,6 +506,20 @@ ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName
 	ASSIMP_END_EXCEPTION_REGION(void);
 }
 
+// ------------------------------------------------------------------------------------------------
+// Importer::SetPropertyMatrix
+ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName,
+	const C_STRUCT aiMatrix4x4* mat)
+{
+	if (!mat) {
+		return;
+	}
+	ASSIMP_BEGIN_EXCEPTION_REGION();
+	PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+	SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat,NULL);
+	ASSIMP_END_EXCEPTION_REGION(void);
+}
+
 // ------------------------------------------------------------------------------------------------
 // Rotation matrix to quaternion
 ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)

+ 16 - 16
code/AssimpPCH.cpp

@@ -69,27 +69,27 @@ ASSIMP_API unsigned int aiGetVersionRevision ()
 }
 
 // ------------------------------------------------------------------------------------------------
-aiScene::aiScene()
-	: mFlags()
-	, mRootNode()
-	, mNumMeshes()
-	, mMeshes()
-	, mNumMaterials()
-	, mMaterials()
-	, mNumAnimations()
-	, mAnimations()
-	, mNumTextures()
-	, mTextures()
-	, mNumLights()
-	, mLights()
-	, mNumCameras()
-	, mCameras()
+ASSIMP_API aiScene::aiScene()
+	: mFlags(0)
+	, mRootNode(NULL)
+	, mNumMeshes(0)
+	, mMeshes(NULL)
+	, mNumMaterials(0)
+	, mMaterials(NULL)
+	, mNumAnimations(0)
+	, mAnimations(NULL)
+	, mNumTextures(0)
+	, mTextures(NULL)
+	, mNumLights(0)
+	, mLights(NULL)
+	, mNumCameras(0)
+	, mCameras(NULL)
 	, mPrivate(new Assimp::ScenePrivateData())
 	{
 	}
 
 // ------------------------------------------------------------------------------------------------
-aiScene::~aiScene()
+ASSIMP_API aiScene::~aiScene()
 {
 	// delete all sub-objects recursively
 	delete mRootNode;

+ 1 - 1
code/AssimpPCH.h

@@ -74,7 +74,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 /* Helper macro to set a pointer to NULL in debug builds
  */
-#if (defined _DEBUG)
+#if (defined ASSIMP_BUILD_DEBUG)
 #	define AI_DEBUG_INVALIDATE_PTR(x) x = NULL;
 #else
 #	define AI_DEBUG_INVALIDATE_PTR(x)

+ 39 - 1
code/BaseImporter.cpp

@@ -379,6 +379,43 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
 	}
 }
 
+// ------------------------------------------------------------------------------------------------
+// Convert to UTF8 data to ISO-8859-1
+void BaseImporter::ConvertUTF8toISO8859_1(std::string& data)
+{
+	unsigned int size = data.size();
+	unsigned int i = 0, j = 0;
+
+	while(i < size) {
+		if((unsigned char) data[i] < 0x80) {
+			data[j] = data[i];
+		} else if(i < size - 1) {
+			if((unsigned char) data[i] == 0xC2) {
+				data[j] = data[++i];
+			} else if((unsigned char) data[i] == 0xC3) {
+				data[j] = ((unsigned char) data[++i] + 0x40);
+			} else {
+				std::stringstream stream;
+
+				stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
+
+				DefaultLogger::get()->error(stream.str());
+
+				data[j++] = data[i++];
+				data[j] = data[i];
+			}
+		} else {
+			DefaultLogger::get()->error("UTF8 code but only one character remaining");
+
+			data[j] = data[i];
+		}
+
+		i++; j++;
+	}
+
+	data.resize(j);
+}
+
 // ------------------------------------------------------------------------------------------------
 void BaseImporter::TextFileToBuffer(IOStream* stream,
 	std::vector<char>& data)
@@ -533,7 +570,7 @@ void BatchLoader::LoadAll()
 	for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it)	{
 		// force validation in debug builds
 		unsigned int pp = (*it).flags;
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		pp |= aiProcess_ValidateDataStructure;
 #endif
 		// setup config properties if necessary
@@ -541,6 +578,7 @@ void BatchLoader::LoadAll()
 		pimpl->mFloatProperties  = (*it).map.floats;
 		pimpl->mIntProperties    = (*it).map.ints;
 		pimpl->mStringProperties = (*it).map.strings;
+		pimpl->mMatrixProperties = (*it).map.matrices;
 
 		if (!DefaultLogger::isNullLogger())
 		{

+ 9 - 0
code/BaseImporter.h

@@ -331,6 +331,15 @@ public: // static utilities
 	static void ConvertToUTF8(
 		std::vector<char>& data);
 
+	// -------------------------------------------------------------------
+	/** An utility for all text file loaders. It converts a file from our
+	 *   UTF8 character set back to ISO-8859-1. Errors are reported, but ignored.
+	 *
+	 *  @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer
+	 *  is resized as appropriate. */
+	static void ConvertUTF8toISO8859_1(
+		std::string& data);
+
 	// -------------------------------------------------------------------
 	/** Utility for text file loaders which copies the contents of the
 	 *  file into a memory buffer and converts it to our UTF8

+ 145 - 0
code/Bitmap.cpp

@@ -0,0 +1,145 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2012, 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.
+---------------------------------------------------------------------------
+*/
+
+/** @file Bitmap.cpp
+ *  @brief Defines bitmap format helper for textures
+ *
+ * Used for file formats which embed their textures into the model file.
+ */
+
+#include "AssimpPCH.h"
+
+#include "Bitmap.h"
+
+namespace Assimp {
+
+	void Bitmap::Save(aiTexture* texture, IOStream* file) {
+		if(file != NULL) {
+			Header header;
+			DIB dib;
+
+			dib.size = DIB::dib_size;
+			dib.width = texture->mWidth;
+			dib.height = texture->mHeight;
+			dib.planes = 1;
+			dib.bits_per_pixel = 8 * mBytesPerPixel;
+			dib.compression = 0;
+			dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height;
+			dib.x_resolution = 0;
+			dib.y_resolution = 0;
+			dib.nb_colors = 0;
+			dib.nb_important_colors = 0;
+
+			header.type = 0x4D42; // 'BM'
+			header.offset = Header::header_size + DIB::dib_size;
+			header.size = header.offset + dib.image_size;
+			header.reserved1 = 0;
+			header.reserved2 = 0;
+
+			WriteHeader(header, file);
+			WriteDIB(dib, file);
+			WriteData(texture, file);
+		}
+	}
+
+	template<typename T>
+	inline std::size_t Copy(uint8_t* data, T& field) {
+		std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
+	}
+
+	void Bitmap::WriteHeader(Header& header, IOStream* file) {
+		uint8_t data[Header::header_size];
+
+		std::size_t offset = 0;
+
+		offset += Copy(&data[offset], header.type);
+		offset += Copy(&data[offset], header.size);
+		offset += Copy(&data[offset], header.reserved1);
+		offset += Copy(&data[offset], header.reserved2);
+		offset += Copy(&data[offset], header.offset);
+
+		file->Write(data, Header::header_size, 1);
+	}
+
+	void Bitmap::WriteDIB(DIB& dib, IOStream* file) {
+		uint8_t data[DIB::dib_size];
+
+		std::size_t offset = 0;
+
+		offset += Copy(&data[offset], dib.size);
+		offset += Copy(&data[offset], dib.width);
+		offset += Copy(&data[offset], dib.height);
+		offset += Copy(&data[offset], dib.planes);
+		offset += Copy(&data[offset], dib.bits_per_pixel);
+		offset += Copy(&data[offset], dib.compression);
+		offset += Copy(&data[offset], dib.image_size);
+		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);
+
+		file->Write(data, DIB::dib_size, 1);
+	}
+
+	void Bitmap::WriteData(aiTexture* texture, IOStream* file) {
+		static const std::size_t padding_offset = 4;
+		static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0};
+
+		unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset;
+		uint8_t pixel[mBytesPerPixel];
+
+		for(std::size_t i = 0; i < texture->mHeight; ++i) {
+			for(std::size_t j = 0; j < texture->mWidth; ++j) {
+				const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format
+
+				pixel[0] = texel.r;
+				pixel[1] = texel.g;
+				pixel[2] = texel.b;
+				pixel[3] = texel.a;
+
+				file->Write(pixel, mBytesPerPixel, 1);
+			}
+
+			file->Write(padding_data, padding, 1);
+		}
+	}
+
+}

+ 139 - 0
code/Bitmap.h

@@ -0,0 +1,139 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2012, 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.
+---------------------------------------------------------------------------
+*/
+
+/** @file Bitmap.h
+ *  @brief Defines bitmap format helper for textures
+ *
+ * Used for file formats which embed their textures into the model file.
+ */
+
+#ifndef AI_BITMAP_H_INC
+#define AI_BITMAP_H_INC
+
+namespace Assimp {
+
+class Bitmap {
+
+	protected:
+
+		struct Header {
+
+			uint16_t type;
+
+			uint32_t size;
+
+			uint16_t reserved1;
+
+			uint16_t reserved2;
+
+			uint32_t offset;
+
+			// We define the struct size because sizeof(Header) might return a wrong result because of structure padding.
+			// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
+			static const std::size_t header_size =
+				sizeof(uint16_t) + // type
+				sizeof(uint32_t) + // size
+				sizeof(uint16_t) + // reserved1
+				sizeof(uint16_t) + // reserved2
+				sizeof(uint32_t);  // offset
+
+		};
+
+		struct DIB {
+
+			uint32_t size;
+
+			int32_t width;
+
+			int32_t height;
+
+			uint16_t planes;
+
+			uint16_t bits_per_pixel;
+
+			uint32_t compression;
+
+			uint32_t image_size;
+
+			int32_t x_resolution;
+
+			int32_t y_resolution;
+
+			uint32_t nb_colors;
+
+			uint32_t nb_important_colors;
+
+			// We define the struct size because sizeof(DIB) might return a wrong result because of structure padding.
+			// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
+			static const std::size_t dib_size =
+				sizeof(uint32_t) + // size
+				sizeof(int32_t) +  // width
+				sizeof(int32_t) +  // height
+				sizeof(uint16_t) + // planes
+				sizeof(uint16_t) + // bits_per_pixel
+				sizeof(uint32_t) + // compression
+				sizeof(uint32_t) + // image_size
+				sizeof(int32_t) +  // x_resolution
+				sizeof(int32_t) +  // y_resolution
+				sizeof(uint32_t) + // nb_colors
+				sizeof(uint32_t);  // nb_important_colors
+
+		};
+
+		static const std::size_t mBytesPerPixel = 4;
+
+	public:
+
+		static void Save(aiTexture* texture, IOStream* file);
+
+	protected:
+
+		static void WriteHeader(Header& header, IOStream* file);
+
+		static void WriteDIB(DIB& dib, IOStream* file);
+
+		static void WriteData(aiTexture* texture, IOStream* file);
+
+};
+
+}
+
+#endif // AI_BITMAP_H_INC

+ 1 - 1
code/BlenderDNA.h

@@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "TinyFormatter.h"
 
 // enable verbose log output. really verbose, so be careful.
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 #	define ASSIMP_BUILD_BLENDER_DEBUG
 #endif
 

+ 17 - 5
code/CMakeLists.txt

@@ -76,13 +76,13 @@ SOURCE_GROUP(Boost FILES ${Boost_SRCS})
 
 SET( Logging_SRCS
 	${HEADER_PATH}/DefaultLogger.hpp
-	${HEADER_PATH}/IOStream.hpp
 	${HEADER_PATH}/LogStream.hpp
 	${HEADER_PATH}/Logger.hpp
 	${HEADER_PATH}/NullLogger.hpp
 	Win32DebugLogStream.h
 	DefaultLogger.cpp
 	FileLogStream.h
+	StdOStreamLogStream.h
 )
 SOURCE_GROUP(Logging FILES ${Logging_SRCS})
 
@@ -107,8 +107,8 @@ SET( Common_SRCS
 	Hash.h
 	Importer.cpp
 	IFF.h
+	MemoryIOWrapper.h
 	ParsingUtils.h
-	StdOStreamLogStream.h
 	StreamReader.h
 	StringComparison.h
 	SGSpatialSort.cpp
@@ -140,6 +140,8 @@ SET( Common_SRCS
 	TinyFormatter.h
 	Profiler.h
 	LogAux.h
+	Bitmap.cpp
+	Bitmap.h
 )
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 
@@ -461,8 +463,6 @@ SET( PostProcessing_SRCS
 	SortByPTypeProcess.h
 	SplitLargeMeshes.cpp
 	SplitLargeMeshes.h
-	TerragenLoader.cpp
-	TerragenLoader.h
 	TextureTransform.cpp
 	TextureTransform.h
 	TriangulateProcess.cpp
@@ -520,6 +520,12 @@ SET( STL_SRCS
 )
 SOURCE_GROUP( STL FILES ${STL_SRCS})
 
+SET( Terragen_SRCS
+	TerragenLoader.cpp
+	TerragenLoader.h
+)
+SOURCE_GROUP( Terragen FILES ${Terragen_SRCS})
+
 SET( Unreal_SRCS
 	UnrealLoader.cpp
 	UnrealLoader.h
@@ -655,6 +661,7 @@ SET( assimp_src
 	${Raw_SRCS}
 	${SMD_SRCS}
 	${STL_SRCS}
+	${Terragen_SRCS}
 	${Unreal_SRCS}
 	${XFile_SRCS}
 	${Extra_SRCS}
@@ -677,9 +684,14 @@ SET( assimp_src
 
 	${PUBLIC_HEADERS}
 	${COMPILER_HEADERS}
+	
+	# Old precompiled header
+	# (removed because the precompiled header is not updated when visual studio switch configuration which leads to failed compilation.
+	# Moreover it's a drag to recompile assimp entirely each time a modification is made to one of the included header, which is definitely counter-productive.)
+	AssimpPCH.cpp
 )
 
-ADD_MSVC_PRECOMPILED_HEADER("AssimpPCH.h" "AssimpPCH.cpp" assimp_src)
+#ADD_MSVC_PRECOMPILED_HEADER("AssimpPCH.h" "AssimpPCH.cpp" assimp_src)
 
 ADD_LIBRARY( assimp ${assimp_src} )
 

+ 263 - 55
code/ColladaExporter.cpp

@@ -44,6 +44,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
 #include "ColladaExporter.h"
 
+#include "Bitmap.h"
+#include "fast_atof.h"
+#include "SceneCombiner.h" 
+
+#include <ctime>
+#include <set>
+
 using namespace Assimp;
 
 namespace Assimp
@@ -53,8 +60,25 @@ namespace Assimp
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
 void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
 {
+	std::string path = "";
+	std::string file = pFile;
+
+	// We need to test both types of folder separators because pIOSystem->getOsSeparator() is not reliable.
+	// Moreover, the path given by some applications is not even consistent with the OS specific type of separator.
+	const char* end_path = std::max(strrchr(pFile, '\\'), strrchr(pFile, '/'));
+
+	if(end_path != NULL) {
+		path = std::string(pFile, end_path + 1 - pFile);
+		file = file.substr(end_path + 1 - pFile, file.npos);
+
+		std::size_t pos = file.find_last_of('.');
+		if(pos != file.npos) {
+			file = file.substr(0, pos);
+		}
+	}
+
 	// invoke the exporter 
-	ColladaExporter iDoTheExportThing( pScene);
+	ColladaExporter iDoTheExportThing( pScene, pIOSystem, path, file);
 
 	// we're still here - export successfully completed. Write result to the given IOSYstem
 	boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
@@ -71,12 +95,13 @@ void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pS
 
 // ------------------------------------------------------------------------------------------------
 // Constructor for a specific scene to export
-ColladaExporter::ColladaExporter( const aiScene* pScene)
+ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file)
 {
 	// make sure that all formatting happens using the standard, C locale and not the user's current locale
 	mOutput.imbue( std::locale("C") );
 
 	mScene = pScene;
+	mSceneOwned = false;
 
 	// set up strings
 	endstr = "\n"; 
@@ -85,6 +110,15 @@ ColladaExporter::ColladaExporter( const aiScene* pScene)
 	WriteFile();
 }
 
+// ------------------------------------------------------------------------------------------------
+// Destructor
+ColladaExporter::~ColladaExporter()
+{
+	if(mSceneOwned) {
+		delete mScene;
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // Starts writing the contents
 void ColladaExporter::WriteFile()
@@ -95,9 +129,10 @@ void ColladaExporter::WriteFile()
 	mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
 	PushTag();
 
+	WriteTextures();
 	WriteHeader();
 
-  WriteMaterials();
+	WriteMaterials();
 	WriteGeometryLibrary();
 
 	WriteSceneLibrary();
@@ -105,7 +140,7 @@ void ColladaExporter::WriteFile()
 	// useless Collada fu at the end, just in case we haven't had enough indirections, yet. 
 	mOutput << startstr << "<scene>" << endstr;
 	PushTag();
-	mOutput << startstr << "<instance_visual_scene url=\"#myScene\" />" << endstr;
+	mOutput << startstr << "<instance_visual_scene url=\"#" + std::string(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr;
 	PopTag();
 	mOutput << startstr << "</scene>" << endstr;
 	PopTag();
@@ -116,23 +151,131 @@ void ColladaExporter::WriteFile()
 // Writes the asset header
 void ColladaExporter::WriteHeader()
 {
-	// Dummy stuff. Nobody actually cares for it anyways
+	static const float epsilon = 0.000001f;
+	static const aiQuaternion x_rot(aiMatrix3x3( 
+		0, -1,  0,
+		1,  0,  0,
+		0,  0,  1));
+	static const aiQuaternion y_rot(aiMatrix3x3(
+		1,  0,  0,
+		0,  1,  0,
+		0,  0,  1));
+	static const aiQuaternion z_rot(aiMatrix3x3(
+		1,  0,  0,
+		0,  0,  1,
+		0, -1,  0));
+
+	static const unsigned int date_nb_chars = 20;
+	char date_str[date_nb_chars];
+	std::time_t date = std::time(NULL);
+	std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date));
+
+	std::string scene_name = mScene->mRootNode->mName.C_Str();
+
+	aiVector3D scaling;
+	aiQuaternion rotation;
+	aiVector3D position;
+	mScene->mRootNode->mTransformation.Decompose(scaling, rotation, position);
+
+	bool add_root_node = false;
+
+	float scale = 1.0;
+	if(std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) {
+		scale = (float) ((((double) scaling.x) + ((double) scaling.y) + ((double) scaling.z)) / 3.0);
+	} else {
+		add_root_node = true;
+	}
+
+	std::string up_axis = "Y_UP";
+	if(rotation.Equal(x_rot, epsilon)) {
+		up_axis = "X_UP";
+	} else if(rotation.Equal(y_rot, epsilon)) {
+		up_axis = "Y_UP";
+	} else if(rotation.Equal(z_rot, epsilon)) {
+		up_axis = "Z_UP";
+	} else {
+		add_root_node = true;
+	}
+
+	if(! position.Equal(aiVector3D(0, 0, 0))) {
+		add_root_node = true;
+	}
+
+	if(mScene->mRootNode->mNumChildren == 0) {
+		add_root_node = true;
+	}
+
+	if(add_root_node) {
+		aiScene* scene;
+		SceneCombiner::CopyScene(&scene, mScene);
+
+		aiNode* root = new aiNode("Scene");
+
+		root->mNumChildren = 1;
+		root->mChildren = new aiNode*[root->mNumChildren];
+
+		root->mChildren[0] = scene->mRootNode;
+		scene->mRootNode->mParent = root;
+		scene->mRootNode = root;
+
+		mScene = scene;
+		mSceneOwned = true;
+
+		up_axis = "Y_UP";
+		scale = 1.0;
+	}
+
 	mOutput << startstr << "<asset>" << endstr;
 	PushTag();
 	mOutput << startstr << "<contributor>" << endstr;
 	PushTag();
-	mOutput << startstr << "<author>Someone</author>" << endstr;
+	mOutput << startstr << "<author>Assimp</author>" << endstr;
 	mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr;
 	PopTag();
 	mOutput << startstr << "</contributor>" << endstr;
-  mOutput << startstr << "<created>2000-01-01T23:59:59</created>" << endstr;
-  mOutput << startstr << "<modified>2000-01-01T23:59:59</modified>" << endstr;
-	mOutput << startstr << "<unit name=\"centimeter\" meter=\"0.01\" />" << endstr;
-	mOutput << startstr << "<up_axis>Y_UP</up_axis>" << endstr;
+	mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
+	mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr;
+	mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr;
+	mOutput << startstr << "<up_axis>" << up_axis << "</up_axis>" << endstr;
 	PopTag();
 	mOutput << startstr << "</asset>" << endstr;
 }
 
+// ------------------------------------------------------------------------------------------------
+// Write the embedded textures
+void ColladaExporter::WriteTextures() {
+	static const unsigned int buffer_size = 1024;
+	char str[buffer_size];
+
+	if(mScene->HasTextures()) {
+		for(unsigned int i = 0; i < mScene->mNumTextures; i++) {
+			// It would be great to be able to create a directory in portable standard C++, but it's not the case,
+			// so we just write the textures in the current directory.
+
+			aiTexture* texture = mScene->mTextures[i];
+
+			ASSIMP_itoa10(str, buffer_size, i + 1);
+
+			std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint);
+
+			boost::scoped_ptr<IOStream> outfile(mIOSystem->Open(mPath + name, "wb"));
+			if(outfile == NULL) {
+				throw DeadlyExportError("could not open output texture file: " + mPath + name);
+			}
+
+			if(texture->mHeight == 0) {
+				outfile->Write((void*) texture->pcData, texture->mWidth, 1);
+			} else {
+				Bitmap::Save(texture, outfile.get());
+			}
+
+			outfile->Flush();
+
+			textures.insert(std::make_pair(i, name));
+		}
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // Reads a single surface entry from the given material keys
 void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex)
@@ -142,12 +285,39 @@ void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial*
     aiString texfile;
     unsigned int uvChannel = 0;
     pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel);
-    poSurface.texture = texfile.C_Str();
+
+    std::string index_str(texfile.C_Str());
+
+    if(index_str.size() != 0 && index_str[0] == '*')
+    {
+		unsigned int index;
+
+    	index_str = index_str.substr(1, std::string::npos);
+
+    	try {
+    		index = (unsigned int) strtoul10_64(index_str.c_str());
+    	} catch(std::exception& error) {
+    		throw DeadlyExportError(error.what());
+    	}
+
+    	std::map<unsigned int, std::string>::const_iterator name = textures.find(index);
+
+    	if(name != textures.end()) {
+    		poSurface.texture = name->second;
+    	} else {
+    		throw DeadlyExportError("could not find embedded texture at index " + index_str);
+    	}
+    } else
+    {
+		poSurface.texture = texfile.C_Str();
+    }
+
     poSurface.channel = uvChannel;
+	poSurface.exist = true;
   } else
   {
     if( pKey )
-      pSrcMat->Get( pKey, pType, pIndex, poSurface.color);
+      poSurface.exist = pSrcMat->Get( pKey, pType, pIndex, poSurface.color) == aiReturn_SUCCESS;
   }
 }
 
@@ -177,17 +347,19 @@ void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::strin
 // Writes a color-or-texture entry into an effect definition
 void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName)
 {
-  mOutput << startstr << "<" << pTypeName << ">" << endstr;
-  PushTag();
-  if( pSurface.texture.empty() )
-  {
-    mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
-  } else
-  {
-    mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
+  if(pSurface.exist) {
+    mOutput << startstr << "<" << pTypeName << ">" << endstr;
+    PushTag();
+    if( pSurface.texture.empty() )
+    {
+      mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
+    } else
+    {
+      mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
+    }
+    PopTag();
+    mOutput << startstr << "</" << pTypeName << ">" << endstr;
   }
-  PopTag();
-  mOutput << startstr << "</" << pTypeName << ">" << endstr;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -219,12 +391,27 @@ void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std
   }
 }
 
+// ------------------------------------------------------------------------------------------------
+// Writes a scalar property
+void ColladaExporter::WriteFloatEntry( const Property& pProperty, const std::string& pTypeName)
+{
+	if(pProperty.exist) {
+		mOutput << startstr << "<" << pTypeName << ">" << endstr;
+		PushTag();
+		mOutput << startstr << "<float sid=\"" << pTypeName << "\">" << pProperty.value << "</float>" << endstr;
+		PopTag();
+		mOutput << startstr << "</" << pTypeName << ">" << endstr;
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // Writes the material setup
 void ColladaExporter::WriteMaterials()
 {
   materials.resize( mScene->mNumMaterials);
 
+  std::set<std::string> material_names;
+
   /// collect all materials from the scene
   size_t numTextures = 0;
   for( size_t a = 0; a < mScene->mNumMaterials; ++a )
@@ -233,16 +420,30 @@ void ColladaExporter::WriteMaterials()
 
     aiString name;
     if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS )
-      name = "mat";
+      name = "mat";
     materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str();
     for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) {
 		// isalnum on MSVC asserts for code points in [0,255]. Thus prevent unwanted promotion
 		// of char to signed int and take the unsigned char value.
-      if( !isalnum( static_cast<uint8_t>(*it) ) ) {
+      if( !isalnum( static_cast<uint8_t>(*it) ) ) {
         *it = '_';
 	  }
 	}
 
+	aiShadingMode shading;
+	materials[a].shading_model = "phong";
+	if(mat->Get( AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) {
+		if(shading == aiShadingMode_Phong) {
+			materials[a].shading_model = "phong";
+		} else if(shading == aiShadingMode_Blinn) {
+			materials[a].shading_model = "blinn";
+		} else if(shading == aiShadingMode_NoShading) {
+			materials[a].shading_model = "constant";
+		} else if(shading == aiShadingMode_Gouraud) {
+			materials[a].shading_model = "lambert";
+		}
+	}
+
     ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
     if( !materials[a].ambient.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
@@ -253,10 +454,15 @@ void ColladaExporter::WriteMaterials()
     if( !materials[a].emissive.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE);
     if( !materials[a].reflective.texture.empty() ) numTextures++;
+	ReadMaterialSurface( materials[a].transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT);
+    if( !materials[a].transparent.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0);
     if( !materials[a].normal.texture.empty() ) numTextures++;
 
-    mat->Get( AI_MATKEY_SHININESS, materials[a].shininess);
+	materials[a].shininess.exist = mat->Get( AI_MATKEY_SHININESS, materials[a].shininess.value) == aiReturn_SUCCESS;
+	materials[a].transparency.exist = mat->Get( AI_MATKEY_OPACITY, materials[a].transparency.value) == aiReturn_SUCCESS;
+	materials[a].transparency.value = 1 - materials[a].transparency.value;
+	materials[a].index_refraction.exist = mat->Get( AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS;
   }
 
   // output textures if present
@@ -270,8 +476,9 @@ void ColladaExporter::WriteMaterials()
       WriteImageEntry( mat.ambient, mat.name + "-ambient-image");
       WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image");
       WriteImageEntry( mat.specular, mat.name + "-specular-image");
-      WriteImageEntry( mat.emissive, mat.name + "-emissive-image");
+      WriteImageEntry( mat.emissive, mat.name + "-emission-image");
       WriteImageEntry( mat.reflective, mat.name + "-reflective-image");
+	  WriteImageEntry( mat.transparent, mat.name + "-transparent-image");
       WriteImageEntry( mat.normal, mat.name + "-normal-image");
     }
     PopTag();
@@ -293,37 +500,35 @@ void ColladaExporter::WriteMaterials()
       PushTag();
 
       // write sampler- and surface params for the texture entries
-      WriteTextureParamEntry( mat.emissive, "emissive", mat.name);
+      WriteTextureParamEntry( mat.emissive, "emission", mat.name);
       WriteTextureParamEntry( mat.ambient, "ambient", mat.name);
       WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name);
       WriteTextureParamEntry( mat.specular, "specular", mat.name);
       WriteTextureParamEntry( mat.reflective, "reflective", mat.name);
+	  WriteTextureParamEntry( mat.transparent, "transparent", mat.name);
+	  WriteTextureParamEntry( mat.normal, "normal", mat.name);
 
       mOutput << startstr << "<technique sid=\"standard\">" << endstr;
       PushTag();
-      mOutput << startstr << "<phong>" << endstr;
+	  mOutput << startstr << "<" << mat.shading_model << ">" << endstr;
       PushTag();
 
-      WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emissive-sampler");
+      WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emission-sampler");
       WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "-ambient-sampler");
       WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler");
       WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-sampler");
-
-      mOutput << startstr << "<shininess>" << endstr;
-      PushTag();
-      mOutput << startstr << "<float sid=\"shininess\">" << mat.shininess << "</float>" << endstr;
-      PopTag();
-      mOutput << startstr << "</shininess>" << endstr;
-
+	  WriteFloatEntry(mat.shininess, "shininess");
       WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "-reflective-sampler");
+	  WriteTextureColorEntry( mat.transparent, "transparent", mat.name + "-transparent-sampler");
+	  WriteFloatEntry(mat.transparency, "transparency");
+	  WriteFloatEntry(mat.index_refraction, "index_of_refraction");
 
-  // deactivated because the Collada spec PHONG model does not allow other textures.
-  //    if( !mat.normal.texture.empty() )
-  //      WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler");
-
+	  if(! mat.normal.texture.empty()) {
+		WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler");
+	  }
 
       PopTag();
-      mOutput << startstr << "</phong>" << endstr;
+      mOutput << startstr << "</" << mat.shading_model << ">" << endstr;
       PopTag();
       mOutput << startstr << "</technique>" << endstr;
       PopTag();
@@ -546,13 +751,16 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
 // Writes the scene library
 void ColladaExporter::WriteSceneLibrary()
 {
+	std::string scene_name = mScene->mRootNode->mName.C_Str();
+
 	mOutput << startstr << "<library_visual_scenes>" << endstr;
 	PushTag();
-	mOutput << startstr << "<visual_scene id=\"myScene\" name=\"myScene\">" << endstr;
+	mOutput << startstr << "<visual_scene id=\"" + scene_name + "\" name=\"" + scene_name + "\">" << endstr;
 	PushTag();
 
 	// start recursive write at the root node
-	WriteNode( mScene->mRootNode);
+	for( size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a )
+		WriteNode( mScene->mRootNode->mChildren[a]);
 
 	PopTag();
 	mOutput << startstr << "</visual_scene>" << endstr;
@@ -581,22 +789,22 @@ void ColladaExporter::WriteNode( const 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
-    if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
-      continue;
+	// do not instanciate mesh if empty. I wonder how this could happen
+	if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
+		continue;
 
 		mOutput << startstr << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr;
 		PushTag();
-    mOutput << startstr << "<bind_material>" << endstr;
-    PushTag();
-    mOutput << startstr << "<technique_common>" << endstr;
-    PushTag();
-    mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr;
+	mOutput << startstr << "<bind_material>" << endstr;
+	PushTag();
+	mOutput << startstr << "<technique_common>" << endstr;
+	PushTag();
+	mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr;
 		PopTag();
-    mOutput << startstr << "</technique_common>" << endstr;
-    PopTag();
-    mOutput << startstr << "</bind_material>" << endstr;
-    PopTag();
+	mOutput << startstr << "</technique_common>" << endstr;
+	PopTag();
+	mOutput << startstr << "</bind_material>" << endstr;
+	PopTag();
 		mOutput << startstr << "</instance_geometry>" << endstr;
 	}
 

+ 36 - 7
code/ColladaExporter.h

@@ -59,7 +59,10 @@ class ColladaExporter
 {
 public:
 	/// Constructor for a specific scene to export
-	ColladaExporter( const aiScene* pScene);
+	ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file);
+
+	/// Destructor
+	virtual ~ColladaExporter();
 
 protected:
 	/// Starts writing the contents
@@ -68,8 +71,11 @@ protected:
 	/// Writes the asset header
 	void WriteHeader();
 
-  /// Writes the material setup
-  void WriteMaterials();
+	/// Writes the embedded textures
+	void WriteTextures();
+
+	/// Writes the material setup
+	void WriteMaterials();
 
 	/// Writes the geometry library
 	void WriteGeometryLibrary();
@@ -101,8 +107,18 @@ public:
 	std::stringstream mOutput;
 
 protected:
+	/// The IOSystem for output
+	IOSystem* mIOSystem;
+
+	/// Path of the directory where the scene will be exported
+	const std::string mPath;
+
+	/// Name of the file (without extension) where the scene will be exported
+	const std::string mFile;
+
 	/// The scene to be written
 	const aiScene* mScene;
+	bool mSceneOwned;
 
 	/// current line start string, contains the current indentation for simple stream insertion
 	std::string startstr;
@@ -112,24 +128,35 @@ protected:
   // pair of color and texture - texture precedences color
   struct Surface 
   { 
+    bool exist;
     aiColor4D color; 
     std::string texture; 
     size_t channel; 
-    Surface() { channel = 0; }
+    Surface() { exist = false; channel = 0; }
+  };
+
+  struct Property
+  {
+    bool exist;
+	float value;
+	Property() { exist = false; }
   };
 
   // summarize a material in an convinient way. 
   struct Material
   {
     std::string name;
-    Surface ambient, diffuse, specular, emissive, reflective, normal;
-    float shininess; /// specular exponent
+    std::string shading_model;
+    Surface ambient, diffuse, specular, emissive, reflective, transparent, normal;
+   	Property shininess, transparency, index_refraction;
 
-    Material() { shininess = 16.0f; }
+    Material() {}
   };
 
   std::vector<Material> materials;
 
+  std::map<unsigned int, std::string> textures;
+
 protected:
   /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
   /// Reads a single surface entry from the given material keys
@@ -140,6 +167,8 @@ protected:
   void WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName);
   /// Writes a color-or-texture entry into an effect definition
   void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName);
+  /// Writes a scalar property
+  void WriteFloatEntry( const Property& pProperty, const std::string& pTypeName);
 };
 
 }

+ 4 - 4
code/DefaultLogger.cpp

@@ -253,7 +253,7 @@ void DefaultLogger::OnDebug( const char* message )
 	if ( m_Severity == Logger::NORMAL )
 		return;
 
-	char msg[MAX_LOG_MESSAGE_LENGTH*2];
+	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
 	::sprintf(msg,"Debug, T%i: %s", GetThreadID(), message );
 
 	WriteToStreams( msg, Logger::Debugging );
@@ -263,7 +263,7 @@ void DefaultLogger::OnDebug( const char* message )
 //	Logs an info
 void DefaultLogger::OnInfo( const char* message )
 {
-	char msg[MAX_LOG_MESSAGE_LENGTH*2];
+	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
 	::sprintf(msg,"Info,  T%i: %s", GetThreadID(), message );
 
 	WriteToStreams( msg , Logger::Info );
@@ -273,7 +273,7 @@ void DefaultLogger::OnInfo( const char* message )
 //	Logs a warning
 void DefaultLogger::OnWarn( const char* message )
 {
-	char msg[MAX_LOG_MESSAGE_LENGTH*2];
+	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
 	::sprintf(msg,"Warn,  T%i: %s", GetThreadID(), message );
 
 	WriteToStreams( msg, Logger::Warn );
@@ -283,7 +283,7 @@ void DefaultLogger::OnWarn( const char* message )
 //	Logs an error
 void DefaultLogger::OnError( const char* message )
 {
-	char msg[MAX_LOG_MESSAGE_LENGTH*2];
+	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
 	::sprintf(msg,"Error, T%i: %s", GetThreadID(), message );
 
 	WriteToStreams( msg, Logger::Err );

+ 2 - 0
code/Exporter.cpp

@@ -176,6 +176,8 @@ Exporter :: Exporter()
 Exporter :: ~Exporter()
 {
 	FreeBlob();
+
+	delete pimpl;
 }
 
 

+ 1 - 1
code/FBXConverter.cpp

@@ -2014,7 +2014,7 @@ private:
 		ai_assert(curves.size());
 
 		// sanity check whether the input is ok
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		{ const Object* target = NULL;
 		BOOST_FOREACH(const AnimationCurveNode* node, curves) {
 			if(!target) {

+ 1 - 1
code/FBXParser.cpp

@@ -565,7 +565,7 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha
 		// terminate zlib
 		inflateEnd(&zstream);
 	}
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	else {
 		// runtime check for this happens at tokenization stage
 		ai_assert(false);

+ 2 - 2
code/IFCBoolean.cpp

@@ -221,7 +221,7 @@ bool IntersectsBoundaryProfile( const IfcVector3& e0, const IfcVector3& e1, cons
 		const IfcFloat s = (x*e.y - e.x*y)/det;
 		const IfcFloat t = (x*b.y - b.x*y)/det;
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		const IfcVector3 check = b0 + b*s  - (e0 + e*t);
 		ai_assert((IfcVector2(check.x,check.y)).SquareLength() < 1e-5);
 #endif
@@ -417,7 +417,7 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBounded
 			IfcVector3 isectpos;
 			const Intersect isect =  extra_point_flag ? Intersect_No : IntersectSegmentPlane(p,n,e0,e1,isectpos);
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 			if (isect == Intersect_Yes) {
 				const IfcFloat f = fabs((isectpos - p)*n);
 				ai_assert(f < 1e-5);

+ 1 - 1
code/IFCCurve.cpp

@@ -550,7 +550,7 @@ Curve* Curve :: Convert(const IFC::IfcCurve& curve,ConversionData& conv)
 	return NULL;
 }
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 // ------------------------------------------------------------------------------------------------
 bool Curve :: InRange(IfcFloat u) const 
 {

+ 3 - 17
code/IFCLoader.cpp

@@ -192,24 +192,17 @@ void IFCImporter::InternReadFile( const std::string& pFile,
 		}
 
 		// search file (same name as the IFCZIP except for the file extension) and place file pointer there
-		
 		if(UNZ_OK == unzGoToFirstFile(zip)) {
 			do {
-				//
-
 				// get file size, etc.
 				unz_file_info fileInfo;
 				char filename[256];
 				unzGetCurrentFileInfo( zip , &fileInfo, filename, sizeof(filename), 0, 0, 0, 0 );
-				
 				if (GetExtension(filename) != "ifc") {
 					continue;
 				}
-
 				uint8_t* buff = new uint8_t[fileInfo.uncompressed_size];
-
 				LogInfo("Decompressing IFCZIP file");
-
 				unzOpenCurrentFile( zip  );
 				const int ret = unzReadCurrentFile( zip, buff, fileInfo.uncompressed_size);
 				size_t filesize = fileInfo.uncompressed_size;
@@ -271,7 +264,6 @@ void IFCImporter::InternReadFile( const std::string& pFile,
 
 	// feed the IFC schema into the reader and pre-parse all lines
 	STEP::ReadFile(*db, schema, types_to_track, inverse_indices_to_track);
-
 	const STEP::LazyObject* proj =  db->GetObject("ifcproject");
 	if (!proj) {
 		ThrowException("missing IfcProject entity");
@@ -287,9 +279,9 @@ void IFCImporter::InternReadFile( const std::string& pFile,
 	// in a build with no entities disabled. See 
 	//     scripts/IFCImporter/CPPGenerator.py
 	// for more information.
-#ifdef ASSIMP_IFC_TEST
-	db->EvaluateAll();
-#endif
+	#ifdef ASSIMP_IFC_TEST
+		db->EvaluateAll();
+	#endif
 
 	// do final data copying
 	if (conv.meshes.size()) {
@@ -565,21 +557,16 @@ void ProcessProductRepresentation(const IfcProduct& el, aiNode* nd, std::vector<
 	if(!el.Representation) {
 		return;
 	}
-
-
 	std::vector<unsigned int> meshes;
-	
 	// we want only one representation type, so bring them in a suitable order (i.e try those
 	// that look as if we could read them quickly at first). This way of reading
 	// representation is relatively generic and allows the concrete implementations
 	// for the different representation types to make some sensible choices what
 	// to load and what not to load.
 	const STEP::ListOf< STEP::Lazy< IfcRepresentation >, 1, 0 >& src = el.Representation.Get()->Representations;
-
 	std::vector<const IfcRepresentation*> repr_ordered(src.size());
 	std::copy(src.begin(),src.end(),repr_ordered.begin());
 	std::sort(repr_ordered.begin(),repr_ordered.end(),RateRepresentationPredicate());
-
 	BOOST_FOREACH(const IfcRepresentation* repr, repr_ordered) {
 		bool res = false;
 		BOOST_FOREACH(const IfcRepresentationItem& item, repr->Items) {
@@ -595,7 +582,6 @@ void ProcessProductRepresentation(const IfcProduct& el, aiNode* nd, std::vector<
 			break;
 		}
 	}
-
 	AssignAddedMeshes(meshes,nd,conv);
 }
 

+ 2 - 2
code/IFCOpenings.cpp

@@ -1063,7 +1063,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
 	if(!ok) {
 		return IfcMatrix4();
 	}
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	const IfcFloat det = m.Determinant();
 	ai_assert(fabs(det-1) < 1e-5);
 #endif
@@ -1119,7 +1119,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
 	m = mult * m;
 
 	// debug code to verify correctness
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	std::vector<IfcVector2> out_contour2;
 	BOOST_FOREACH(const IfcVector3& x, in_verts) {
 		const IfcVector3& vv = m * x;

+ 1 - 1
code/IFCUtil.cpp

@@ -193,7 +193,7 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
 			temp[cnt++] = v.x;
 			temp[cnt++] = v.y;
 			temp[cnt++] = v.z;
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 			temp[cnt] = std::numeric_limits<IfcFloat>::quiet_NaN();
 #endif
 			++cnt;

+ 1 - 1
code/IFCUtil.h

@@ -365,7 +365,7 @@ public:
 	// and append the result to the mesh
 	virtual void SampleDiscrete(TempMesh& out,IfcFloat start,IfcFloat end) const;
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	// check if a particular parameter value lies within the well-defined range
 	bool InRange(IfcFloat) const;
 #endif 

+ 26 - 7
code/Importer.cpp

@@ -197,6 +197,7 @@ Importer::Importer(const Importer &other)
 	pimpl->mIntProperties    = other.pimpl->mIntProperties;
 	pimpl->mFloatProperties  = other.pimpl->mFloatProperties;
 	pimpl->mStringProperties = other.pimpl->mStringProperties;
+	pimpl->mMatrixProperties = other.pimpl->mMatrixProperties;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -232,7 +233,7 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
 
 	for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		if (IsExtensionSupported(*it)) {
 			DefaultLogger::get()->warn("The file extension " + *it + " is already in use");
 		}
@@ -558,7 +559,7 @@ void WriteLogOpening(const std::string& file)
 		<< "<unknown compiler>"
 #endif
 
-#ifndef NDEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		<< " debug"
 #endif
 
@@ -749,10 +750,10 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 		}
 	}
 #endif // no validation
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	if (pimpl->bExtraVerbose)
 	{
-#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
+#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
 		DefaultLogger::get()->error("Verbose Import is not available due to build settings");
 #endif  // no validation
 		pFlags |= aiProcess_ValidateDataStructure;
@@ -783,9 +784,9 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 		if( !pimpl->mScene) {
 			break; 
 		}
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 
-#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
+#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
 		continue;
 #endif  // no validation
 
@@ -937,6 +938,16 @@ void Importer::SetPropertyString(const char* szName, const std::string& value,
 	ASSIMP_END_EXCEPTION_REGION(void);
 }
 
+// ------------------------------------------------------------------------------------------------
+// Set a configuration property
+void Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value, 
+	bool* bWasExisting /*= NULL*/)
+{
+	ASSIMP_BEGIN_EXCEPTION_REGION();
+	SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value,bWasExisting);	
+	ASSIMP_END_EXCEPTION_REGION(void);
+}
+
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 int Importer::GetPropertyInteger(const char* szName, 
@@ -955,12 +966,20 @@ float Importer::GetPropertyFloat(const char* szName,
 
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
-const std::string& Importer::GetPropertyString(const char* szName, 
+const std::string Importer::GetPropertyString(const char* szName, 
 	const std::string& iErrorReturn /*= ""*/) const
 {
 	return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
 }
 
+// ------------------------------------------------------------------------------------------------
+// Get a configuration property
+const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, 
+	const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
+{
+	return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
+}
+
 // ------------------------------------------------------------------------------------------------
 // Get the memory requirements of a single node
 inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)

+ 8 - 3
code/Importer.h

@@ -63,11 +63,12 @@ public:
 	// Data type to store the key hash
 	typedef unsigned int KeyType;
 	
-	// typedefs for our three configuration maps.
+	// typedefs for our four configuration maps.
 	// We don't need more, so there is no need for a generic solution
 	typedef std::map<KeyType, int> IntPropertyMap;
 	typedef std::map<KeyType, float> FloatPropertyMap;
 	typedef std::map<KeyType, std::string> StringPropertyMap;
+	typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
 
 public:
 
@@ -100,6 +101,9 @@ public:
 	/** List of string properties */
 	StringPropertyMap mStringProperties;
 
+	/** List of Matrix properties */
+	MatrixPropertyMap mMatrixProperties;
+
 	/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
 	 *  to be executed before and after every single postprocess step */
 	bool bExtraVerbose;
@@ -135,14 +139,15 @@ public:
 		ImporterPimpl::IntPropertyMap     ints;
 		ImporterPimpl::FloatPropertyMap   floats;
 		ImporterPimpl::StringPropertyMap  strings;
+		ImporterPimpl::MatrixPropertyMap  matrices;
 
 		bool operator == (const PropertyMap& prop) const {
 			// fixme: really isocpp? gcc complains
-			return ints == prop.ints && floats == prop.floats && strings == prop.strings; 
+			return ints == prop.ints && floats == prop.floats && strings == prop.strings && matrices == prop.matrices; 
 		}
 
 		bool empty () const {
-			return ints.empty() && floats.empty() && strings.empty();
+			return ints.empty() && floats.empty() && strings.empty() && matrices.empty();
 		}
 	};
 	//! @endcond

+ 1 - 1
code/LWOLoader.cpp

@@ -294,7 +294,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 				unsigned int vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 				unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS];
 
-#if _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 				for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
 					vUVChannelIndices[mui] = UINT_MAX;
 				}

+ 238 - 242
code/LineSplitter.h

@@ -1,242 +1,238 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2012, 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.
-
-----------------------------------------------------------------------
-*/
-
-/** @file  LineSplitter.h
- *  @brief LineSplitter, a helper class to iterate through all lines
- *    of a file easily. Works with StreamReader.
- */
-#ifndef INCLUDED_LINE_SPLITTER_H
-#define INCLUDED_LINE_SPLITTER_H
-
-#include <stdexcept>
-
-#include "StreamReader.h"
-#include "ParsingUtils.h"
-
-namespace Assimp {
-
-// ------------------------------------------------------------------------------------------------
-/** Usage:
-@code
-for(LineSplitter splitter(stream);splitter;++splitter) {
-
-	if (*splitter == "hi!") {
-	   ...
-	}
-    else if (splitter->substr(0,5) == "hello") {
-	   ...
-	   // access the third token in the line (tokens are space-separated)
-	   if (strtol(splitter[2]) > 5) { .. }
-	}
-
-	std::cout << "Current line is: " << splitter.get_index() << std::endl;
-}
-@endcode */
-// ------------------------------------------------------------------------------------------------
-class LineSplitter
-{
-public:
-
-	typedef size_t line_idx;
-
-public:
-
-	// -----------------------------------------
-	/** construct from existing stream reader 
-	note: trim is *always* assumed true if skyp_empty_lines==true
-	*/
-	LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true)
-		: stream(stream)
-		, swallow()
-		, skip_empty_lines(skip_empty_lines)
-		, trim(trim)
-	{
-		cur.reserve(1024);
-		operator++();
-
-		idx = 0;
-	}
-
-public:
-
-	// -----------------------------------------
-	/** pseudo-iterator increment */
-	LineSplitter& operator++() {
-		if(swallow) {
-			swallow = false;
-			return *this;
-		}
-		
-		if (!*this) {
-			throw std::logic_error("End of file, no more lines to be retrieved.");
-		}
-
-		char s;
-
-		cur.clear();
-		while(stream.GetRemainingSize() && (s = stream.GetI1(),1)) {
-			if (s == '\n' || s == '\r') {
-				if (skip_empty_lines) {
-					while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\r' || s == '\n'));
-					if (stream.GetRemainingSize()) {
-						stream.IncPtr(-1);
-					}
-				}
-				else {
-					// skip both potential line terminators but don't read past this line.
-					if (stream.GetRemainingSize() && (s == '\r' && stream.GetI1() != '\n')) {
-						stream.IncPtr(-1);
-					}
-
-					if (trim) {
-						while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\t'));
-						if (stream.GetRemainingSize()) {
-							stream.IncPtr(-1);
-						}
-					}
-				}
-				
-				break;
-			}
-			cur += s;
-		}
-
-		++idx;
-		return *this;
-	}
-
-	// -----------------------------------------
-	LineSplitter& operator++(int) {
-		return ++(*this);
-	}
-
-	// -----------------------------------------
-	/** get a pointer to the beginning of a particular token */
-	const char* operator[] (size_t idx) const {
-		const char* s = operator->()->c_str();
-
-		SkipSpaces(&s);
-		for(size_t i = 0; i < idx; ++i) {
-
-			for(;!IsSpace(*s); ++s) {
-				if(IsLineEnd(*s)) {
-					throw std::range_error("Token index out of range, EOL reached");
-				}
-			}
-			SkipSpaces(&s);
-		}
-		return s;
-	}
-
-	// -----------------------------------------
-	/** extract the start positions of N tokens from the current line*/
-	template <size_t N>
-	void get_tokens(const char* (&tokens)[N]) const {
-		const char* s = operator->()->c_str();
-
-		SkipSpaces(&s);
-		for(size_t i = 0; i < N; ++i) {
-			if(IsLineEnd(*s)) {
-				throw std::range_error("Token count out of range, EOL reached");
-			}
-			tokens[i] = s;
-
-			for(;*s && !IsSpace(*s); ++s);
-			SkipSpaces(&s);
-		}
-	}
-
-	// -----------------------------------------
-	/** member access */
-	const std::string* operator -> () const {
-		return &cur;
-	}
-
-	std::string operator* () const {
-		return cur;
-	}
-
-	// -----------------------------------------
-	/** boolean context */
-	operator bool() const {
-		return stream.GetRemainingSize()>0;
-	}
-
-	// -----------------------------------------
-	/** line indices are zero-based, empty lines are included */
-	operator line_idx() const {
-		return idx;
-	}
-
-	line_idx get_index() const {
-		return idx;
-	}
-
-	// -----------------------------------------
-	/** access the underlying stream object */
-	StreamReaderLE& get_stream() {
-		return stream;
-	}
-
-	// -----------------------------------------
-	/** !strcmp((*this)->substr(0,strlen(check)),check) */
-	bool match_start(const char* check) {
-		const size_t len = strlen(check);
-		
-		return len <= cur.length() && std::equal(check,check+len,cur.begin());
-	}
-
-
-	// -----------------------------------------
-	/** swallow the next call to ++, return the previous value. */
-	void swallow_next_increment() {
-		swallow = true;
-	}
-
-private:
-
-	line_idx idx;
-	std::string cur;
-	StreamReaderLE& stream;
-	bool swallow, skip_empty_lines, trim;
-};
-
-}
-#endif // INCLUDED_LINE_SPLITTER_H
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, 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.
+
+----------------------------------------------------------------------
+*/
+
+/** @file  LineSplitter.h
+ *  @brief LineSplitter, a helper class to iterate through all lines
+ *    of a file easily. Works with StreamReader.
+ */
+#ifndef INCLUDED_LINE_SPLITTER_H
+#define INCLUDED_LINE_SPLITTER_H
+
+#include <stdexcept>
+
+#include "StreamReader.h"
+#include "ParsingUtils.h"
+
+namespace Assimp {
+
+// ------------------------------------------------------------------------------------------------
+/** Usage:
+@code
+for(LineSplitter splitter(stream);splitter;++splitter) {
+
+	if (*splitter == "hi!") {
+	   ...
+	}
+    else if (splitter->substr(0,5) == "hello") {
+	   ...
+	   // access the third token in the line (tokens are space-separated)
+	   if (strtol(splitter[2]) > 5) { .. }
+	}
+
+	std::cout << "Current line is: " << splitter.get_index() << std::endl;
+}
+@endcode */
+// ------------------------------------------------------------------------------------------------
+class LineSplitter
+{
+public:
+
+	typedef size_t line_idx;
+
+public:
+
+	// -----------------------------------------
+	/** construct from existing stream reader 
+	note: trim is *always* assumed true if skyp_empty_lines==true
+	*/
+	LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true)
+		: stream(stream)
+		, swallow()
+		, skip_empty_lines(skip_empty_lines)
+		, trim(trim)
+	{
+		cur.reserve(1024);
+		operator++();
+
+		idx = 0;
+	}
+
+public:
+
+	// -----------------------------------------
+	/** pseudo-iterator increment */
+	LineSplitter& operator++() {
+		if(swallow) {
+			swallow = false;
+			return *this;
+		}
+		if (!*this) {
+			throw std::logic_error("End of file, no more lines to be retrieved.");
+		}
+		char s;
+		cur.clear();
+		while(stream.GetRemainingSize() && (s = stream.GetI1(),1)) {
+			if (s == '\n' || s == '\r') {
+				if (skip_empty_lines) {
+					while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\r' || s == '\n'));
+					if (stream.GetRemainingSize()) {
+						stream.IncPtr(-1);
+					}
+				}
+				else {
+					// skip both potential line terminators but don't read past this line.
+					if (stream.GetRemainingSize() && (s == '\r' && stream.GetI1() != '\n')) {
+						stream.IncPtr(-1);
+					}
+					if (trim) {
+						while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\t'));
+						if (stream.GetRemainingSize()) {
+							stream.IncPtr(-1);
+						}
+					}
+				}
+				break;
+			}
+			cur += s;
+		}
+		++idx;
+		return *this;
+	}
+
+	// -----------------------------------------
+	LineSplitter& operator++(int) {
+		return ++(*this);
+	}
+
+	// -----------------------------------------
+	/** get a pointer to the beginning of a particular token */
+	const char* operator[] (size_t idx) const {
+		const char* s = operator->()->c_str();
+
+		SkipSpaces(&s);
+		for(size_t i = 0; i < idx; ++i) {
+
+			for(;!IsSpace(*s); ++s) {
+				if(IsLineEnd(*s)) {
+					throw std::range_error("Token index out of range, EOL reached");
+				}
+			}
+			SkipSpaces(&s);
+		}
+		return s;
+	}
+
+	// -----------------------------------------
+	/** extract the start positions of N tokens from the current line*/
+	template <size_t N>
+	void get_tokens(const char* (&tokens)[N]) const {
+		const char* s = operator->()->c_str();
+
+		SkipSpaces(&s);
+		for(size_t i = 0; i < N; ++i) {
+			if(IsLineEnd(*s)) {
+
+				throw std::range_error("Token count out of range, EOL reached");
+
+			}
+			tokens[i] = s;
+
+			for(;*s && !IsSpace(*s); ++s);
+			SkipSpaces(&s);
+		}
+	}
+
+	// -----------------------------------------
+	/** member access */
+	const std::string* operator -> () const {
+		return &cur;
+	}
+
+	std::string operator* () const {
+		return cur;
+	}
+
+	// -----------------------------------------
+	/** boolean context */
+	operator bool() const {
+		return stream.GetRemainingSize()>0;
+	}
+
+	// -----------------------------------------
+	/** line indices are zero-based, empty lines are included */
+	operator line_idx() const {
+		return idx;
+	}
+
+	line_idx get_index() const {
+		return idx;
+	}
+
+	// -----------------------------------------
+	/** access the underlying stream object */
+	StreamReaderLE& get_stream() {
+		return stream;
+	}
+
+	// -----------------------------------------
+	/** !strcmp((*this)->substr(0,strlen(check)),check) */
+	bool match_start(const char* check) {
+		const size_t len = strlen(check);
+		
+		return len <= cur.length() && std::equal(check,check+len,cur.begin());
+	}
+
+
+	// -----------------------------------------
+	/** swallow the next call to ++, return the previous value. */
+	void swallow_next_increment() {
+		swallow = true;
+	}
+
+private:
+
+	line_idx idx;
+	std::string cur;
+	StreamReaderLE& stream;
+	bool swallow, skip_empty_lines, trim;
+};
+
+}
+#endif // INCLUDED_LINE_SPLITTER_H

+ 12 - 0
code/MaterialSystem.cpp

@@ -247,6 +247,18 @@ aiReturn aiGetMaterialColor(const aiMaterial* pMat,
 	return eRet;
 }
 
+// ------------------------------------------------------------------------------------------------
+// Get a aiUVTransform (4 floats) from the material
+aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat, 
+	const char* pKey,
+	unsigned int type,
+	unsigned int index,
+	aiUVTransform* pOut)
+{
+	unsigned int iMax = 4;
+	return  aiGetMaterialFloatArray(pMat,pKey,type,index,(float*)pOut,&iMax);
+}
+
 // ------------------------------------------------------------------------------------------------
 // Get a string from the material
 aiReturn aiGetMaterialString(const aiMaterial* pMat, 

+ 5 - 5
code/ParsingUtils.h

@@ -115,7 +115,7 @@ AI_FORCE_INLINE bool SkipSpaces( const char_t** inout)
 }
 // ---------------------------------------------------------------------------------
 template <class char_t>
-inline bool SkipLine( const char_t* in, const char_t** out)
+AI_FORCE_INLINE bool SkipLine( const char_t* in, const char_t** out)
 {
 	while (*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0')in++;
 
@@ -126,13 +126,13 @@ inline bool SkipLine( const char_t* in, const char_t** out)
 }
 // ---------------------------------------------------------------------------------
 template <class char_t>
-inline bool SkipLine( const char_t** inout)
+AI_FORCE_INLINE bool SkipLine( const char_t** inout)
 {
 	return SkipLine<char_t>(*inout,inout);
 }
 // ---------------------------------------------------------------------------------
 template <class char_t>
-inline bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out)
+AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out)
 {
 	while (*in == (char_t)' ' || *in == (char_t)'\t' ||
 		*in == (char_t)'\r' || *in == (char_t)'\n')in++;
@@ -141,13 +141,13 @@ inline bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out)
 }
 // ---------------------------------------------------------------------------------
 template <class char_t>
-inline bool SkipSpacesAndLineEnd( const char_t** inout)
+AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t** inout)
 {
 	return SkipSpacesAndLineEnd<char_t>(*inout,inout);
 }
 // ---------------------------------------------------------------------------------
 template <class char_t>
-inline bool GetNextLine(const char_t*& buffer, char_t out[4096])
+AI_FORCE_INLINE bool GetNextLine(const char_t*& buffer, char_t out[4096])
 {
 	if ((char_t)'\0' == *buffer)return false;
 

+ 9 - 9
code/PostStepRegistry.cpp

@@ -133,6 +133,15 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 	// validated - as RegisterPPStep() does - all dependencies must be given.
 	// ----------------------------------------------------------------------------
 	out.reserve(25);
+#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
+	out.push_back( new MakeLeftHandedProcess());
+#endif
+#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS)
+	out.push_back( new FlipUVsProcess());
+#endif
+#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
+	out.push_back( new FlipWindingOrderProcess());
+#endif
 #if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS)
 	out.push_back( new RemoveVCProcess());
 #endif
@@ -207,15 +216,6 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 #if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
 	out.push_back( new SplitLargeMeshesProcess_Vertex());
 #endif
-#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
-	out.push_back( new MakeLeftHandedProcess());
-#endif
-#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS)
-	out.push_back( new FlipUVsProcess());
-#endif
-#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
-	out.push_back( new FlipWindingOrderProcess());
-#endif
 #if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS)
 	out.push_back( new DeboneProcess());
 #endif

+ 12 - 2
code/PretransformVertices.cpp

@@ -57,7 +57,7 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 PretransformVertices::PretransformVertices()
-:	configKeepHierarchy (false)
+:	configKeepHierarchy (false), configNormalize(false), configTransform(false), configTransformation()
 {
 }
 
@@ -79,9 +79,13 @@ bool PretransformVertices::IsActive( unsigned int pFlags) const
 // Setup import configuration
 void PretransformVertices::SetupProperties(const Importer* pImp)
 {
-	// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY and AI_CONFIG_PP_PTV_NORMALIZE
+	// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE,
+	// AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION
 	configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0));
 	configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0));
+	configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION,0));
+
+	configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4());
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -391,6 +395,8 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in
 				ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
 
 				out.push_back(ntz);
+
+				node->mMeshes[i] = numIn + out.size() - 1;
 			}
 		}
 	}
@@ -437,6 +443,10 @@ void PretransformVertices::Execute( aiScene* pScene)
 	const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
 	const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
 
+	if(configTransform) {
+		pScene->mRootNode->mTransformation = configTransformation;
+	}
+
 	// first compute absolute transformation matrices for all nodes
 	ComputeAbsoluteTransform(pScene->mRootNode);
 

+ 4 - 2
code/PretransformVertices.h

@@ -152,8 +152,10 @@ private:
 
 
 	//! Configuration option: keep scene hierarchy as long as possible
-	bool configKeepHierarchy, configNormalize;
-
+	bool configKeepHierarchy;
+	bool configNormalize;
+	bool configTransform;
+	aiMatrix4x4 configTransformation;
 };
 
 } // end of namespace Assimp

+ 2 - 2
code/Q3BSPFileImporter.cpp

@@ -185,9 +185,9 @@ const aiImporterDesc* Q3BSPFileImporter::GetInfo () const
 
 // ------------------------------------------------------------------------------------------------
 //	Import method.
-void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* pScene, IOSystem* /*pIOHandler*/)
+void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* pScene, IOSystem* pIOHandler)
 {
-	Q3BSPZipArchive Archive( rFile );
+	Q3BSPZipArchive Archive( pIOHandler, rFile );
 	if ( !Archive.isOpen() )
 	{
 		throw DeadlyImportError( "Failed to open file " + rFile + "." );

+ 213 - 97
code/Q3BSPZipArchive.cpp

@@ -46,23 +46,144 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <algorithm>
 #include <cassert>
 
-namespace Assimp
-{
-namespace Q3BSP
-{
+namespace Assimp {
+namespace Q3BSP {
+
+voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
+	IOSystem* io_system = (IOSystem*) opaque;
+
+	const char* mode_fopen = NULL;
+	if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) {
+		mode_fopen = "rb";
+	} else {
+		if(mode & ZLIB_FILEFUNC_MODE_EXISTING) {
+			mode_fopen = "r+b";
+		} else {
+			if(mode & ZLIB_FILEFUNC_MODE_CREATE) {
+				mode_fopen = "wb";
+			}
+		}
+	}
+
+	return (voidpf) io_system->Open(filename, mode_fopen);
+}
+
+uLong IOSystem2Unzip::read(voidpf opaque, voidpf stream, void* buf, uLong size) {
+	IOStream* io_stream = (IOStream*) stream;
+
+	return io_stream->Read(buf, 1, size);
+}
+
+uLong IOSystem2Unzip::write(voidpf opaque, voidpf stream, const void* buf, uLong size) {
+	IOStream* io_stream = (IOStream*) stream;
+
+	return io_stream->Write(buf, 1, size);
+}
+
+long IOSystem2Unzip::tell(voidpf opaque, voidpf stream) {
+	IOStream* io_stream = (IOStream*) stream;
+
+	return io_stream->Tell();
+}
+
+long IOSystem2Unzip::seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
+	IOStream* io_stream = (IOStream*) stream;
+
+	aiOrigin assimp_origin;
+	switch (origin) {
+		default:
+		case ZLIB_FILEFUNC_SEEK_CUR:
+			assimp_origin = aiOrigin_CUR;
+			break;
+		case ZLIB_FILEFUNC_SEEK_END:
+			assimp_origin = aiOrigin_END;
+			break;
+		case ZLIB_FILEFUNC_SEEK_SET:
+			assimp_origin = aiOrigin_SET;
+			break;
+	}
+
+	return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
+}
+
+int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
+	IOSystem* io_system = (IOSystem*) opaque;
+	IOStream* io_stream = (IOStream*) stream;
+
+	io_system->Close(io_stream);
+
+	return 0;
+}
+
+int IOSystem2Unzip::testerror(voidpf opaque, voidpf stream) {
+	return 0;
+}
+
+zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
+	zlib_filefunc_def mapping;
+
+	mapping.zopen_file = open;
+	mapping.zread_file = read;
+	mapping.zwrite_file = write;
+	mapping.ztell_file = tell;
+	mapping.zseek_file = seek;
+	mapping.zclose_file = close;
+	mapping.zerror_file = testerror;
+	mapping.opaque = (voidpf) pIOHandler;
+
+	return mapping;
+}
+
+// ------------------------------------------------------------------------------------------------
+ZipFile::ZipFile(size_t size) : m_Size(size) {
+	ai_assert(m_Size != 0);
+
+	m_Buffer = std::malloc(m_Size);
+}
+	
+ZipFile::~ZipFile() {
+	std::free(m_Buffer);
+	m_Buffer = NULL;
+}
+
+size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
+	const size_t size = pSize * pCount;
+	assert(size <= m_Size);
+			
+	std::memcpy(pvBuffer, m_Buffer, size);
+
+	return size;
+}
+
+size_t ZipFile::Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
+	return 0;
+}
+
+size_t ZipFile::FileSize() const {
+	return m_Size;
+}
+
+aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
+	return aiReturn_FAILURE;
+}
+
+size_t ZipFile::Tell() const {
+	return 0;
+}
+
+void ZipFile::Flush() {
+	// empty
+}
 
 // ------------------------------------------------------------------------------------------------
 //	Constructor.
-Q3BSPZipArchive::Q3BSPZipArchive( const std::string& rFile ) :
-	m_ZipFileHandle( NULL ),
-	m_FileList(),
-	m_bDirty( true )
-{
-	if ( !rFile.empty() )
-	{
-		m_ZipFileHandle = unzOpen( rFile.c_str() );
-		if ( NULL != m_ZipFileHandle )
-		{
+Q3BSPZipArchive::Q3BSPZipArchive(IOSystem* pIOHandler, const std::string& rFile) : m_ZipFileHandle(NULL), m_ArchiveMap() {
+	if (! rFile.empty()) {
+		zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
+
+		m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
+
+		if(m_ZipFileHandle != NULL) {
 			mapArchive();
 		}
 	}
@@ -70,127 +191,122 @@ Q3BSPZipArchive::Q3BSPZipArchive( const std::string& rFile ) :
 
 // ------------------------------------------------------------------------------------------------
 //	Destructor.
-Q3BSPZipArchive::~Q3BSPZipArchive()
-{
-	if ( NULL != m_ZipFileHandle )
-	{
-		unzClose( m_ZipFileHandle );
+Q3BSPZipArchive::~Q3BSPZipArchive() {
+	for( std::map<std::string, ZipFile*>::iterator it(m_ArchiveMap.begin()), end(m_ArchiveMap.end()); it != end; ++it ) {
+		delete it->second;
+	}
+	m_ArchiveMap.clear();
+
+	if(m_ZipFileHandle != NULL) {
+		unzClose(m_ZipFileHandle);
+		m_ZipFileHandle = NULL;
 	}
-	m_ZipFileHandle = NULL;
-	m_FileList.clear();
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Returns true, if the archive is already open.
-bool Q3BSPZipArchive::isOpen() const
-{
-	return ( NULL != m_ZipFileHandle );
+bool Q3BSPZipArchive::isOpen() const {
+	return (m_ZipFileHandle != NULL);
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Returns true, if the filename is part of the archive.
-bool Q3BSPZipArchive::Exists( const char* pFile ) const
-{
-	ai_assert( NULL != pFile );
-	if ( NULL == pFile )
-	{
-		return false;
-	}
+bool Q3BSPZipArchive::Exists(const char* pFile) const {
+	ai_assert(pFile != NULL);
+
+	bool exist = false;
+
+	if (pFile != NULL) {
+		std::string rFile(pFile);
+		std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile);
 
-	std::string rFile( pFile );
-	std::vector<std::string>::const_iterator it = std::find( m_FileList.begin(), m_FileList.end(), rFile );
-	if ( m_FileList.end() == it )
-	{
-		return false;
+		if(it != m_ArchiveMap.end()) {
+			exist = true;
+		}
 	}
 
-	return true;
+	return exist;
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Returns the separator delimiter.
-char Q3BSPZipArchive::getOsSeparator() const
-{
+char Q3BSPZipArchive::getOsSeparator() const {
+#ifndef _WIN32
 	return '/';
+#else
+	return '\\';
+#endif
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Opens a file, which is part of the archive.
-IOStream *Q3BSPZipArchive::Open( const char* pFile, const char* /*pMode*/ )
-{
-	ai_assert( NULL != pFile );
+IOStream *Q3BSPZipArchive::Open(const char* pFile, const char* /*pMode*/) {
+	ai_assert(pFile != NULL);
+
+	IOStream* result = NULL;
 
-	std::string rItem( pFile );
-	std::vector<std::string>::iterator it = std::find( m_FileList.begin(), m_FileList.end(), rItem );
-	if ( m_FileList.end() == it )
-		return NULL;
+	std::map<std::string, ZipFile*>::iterator it = m_ArchiveMap.find(pFile);
 
-	ZipFile *pZipFile = new ZipFile( *it, m_ZipFileHandle );
-	m_ArchiveMap[ rItem ] = pZipFile;
+	if(it != m_ArchiveMap.end()) {
+		result = (IOStream*) it->second;
+	}
 
-	return pZipFile;
+	return result;
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Close a filestream.
-void Q3BSPZipArchive::Close( IOStream *pFile )
-{
-	ai_assert( NULL != pFile );
-
-	std::map<std::string, IOStream*>::iterator it;
-	for ( it = m_ArchiveMap.begin(); it != m_ArchiveMap.end(); ++it )
-	{
-		if ( (*it).second == pFile )
-		{
-			ZipFile *pZipFile = reinterpret_cast<ZipFile*>( (*it).second ); 
-			delete pZipFile;
-			m_ArchiveMap.erase( it );
-			break;
-		}
-	}
+void Q3BSPZipArchive::Close(IOStream *pFile) {
+	ai_assert(pFile != NULL);
+
+	// We don't do anything in case the file would be opened again in the future
 }
 // ------------------------------------------------------------------------------------------------
 //	Returns the file-list of the archive.
-void Q3BSPZipArchive::getFileList( std::vector<std::string> &rFileList )
-{
-	rFileList = m_FileList;
+void Q3BSPZipArchive::getFileList(std::vector<std::string> &rFileList) {
+	rFileList.clear();
+
+	for(std::map<std::string, ZipFile*>::iterator it(m_ArchiveMap.begin()), end(m_ArchiveMap.end()); it != end; ++it) {
+		rFileList.push_back(it->first);
+	}
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Maps the archive content.
-bool Q3BSPZipArchive::mapArchive()
-{
-	if ( NULL == m_ZipFileHandle )
-		return false;
-
-	if ( !m_bDirty )
-		return true;
-
-	if ( !m_FileList.empty() )
-		m_FileList.resize( 0 );
-
-	//	At first ensure file is already open
-	if ( UNZ_OK == unzGoToFirstFile( m_ZipFileHandle ) ) 
-	{
-		char filename[ FileNameSize ];
-		unzGetCurrentFileInfo( m_ZipFileHandle, NULL, filename, FileNameSize, NULL, 0, NULL, 0 );
-		m_FileList.push_back( filename );
-		unzCloseCurrentFile( m_ZipFileHandle );
-			
-		// Loop over all files
-		while ( unzGoToNextFile( m_ZipFileHandle ) != UNZ_END_OF_LIST_OF_FILE )  
-		{
-			char filename[ FileNameSize ];
-			unzGetCurrentFileInfo( m_ZipFileHandle, NULL, filename, FileNameSize, NULL, 0, NULL, 0 );
-			m_FileList.push_back( filename );
-			unzCloseCurrentFile( m_ZipFileHandle );
+bool Q3BSPZipArchive::mapArchive() {
+	bool success = false;
+
+	if(m_ZipFileHandle != NULL) {
+		if(m_ArchiveMap.empty()) {
+			//	At first ensure file is already open
+			if(unzGoToFirstFile(m_ZipFileHandle) == UNZ_OK) {	
+				// Loop over all files  
+				do {
+					char filename[FileNameSize];
+					unz_file_info fileInfo;
+
+					if(unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, NULL, 0, NULL, 0) == UNZ_OK) {
+						// The file has EXACTLY the size of uncompressed_size. In C
+						// you need to mark the last character with '\0', so add
+						// another character
+						if(unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) {
+							std::pair<std::map<std::string, ZipFile*>::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size)));
+
+							if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) {
+								if(unzCloseCurrentFile(m_ZipFileHandle) == UNZ_OK) {
+									// Nothing to do anymore...
+								}
+							}
+						}
+					}
+				} while(unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
+			}
 		}
+
+		success = true;
 	}
-	
-	std::sort( m_FileList.begin(), m_FileList.end() );
-	m_bDirty = false;
 
-	return true;
+	return success;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 89 - 108
code/Q3BSPZipArchive.h

@@ -48,10 +48,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <map>
 #include <cassert>
 
-namespace Assimp
-{
-namespace Q3BSP
-{
+namespace Assimp {
+namespace Q3BSP {
+
+// ------------------------------------------------------------------------------------------------
+///	\class		IOSystem2Unzip
+///	\ingroup	Assimp::Q3BSP
+///
+///	\brief
+// ------------------------------------------------------------------------------------------------
+class IOSystem2Unzip {
+
+	public:
+
+		static voidpf open(voidpf opaque, const char* filename, int mode);
+
+		static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
+
+		static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
+
+		static long tell(voidpf opaque, voidpf stream);
+
+		static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
+
+		static int close(voidpf opaque, voidpf stream);
+
+		static int testerror(voidpf opaque, voidpf stream);
+
+		static zlib_filefunc_def get(IOSystem* pIOHandler);
+};
 
 // ------------------------------------------------------------------------------------------------
 ///	\class		ZipFile
@@ -59,88 +84,33 @@ namespace Q3BSP
 ///
 ///	\brief
 // ------------------------------------------------------------------------------------------------
-class ZipFile : public IOStream
-{
-public:
-	ZipFile( const std::string &rFileName, unzFile zipFile ) :
-		m_Name( rFileName ),
-		m_zipFile( zipFile )
-	{
-		ai_assert( NULL != m_zipFile );
-	}
+class ZipFile : public IOStream {
+
+	friend class Q3BSPZipArchive;
+
+	public:
+
+		ZipFile(size_t size);
 	
-	~ZipFile()
-	{
-		m_zipFile = NULL;
-	}
-
-	size_t Read(void* pvBuffer, size_t pSize, size_t pCount )
-	{
-		size_t bytes_read = 0;
-		if ( NULL == m_zipFile )
-			return bytes_read;
-		
-		// search file and place file pointer there
-		if ( unzLocateFile( m_zipFile, m_Name.c_str(), 0 ) == UNZ_OK )
-		{
-			// get file size, etc.
-			unz_file_info fileInfo;
-			unzGetCurrentFileInfo( m_zipFile, &fileInfo, 0, 0, 0, 0, 0, 0 );
-			const size_t size = pSize * pCount;
-			assert( size <= fileInfo.uncompressed_size );
-			
-			// The file has EXACTLY the size of uncompressed_size. In C
-			// you need to mark the last character with '\0', so add 
-			// another character
-			unzOpenCurrentFile( m_zipFile );
-			const int ret = unzReadCurrentFile( m_zipFile, pvBuffer, fileInfo.uncompressed_size);
-			size_t filesize = fileInfo.uncompressed_size;
-			if ( ret < 0 || size_t(ret) != filesize )
-			{
-				return 0;
-			}
-			bytes_read = ret;
-			unzCloseCurrentFile( m_zipFile );
-		}
-		return bytes_read;
-	}
-
-	size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/)
-	{
-		return 0;
-	}
-
-	size_t FileSize() const
-	{
-		if ( NULL == m_zipFile )
-			return 0;
-		if ( unzLocateFile( m_zipFile, m_Name.c_str(), 0 ) == UNZ_OK ) 
-		{
-			unz_file_info fileInfo;
-			unzGetCurrentFileInfo( m_zipFile, &fileInfo, 0, 0, 0, 0, 0, 0 );
-			return fileInfo.uncompressed_size;
-		}
-		return 0;
-	}
-
-	aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/)
-	{
-		return aiReturn_FAILURE;
-	}
-
-    size_t Tell() const
-	{
-		return 0;
-	}
-
-	void Flush()
-	{
-		// empty
-	}
-
-private:
-	std::string m_Name;
-	unzFile m_zipFile;
+		~ZipFile();
+
+		size_t Read(void* pvBuffer, size_t pSize, size_t pCount );
+
+		size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/);
+
+		size_t FileSize() const;
+
+		aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/);
+
+		size_t Tell() const;
+
+		void Flush();
+
+	private:
+
+		void* m_Buffer;
+
+		size_t m_Size;
 };
 
 // ------------------------------------------------------------------------------------------------
@@ -150,29 +120,40 @@ private:
 ///	\brief	IMplements a zip archive like the WinZip archives. Will be also used to import data 
 ///	from a P3K archive ( Quake level format ).
 // ------------------------------------------------------------------------------------------------
-class Q3BSPZipArchive : public Assimp::IOSystem
-{
-public:
-	static const unsigned int FileNameSize = 256;
-
-public:
-	Q3BSPZipArchive( const std::string & rFile );
-	~Q3BSPZipArchive();
-	bool Exists( const char* pFile) const;
-	char getOsSeparator() const;
-	IOStream* Open(const char* pFile, const char* pMode = "rb");
-	void Close( IOStream* pFile);
-	bool isOpen() const;
-	void getFileList( std::vector<std::string> &rFileList );
-
-private:
-	bool mapArchive();
-
-private:
-	unzFile m_ZipFileHandle;
-	std::map<std::string, IOStream*> m_ArchiveMap;
-	std::vector<std::string> m_FileList;
-	bool m_bDirty;
+class Q3BSPZipArchive : public Assimp::IOSystem {
+
+	public:
+
+		static const unsigned int FileNameSize = 256;
+
+	public:
+
+		Q3BSPZipArchive(IOSystem* pIOHandler, const std::string & rFile);
+
+		~Q3BSPZipArchive();
+
+		bool Exists(const char* pFile) const;
+
+		char getOsSeparator() const;
+
+		IOStream* Open(const char* pFile, const char* pMode = "rb");
+
+		void Close(IOStream* pFile);
+
+		bool isOpen() const;
+
+		void getFileList(std::vector<std::string> &rFileList);
+
+	private:
+
+		bool mapArchive();
+
+	private:
+
+		unzFile m_ZipFileHandle;
+
+		std::map<std::string, ZipFile*> m_ArchiveMap;
+
 };
 
 // ------------------------------------------------------------------------------------------------

+ 1 - 0
code/RemoveRedundantMaterials.cpp

@@ -142,6 +142,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 			// if the material is not referenced ... remove it
 			if (!abReferenced[i])	{
 				++unreferenced;
+				delete pScene->mMaterials[i];
 				continue;
 			}
 

+ 13 - 13
code/STEPFile.h

@@ -192,19 +192,19 @@ namespace STEP {
 			}
 
 			// utilities to deal with SELECT entities, which currently lack automatic
-			// conversion support.
-			template <typename T>
-			const T& ResolveSelect(const DB& db) const {
-				return Couple<T>(db).MustGetObject(To<EXPRESS::ENTITY>())->template To<T>();
-			}
-
-			template <typename T>
-			const T* ResolveSelectPtr(const DB& db) const {
-				const EXPRESS::ENTITY* e = ToPtr<EXPRESS::ENTITY>();
-				return e?Couple<T>(db).MustGetObject(*e)->template ToPtr<T>():(const T*)0;
-			}
-
-		public:
+			// conversion support.
+			template <typename T>
+			const T& ResolveSelect(const DB& db) const {
+				return Couple<T>(db).MustGetObject(To<EXPRESS::ENTITY>())->template To<T>();
+			}
+
+			template <typename T>
+			const T* ResolveSelectPtr(const DB& db) const {
+				const EXPRESS::ENTITY* e = ToPtr<EXPRESS::ENTITY>();
+				return e?Couple<T>(db).MustGetObject(*e)->template ToPtr<T>():(const T*)0;
+			}
+
+		public:
 
 			/** parse a variable from a string and set 'inout' to the character 
 			 *  behind the last consumed character. An optional schema enables,

+ 4 - 18
code/STEPFileReader.cpp

@@ -175,7 +175,7 @@ bool IsEntityDef(const std::string& snext)
 			if (*it == '=') {
 				return true;
 			}
-			if (*it < '0' || *it > '9') {
+			if ((*it < '0' || *it > '9') && *it != ' ') {
 				break;
 			}
 		}
@@ -197,16 +197,17 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 
 	const DB::ObjectMap& map = db.GetObjects();
 	LineSplitter& splitter = db.GetSplitter();
+	
 	while (splitter) {
 		bool has_next = false;
 		std::string s = *splitter;
 		if (s == "ENDSEC;") {
 			break;
 		}
+		s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
 
 		// want one-based line numbers for human readers, so +1
 		const uint64_t line = splitter.get_index()+1;
-
 		// LineSplitter already ignores empty lines
 		ai_assert(s.length());
 		if (s[0] != '#') {
@@ -214,12 +215,10 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 			++splitter;
 			continue;
 		}
-
 		// ---
 		// extract id, entity class name and argument string,
 		// but don't create the actual object yet. 
 		// ---
-
 		const std::string::size_type n0 = s.find_first_of('=');
 		if (n0 == std::string::npos) {
 			DefaultLogger::get()->warn(AddLineNumber("expected token \'=\'",line));
@@ -233,13 +232,10 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 			++splitter;
 			continue;
 		}
-
 		std::string::size_type n1 = s.find_first_of('(',n0);
 		if (n1 == std::string::npos) {
-
 			has_next = true;
 			bool ok = false;
-
 			for( ++splitter; splitter; ++splitter) {
 				const std::string& snext = *splitter;
 				if (snext.empty()) {
@@ -269,13 +265,11 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 			
 			has_next = true;
 			bool ok = false;
-
 			for( ++splitter; splitter; ++splitter) {
 				const std::string& snext = *splitter;
 				if (snext.empty()) {
 					continue;
 				}
-
 				// the next line doesn't start an entity, so maybe it is 
 				// just a continuation  for this line, keep going
 				if (!IsEntityDef(snext)) {
@@ -287,7 +281,6 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 					break;
 				}
 			}
-
 			if(!ok) {
 				DefaultLogger::get()->warn(AddLineNumber("expected token \')\'",line));
 				continue;
@@ -300,24 +293,18 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 
 		std::string::size_type ns = n0;
 		do ++ns; while( IsSpace(s.at(ns)));
-
 		std::string::size_type ne = n1;
 		do --ne; while( IsSpace(s.at(ne)));
-
 		std::string type = s.substr(ns,ne-ns+1);
 		std::transform( type.begin(), type.end(), type.begin(), &Assimp::ToLower<char>  );
-
 		const char* sz = scheme.GetStaticStringForToken(type);
 		if(sz) {
-		
 			const std::string::size_type len = n2-n1+1;
 			char* const copysz = new char[len+1];
 			std::copy(s.c_str()+n1,s.c_str()+n2+1,copysz);
 			copysz[len] = '\0';
-
 			db.InternInsert(new LazyObject(db,id,line,sz,copysz));
 		}
-
 		if(!has_next) {
 			++splitter;
 		}
@@ -327,7 +314,7 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 		DefaultLogger::get()->warn("STEP: ignoring unexpected EOF");
 	}
 
-	if ( !DefaultLogger::isNullLogger() ){
+	if ( !DefaultLogger::isNullLogger()){
 		DefaultLogger::get()->debug((Formatter::format(),"STEP: got ",map.size()," object records with ",
 			db.GetRefs().size()," inverse index entries"));
 	}
@@ -338,7 +325,6 @@ boost::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*&
 {
 	const char* cur = inout;
 	SkipSpaces(&cur);
-
 	if (*cur == ',' || IsSpaceOrNewLine(*cur)) {
 		throw STEP::SyntaxError("unexpected token, expected parameter",line);
 	}

+ 0 - 4
code/STEPFileReader.h

@@ -47,12 +47,10 @@ namespace Assimp {
 namespace STEP {
 
 	// ### Parsing a STEP file is a twofold procedure ###
-
 	// --------------------------------------------------------------------------
 	// 1) read file header and return to caller, who checks if the 
 	//    file is of a supported schema ..
 	DB* ReadFileHeader(boost::shared_ptr<IOStream> stream);
-
 	// --------------------------------------------------------------------------
 	// 2) read the actual file contents using a user-supplied set of
 	//    conversion functions to interpret the data.
@@ -60,8 +58,6 @@ namespace STEP {
 	template <size_t N, size_t N2> inline void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const (&arr)[N], const char* const (&arr2)[N2]) {
 		return ReadFile(db,scheme,arr,N,arr2,N2);
 	}
-	
-
 } // ! STEP
 } // ! Assimp
 

+ 57 - 0
code/SceneCombiner.cpp

@@ -880,6 +880,59 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/,
 		delete *it;
 }
 
+// ------------------------------------------------------------------------------------------------
+void SceneCombiner::MergeMaterials(aiMaterial** dest,
+		std::vector<aiMaterial*>::const_iterator begin,
+		std::vector<aiMaterial*>::const_iterator end)
+{
+	ai_assert(NULL != dest);
+
+	if (begin == end)	{
+		*dest = NULL; // no materials ...
+		return;
+	}
+
+	// Allocate the output material
+	aiMaterial* out = *dest = new aiMaterial();
+
+	// Get the maximal number of properties
+	unsigned int size = 0;
+	for (std::vector<aiMaterial*>::const_iterator it = begin; it != end; ++it) {
+		size += (*it)->mNumProperties;
+	}
+
+	out->Clear();
+	delete[] out->mProperties;
+
+	out->mNumAllocated = size;
+	out->mNumProperties = 0;
+	out->mProperties = new aiMaterialProperty*[out->mNumAllocated];
+
+	for (std::vector<aiMaterial*>::const_iterator it = begin; it != end; ++it) {
+		for(unsigned int i = 0; i < (*it)->mNumProperties; ++i) {
+			aiMaterialProperty* sprop = (*it)->mProperties[i];
+
+			// Test if we already have a matching property 
+			const aiMaterialProperty* prop_exist;
+			if(aiGetMaterialProperty(out, sprop->mKey.C_Str(), sprop->mType, sprop->mIndex, &prop_exist) != AI_SUCCESS) {
+				// If not, we add it to the new material
+				aiMaterialProperty* prop = out->mProperties[out->mNumProperties] = new aiMaterialProperty();
+
+				prop->mDataLength = sprop->mDataLength;
+				prop->mData = new char[prop->mDataLength];
+				::memcpy(prop->mData, sprop->mData, prop->mDataLength);
+
+				prop->mIndex    = sprop->mIndex;
+				prop->mSemantic = sprop->mSemantic;
+				prop->mKey      = sprop->mKey;
+				prop->mType		= sprop->mType;
+
+				out->mNumProperties++;
+			}
+		}
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 template <typename Type>
 inline void CopyPtrArray (Type**& dest, const Type* const * src, unsigned int num)
@@ -1012,6 +1065,10 @@ void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src)
 	ai_assert(NULL != _dest && NULL != src);
 
 	aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() );
+
+	dest->Clear();
+	delete[] dest->mProperties;
+
 	dest->mNumAllocated  =  src->mNumAllocated;
 	dest->mNumProperties =  src->mNumProperties;
 	dest->mProperties    =  new aiMaterialProperty* [dest->mNumAllocated];

+ 14 - 0
code/SceneCombiner.h

@@ -248,6 +248,20 @@ public:
 	static void MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
 		std::vector<aiMesh*>::const_iterator end);
 
+	// -------------------------------------------------------------------
+	/** Merges two or more materials
+	 *
+	 *  The materials should be complementary as much as possible. In case
+	 *  of a property present in different materials, the first occurence
+	 *  is used.
+	 *
+	 *  @param dest Destination material. Must be empty.
+	 *  @param begin First material to be processed
+	 *  @param end Points to the material after the last material to be processed
+	 */
+	static void MergeMaterials(aiMaterial** dest,
+		std::vector<aiMaterial*>::const_iterator begin,
+		std::vector<aiMaterial*>::const_iterator end);
 
 	// -------------------------------------------------------------------
 	/** Builds a list of uniquely named bones in a mesh list

+ 1 - 1
code/ScenePreprocessor.cpp

@@ -72,7 +72,7 @@ void ScenePreprocessor::ProcessScene ()
 		aiColor3D clr(0.6f,0.6f,0.6f);
 		helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
 
-		// setup the default name to make this material identifyable
+		// setup the default name to make this material identifiable
 		name.Set(AI_DEFAULT_MATERIAL_NAME);
 		helper->AddProperty(&name,AI_MATKEY_NAME);
 

+ 1 - 1
code/SmoothingGroups.h

@@ -52,7 +52,7 @@ struct FaceWithSmoothingGroup
 	{
 		// let the rest uninitialized for performance - in release builds.
 		// in debug builds set all indices to a common magic value
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		this->mIndices[0] = 0xffffffff;
 		this->mIndices[1] = 0xffffffff;
 		this->mIndices[2] = 0xffffffff;

+ 1 - 1
code/SpatialSort.cpp

@@ -329,7 +329,7 @@ unsigned int SpatialSort::GenerateMappingTable(std::vector<unsigned int>& fill,f
 		++t;
 	}
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 
 	// debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1
 	for (size_t i = 0; i < fill.size(); ++i) {

+ 3 - 3
code/Subdivision.cpp

@@ -383,7 +383,7 @@ void CatmullClarkSubdivider::InternSubdivide (
 	} 
 	
 	// check the other way round for consistency
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 
 	for (size_t t = 0; t < ofsadjvec.size()-1; ++t) {
 		for (unsigned int m = 0; m <  cntadjfac[t]; ++m) {
@@ -530,7 +530,7 @@ void CatmullClarkSubdivider::InternSubdivide (
 
 							ai_assert(adj[o]-moffsets[nidx].first < mp->mNumFaces);
 							const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first];
-#				ifdef _DEBUG
+#				ifdef ASSIMP_BUILD_DEBUG
 							bool haveit = false;
 #				endif
 
@@ -553,7 +553,7 @@ void CatmullClarkSubdivider::InternSubdivide (
 									// fixme: replace with mod face.mNumIndices? 
 									R += c0.midpoint+c1.midpoint;
 
-#						ifdef _DEBUG
+#						ifdef ASSIMP_BUILD_DEBUG
 									haveit = true;
 #						endif
 									break;

+ 1 - 1
code/ValidateDataStructure.cpp

@@ -86,7 +86,7 @@ AI_WONT_RETURN void ValidateDSProcess::ReportError(const char* msg,...)
 	ai_assert(iLen > 0);
 
 	va_end(args);
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	ai_assert( false );
 #endif
 	throw DeadlyImportError("Validation failed: " + std::string(szBuffer,iLen));

+ 24 - 21
code/fast_atof.h

@@ -21,23 +21,23 @@
 namespace Assimp
 {
 
-const float fast_atof_table[16] =	{  // we write [16] here instead of [] to work around a swig bug
-	0.f,
-	0.1f,
-	0.01f,
-	0.001f,
-	0.0001f,
-	0.00001f,
-	0.000001f,
-	0.0000001f,
-	0.00000001f,
-	0.000000001f,
-	0.0000000001f,
-	0.00000000001f,
-	0.000000000001f,
-	0.0000000000001f,
-	0.00000000000001f,
-	0.000000000000001f
+const double fast_atof_table[16] =	{  // we write [16] here instead of [] to work around a swig bug
+	0.0,
+	0.1,
+	0.01,
+	0.001,
+	0.0001,
+	0.00001,
+	0.000001,
+	0.0000001,
+	0.00000001,
+	0.000000001,
+	0.0000000001,
+	0.00000000001,
+	0.000000000001,
+	0.0000000000001,
+	0.00000000000001,
+	0.000000000000001
 };
 
 
@@ -179,6 +179,9 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
 	unsigned int cur = 0;
 	uint64_t value = 0;
 
+	if ( *in < '0' || *in > '9' )
+			throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value.");
+
 	bool running = true;
 	while ( running )
 	{
@@ -188,7 +191,7 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
 		const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
 		
 		if (new_value < value) /* numeric overflow, we rely on you */
-			return value;
+			throw std::overflow_error(std::string("Converting the string \"") + in + "\" into a value resulted in overflow.");
 
 		value = new_value;
 
@@ -224,7 +227,7 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
 // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
 // ------------------------------------------------------------------------------------
 template <typename Real>
-inline const char* fast_atoreal_move( const char* c, Real& out)
+inline const char* fast_atoreal_move( const char* c, Real& out, bool check_comma = true)
 {
 	Real f;
 
@@ -234,7 +237,7 @@ inline const char* fast_atoreal_move( const char* c, Real& out)
 	}
 
 	f = static_cast<Real>( strtoul10_64 ( c, &c) );
-	if (*c == '.' || (c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too
+	if (*c == '.' || (check_comma && c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too
 	{
 		++c;
 
@@ -270,7 +273,7 @@ inline const char* fast_atoreal_move( const char* c, Real& out)
 		if (einv) {
 			exp = -exp;
 		}
-		f *= pow(static_cast<Real>(10.0f), exp);
+		f *= pow(static_cast<Real>(10.0), exp);
 	}
 
 	if (inv) {

+ 11 - 1
code/irrXMLWrapper.h

@@ -81,12 +81,22 @@ public:
 		// Map the buffer into memory and convert it to UTF8. IrrXML provides its
 		// own conversion, which is merely a cast from uintNN_t to uint8_t. Thus,
 		// it is not suitable for our purposes and we have to do it BEFORE IrrXML
-		// gets the buffer. Sadly, this forces as to map the whole file into
+		// gets the buffer. Sadly, this forces us to map the whole file into
 		// memory.
 
 		data.resize(stream->FileSize());
 		stream->Read(&data[0],data.size(),1);
 
+		// Remove null characters from the input sequence otherwise the parsing will utterly fail
+		unsigned int size = 0;
+		unsigned int size_max = data.size();
+		for(unsigned int i = 0; i < size_max; i++) {
+			if(data[i] != '\0') {
+				data[size++] = data[i];
+			}
+		}
+		data.resize(size);
+
 		BaseImporter::ConvertToUTF8(data);
 	}
 

+ 1 - 1
contrib/irrXML/CXMLReaderImpl.h

@@ -215,7 +215,7 @@ private:
 	{
 		char_type* start = P;
 
-		// more forward until '<' found
+		// move forward until '<' found
 		while(*P != L'<' && *P)
 			++P;
 

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

@@ -0,0 +1,513 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#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,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
+#  define Z_PREFIX_SET
+
+/* all linked symbols */
+#  define _dist_code            z__dist_code
+#  define _length_code          z__length_code
+#  define _tr_align             z__tr_align
+#  define _tr_flush_bits        z__tr_flush_bits
+#  define _tr_flush_block       z__tr_flush_block
+#  define _tr_init              z__tr_init
+#  define _tr_stored_block      z__tr_stored_block
+#  define _tr_tally             z__tr_tally
+#  define adler32               z_adler32
+#  define adler32_combine       z_adler32_combine
+#  define adler32_combine64     z_adler32_combine64
+#  ifndef Z_SOLO
+#    define compress              z_compress
+#    define compress2             z_compress2
+#    define compressBound         z_compressBound
+#  endif
+#  define crc32                 z_crc32
+#  define crc32_combine         z_crc32_combine
+#  define crc32_combine64       z_crc32_combine64
+#  define deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateInit_          z_deflateInit_
+#  define deflateParams         z_deflateParams
+#  define deflatePending        z_deflatePending
+#  define deflatePrime          z_deflatePrime
+#  define deflateReset          z_deflateReset
+#  define deflateResetKeep      z_deflateResetKeep
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateSetHeader      z_deflateSetHeader
+#  define deflateTune           z_deflateTune
+#  define deflate_copyright     z_deflate_copyright
+#  define get_crc_table         z_get_crc_table
+#  ifndef Z_SOLO
+#    define gz_error              z_gz_error
+#    define gz_intmax             z_gz_intmax
+#    define gz_strwinerror        z_gz_strwinerror
+#    define gzbuffer              z_gzbuffer
+#    define gzclearerr            z_gzclearerr
+#    define gzclose               z_gzclose
+#    define gzclose_r             z_gzclose_r
+#    define gzclose_w             z_gzclose_w
+#    define gzdirect              z_gzdirect
+#    define gzdopen               z_gzdopen
+#    define gzeof                 z_gzeof
+#    define gzerror               z_gzerror
+#    define gzflush               z_gzflush
+#    define gzgetc                z_gzgetc
+#    define gzgetc_               z_gzgetc_
+#    define gzgets                z_gzgets
+#    define gzoffset              z_gzoffset
+#    define gzoffset64            z_gzoffset64
+#    define gzopen                z_gzopen
+#    define gzopen64              z_gzopen64
+#    ifdef _WIN32
+#      define gzopen_w              z_gzopen_w
+#    endif
+#    define gzprintf              z_gzprintf
+#    define gzvprintf             z_gzvprintf
+#    define gzputc                z_gzputc
+#    define gzputs                z_gzputs
+#    define gzread                z_gzread
+#    define gzrewind              z_gzrewind
+#    define gzseek                z_gzseek
+#    define gzseek64              z_gzseek64
+#    define gzsetparams           z_gzsetparams
+#    define gztell                z_gztell
+#    define gztell64              z_gztell64
+#    define gzungetc              z_gzungetc
+#    define gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetHeader      z_inflateGetHeader
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateInit_          z_inflateInit_
+#  define inflateMark           z_inflateMark
+#  define inflatePrime          z_inflatePrime
+#  define inflateReset          z_inflateReset
+#  define inflateReset2         z_inflateReset2
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateResetKeep      z_inflateResetKeep
+#  define inflate_copyright     z_inflate_copyright
+#  define inflate_fast          z_inflate_fast
+#  define inflate_table         z_inflate_table
+#  ifndef Z_SOLO
+#    define uncompress            z_uncompress
+#  endif
+#  define zError                z_zError
+#  ifndef Z_SOLO
+#    define zcalloc               z_zcalloc
+#    define zcfree                z_zcfree
+#  endif
+#  define zlibCompileFlags      z_zlibCompileFlags
+#  define zlibVersion           z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+#  define Byte                  z_Byte
+#  define Bytef                 z_Bytef
+#  define alloc_func            z_alloc_func
+#  define charf                 z_charf
+#  define free_func             z_free_func
+#  ifndef Z_SOLO
+#    define gzFile                z_gzFile
+#  endif
+#  define gz_header             z_gz_header
+#  define gz_headerp            z_gz_headerp
+#  define in_func               z_in_func
+#  define intf                  z_intf
+#  define out_func              z_out_func
+#  define uInt                  z_uInt
+#  define uIntf                 z_uIntf
+#  define uLong                 z_uLong
+#  define uLongf                z_uLongf
+#  define voidp                 z_voidp
+#  define voidpc                z_voidpc
+#  define voidpf                z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+#  define gz_header_s           z_gz_header_s
+#  define internal_state        z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+#  define z_const const
+#else
+#  define z_const
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#    define Z_ARG(args)  args
+#  else
+#    define Z_ARG(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+#  include <limits.h>
+#  if (UINT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned
+#  elif (ULONG_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned long
+#  elif (USHRT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned short
+#  endif
+#endif
+
+#ifdef Z_U4
+   typedef Z_U4 z_crc_t;
+#else
+   typedef unsigned long z_crc_t;
+#endif
+
+#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+#  ifndef Z_SOLO
+#    include <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* for wchar_t */
+#  endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+#  undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* for off_t */
+#    endif
+#    ifndef z_off_t
+#      define z_off_t off_t
+#    endif
+#  endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+#  define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+#  define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+#  define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+#  define z_off64_t off64_t
+#else
+#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+#    define z_off64_t __int64
+#  else
+#    define z_off64_t z_off_t
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+  #pragma map(deflateInit_,"DEIN")
+  #pragma map(deflateInit2_,"DEIN2")
+  #pragma map(deflateEnd,"DEEND")
+  #pragma map(deflateBound,"DEBND")
+  #pragma map(inflateInit_,"ININ")
+  #pragma map(inflateInit2_,"ININ2")
+  #pragma map(inflateEnd,"INEND")
+  #pragma map(inflateSync,"INSY")
+  #pragma map(inflateSetDictionary,"INSEDI")
+  #pragma map(compressBound,"CMBND")
+  #pragma map(inflate_table,"INTABL")
+  #pragma map(inflate_fast,"INFA")
+  #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */

+ 4 - 1
include/assimp/IOStream.hpp

@@ -61,7 +61,10 @@ namespace Assimp	{
  *  to the Importer. If you implement this interface, be sure to also provide an
  *  implementation for IOSystem that creates instances of your custom IO class.
 */
-class ASSIMP_API IOStream : public Intern::AllocateFromAssimpHeap
+class ASSIMP_API IOStream
+#ifndef SWIG
+	: public Intern::AllocateFromAssimpHeap
+#endif
 {
 protected:
 	/** Constructor protected, use IOSystem::Open() to create an instance. */

+ 4 - 1
include/assimp/IOSystem.hpp

@@ -64,7 +64,10 @@ class IOStream;
  *  supply a custom implementation for IOStream.
  *
  *  @see Importer::SetIOHandler() */
-class ASSIMP_API IOSystem : public Intern::AllocateFromAssimpHeap
+class ASSIMP_API IOSystem
+#ifndef SWIG
+	: public Intern::AllocateFromAssimpHeap
+#endif
 {
 public:
 

+ 17 - 1
include/assimp/Importer.hpp

@@ -230,6 +230,13 @@ public:
 	void SetPropertyString(const char* szName, const std::string& sValue, 
 		bool* bWasExisting = NULL);
 
+	// -------------------------------------------------------------------
+	/** Set a matrix configuration property.
+	 * @see SetPropertyInteger()
+	 */
+	void SetPropertyMatrix(const char* szName, const aiMatrix4x4& sValue, 
+		bool* bWasExisting = NULL);
+
 	// -------------------------------------------------------------------
 	/** Get a configuration property.
 	 * @param szName Name of the property. All supported properties
@@ -270,9 +277,18 @@ public:
 	 *  The return value remains valid until the property is modified.
 	 * @see GetPropertyInteger()
 	 */
-	const std::string& GetPropertyString(const char* szName,
+	const std::string GetPropertyString(const char* szName,
 		const std::string& sErrorReturn = "") const;
 
+	// -------------------------------------------------------------------
+	/** Get a matrix configuration property
+	 *
+	 *  The return value remains valid until the property is modified.
+	 * @see GetPropertyInteger()
+	 */
+	const aiMatrix4x4 GetPropertyMatrix(const char* szName,
+		const aiMatrix4x4& sErrorReturn = aiMatrix4x4()) const;
+
 	// -------------------------------------------------------------------
 	/** Supplies a custom IO handler to the importer to use to open and
 	 * access files. If you need the importer to use custion IO logic to 

+ 5 - 2
include/assimp/LogStream.hpp

@@ -53,8 +53,11 @@ class IOSystem;
  *  Several default implementations are provided, see #aiDefaultLogStream for more
  *  details. Writing your own implementation of LogStream is just necessary if these
  *  are not enough for your purpose. */
-class ASSIMP_API LogStream 
-	: public Intern::AllocateFromAssimpHeap	{
+class ASSIMP_API LogStream
+#ifndef SWIG
+	: public Intern::AllocateFromAssimpHeap
+#endif
+{
 protected:
 	/** @brief	Default constructor	*/
 	LogStream() {

+ 5 - 2
include/assimp/Logger.hpp

@@ -56,8 +56,11 @@ class LogStream;
  *  Assimp provides a default implementation and uses it for almost all 
  *  logging stuff ('DefaultLogger'). This class defines just basic logging
  *  behaviour and is not of interest for you. Instead, take a look at #DefaultLogger. */
-class ASSIMP_API Logger 
-	: public Intern::AllocateFromAssimpHeap	{
+class ASSIMP_API Logger
+#ifndef SWIG
+	: public Intern::AllocateFromAssimpHeap
+#endif
+{
 public:
 
 	// ----------------------------------------------------------------------

+ 5 - 2
include/assimp/ProgressHandler.hpp

@@ -51,8 +51,11 @@ namespace Assimp	{
  *
  *  Each #Importer instance maintains its own #ProgressHandler. The default 
  *  implementation provided by Assimp doesn't do anything at all. */
-class ASSIMP_API ProgressHandler 
-	: public Intern::AllocateFromAssimpHeap	{
+class ASSIMP_API ProgressHandler
+#ifndef SWIG
+	: public Intern::AllocateFromAssimpHeap
+#endif
+{
 protected:
 	/** @brief	Default constructor	*/
 	ProgressHandler () {

+ 1 - 1
include/assimp/ai_assert.h

@@ -3,7 +3,7 @@
 #ifndef AI_DEBUG_H_INC
 #define AI_DEBUG_H_INC
 
-#ifdef _DEBUG  
+#ifdef ASSIMP_BUILD_DEBUG  
 #	include <assert.h>
 #	define	ai_assert(expression) assert(expression)
 #else

+ 18 - 0
include/assimp/cimport.h

@@ -79,6 +79,7 @@ struct aiLogStream
  *  @see aiSetPropertyInteger
  *  @see aiSetPropertyFloat
  *  @see aiSetPropertyString
+ *  @see aiSetPropertyMatrix
  */
 // --------------------------------------------------------------------------------
 struct aiPropertyStore { char sentinel; };
@@ -397,6 +398,23 @@ ASSIMP_API void aiSetImportPropertyString(
 	const char* szName,
 	const C_STRUCT aiString* st);
 
+// --------------------------------------------------------------------------------
+/** Set a matrix property. 
+ *
+ *  This is the C-version of #Assimp::Importer::SetPropertyMatrix(). In the C 
+ *  interface, properties are always shared by all imports. It is not possible to 
+ *  specify them per import.
+ *
+ * @param property store to modify. Use #aiCreatePropertyStore to obtain a store.
+ * @param szName Name of the configuration property to be set. All supported 
+ *   public properties are defined in the config.h header file (#AI_CONFIG_XXX).
+ * @param value New value for the property
+ */
+ASSIMP_API void aiSetImportPropertyMatrix(
+	C_STRUCT aiPropertyStore* store,
+	const char* szName,
+	const C_STRUCT aiMatrix4x4* mat);
+
 // --------------------------------------------------------------------------------
 /** Construct a quaternion from a 3x3 rotation matrix.
  *  @param quat Receives the output quaternion.

+ 1 - 0
include/assimp/color4.h

@@ -74,6 +74,7 @@ public:
 	// comparison
 	bool operator == (const aiColor4t& other) const;
 	bool operator != (const aiColor4t& other) const;
+	bool operator <  (const aiColor4t& other) const;
 
 	// color tuple access, rgba order
 	inline TReal operator[](unsigned int i) const;

+ 17 - 0
include/assimp/color4.inl

@@ -94,6 +94,23 @@ AI_FORCE_INLINE bool aiColor4t<TReal>::operator!= (const aiColor4t<TReal>& other
 }
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
+AI_FORCE_INLINE bool aiColor4t<TReal>::operator< (const aiColor4t<TReal>& other) const {
+	return r < other.r || (
+		r == other.r && (
+			g < other.g || (
+				g == other.g && (
+					b < other.b || (
+						b == other.b && (
+							a < other.a
+						)
+					)
+				)
+			)
+		)
+	);
+}
+// ------------------------------------------------------------------------------------------------
+template <typename TReal>
 AI_FORCE_INLINE aiColor4t<TReal> operator + (const aiColor4t<TReal>& v1, const aiColor4t<TReal>& v2)	{
 	return aiColor4t<TReal>( v1.r + v2.r, v1.g + v2.g, v1.b + v2.b, v1.a + v2.a);
 }

+ 19 - 0
include/assimp/config.h

@@ -233,6 +233,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_CONFIG_PP_PTV_NORMALIZE	\
 	"PP_PTV_NORMALIZE"
 
+// ---------------------------------------------------------------------------
+/** @brief Configures the #aiProcess_PretransformVertices step to use
+ *  a users defined matrix as the scene root node transformation before
+ *  transforming vertices. 
+ *  Property type: bool. Default value: false.
+ */
+#define AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION	\
+	"PP_PTV_ADD_ROOT_TRANSFORMATION"
+
+// ---------------------------------------------------------------------------
+/** @brief Configures the #aiProcess_PretransformVertices step to use
+ *  a users defined matrix as the scene root node transformation before
+ *  transforming vertices. This property correspond to the 'a1' component
+ *  of the transformation matrix.
+ *  Property type: aiMatrix4x4.
+ */
+#define AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION	\
+	"PP_PTV_ROOT_TRANSFORMATION"
+
 // ---------------------------------------------------------------------------
 /** @brief Configures the #aiProcess_FindDegenerates step to
  *  remove degenerated primitives from the import - immediately.

+ 1 - 5
include/assimp/defs.h

@@ -238,11 +238,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #	define ASSIMP_BUILD_SINGLETHREADED
 #endif
 
-#ifndef ASSIMP_BUILD_SINGLETHREADED
-#	define AI_C_THREADSAFE
-#endif // !! ASSIMP_BUILD_SINGLETHREADED
-
-#ifdef _DEBUG 
+#if defined(_DEBUG) || ! defined(NDEBUG)
 #	define ASSIMP_BUILD_DEBUG
 #endif
 

+ 12 - 0
include/assimp/material.h

@@ -1473,6 +1473,18 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialColor(const C_STRUCT aiMaterial* pMat,
 	 C_STRUCT aiColor4D* pOut);
 
 
+// ---------------------------------------------------------------------------
+/** @brief Retrieve a aiUVTransform value from the material property table
+*
+* See the sample for aiGetMaterialFloat for more information*/
+// ---------------------------------------------------------------------------
+ASSIMP_API C_ENUM aiReturn aiGetMaterialUVTransform(const C_STRUCT aiMaterial* pMat, 
+    const char* pKey,
+	 unsigned int type,
+    unsigned int index,
+	 C_STRUCT aiUVTransform* pOut);
+
+
 // ---------------------------------------------------------------------------
 /** @brief Retrieve a string from the material property table
 *

+ 6 - 0
include/assimp/material.inl

@@ -167,6 +167,12 @@ inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
 {
 	return aiGetMaterialString(this,pKey,type,idx,&pOut);
 }
+// ---------------------------------------------------------------------------
+inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
+	unsigned int idx,aiUVTransform& pOut) const
+{
+	return aiGetMaterialUVTransform(this,pKey,type,idx,&pOut);
+}
 
 
 // ---------------------------------------------------------------------------

+ 4 - 2
include/assimp/matrix3x3.h

@@ -90,8 +90,10 @@ public:
 	const TReal* operator[] (unsigned int p_iIndex) const;
 
 	// comparison operators
-	bool operator== (const aiMatrix4x4t<TReal> m) const;
-	bool operator!= (const aiMatrix4x4t<TReal> m) const;
+	bool operator== (const aiMatrix4x4t<TReal>& m) const;
+	bool operator!= (const aiMatrix4x4t<TReal>& m) const;
+
+	bool Equal(const aiMatrix4x4t<TReal>& m, TReal epsilon = 1e-6) const;
 
 	template <typename TOther>
 	operator aiMatrix3x3t<TOther> () const;

+ 18 - 2
include/assimp/matrix3x3.inl

@@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "matrix4x4.h"
 #include <algorithm>
+#include <cmath>
 #include <limits>
 
 // ------------------------------------------------------------------------------------------------
@@ -113,7 +114,7 @@ inline const TReal* aiMatrix3x3t<TReal>::operator[] (unsigned int p_iIndex) cons
 
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
-inline bool aiMatrix3x3t<TReal>::operator== (const aiMatrix4x4t<TReal> m) const
+inline bool aiMatrix3x3t<TReal>::operator== (const aiMatrix4x4t<TReal>& m) const
 {
 	return a1 == m.a1 && a2 == m.a2 && a3 == m.a3 &&
 		   b1 == m.b1 && b2 == m.b2 && b3 == m.b3 &&
@@ -122,11 +123,26 @@ inline bool aiMatrix3x3t<TReal>::operator== (const aiMatrix4x4t<TReal> m) const
 
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
-inline bool aiMatrix3x3t<TReal>::operator!= (const aiMatrix4x4t<TReal> m) const
+inline bool aiMatrix3x3t<TReal>::operator!= (const aiMatrix4x4t<TReal>& m) const
 {
 	return !(*this == m);
 }
 
+// ---------------------------------------------------------------------------
+template<typename TReal>
+inline bool aiMatrix3x3t<TReal>::Equal(const aiMatrix4x4t<TReal>& m, TReal epsilon) const {
+	return
+		std::abs(a1 - m.a1) <= epsilon &&
+		std::abs(a2 - m.a2) <= epsilon &&
+		std::abs(a3 - m.a3) <= epsilon &&
+		std::abs(b1 - m.b1) <= epsilon &&
+		std::abs(b2 - m.b2) <= epsilon &&
+		std::abs(b3 - m.b3) <= epsilon &&
+		std::abs(c1 - m.c1) <= epsilon &&
+		std::abs(c2 - m.c2) <= epsilon &&
+		std::abs(c3 - m.c3) <= epsilon;
+}
+
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 inline aiMatrix3x3t<TReal>& aiMatrix3x3t<TReal>::Transpose()

+ 12 - 2
include/assimp/matrix4x4.h

@@ -78,6 +78,14 @@ public:
 
 	/** construction from 3x3 matrix, remaining elements are set to identity */
 	explicit aiMatrix4x4t( const aiMatrix3x3t<TReal>& m);
+	
+	/** construction from position, rotation and scaling components
+	 * @param scaling The scaling for the x,y,z axes
+	 * @param rotation The rotation as a hamilton quaternion 
+	 * @param position The position for the x,y,z axes
+	 */
+	aiMatrix4x4t(aiVector3t<TReal>& scaling, aiQuaterniont<TReal>& rotation,
+		aiVector3t<TReal>& position);
 
 public:
 
@@ -86,8 +94,10 @@ public:
 	const TReal* operator[] (unsigned int p_iIndex) const;
 
 	// comparison operators
-	bool operator== (const aiMatrix4x4t m) const;
-	bool operator!= (const aiMatrix4x4t m) const;
+	bool operator== (const aiMatrix4x4t& m) const;
+	bool operator!= (const aiMatrix4x4t& m) const;
+
+	bool Equal(const aiMatrix4x4t& m, TReal epsilon = 1e-6) const;
 
 	// matrix multiplication. 
 	aiMatrix4x4t& operator *= (const aiMatrix4x4t& m);

+ 81 - 31
include/assimp/matrix4x4.inl

@@ -7,8 +7,8 @@ Copyright (c) 2006-2012, 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 
+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
@@ -25,16 +25,16 @@ conditions are met:
   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 
+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 
+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 
+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 
+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.
 ---------------------------------------------------------------------------
 */
@@ -52,19 +52,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "quaternion.h"
 
 #include <algorithm>
-#include <limits>
+#include <limits>
 
 #ifdef __cplusplus
 #   include <cmath>
 #else
 #   include <math.h>
-#endif
+#endif
 
 // ----------------------------------------------------------------------------------------
 template <typename TReal>
-aiMatrix4x4t<TReal> ::aiMatrix4x4t () :	
-	a1(1.0f), a2(), a3(), a4(), 
-	b1(), b2(1.0f), b3(), b4(), 
+aiMatrix4x4t<TReal> ::aiMatrix4x4t () :
+	a1(1.0f), a2(), a3(), a4(),
+	b1(), b2(1.0f), b3(), b4(),
 	c1(), c2(), c3(1.0f), c4(),
 	d1(), d2(), d3(), d4(1.0f)
 {
@@ -76,13 +76,13 @@ template <typename TReal>
 aiMatrix4x4t<TReal> ::aiMatrix4x4t (TReal _a1, TReal _a2, TReal _a3, TReal _a4,
 			  TReal _b1, TReal _b2, TReal _b3, TReal _b4,
 			  TReal _c1, TReal _c2, TReal _c3, TReal _c4,
-			  TReal _d1, TReal _d2, TReal _d3, TReal _d4) :	
-	a1(_a1), a2(_a2), a3(_a3), a4(_a4),  
-	b1(_b1), b2(_b2), b3(_b3), b4(_b4), 
+			  TReal _d1, TReal _d2, TReal _d3, TReal _d4) :
+	a1(_a1), a2(_a2), a3(_a3), a4(_a4),
+	b1(_b1), b2(_b2), b3(_b3), b4(_b4),
 	c1(_c1), c2(_c2), c3(_c3), c4(_c4),
 	d1(_d1), d2(_d2), d3(_d3), d4(_d4)
 {
-	
+
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -107,6 +107,34 @@ inline aiMatrix4x4t<TReal>::aiMatrix4x4t (const aiMatrix3x3t<TReal>& m)
 	d1 = static_cast<TReal>(0.0); d2 = static_cast<TReal>(0.0); d3 = static_cast<TReal>(0.0); d4 = static_cast<TReal>(1.0);
 }
 
+// ----------------------------------------------------------------------------------------
+template <typename TReal>
+inline aiMatrix4x4t<TReal>::aiMatrix4x4t (aiVector3t<TReal>& scaling, aiQuaterniont<TReal>& rotation, aiVector3t<TReal>& position)
+{
+	// build a 3x3 rotation matrix
+	aiMatrix3x3t<TReal> m = rotation.GetMatrix();
+
+	a1 = m.a1 * scaling.x;
+	a2 = m.a2 * scaling.x;
+	a3 = m.a3 * scaling.x;
+	a4 = position.x;
+
+	b1 = m.b1 * scaling.y;
+	b2 = m.b2 * scaling.y;
+	b3 = m.b3 * scaling.y;
+	b4 = position.y;
+	
+	c1 = m.c1 * scaling.z;
+	c2 = m.c2 * scaling.z;
+	c3 = m.c3 * scaling.z;
+	c4= position.z;
+
+	d1 = static_cast<TReal>(0.0);
+	d2 = static_cast<TReal>(0.0);
+	d3 = static_cast<TReal>(0.0);
+	d4 = static_cast<TReal>(1.0);
+}
+
 // ----------------------------------------------------------------------------------------
 template <typename TReal>
 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::operator *= (const aiMatrix4x4t<TReal>& m)
@@ -160,10 +188,10 @@ inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Transpose()
 template <typename TReal>
 inline TReal aiMatrix4x4t<TReal>::Determinant() const
 {
-	return a1*b2*c3*d4 - a1*b2*c4*d3 + a1*b3*c4*d2 - a1*b3*c2*d4 
-		+ a1*b4*c2*d3 - a1*b4*c3*d2 - a2*b3*c4*d1 + a2*b3*c1*d4 
-		- a2*b4*c1*d3 + a2*b4*c3*d1 - a2*b1*c3*d4 + a2*b1*c4*d3 
-		+ a3*b4*c1*d2 - a3*b4*c2*d1 + a3*b1*c2*d4 - a3*b1*c4*d2 
+	return a1*b2*c3*d4 - a1*b2*c4*d3 + a1*b3*c4*d2 - a1*b3*c2*d4
+		+ a1*b4*c2*d3 - a1*b4*c3*d2 - a2*b3*c4*d1 + a2*b3*c1*d4
+		- a2*b4*c1*d3 + a2*b4*c3*d1 - a2*b1*c3*d4 + a2*b1*c4*d3
+		+ a3*b4*c1*d2 - a3*b4*c2*d1 + a3*b1*c2*d4 - a3*b1*c4*d2
 		+ a3*b2*c4*d1 - a3*b2*c1*d4 - a4*b1*c2*d3 + a4*b1*c3*d2
 		- a4*b2*c3*d1 + a4*b2*c1*d3 - a4*b3*c1*d2 + a4*b3*c2*d1;
 }
@@ -174,7 +202,7 @@ inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Inverse()
 {
 	// Compute the reciprocal determinant
 	const TReal det = Determinant();
-	if(det == static_cast<TReal>(0.0)) 
+	if(det == static_cast<TReal>(0.0))
 	{
 		// Matrix not invertible. Setting all elements to nan is not really
 		// correct in a mathematical sense but it is easy to debug for the
@@ -207,7 +235,7 @@ inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Inverse()
 	res.d1 = -invdet * (b1 * (c2 * d3 - c3 * d2) + b2 * (c3 * d1 - c1 * d3) + b3 * (c1 * d2 - c2 * d1));
 	res.d2 = invdet  * (a1 * (c2 * d3 - c3 * d2) + a2 * (c3 * d1 - c1 * d3) + a3 * (c1 * d2 - c2 * d1));
 	res.d3 = -invdet * (a1 * (b2 * d3 - b3 * d2) + a2 * (b3 * d1 - b1 * d3) + a3 * (b1 * d2 - b2 * d1));
-	res.d4 = invdet  * (a1 * (b2 * c3 - b3 * c2) + a2 * (b3 * c1 - b1 * c3) + a3 * (b1 * c2 - b2 * c1)); 
+	res.d4 = invdet  * (a1 * (b2 * c3 - b3 * c2) + a2 * (b3 * c1 - b1 * c3) + a3 * (b1 * c2 - b2 * c1));
 	*this = res;
 
 	return *this;
@@ -231,7 +259,7 @@ inline const TReal* aiMatrix4x4t<TReal>::operator[](unsigned int p_iIndex) const
 
 // ----------------------------------------------------------------------------------------
 template <typename TReal>
-inline bool aiMatrix4x4t<TReal>::operator== (const aiMatrix4x4t<TReal> m) const
+inline bool aiMatrix4x4t<TReal>::operator== (const aiMatrix4x4t<TReal>& m) const
 {
 	return (a1 == m.a1 && a2 == m.a2 && a3 == m.a3 && a4 == m.a4 &&
 			b1 == m.b1 && b2 == m.b2 && b3 == m.b3 && b4 == m.b4 &&
@@ -241,11 +269,33 @@ inline bool aiMatrix4x4t<TReal>::operator== (const aiMatrix4x4t<TReal> m) const
 
 // ----------------------------------------------------------------------------------------
 template <typename TReal>
-inline bool aiMatrix4x4t<TReal>::operator!= (const aiMatrix4x4t<TReal> m) const
+inline bool aiMatrix4x4t<TReal>::operator!= (const aiMatrix4x4t<TReal>& m) const
 {
 	return !(*this == m);
 }
 
+// ---------------------------------------------------------------------------
+template<typename TReal>
+inline bool aiMatrix4x4t<TReal>::Equal(const aiMatrix4x4t<TReal>& m, TReal epsilon) const {
+	return
+		std::abs(a1 - m.a1) <= epsilon &&
+		std::abs(a2 - m.a2) <= epsilon &&
+		std::abs(a3 - m.a3) <= epsilon &&
+		std::abs(a4 - m.a4) <= epsilon &&
+		std::abs(b1 - m.b1) <= epsilon &&
+		std::abs(b2 - m.b2) <= epsilon &&
+		std::abs(b3 - m.b3) <= epsilon &&
+		std::abs(b4 - m.b4) <= epsilon &&
+		std::abs(c1 - m.c1) <= epsilon &&
+		std::abs(c2 - m.c2) <= epsilon &&
+		std::abs(c3 - m.c3) <= epsilon &&
+		std::abs(c4 - m.c4) <= epsilon &&
+		std::abs(d1 - m.d1) <= epsilon &&
+		std::abs(d2 - m.d2) <= epsilon &&
+		std::abs(d3 - m.d3) <= epsilon &&
+		std::abs(d4 - m.d4) <= epsilon;
+}
+
 // ----------------------------------------------------------------------------------------
 template <typename TReal>
 inline void aiMatrix4x4t<TReal>::Decompose (aiVector3t<TReal>& scaling, aiQuaterniont<TReal>& rotation,
@@ -373,9 +423,9 @@ inline bool aiMatrix4x4t<TReal>::IsIdentity() const
 			d1 <= epsilon && d1 >= -epsilon &&
 			d2 <= epsilon && d2 >= -epsilon &&
 			d3 <= epsilon && d3 >= -epsilon &&
-			a1 <= 1.f+epsilon && a1 >= 1.f-epsilon && 
-			b2 <= 1.f+epsilon && b2 >= 1.f-epsilon && 
-			c3 <= 1.f+epsilon && c3 >= 1.f-epsilon && 
+			a1 <= 1.f+epsilon && a1 >= 1.f-epsilon &&
+			b2 <= 1.f+epsilon && b2 >= 1.f-epsilon &&
+			c3 <= 1.f+epsilon && c3 >= 1.f-epsilon &&
 			d4 <= 1.f+epsilon && d4 >= 1.f-epsilon);
 }
 
@@ -477,9 +527,9 @@ inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Scaling( const aiVector3t<TReal
  */
 // ----------------------------------------------------------------------------------------
 template <typename TReal>
-inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::FromToMatrix(const aiVector3t<TReal>& from, 
+inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::FromToMatrix(const aiVector3t<TReal>& from,
 	const aiVector3t<TReal>& to, aiMatrix4x4t<TReal>& mtx)
-{	
+{
 	aiMatrix3x3t<TReal> m3;
 	aiMatrix3x3t<TReal>::FromToMatrix(from,to,m3);
 	mtx = aiMatrix4x4t<TReal>(m3);

+ 1 - 1
include/assimp/mesh.h

@@ -620,7 +620,7 @@ struct aiMesh
 		, mBitangents( NULL )
 		, mFaces( NULL )
 		, mNumBones( 0 )
-		, mBones( 0 )
+		, mBones( NULL )
 		, mMaterialIndex( 0 )
 		, mNumAnimMeshes( 0 )
 		, mAnimMeshes( NULL )

+ 2 - 0
include/assimp/metadata.h

@@ -64,7 +64,9 @@ enum aiMetadataType
 	AI_AISTRING = 4,
 	AI_AIVECTOR3D = 5,
 
+#ifndef SWIG
 	FORCE_32BIT = INT_MAX
+#endif
 };
 
 

+ 2 - 0
include/assimp/quaternion.h

@@ -79,6 +79,8 @@ public:
 	bool operator== (const aiQuaterniont& o) const;
 	bool operator!= (const aiQuaterniont& o) const;
 
+	bool Equal(const aiQuaterniont& o, TReal epsilon = 1e-6) const;
+
 public:
 
 	/** Normalize the quaternion */

+ 11 - 1
include/assimp/quaternion.inl

@@ -48,6 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifdef __cplusplus
 #include "quaternion.h"
 
+#include <cmath>
+
 // ---------------------------------------------------------------------------
 template<typename TReal>
 bool aiQuaterniont<TReal>::operator== (const aiQuaterniont& o) const
@@ -62,7 +64,15 @@ bool aiQuaterniont<TReal>::operator!= (const aiQuaterniont& o) const
 	return !(*this == o);
 }
 
-
+// ---------------------------------------------------------------------------
+template<typename TReal>
+inline bool aiQuaterniont<TReal>::Equal(const aiQuaterniont& o, TReal epsilon) const {
+	return
+		std::abs(x - o.x) <= epsilon &&
+		std::abs(y - o.y) <= epsilon &&
+		std::abs(z - o.z) <= epsilon &&
+		std::abs(w - o.w) <= epsilon;
+}
 
 // ---------------------------------------------------------------------------
 // Constructs a quaternion from a rotation matrix

+ 17 - 17
include/assimp/scene.h

@@ -122,14 +122,14 @@ struct aiNode
 #ifdef __cplusplus
 	/** Constructor */
 	aiNode() 
-		// set all members to zero by default
-		: mName()
-		, mParent()
-		, mNumChildren()
-		, mChildren()
-		, mNumMeshes()
-		, mMeshes()
-		, mMetaData()
+		// set all members to zero by default
+		: mName("")
+		, mParent(NULL)
+		, mNumChildren(0)
+		, mChildren(NULL)
+		, mNumMeshes(0)
+		, mMeshes(NULL)
+		, mMetaData(NULL)
 	{
 	}
 	
@@ -137,13 +137,13 @@ struct aiNode
 	/** Construction from a specific name */
 	aiNode(const std::string& name) 
 		// set all members to zero by default
-		: mName(name)
-		, mParent()
-		, mNumChildren()
-		, mChildren()
-		, mNumMeshes()
-		, mMeshes()
-		, mMetaData()
+		: mName(name)
+		, mParent(NULL)
+		, mNumChildren(0)
+		, mChildren(NULL)
+		, mNumMeshes(0)
+		, mMeshes(NULL)
+		, mMetaData(NULL)
 	{
 	}
 
@@ -378,10 +378,10 @@ struct aiScene
 #ifdef __cplusplus
 
 	//! Default constructor - set everything to 0/NULL
-	aiScene();
+	ASSIMP_API aiScene();
 
 	//! Destructor
-	~aiScene();
+	ASSIMP_API ~aiScene();
 
 	//! Check whether the scene contains meshes
 	//! Unless no special scene flags are set this will always be true.

+ 12 - 2
include/assimp/types.h

@@ -174,6 +174,16 @@ struct aiColor3D
 	bool operator != (const aiColor3D& other) const
 		{return r != other.r || g != other.g || b != other.b;}
 
+	/** Component-wise comparison */
+	// TODO: add epsilon?
+	bool operator < (const aiColor3D& other) const {
+		return r < other.r || (
+			r == other.r && (g < other.g ||
+				(g == other.g && b < other.b)
+			)
+		);
+	}
+
 	/** Component-wise addition */
 	aiColor3D operator+(const aiColor3D& c) const {
 		return aiColor3D(r+c.r,g+c.g,b+c.b);
@@ -247,7 +257,7 @@ struct aiString
 	{
 		data[0] = '\0';
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		// Debug build: overwrite the string on its full length with ESC (27)
 		memset(data+1,27,MAXLEN-1);
 #endif
@@ -334,7 +344,7 @@ struct aiString
 		length  = 0;
 		data[0] = '\0';
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		// Debug build: overwrite the string on its full length with ESC (27)
 		memset(data+1,27,MAXLEN-1);
 #endif

+ 4 - 2
include/assimp/vector2.h

@@ -43,13 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #ifndef AI_VECTOR2D_H_INC
 #define AI_VECTOR2D_H_INC
-
+
 #ifdef __cplusplus
 #   include <cmath>
 #else
 #   include <math.h>
 #endif
-
+
 #include "./Compiler/pushpack1.h"
 
 // ----------------------------------------------------------------------------------
@@ -87,6 +87,8 @@ public:
 	bool operator== (const aiVector2t& other) const;
 	bool operator!= (const aiVector2t& other) const;
 
+	bool Equal(const aiVector2t& other, TReal epsilon = 1e-6) const;
+
 	aiVector2t& operator= (TReal f);
 	const aiVector2t SymMul(const aiVector2t& o);
 

+ 10 - 0
include/assimp/vector2.inl

@@ -48,6 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifdef __cplusplus
 #include "vector2.h"
 
+#include <cmath>
+
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 template <typename TOther>
@@ -131,6 +133,14 @@ bool aiVector2t<TReal>::operator!= (const aiVector2t& other) const {
 	return x != other.x || y != other.y;
 }
 
+// ---------------------------------------------------------------------------
+template<typename TReal>
+bool aiVector2t<TReal>::Equal(const aiVector2t& other, TReal epsilon) const {
+	return
+		std::abs(x - other.x) <= epsilon &&
+		std::abs(y - other.y) <= epsilon;
+}
+
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 aiVector2t<TReal>& aiVector2t<TReal>::operator= (TReal f)	{

+ 4 - 2
include/assimp/vector3.h

@@ -43,13 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #ifndef AI_VECTOR3D_H_INC
 #define AI_VECTOR3D_H_INC
-
+
 #ifdef __cplusplus
 #   include <cmath>
 #else
 #   include <math.h>
 #endif
-
+
 #include "./Compiler/pushpack1.h"
 
 #ifdef __cplusplus
@@ -89,6 +89,8 @@ public:
 	bool operator== (const aiVector3t& other) const;
 	bool operator!= (const aiVector3t& other) const;
 
+	bool Equal(const aiVector3t& other, TReal epsilon = 1e-6) const;
+
 	template <typename TOther>
 	operator aiVector3t<TOther> () const;
 

+ 10 - 0
include/assimp/vector3.inl

@@ -48,6 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifdef __cplusplus
 #include "vector3.h"
 
+#include <cmath>
+
 // ------------------------------------------------------------------------------------------------
 /** Transformation of a vector by a 3x3 matrix */
 template <typename TReal>
@@ -147,6 +149,14 @@ template <typename TReal>
 AI_FORCE_INLINE bool aiVector3t<TReal>::operator!= (const aiVector3t<TReal>& other) const {
 	return x != other.x || y != other.y || z != other.z;
 }
+// ---------------------------------------------------------------------------
+template<typename TReal>
+AI_FORCE_INLINE bool aiVector3t<TReal>::Equal(const aiVector3t<TReal>& other, TReal epsilon) const {
+	return
+		std::abs(x - other.x) <= epsilon &&
+		std::abs(y - other.y) <= epsilon &&
+		std::abs(z - other.z) <= epsilon;
+}
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 AI_FORCE_INLINE const aiVector3t<TReal> aiVector3t<TReal>::SymMul(const aiVector3t<TReal>& o) {

+ 1 - 1
tools/assimp_cmd/Main.cpp

@@ -51,7 +51,7 @@ const char* AICMD_MSG_ABOUT =
 " -- Commandline toolchain --\n"
 "------------------------------------------------------ \n\n"
 
-"Version %i.%i-%s%s%s%s%s (SVNREV %i)\n\n";
+"Version %i.%i %s%s%s%s%s(SVNREV %i)\n\n";
 
 const char* AICMD_MSG_HELP = 
 "assimp <verb> <parameters>\n\n"

+ 21 - 5
tools/assimp_view/MessageProc.cpp

@@ -1041,27 +1041,35 @@ void DoExport(size_t formatId)
 	char szFileName[MAX_PATH*2];
 	DWORD dwTemp;
 	if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,"ModelExportDest",NULL,NULL,(BYTE*)szFileName,&dwTemp)) {
+		ai_assert(dwTemp == MAX_PATH + 1);
+		ai_assert(strlen(szFileName) <= MAX_PATH);
+
 		// invent a nice default file name 
 		char* sz = std::max(strrchr(szFileName,'\\'),strrchr(szFileName,'/'));
 		if (sz) {
-			strcpy(sz,std::max(strrchr(g_szFileName,'\\'),strrchr(g_szFileName,'/')));
+			strncpy(sz,std::max(strrchr(g_szFileName,'\\'),strrchr(g_szFileName,'/')),MAX_PATH);
 		}
 	}
 	else {
 		// Key was not found. Use the folder where the asset comes from
-		strcpy(szFileName,g_szFileName);
+		strncpy(szFileName,g_szFileName,MAX_PATH);
 	}
 
 	// fix file extension
 	{	char * const sz = strrchr(szFileName,'.');
-		if(sz) strcpy(sz+1,e->fileExtension);
+		if(sz) {
+			ai_assert((sz - &szFileName[0]) + strlen(e->fileExtension) + 1 <= MAX_PATH);
+			strcpy(sz+1,e->fileExtension);
+		}
 	}
 
 	// build the stupid info string for GetSaveFileName() - can't use sprintf() because the string must contain binary zeros.
 	char desc[256] = {0};
 	char* c = strcpy(desc,e->description) + strlen(e->description)+1;
 	c += sprintf(c,"*.%s",e->fileExtension)+1;
-	strcpy(c, "*.*\0");
+	strcpy(c, "*.*\0"); c += 4; 
+
+	ai_assert(c - &desc[0] <= 256);
 
 	const std::string ext = "."+std::string(e->fileExtension);
 	OPENFILENAME sFilename1 = {
@@ -1084,7 +1092,15 @@ void DoExport(size_t formatId)
 	}
 
 	// export the file
-	const aiReturn res = exp.Export(g_pcAsset->pcScene,e->id,sFinal.c_str());
+	const aiReturn res = exp.Export(g_pcAsset->pcScene,e->id,sFinal.c_str(),
+		ppsteps | /* configurable pp steps */
+		aiProcess_GenSmoothNormals		   | // generate smooth normal vectors if not existing
+		aiProcess_SplitLargeMeshes         | // split large, unrenderable meshes into submeshes
+		aiProcess_Triangulate			   | // triangulate polygons with more than 3 edges
+		aiProcess_ConvertToLeftHanded	   | // convert everything to D3D left handed space
+		aiProcess_SortByPType              | // make 'clean' meshes which consist of a single typ of primitives
+		0
+	);
 	if (res == aiReturn_SUCCESS) {
 		CLogDisplay::Instance().AddEntry("[INFO] Exported file " + sFinal,D3DCOLOR_ARGB(0xFF,0x00,0xFF,0x00));
 		return;