瀏覽代碼

Merge pull request #261 from terziman/master

Improvement of collada exporter & bug fixes
Kim Kulling 11 年之前
父節點
當前提交
562dd01655
共有 80 個文件被更改,包括 2298 次插入749 次删除
  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
 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(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-dev)
 set(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
 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....
   add_definitions(-fPIC) # this is a very important switch and some libraries seem now to have it....
   # hide all not-exported symbols
   # hide all not-exported symbols
   add_definitions( -fvisibility=hidden -Wall )
   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"
 #include "Importer.h"
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 #	include <boost/thread/thread.hpp>
 #	include <boost/thread/thread.hpp>
 #	include <boost/thread/mutex.hpp>
 #	include <boost/thread/mutex.hpp>
 #endif
 #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 */
 /** Global mutex to manage the access to the logstream map */
 static boost::mutex gLogStreamMutex;
 static boost::mutex gLogStreamMutex;
 #endif
 #endif
@@ -104,7 +104,7 @@ public:
 	}
 	}
 
 
 	~LogToCallbackRedirector()	{
 	~LogToCallbackRedirector()	{
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 		boost::mutex::scoped_lock lock(gLogStreamMutex);
 		boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 #endif
 		// (HACK) Check whether the 'stream.user' pointer points to a
 		// (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->mIntProperties = pp->ints;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mStringProperties = pp->strings;
 		pimpl->mStringProperties = pp->strings;
+		pimpl->mMatrixProperties = pp->matrices;
 	}
 	}
 	// setup a custom IO system if necessary
 	// setup a custom IO system if necessary
 	if (pFS)	{
 	if (pFS)	{
@@ -230,6 +231,7 @@ const aiScene* aiImportFileFromMemoryWithProperties(
 		pimpl->mIntProperties = pp->ints;
 		pimpl->mIntProperties = pp->ints;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mStringProperties = pp->strings;
 		pimpl->mStringProperties = pp->strings;
+		pimpl->mMatrixProperties = pp->matrices;
 	}
 	}
 
 
 	// and have it read the file from the memory buffer
 	// 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();
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 #endif
 
 
@@ -356,7 +358,7 @@ ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
 {
 {
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 #endif
 	// find the logstream associated with this data
 	// find the logstream associated with this data
@@ -381,7 +383,7 @@ ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
 ASSIMP_API void aiDetachAllLogStreams(void)
 ASSIMP_API void aiDetachAllLogStreams(void)
 {
 {
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 	ASSIMP_BEGIN_EXCEPTION_REGION();
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 #endif
 	for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
 	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);
 	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
 // Rotation matrix to quaternion
 ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
 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())
 	, mPrivate(new Assimp::ScenePrivateData())
 	{
 	{
 	}
 	}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-aiScene::~aiScene()
+ASSIMP_API aiScene::~aiScene()
 {
 {
 	// delete all sub-objects recursively
 	// delete all sub-objects recursively
 	delete mRootNode;
 	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
 /* 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;
 #	define AI_DEBUG_INVALIDATE_PTR(x) x = NULL;
 #else
 #else
 #	define AI_DEBUG_INVALIDATE_PTR(x)
 #	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,
 void BaseImporter::TextFileToBuffer(IOStream* stream,
 	std::vector<char>& data)
 	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)	{
 	for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it)	{
 		// force validation in debug builds
 		// force validation in debug builds
 		unsigned int pp = (*it).flags;
 		unsigned int pp = (*it).flags;
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		pp |= aiProcess_ValidateDataStructure;
 		pp |= aiProcess_ValidateDataStructure;
 #endif
 #endif
 		// setup config properties if necessary
 		// setup config properties if necessary
@@ -541,6 +578,7 @@ void BatchLoader::LoadAll()
 		pimpl->mFloatProperties  = (*it).map.floats;
 		pimpl->mFloatProperties  = (*it).map.floats;
 		pimpl->mIntProperties    = (*it).map.ints;
 		pimpl->mIntProperties    = (*it).map.ints;
 		pimpl->mStringProperties = (*it).map.strings;
 		pimpl->mStringProperties = (*it).map.strings;
+		pimpl->mMatrixProperties = (*it).map.matrices;
 
 
 		if (!DefaultLogger::isNullLogger())
 		if (!DefaultLogger::isNullLogger())
 		{
 		{

+ 9 - 0
code/BaseImporter.h

@@ -331,6 +331,15 @@ public: // static utilities
 	static void ConvertToUTF8(
 	static void ConvertToUTF8(
 		std::vector<char>& data);
 		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
 	/** Utility for text file loaders which copies the contents of the
 	 *  file into a memory buffer and converts it to our UTF8
 	 *  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"
 #include "TinyFormatter.h"
 
 
 // enable verbose log output. really verbose, so be careful.
 // enable verbose log output. really verbose, so be careful.
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 #	define ASSIMP_BUILD_BLENDER_DEBUG
 #	define ASSIMP_BUILD_BLENDER_DEBUG
 #endif
 #endif
 
 

+ 17 - 5
code/CMakeLists.txt

@@ -76,13 +76,13 @@ SOURCE_GROUP(Boost FILES ${Boost_SRCS})
 
 
 SET( Logging_SRCS
 SET( Logging_SRCS
 	${HEADER_PATH}/DefaultLogger.hpp
 	${HEADER_PATH}/DefaultLogger.hpp
-	${HEADER_PATH}/IOStream.hpp
 	${HEADER_PATH}/LogStream.hpp
 	${HEADER_PATH}/LogStream.hpp
 	${HEADER_PATH}/Logger.hpp
 	${HEADER_PATH}/Logger.hpp
 	${HEADER_PATH}/NullLogger.hpp
 	${HEADER_PATH}/NullLogger.hpp
 	Win32DebugLogStream.h
 	Win32DebugLogStream.h
 	DefaultLogger.cpp
 	DefaultLogger.cpp
 	FileLogStream.h
 	FileLogStream.h
+	StdOStreamLogStream.h
 )
 )
 SOURCE_GROUP(Logging FILES ${Logging_SRCS})
 SOURCE_GROUP(Logging FILES ${Logging_SRCS})
 
 
@@ -107,8 +107,8 @@ SET( Common_SRCS
 	Hash.h
 	Hash.h
 	Importer.cpp
 	Importer.cpp
 	IFF.h
 	IFF.h
+	MemoryIOWrapper.h
 	ParsingUtils.h
 	ParsingUtils.h
-	StdOStreamLogStream.h
 	StreamReader.h
 	StreamReader.h
 	StringComparison.h
 	StringComparison.h
 	SGSpatialSort.cpp
 	SGSpatialSort.cpp
@@ -140,6 +140,8 @@ SET( Common_SRCS
 	TinyFormatter.h
 	TinyFormatter.h
 	Profiler.h
 	Profiler.h
 	LogAux.h
 	LogAux.h
+	Bitmap.cpp
+	Bitmap.h
 )
 )
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 
 
@@ -461,8 +463,6 @@ SET( PostProcessing_SRCS
 	SortByPTypeProcess.h
 	SortByPTypeProcess.h
 	SplitLargeMeshes.cpp
 	SplitLargeMeshes.cpp
 	SplitLargeMeshes.h
 	SplitLargeMeshes.h
-	TerragenLoader.cpp
-	TerragenLoader.h
 	TextureTransform.cpp
 	TextureTransform.cpp
 	TextureTransform.h
 	TextureTransform.h
 	TriangulateProcess.cpp
 	TriangulateProcess.cpp
@@ -520,6 +520,12 @@ SET( STL_SRCS
 )
 )
 SOURCE_GROUP( STL FILES ${STL_SRCS})
 SOURCE_GROUP( STL FILES ${STL_SRCS})
 
 
+SET( Terragen_SRCS
+	TerragenLoader.cpp
+	TerragenLoader.h
+)
+SOURCE_GROUP( Terragen FILES ${Terragen_SRCS})
+
 SET( Unreal_SRCS
 SET( Unreal_SRCS
 	UnrealLoader.cpp
 	UnrealLoader.cpp
 	UnrealLoader.h
 	UnrealLoader.h
@@ -655,6 +661,7 @@ SET( assimp_src
 	${Raw_SRCS}
 	${Raw_SRCS}
 	${SMD_SRCS}
 	${SMD_SRCS}
 	${STL_SRCS}
 	${STL_SRCS}
+	${Terragen_SRCS}
 	${Unreal_SRCS}
 	${Unreal_SRCS}
 	${XFile_SRCS}
 	${XFile_SRCS}
 	${Extra_SRCS}
 	${Extra_SRCS}
@@ -677,9 +684,14 @@ SET( assimp_src
 
 
 	${PUBLIC_HEADERS}
 	${PUBLIC_HEADERS}
 	${COMPILER_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} )
 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
 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
 #include "ColladaExporter.h"
 #include "ColladaExporter.h"
 
 
+#include "Bitmap.h"
+#include "fast_atof.h"
+#include "SceneCombiner.h" 
+
+#include <ctime>
+#include <set>
+
 using namespace Assimp;
 using namespace Assimp;
 
 
 namespace Assimp
 namespace Assimp
@@ -53,8 +60,25 @@ namespace Assimp
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
 void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
 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 
 	// 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
 	// we're still here - export successfully completed. Write result to the given IOSYstem
 	boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
 	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
 // 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
 	// make sure that all formatting happens using the standard, C locale and not the user's current locale
 	mOutput.imbue( std::locale("C") );
 	mOutput.imbue( std::locale("C") );
 
 
 	mScene = pScene;
 	mScene = pScene;
+	mSceneOwned = false;
 
 
 	// set up strings
 	// set up strings
 	endstr = "\n"; 
 	endstr = "\n"; 
@@ -85,6 +110,15 @@ ColladaExporter::ColladaExporter( const aiScene* pScene)
 	WriteFile();
 	WriteFile();
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Destructor
+ColladaExporter::~ColladaExporter()
+{
+	if(mSceneOwned) {
+		delete mScene;
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Starts writing the contents
 // Starts writing the contents
 void ColladaExporter::WriteFile()
 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;
 	mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
 	PushTag();
 	PushTag();
 
 
+	WriteTextures();
 	WriteHeader();
 	WriteHeader();
 
 
-  WriteMaterials();
+	WriteMaterials();
 	WriteGeometryLibrary();
 	WriteGeometryLibrary();
 
 
 	WriteSceneLibrary();
 	WriteSceneLibrary();
@@ -105,7 +140,7 @@ void ColladaExporter::WriteFile()
 	// useless Collada fu at the end, just in case we haven't had enough indirections, yet. 
 	// useless Collada fu at the end, just in case we haven't had enough indirections, yet. 
 	mOutput << startstr << "<scene>" << endstr;
 	mOutput << startstr << "<scene>" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<instance_visual_scene url=\"#myScene\" />" << endstr;
+	mOutput << startstr << "<instance_visual_scene url=\"#" + std::string(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr;
 	PopTag();
 	PopTag();
 	mOutput << startstr << "</scene>" << endstr;
 	mOutput << startstr << "</scene>" << endstr;
 	PopTag();
 	PopTag();
@@ -116,23 +151,131 @@ void ColladaExporter::WriteFile()
 // Writes the asset header
 // Writes the asset header
 void ColladaExporter::WriteHeader()
 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;
 	mOutput << startstr << "<asset>" << endstr;
 	PushTag();
 	PushTag();
 	mOutput << startstr << "<contributor>" << endstr;
 	mOutput << startstr << "<contributor>" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<author>Someone</author>" << endstr;
+	mOutput << startstr << "<author>Assimp</author>" << endstr;
 	mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr;
 	mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr;
 	PopTag();
 	PopTag();
 	mOutput << startstr << "</contributor>" << endstr;
 	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();
 	PopTag();
 	mOutput << startstr << "</asset>" << endstr;
 	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
 // 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)
 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;
     aiString texfile;
     unsigned int uvChannel = 0;
     unsigned int uvChannel = 0;
     pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel);
     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.channel = uvChannel;
+	poSurface.exist = true;
   } else
   } else
   {
   {
     if( pKey )
     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
 // Writes a color-or-texture entry into an effect definition
 void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName)
 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
 // Writes the material setup
 void ColladaExporter::WriteMaterials()
 void ColladaExporter::WriteMaterials()
 {
 {
   materials.resize( mScene->mNumMaterials);
   materials.resize( mScene->mNumMaterials);
 
 
+  std::set<std::string> material_names;
+
   /// collect all materials from the scene
   /// collect all materials from the scene
   size_t numTextures = 0;
   size_t numTextures = 0;
   for( size_t a = 0; a < mScene->mNumMaterials; ++a )
   for( size_t a = 0; a < mScene->mNumMaterials; ++a )
@@ -233,16 +420,30 @@ void ColladaExporter::WriteMaterials()
 
 
     aiString name;
     aiString name;
     if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS )
     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();
     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 ) {
     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
 		// 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.
 		// 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 = '_';
         *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);
     ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
     if( !materials[a].ambient.texture.empty() ) numTextures++;
     if( !materials[a].ambient.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
     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++;
     if( !materials[a].emissive.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE);
     ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE);
     if( !materials[a].reflective.texture.empty() ) numTextures++;
     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);
     ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0);
     if( !materials[a].normal.texture.empty() ) numTextures++;
     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
   // output textures if present
@@ -270,8 +476,9 @@ void ColladaExporter::WriteMaterials()
       WriteImageEntry( mat.ambient, mat.name + "-ambient-image");
       WriteImageEntry( mat.ambient, mat.name + "-ambient-image");
       WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image");
       WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image");
       WriteImageEntry( mat.specular, mat.name + "-specular-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.reflective, mat.name + "-reflective-image");
+	  WriteImageEntry( mat.transparent, mat.name + "-transparent-image");
       WriteImageEntry( mat.normal, mat.name + "-normal-image");
       WriteImageEntry( mat.normal, mat.name + "-normal-image");
     }
     }
     PopTag();
     PopTag();
@@ -293,37 +500,35 @@ void ColladaExporter::WriteMaterials()
       PushTag();
       PushTag();
 
 
       // write sampler- and surface params for the texture entries
       // 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.ambient, "ambient", mat.name);
       WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name);
       WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name);
       WriteTextureParamEntry( mat.specular, "specular", mat.name);
       WriteTextureParamEntry( mat.specular, "specular", mat.name);
       WriteTextureParamEntry( mat.reflective, "reflective", 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;
       mOutput << startstr << "<technique sid=\"standard\">" << endstr;
       PushTag();
       PushTag();
-      mOutput << startstr << "<phong>" << endstr;
+	  mOutput << startstr << "<" << mat.shading_model << ">" << endstr;
       PushTag();
       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.ambient, "ambient", mat.name + "-ambient-sampler");
       WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler");
       WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler");
       WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-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.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();
       PopTag();
-      mOutput << startstr << "</phong>" << endstr;
+      mOutput << startstr << "</" << mat.shading_model << ">" << endstr;
       PopTag();
       PopTag();
       mOutput << startstr << "</technique>" << endstr;
       mOutput << startstr << "</technique>" << endstr;
       PopTag();
       PopTag();
@@ -546,13 +751,16 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
 // Writes the scene library
 // Writes the scene library
 void ColladaExporter::WriteSceneLibrary()
 void ColladaExporter::WriteSceneLibrary()
 {
 {
+	std::string scene_name = mScene->mRootNode->mName.C_Str();
+
 	mOutput << startstr << "<library_visual_scenes>" << endstr;
 	mOutput << startstr << "<library_visual_scenes>" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<visual_scene id=\"myScene\" name=\"myScene\">" << endstr;
+	mOutput << startstr << "<visual_scene id=\"" + scene_name + "\" name=\"" + scene_name + "\">" << endstr;
 	PushTag();
 	PushTag();
 
 
 	// start recursive write at the root node
 	// 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();
 	PopTag();
 	mOutput << startstr << "</visual_scene>" << endstr;
 	mOutput << startstr << "</visual_scene>" << endstr;
@@ -581,22 +789,22 @@ void ColladaExporter::WriteNode( const aiNode* pNode)
 	for( size_t a = 0; a < pNode->mNumMeshes; ++a )
 	for( size_t a = 0; a < pNode->mNumMeshes; ++a )
 	{
 	{
 		const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[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;
 		mOutput << startstr << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr;
 		PushTag();
 		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();
 		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;
 		mOutput << startstr << "</instance_geometry>" << endstr;
 	}
 	}
 
 

+ 36 - 7
code/ColladaExporter.h

@@ -59,7 +59,10 @@ class ColladaExporter
 {
 {
 public:
 public:
 	/// Constructor for a specific scene to export
 	/// 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:
 protected:
 	/// Starts writing the contents
 	/// Starts writing the contents
@@ -68,8 +71,11 @@ protected:
 	/// Writes the asset header
 	/// Writes the asset header
 	void WriteHeader();
 	void WriteHeader();
 
 
-  /// Writes the material setup
-  void WriteMaterials();
+	/// Writes the embedded textures
+	void WriteTextures();
+
+	/// Writes the material setup
+	void WriteMaterials();
 
 
 	/// Writes the geometry library
 	/// Writes the geometry library
 	void WriteGeometryLibrary();
 	void WriteGeometryLibrary();
@@ -101,8 +107,18 @@ public:
 	std::stringstream mOutput;
 	std::stringstream mOutput;
 
 
 protected:
 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
 	/// The scene to be written
 	const aiScene* mScene;
 	const aiScene* mScene;
+	bool mSceneOwned;
 
 
 	/// current line start string, contains the current indentation for simple stream insertion
 	/// current line start string, contains the current indentation for simple stream insertion
 	std::string startstr;
 	std::string startstr;
@@ -112,24 +128,35 @@ protected:
   // pair of color and texture - texture precedences color
   // pair of color and texture - texture precedences color
   struct Surface 
   struct Surface 
   { 
   { 
+    bool exist;
     aiColor4D color; 
     aiColor4D color; 
     std::string texture; 
     std::string texture; 
     size_t channel; 
     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. 
   // summarize a material in an convinient way. 
   struct Material
   struct Material
   {
   {
     std::string name;
     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::vector<Material> materials;
 
 
+  std::map<unsigned int, std::string> textures;
+
 protected:
 protected:
   /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
   /// 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
   /// 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);
   void WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName);
   /// Writes a color-or-texture entry into an effect definition
   /// Writes a color-or-texture entry into an effect definition
   void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName);
   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 )
 	if ( m_Severity == Logger::NORMAL )
 		return;
 		return;
 
 
-	char msg[MAX_LOG_MESSAGE_LENGTH*2];
+	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
 	::sprintf(msg,"Debug, T%i: %s", GetThreadID(), message );
 	::sprintf(msg,"Debug, T%i: %s", GetThreadID(), message );
 
 
 	WriteToStreams( msg, Logger::Debugging );
 	WriteToStreams( msg, Logger::Debugging );
@@ -263,7 +263,7 @@ void DefaultLogger::OnDebug( const char* message )
 //	Logs an info
 //	Logs an info
 void DefaultLogger::OnInfo( const char* message )
 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 );
 	::sprintf(msg,"Info,  T%i: %s", GetThreadID(), message );
 
 
 	WriteToStreams( msg , Logger::Info );
 	WriteToStreams( msg , Logger::Info );
@@ -273,7 +273,7 @@ void DefaultLogger::OnInfo( const char* message )
 //	Logs a warning
 //	Logs a warning
 void DefaultLogger::OnWarn( const char* message )
 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 );
 	::sprintf(msg,"Warn,  T%i: %s", GetThreadID(), message );
 
 
 	WriteToStreams( msg, Logger::Warn );
 	WriteToStreams( msg, Logger::Warn );
@@ -283,7 +283,7 @@ void DefaultLogger::OnWarn( const char* message )
 //	Logs an error
 //	Logs an error
 void DefaultLogger::OnError( const char* message )
 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 );
 	::sprintf(msg,"Error, T%i: %s", GetThreadID(), message );
 
 
 	WriteToStreams( msg, Logger::Err );
 	WriteToStreams( msg, Logger::Err );

+ 2 - 0
code/Exporter.cpp

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

+ 1 - 1
code/FBXConverter.cpp

@@ -2014,7 +2014,7 @@ private:
 		ai_assert(curves.size());
 		ai_assert(curves.size());
 
 
 		// sanity check whether the input is ok
 		// sanity check whether the input is ok
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		{ const Object* target = NULL;
 		{ const Object* target = NULL;
 		BOOST_FOREACH(const AnimationCurveNode* node, curves) {
 		BOOST_FOREACH(const AnimationCurveNode* node, curves) {
 			if(!target) {
 			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
 		// terminate zlib
 		inflateEnd(&zstream);
 		inflateEnd(&zstream);
 	}
 	}
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	else {
 	else {
 		// runtime check for this happens at tokenization stage
 		// runtime check for this happens at tokenization stage
 		ai_assert(false);
 		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 s = (x*e.y - e.x*y)/det;
 		const IfcFloat t = (x*b.y - b.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);
 		const IfcVector3 check = b0 + b*s  - (e0 + e*t);
 		ai_assert((IfcVector2(check.x,check.y)).SquareLength() < 1e-5);
 		ai_assert((IfcVector2(check.x,check.y)).SquareLength() < 1e-5);
 #endif
 #endif
@@ -417,7 +417,7 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBounded
 			IfcVector3 isectpos;
 			IfcVector3 isectpos;
 			const Intersect isect =  extra_point_flag ? Intersect_No : IntersectSegmentPlane(p,n,e0,e1,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) {
 			if (isect == Intersect_Yes) {
 				const IfcFloat f = fabs((isectpos - p)*n);
 				const IfcFloat f = fabs((isectpos - p)*n);
 				ai_assert(f < 1e-5);
 				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;
 	return NULL;
 }
 }
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 bool Curve :: InRange(IfcFloat u) const 
 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
 		// search file (same name as the IFCZIP except for the file extension) and place file pointer there
-		
 		if(UNZ_OK == unzGoToFirstFile(zip)) {
 		if(UNZ_OK == unzGoToFirstFile(zip)) {
 			do {
 			do {
-				//
-
 				// get file size, etc.
 				// get file size, etc.
 				unz_file_info fileInfo;
 				unz_file_info fileInfo;
 				char filename[256];
 				char filename[256];
 				unzGetCurrentFileInfo( zip , &fileInfo, filename, sizeof(filename), 0, 0, 0, 0 );
 				unzGetCurrentFileInfo( zip , &fileInfo, filename, sizeof(filename), 0, 0, 0, 0 );
-				
 				if (GetExtension(filename) != "ifc") {
 				if (GetExtension(filename) != "ifc") {
 					continue;
 					continue;
 				}
 				}
-
 				uint8_t* buff = new uint8_t[fileInfo.uncompressed_size];
 				uint8_t* buff = new uint8_t[fileInfo.uncompressed_size];
-
 				LogInfo("Decompressing IFCZIP file");
 				LogInfo("Decompressing IFCZIP file");
-
 				unzOpenCurrentFile( zip  );
 				unzOpenCurrentFile( zip  );
 				const int ret = unzReadCurrentFile( zip, buff, fileInfo.uncompressed_size);
 				const int ret = unzReadCurrentFile( zip, buff, fileInfo.uncompressed_size);
 				size_t filesize = 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
 	// feed the IFC schema into the reader and pre-parse all lines
 	STEP::ReadFile(*db, schema, types_to_track, inverse_indices_to_track);
 	STEP::ReadFile(*db, schema, types_to_track, inverse_indices_to_track);
-
 	const STEP::LazyObject* proj =  db->GetObject("ifcproject");
 	const STEP::LazyObject* proj =  db->GetObject("ifcproject");
 	if (!proj) {
 	if (!proj) {
 		ThrowException("missing IfcProject entity");
 		ThrowException("missing IfcProject entity");
@@ -287,9 +279,9 @@ void IFCImporter::InternReadFile( const std::string& pFile,
 	// in a build with no entities disabled. See 
 	// in a build with no entities disabled. See 
 	//     scripts/IFCImporter/CPPGenerator.py
 	//     scripts/IFCImporter/CPPGenerator.py
 	// for more information.
 	// for more information.
-#ifdef ASSIMP_IFC_TEST
-	db->EvaluateAll();
-#endif
+	#ifdef ASSIMP_IFC_TEST
+		db->EvaluateAll();
+	#endif
 
 
 	// do final data copying
 	// do final data copying
 	if (conv.meshes.size()) {
 	if (conv.meshes.size()) {
@@ -565,21 +557,16 @@ void ProcessProductRepresentation(const IfcProduct& el, aiNode* nd, std::vector<
 	if(!el.Representation) {
 	if(!el.Representation) {
 		return;
 		return;
 	}
 	}
-
-
 	std::vector<unsigned int> meshes;
 	std::vector<unsigned int> meshes;
-	
 	// we want only one representation type, so bring them in a suitable order (i.e try those
 	// 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
 	// that look as if we could read them quickly at first). This way of reading
 	// representation is relatively generic and allows the concrete implementations
 	// representation is relatively generic and allows the concrete implementations
 	// for the different representation types to make some sensible choices what
 	// for the different representation types to make some sensible choices what
 	// to load and what not to load.
 	// to load and what not to load.
 	const STEP::ListOf< STEP::Lazy< IfcRepresentation >, 1, 0 >& src = el.Representation.Get()->Representations;
 	const STEP::ListOf< STEP::Lazy< IfcRepresentation >, 1, 0 >& src = el.Representation.Get()->Representations;
-
 	std::vector<const IfcRepresentation*> repr_ordered(src.size());
 	std::vector<const IfcRepresentation*> repr_ordered(src.size());
 	std::copy(src.begin(),src.end(),repr_ordered.begin());
 	std::copy(src.begin(),src.end(),repr_ordered.begin());
 	std::sort(repr_ordered.begin(),repr_ordered.end(),RateRepresentationPredicate());
 	std::sort(repr_ordered.begin(),repr_ordered.end(),RateRepresentationPredicate());
-
 	BOOST_FOREACH(const IfcRepresentation* repr, repr_ordered) {
 	BOOST_FOREACH(const IfcRepresentation* repr, repr_ordered) {
 		bool res = false;
 		bool res = false;
 		BOOST_FOREACH(const IfcRepresentationItem& item, repr->Items) {
 		BOOST_FOREACH(const IfcRepresentationItem& item, repr->Items) {
@@ -595,7 +582,6 @@ void ProcessProductRepresentation(const IfcProduct& el, aiNode* nd, std::vector<
 			break;
 			break;
 		}
 		}
 	}
 	}
-
 	AssignAddedMeshes(meshes,nd,conv);
 	AssignAddedMeshes(meshes,nd,conv);
 }
 }
 
 

+ 2 - 2
code/IFCOpenings.cpp

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

+ 1 - 1
code/IFCUtil.h

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

+ 26 - 7
code/Importer.cpp

@@ -197,6 +197,7 @@ Importer::Importer(const Importer &other)
 	pimpl->mIntProperties    = other.pimpl->mIntProperties;
 	pimpl->mIntProperties    = other.pimpl->mIntProperties;
 	pimpl->mFloatProperties  = other.pimpl->mFloatProperties;
 	pimpl->mFloatProperties  = other.pimpl->mFloatProperties;
 	pimpl->mStringProperties = other.pimpl->mStringProperties;
 	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) {
 	for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		if (IsExtensionSupported(*it)) {
 		if (IsExtensionSupported(*it)) {
 			DefaultLogger::get()->warn("The file extension " + *it + " is already in use");
 			DefaultLogger::get()->warn("The file extension " + *it + " is already in use");
 		}
 		}
@@ -558,7 +559,7 @@ void WriteLogOpening(const std::string& file)
 		<< "<unknown compiler>"
 		<< "<unknown compiler>"
 #endif
 #endif
 
 
-#ifndef NDEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		<< " debug"
 		<< " debug"
 #endif
 #endif
 
 
@@ -749,10 +750,10 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 		}
 		}
 	}
 	}
 #endif // no validation
 #endif // no validation
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	if (pimpl->bExtraVerbose)
 	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");
 		DefaultLogger::get()->error("Verbose Import is not available due to build settings");
 #endif  // no validation
 #endif  // no validation
 		pFlags |= aiProcess_ValidateDataStructure;
 		pFlags |= aiProcess_ValidateDataStructure;
@@ -783,9 +784,9 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 		if( !pimpl->mScene) {
 		if( !pimpl->mScene) {
 			break; 
 			break; 
 		}
 		}
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 
 
-#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
+#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
 		continue;
 		continue;
 #endif  // no validation
 #endif  // no validation
 
 
@@ -937,6 +938,16 @@ void Importer::SetPropertyString(const char* szName, const std::string& value,
 	ASSIMP_END_EXCEPTION_REGION(void);
 	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
 // Get a configuration property
 int Importer::GetPropertyInteger(const char* szName, 
 int Importer::GetPropertyInteger(const char* szName, 
@@ -955,12 +966,20 @@ float Importer::GetPropertyFloat(const char* szName,
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 // 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
 	const std::string& iErrorReturn /*= ""*/) const
 {
 {
 	return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
 	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
 // Get the memory requirements of a single node
 inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
 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
 	// Data type to store the key hash
 	typedef unsigned int KeyType;
 	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
 	// We don't need more, so there is no need for a generic solution
 	typedef std::map<KeyType, int> IntPropertyMap;
 	typedef std::map<KeyType, int> IntPropertyMap;
 	typedef std::map<KeyType, float> FloatPropertyMap;
 	typedef std::map<KeyType, float> FloatPropertyMap;
 	typedef std::map<KeyType, std::string> StringPropertyMap;
 	typedef std::map<KeyType, std::string> StringPropertyMap;
+	typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
 
 
 public:
 public:
 
 
@@ -100,6 +101,9 @@ public:
 	/** List of string properties */
 	/** List of string properties */
 	StringPropertyMap mStringProperties;
 	StringPropertyMap mStringProperties;
 
 
+	/** List of Matrix properties */
+	MatrixPropertyMap mMatrixProperties;
+
 	/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
 	/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
 	 *  to be executed before and after every single postprocess step */
 	 *  to be executed before and after every single postprocess step */
 	bool bExtraVerbose;
 	bool bExtraVerbose;
@@ -135,14 +139,15 @@ public:
 		ImporterPimpl::IntPropertyMap     ints;
 		ImporterPimpl::IntPropertyMap     ints;
 		ImporterPimpl::FloatPropertyMap   floats;
 		ImporterPimpl::FloatPropertyMap   floats;
 		ImporterPimpl::StringPropertyMap  strings;
 		ImporterPimpl::StringPropertyMap  strings;
+		ImporterPimpl::MatrixPropertyMap  matrices;
 
 
 		bool operator == (const PropertyMap& prop) const {
 		bool operator == (const PropertyMap& prop) const {
 			// fixme: really isocpp? gcc complains
 			// 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 {
 		bool empty () const {
-			return ints.empty() && floats.empty() && strings.empty();
+			return ints.empty() && floats.empty() && strings.empty() && matrices.empty();
 		}
 		}
 	};
 	};
 	//! @endcond
 	//! @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 vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 				unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS];
 				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 ) {
 				for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
 					vUVChannelIndices[mui] = UINT_MAX;
 					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;
 	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
 // Get a string from the material
 aiReturn aiGetMaterialString(const aiMaterial* pMat, 
 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>
 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++;
 	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>
 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);
 	return SkipLine<char_t>(*inout,inout);
 }
 }
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 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' ||
 	while (*in == (char_t)' ' || *in == (char_t)'\t' ||
 		*in == (char_t)'\r' || *in == (char_t)'\n')in++;
 		*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>
 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);
 	return SkipSpacesAndLineEnd<char_t>(*inout,inout);
 }
 }
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 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;
 	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.
 	// validated - as RegisterPPStep() does - all dependencies must be given.
 	// ----------------------------------------------------------------------------
 	// ----------------------------------------------------------------------------
 	out.reserve(25);
 	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)
 #if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS)
 	out.push_back( new RemoveVCProcess());
 	out.push_back( new RemoveVCProcess());
 #endif
 #endif
@@ -207,15 +216,6 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 #if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
 #if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
 	out.push_back( new SplitLargeMeshesProcess_Vertex());
 	out.push_back( new SplitLargeMeshesProcess_Vertex());
 #endif
 #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)
 #if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS)
 	out.push_back( new DeboneProcess());
 	out.push_back( new DeboneProcess());
 #endif
 #endif

+ 12 - 2
code/PretransformVertices.cpp

@@ -57,7 +57,7 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 PretransformVertices::PretransformVertices()
 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
 // Setup import configuration
 void PretransformVertices::SetupProperties(const Importer* pImp)
 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));
 	configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0));
 	configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,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);
 				ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
 
 
 				out.push_back(ntz);
 				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 iOldAnimationChannels = pScene->mNumAnimations;
 	const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
 	const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
 
 
+	if(configTransform) {
+		pScene->mRootNode->mTransformation = configTransformation;
+	}
+
 	// first compute absolute transformation matrices for all nodes
 	// first compute absolute transformation matrices for all nodes
 	ComputeAbsoluteTransform(pScene->mRootNode);
 	ComputeAbsoluteTransform(pScene->mRootNode);
 
 

+ 4 - 2
code/PretransformVertices.h

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

+ 2 - 2
code/Q3BSPFileImporter.cpp

@@ -185,9 +185,9 @@ const aiImporterDesc* Q3BSPFileImporter::GetInfo () const
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Import method.
 //	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() )
 	if ( !Archive.isOpen() )
 	{
 	{
 		throw DeadlyImportError( "Failed to open file " + rFile + "." );
 		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 <algorithm>
 #include <cassert>
 #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.
 //	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();
 			mapArchive();
 		}
 		}
 	}
 	}
@@ -70,127 +191,122 @@ Q3BSPZipArchive::Q3BSPZipArchive( const std::string& rFile ) :
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Destructor.
 //	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.
 //	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.
 //	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.
 //	Returns the separator delimiter.
-char Q3BSPZipArchive::getOsSeparator() const
-{
+char Q3BSPZipArchive::getOsSeparator() const {
+#ifndef _WIN32
 	return '/';
 	return '/';
+#else
+	return '\\';
+#endif
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Opens a file, which is part of the archive.
 //	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.
 //	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.
 //	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.
 //	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 <map>
 #include <cassert>
 #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
 ///	\class		ZipFile
@@ -59,88 +84,33 @@ namespace Q3BSP
 ///
 ///
 ///	\brief
 ///	\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 
 ///	\brief	IMplements a zip archive like the WinZip archives. Will be also used to import data 
 ///	from a P3K archive ( Quake level format ).
 ///	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 the material is not referenced ... remove it
 			if (!abReferenced[i])	{
 			if (!abReferenced[i])	{
 				++unreferenced;
 				++unreferenced;
+				delete pScene->mMaterials[i];
 				continue;
 				continue;
 			}
 			}
 
 

+ 13 - 13
code/STEPFile.h

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

+ 0 - 4
code/STEPFileReader.h

@@ -47,12 +47,10 @@ namespace Assimp {
 namespace STEP {
 namespace STEP {
 
 
 	// ### Parsing a STEP file is a twofold procedure ###
 	// ### Parsing a STEP file is a twofold procedure ###
-
 	// --------------------------------------------------------------------------
 	// --------------------------------------------------------------------------
 	// 1) read file header and return to caller, who checks if the 
 	// 1) read file header and return to caller, who checks if the 
 	//    file is of a supported schema ..
 	//    file is of a supported schema ..
 	DB* ReadFileHeader(boost::shared_ptr<IOStream> stream);
 	DB* ReadFileHeader(boost::shared_ptr<IOStream> stream);
-
 	// --------------------------------------------------------------------------
 	// --------------------------------------------------------------------------
 	// 2) read the actual file contents using a user-supplied set of
 	// 2) read the actual file contents using a user-supplied set of
 	//    conversion functions to interpret the data.
 	//    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]) {
 	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);
 		return ReadFile(db,scheme,arr,N,arr2,N2);
 	}
 	}
-	
-
 } // ! STEP
 } // ! STEP
 } // ! Assimp
 } // ! Assimp
 
 

+ 57 - 0
code/SceneCombiner.cpp

@@ -880,6 +880,59 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/,
 		delete *it;
 		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>
 template <typename Type>
 inline void CopyPtrArray (Type**& dest, const Type* const * src, unsigned int num)
 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);
 	ai_assert(NULL != _dest && NULL != src);
 
 
 	aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() );
 	aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() );
+
+	dest->Clear();
+	delete[] dest->mProperties;
+
 	dest->mNumAllocated  =  src->mNumAllocated;
 	dest->mNumAllocated  =  src->mNumAllocated;
 	dest->mNumProperties =  src->mNumProperties;
 	dest->mNumProperties =  src->mNumProperties;
 	dest->mProperties    =  new aiMaterialProperty* [dest->mNumAllocated];
 	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,
 	static void MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
 		std::vector<aiMesh*>::const_iterator end);
 		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
 	/** 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);
 		aiColor3D clr(0.6f,0.6f,0.6f);
 		helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
 		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);
 		name.Set(AI_DEFAULT_MATERIAL_NAME);
 		helper->AddProperty(&name,AI_MATKEY_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.
 		// let the rest uninitialized for performance - in release builds.
 		// in debug builds set all indices to a common magic value
 		// in debug builds set all indices to a common magic value
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		this->mIndices[0] = 0xffffffff;
 		this->mIndices[0] = 0xffffffff;
 		this->mIndices[1] = 0xffffffff;
 		this->mIndices[1] = 0xffffffff;
 		this->mIndices[2] = 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;
 		++t;
 	}
 	}
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 
 
 	// debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1
 	// debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1
 	for (size_t i = 0; i < fill.size(); ++i) {
 	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
 	// check the other way round for consistency
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 
 
 	for (size_t t = 0; t < ofsadjvec.size()-1; ++t) {
 	for (size_t t = 0; t < ofsadjvec.size()-1; ++t) {
 		for (unsigned int m = 0; m <  cntadjfac[t]; ++m) {
 		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);
 							ai_assert(adj[o]-moffsets[nidx].first < mp->mNumFaces);
 							const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first];
 							const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first];
-#				ifdef _DEBUG
+#				ifdef ASSIMP_BUILD_DEBUG
 							bool haveit = false;
 							bool haveit = false;
 #				endif
 #				endif
 
 
@@ -553,7 +553,7 @@ void CatmullClarkSubdivider::InternSubdivide (
 									// fixme: replace with mod face.mNumIndices? 
 									// fixme: replace with mod face.mNumIndices? 
 									R += c0.midpoint+c1.midpoint;
 									R += c0.midpoint+c1.midpoint;
 
 
-#						ifdef _DEBUG
+#						ifdef ASSIMP_BUILD_DEBUG
 									haveit = true;
 									haveit = true;
 #						endif
 #						endif
 									break;
 									break;

+ 1 - 1
code/ValidateDataStructure.cpp

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

+ 24 - 21
code/fast_atof.h

@@ -21,23 +21,23 @@
 namespace Assimp
 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;
 	unsigned int cur = 0;
 	uint64_t value = 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;
 	bool running = true;
 	while ( running )
 	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' );
 		const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
 		
 		
 		if (new_value < value) /* numeric overflow, we rely on you */
 		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;
 		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.
 // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
 // ------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------
 template <typename Real>
 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;
 	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) );
 	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;
 		++c;
 
 
@@ -270,7 +273,7 @@ inline const char* fast_atoreal_move( const char* c, Real& out)
 		if (einv) {
 		if (einv) {
 			exp = -exp;
 			exp = -exp;
 		}
 		}
-		f *= pow(static_cast<Real>(10.0f), exp);
+		f *= pow(static_cast<Real>(10.0), exp);
 	}
 	}
 
 
 	if (inv) {
 	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
 		// 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,
 		// 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
 		// 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.
 		// memory.
 
 
 		data.resize(stream->FileSize());
 		data.resize(stream->FileSize());
 		stream->Read(&data[0],data.size(),1);
 		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);
 		BaseImporter::ConvertToUTF8(data);
 	}
 	}
 
 

+ 1 - 1
contrib/irrXML/CXMLReaderImpl.h

@@ -215,7 +215,7 @@ private:
 	{
 	{
 		char_type* start = P;
 		char_type* start = P;
 
 
-		// more forward until '<' found
+		// move forward until '<' found
 		while(*P != L'<' && *P)
 		while(*P != L'<' && *P)
 			++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
  *  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.
  *  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:
 protected:
 	/** Constructor protected, use IOSystem::Open() to create an instance. */
 	/** 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.
  *  supply a custom implementation for IOStream.
  *
  *
  *  @see Importer::SetIOHandler() */
  *  @see Importer::SetIOHandler() */
-class ASSIMP_API IOSystem : public Intern::AllocateFromAssimpHeap
+class ASSIMP_API IOSystem
+#ifndef SWIG
+	: public Intern::AllocateFromAssimpHeap
+#endif
 {
 {
 public:
 public:
 
 

+ 17 - 1
include/assimp/Importer.hpp

@@ -230,6 +230,13 @@ public:
 	void SetPropertyString(const char* szName, const std::string& sValue, 
 	void SetPropertyString(const char* szName, const std::string& sValue, 
 		bool* bWasExisting = NULL);
 		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.
 	/** Get a configuration property.
 	 * @param szName Name of the property. All supported properties
 	 * @param szName Name of the property. All supported properties
@@ -270,9 +277,18 @@ public:
 	 *  The return value remains valid until the property is modified.
 	 *  The return value remains valid until the property is modified.
 	 * @see GetPropertyInteger()
 	 * @see GetPropertyInteger()
 	 */
 	 */
-	const std::string& GetPropertyString(const char* szName,
+	const std::string GetPropertyString(const char* szName,
 		const std::string& sErrorReturn = "") const;
 		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
 	/** 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 
 	 * 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
  *  Several default implementations are provided, see #aiDefaultLogStream for more
  *  details. Writing your own implementation of LogStream is just necessary if these
  *  details. Writing your own implementation of LogStream is just necessary if these
  *  are not enough for your purpose. */
  *  are not enough for your purpose. */
-class ASSIMP_API LogStream 
-	: public Intern::AllocateFromAssimpHeap	{
+class ASSIMP_API LogStream
+#ifndef SWIG
+	: public Intern::AllocateFromAssimpHeap
+#endif
+{
 protected:
 protected:
 	/** @brief	Default constructor	*/
 	/** @brief	Default constructor	*/
 	LogStream() {
 	LogStream() {

+ 5 - 2
include/assimp/Logger.hpp

@@ -56,8 +56,11 @@ class LogStream;
  *  Assimp provides a default implementation and uses it for almost all 
  *  Assimp provides a default implementation and uses it for almost all 
  *  logging stuff ('DefaultLogger'). This class defines just basic logging
  *  logging stuff ('DefaultLogger'). This class defines just basic logging
  *  behaviour and is not of interest for you. Instead, take a look at #DefaultLogger. */
  *  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:
 public:
 
 
 	// ----------------------------------------------------------------------
 	// ----------------------------------------------------------------------

+ 5 - 2
include/assimp/ProgressHandler.hpp

@@ -51,8 +51,11 @@ namespace Assimp	{
  *
  *
  *  Each #Importer instance maintains its own #ProgressHandler. The default 
  *  Each #Importer instance maintains its own #ProgressHandler. The default 
  *  implementation provided by Assimp doesn't do anything at all. */
  *  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:
 protected:
 	/** @brief	Default constructor	*/
 	/** @brief	Default constructor	*/
 	ProgressHandler () {
 	ProgressHandler () {

+ 1 - 1
include/assimp/ai_assert.h

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

+ 18 - 0
include/assimp/cimport.h

@@ -79,6 +79,7 @@ struct aiLogStream
  *  @see aiSetPropertyInteger
  *  @see aiSetPropertyInteger
  *  @see aiSetPropertyFloat
  *  @see aiSetPropertyFloat
  *  @see aiSetPropertyString
  *  @see aiSetPropertyString
+ *  @see aiSetPropertyMatrix
  */
  */
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 struct aiPropertyStore { char sentinel; };
 struct aiPropertyStore { char sentinel; };
@@ -397,6 +398,23 @@ ASSIMP_API void aiSetImportPropertyString(
 	const char* szName,
 	const char* szName,
 	const C_STRUCT aiString* st);
 	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.
 /** Construct a quaternion from a 3x3 rotation matrix.
  *  @param quat Receives the output quaternion.
  *  @param quat Receives the output quaternion.

+ 1 - 0
include/assimp/color4.h

@@ -74,6 +74,7 @@ public:
 	// comparison
 	// comparison
 	bool operator == (const aiColor4t& other) const;
 	bool operator == (const aiColor4t& other) const;
 	bool operator != (const aiColor4t& other) const;
 	bool operator != (const aiColor4t& other) const;
+	bool operator <  (const aiColor4t& other) const;
 
 
 	// color tuple access, rgba order
 	// color tuple access, rgba order
 	inline TReal operator[](unsigned int i) const;
 	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>
 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)	{
 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);
 	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	\
 #define AI_CONFIG_PP_PTV_NORMALIZE	\
 	"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
 /** @brief Configures the #aiProcess_FindDegenerates step to
  *  remove degenerated primitives from the import - immediately.
  *  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
 #	define ASSIMP_BUILD_SINGLETHREADED
 #endif
 #endif
 
 
-#ifndef ASSIMP_BUILD_SINGLETHREADED
-#	define AI_C_THREADSAFE
-#endif // !! ASSIMP_BUILD_SINGLETHREADED
-
-#ifdef _DEBUG 
+#if defined(_DEBUG) || ! defined(NDEBUG)
 #	define ASSIMP_BUILD_DEBUG
 #	define ASSIMP_BUILD_DEBUG
 #endif
 #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);
 	 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
 /** @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);
 	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;
 	const TReal* operator[] (unsigned int p_iIndex) const;
 
 
 	// comparison operators
 	// 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>
 	template <typename TOther>
 	operator aiMatrix3x3t<TOther> () const;
 	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 "matrix4x4.h"
 #include <algorithm>
 #include <algorithm>
+#include <cmath>
 #include <limits>
 #include <limits>
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -113,7 +114,7 @@ inline const TReal* aiMatrix3x3t<TReal>::operator[] (unsigned int p_iIndex) cons
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 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 &&
 	return a1 == m.a1 && a2 == m.a2 && a3 == m.a3 &&
 		   b1 == m.b1 && b2 == m.b2 && b3 == m.b3 &&
 		   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>
 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);
 	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>
 template <typename TReal>
 inline aiMatrix3x3t<TReal>& aiMatrix3x3t<TReal>::Transpose()
 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 */
 	/** construction from 3x3 matrix, remaining elements are set to identity */
 	explicit aiMatrix4x4t( const aiMatrix3x3t<TReal>& m);
 	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:
 public:
 
 
@@ -86,8 +94,10 @@ public:
 	const TReal* operator[] (unsigned int p_iIndex) const;
 	const TReal* operator[] (unsigned int p_iIndex) const;
 
 
 	// comparison operators
 	// 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. 
 	// matrix multiplication. 
 	aiMatrix4x4t& operator *= (const aiMatrix4x4t& m);
 	aiMatrix4x4t& operator *= (const aiMatrix4x4t& m);

+ 81 - 31
include/assimp/matrix4x4.inl

@@ -7,8 +7,8 @@ Copyright (c) 2006-2012, assimp team
 
 
 All rights reserved.
 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:
 conditions are met:
 
 
 * Redistributions of source code must retain the above
 * Redistributions of source code must retain the above
@@ -25,16 +25,16 @@ conditions are met:
   derived from this software without specific prior
   derived from this software without specific prior
   written permission of the assimp team.
   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
 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,
 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,
 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.
 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 "quaternion.h"
 
 
 #include <algorithm>
 #include <algorithm>
-#include <limits>
+#include <limits>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 #   include <cmath>
 #   include <cmath>
 #else
 #else
 #   include <math.h>
 #   include <math.h>
-#endif
+#endif
 
 
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 template <typename TReal>
 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(),
 	c1(), c2(), c3(1.0f), c4(),
 	d1(), d2(), d3(), d4(1.0f)
 	d1(), d2(), d3(), d4(1.0f)
 {
 {
@@ -76,13 +76,13 @@ template <typename TReal>
 aiMatrix4x4t<TReal> ::aiMatrix4x4t (TReal _a1, TReal _a2, TReal _a3, TReal _a4,
 aiMatrix4x4t<TReal> ::aiMatrix4x4t (TReal _a1, TReal _a2, TReal _a3, TReal _a4,
 			  TReal _b1, TReal _b2, TReal _b3, TReal _b4,
 			  TReal _b1, TReal _b2, TReal _b3, TReal _b4,
 			  TReal _c1, TReal _c2, TReal _c3, TReal _c4,
 			  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),
 	c1(_c1), c2(_c2), c3(_c3), c4(_c4),
 	d1(_d1), d2(_d2), d3(_d3), d4(_d4)
 	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);
 	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>
 template <typename TReal>
 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::operator *= (const aiMatrix4x4t<TReal>& m)
 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::operator *= (const aiMatrix4x4t<TReal>& m)
@@ -160,10 +188,10 @@ inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Transpose()
 template <typename TReal>
 template <typename TReal>
 inline TReal aiMatrix4x4t<TReal>::Determinant() const
 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
 		+ 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;
 		- 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
 	// Compute the reciprocal determinant
 	const TReal det = 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
 		// Matrix not invertible. Setting all elements to nan is not really
 		// correct in a mathematical sense but it is easy to debug for the
 		// 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.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.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.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;
 	*this = res;
 
 
 	return *this;
 	return *this;
@@ -231,7 +259,7 @@ inline const TReal* aiMatrix4x4t<TReal>::operator[](unsigned int p_iIndex) const
 
 
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 template <typename TReal>
 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 &&
 	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 &&
 			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>
 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);
 	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>
 template <typename TReal>
 inline void aiMatrix4x4t<TReal>::Decompose (aiVector3t<TReal>& scaling, aiQuaterniont<TReal>& rotation,
 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 &&
 			d1 <= epsilon && d1 >= -epsilon &&
 			d2 <= epsilon && d2 >= -epsilon &&
 			d2 <= epsilon && d2 >= -epsilon &&
 			d3 <= epsilon && d3 >= -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);
 			d4 <= 1.f+epsilon && d4 >= 1.f-epsilon);
 }
 }
 
 
@@ -477,9 +527,9 @@ inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Scaling( const aiVector3t<TReal
  */
  */
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 template <typename 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)
 	const aiVector3t<TReal>& to, aiMatrix4x4t<TReal>& mtx)
-{	
+{
 	aiMatrix3x3t<TReal> m3;
 	aiMatrix3x3t<TReal> m3;
 	aiMatrix3x3t<TReal>::FromToMatrix(from,to,m3);
 	aiMatrix3x3t<TReal>::FromToMatrix(from,to,m3);
 	mtx = aiMatrix4x4t<TReal>(m3);
 	mtx = aiMatrix4x4t<TReal>(m3);

+ 1 - 1
include/assimp/mesh.h

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

+ 2 - 0
include/assimp/metadata.h

@@ -64,7 +64,9 @@ enum aiMetadataType
 	AI_AISTRING = 4,
 	AI_AISTRING = 4,
 	AI_AIVECTOR3D = 5,
 	AI_AIVECTOR3D = 5,
 
 
+#ifndef SWIG
 	FORCE_32BIT = INT_MAX
 	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 operator!= (const aiQuaterniont& o) const;
 	bool operator!= (const aiQuaterniont& o) const;
 
 
+	bool Equal(const aiQuaterniont& o, TReal epsilon = 1e-6) const;
+
 public:
 public:
 
 
 	/** Normalize the quaternion */
 	/** 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
 #ifdef __cplusplus
 #include "quaternion.h"
 #include "quaternion.h"
 
 
+#include <cmath>
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 template<typename TReal>
 template<typename TReal>
 bool aiQuaterniont<TReal>::operator== (const aiQuaterniont& o) const
 bool aiQuaterniont<TReal>::operator== (const aiQuaterniont& o) const
@@ -62,7 +64,15 @@ bool aiQuaterniont<TReal>::operator!= (const aiQuaterniont& o) const
 	return !(*this == o);
 	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
 // Constructs a quaternion from a rotation matrix

+ 17 - 17
include/assimp/scene.h

@@ -122,14 +122,14 @@ struct aiNode
 #ifdef __cplusplus
 #ifdef __cplusplus
 	/** Constructor */
 	/** Constructor */
 	aiNode() 
 	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 */
 	/** Construction from a specific name */
 	aiNode(const std::string& name) 
 	aiNode(const std::string& name) 
 		// set all members to zero by default
 		// 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
 #ifdef __cplusplus
 
 
 	//! Default constructor - set everything to 0/NULL
 	//! Default constructor - set everything to 0/NULL
-	aiScene();
+	ASSIMP_API aiScene();
 
 
 	//! Destructor
 	//! Destructor
-	~aiScene();
+	ASSIMP_API ~aiScene();
 
 
 	//! Check whether the scene contains meshes
 	//! Check whether the scene contains meshes
 	//! Unless no special scene flags are set this will always be true.
 	//! 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
 	bool operator != (const aiColor3D& other) const
 		{return r != other.r || g != other.g || b != other.b;}
 		{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 */
 	/** Component-wise addition */
 	aiColor3D operator+(const aiColor3D& c) const {
 	aiColor3D operator+(const aiColor3D& c) const {
 		return aiColor3D(r+c.r,g+c.g,b+c.b);
 		return aiColor3D(r+c.r,g+c.g,b+c.b);
@@ -247,7 +257,7 @@ struct aiString
 	{
 	{
 		data[0] = '\0';
 		data[0] = '\0';
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		// Debug build: overwrite the string on its full length with ESC (27)
 		// Debug build: overwrite the string on its full length with ESC (27)
 		memset(data+1,27,MAXLEN-1);
 		memset(data+1,27,MAXLEN-1);
 #endif
 #endif
@@ -334,7 +344,7 @@ struct aiString
 		length  = 0;
 		length  = 0;
 		data[0] = '\0';
 		data[0] = '\0';
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		// Debug build: overwrite the string on its full length with ESC (27)
 		// Debug build: overwrite the string on its full length with ESC (27)
 		memset(data+1,27,MAXLEN-1);
 		memset(data+1,27,MAXLEN-1);
 #endif
 #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
 #ifndef AI_VECTOR2D_H_INC
 #define AI_VECTOR2D_H_INC
 #define AI_VECTOR2D_H_INC
-
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 #   include <cmath>
 #   include <cmath>
 #else
 #else
 #   include <math.h>
 #   include <math.h>
 #endif
 #endif
-
+
 #include "./Compiler/pushpack1.h"
 #include "./Compiler/pushpack1.h"
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
@@ -87,6 +87,8 @@ public:
 	bool operator== (const aiVector2t& other) const;
 	bool operator== (const aiVector2t& other) const;
 	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);
 	aiVector2t& operator= (TReal f);
 	const aiVector2t SymMul(const aiVector2t& o);
 	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
 #ifdef __cplusplus
 #include "vector2.h"
 #include "vector2.h"
 
 
+#include <cmath>
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 template <typename TReal>
 template <typename TOther>
 template <typename TOther>
@@ -131,6 +133,14 @@ bool aiVector2t<TReal>::operator!= (const aiVector2t& other) const {
 	return x != other.x || y != other.y;
 	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>
 template <typename TReal>
 aiVector2t<TReal>& aiVector2t<TReal>::operator= (TReal f)	{
 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
 #ifndef AI_VECTOR3D_H_INC
 #define AI_VECTOR3D_H_INC
 #define AI_VECTOR3D_H_INC
-
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 #   include <cmath>
 #   include <cmath>
 #else
 #else
 #   include <math.h>
 #   include <math.h>
 #endif
 #endif
-
+
 #include "./Compiler/pushpack1.h"
 #include "./Compiler/pushpack1.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -89,6 +89,8 @@ public:
 	bool operator== (const aiVector3t& other) const;
 	bool operator== (const aiVector3t& other) const;
 	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>
 	template <typename TOther>
 	operator aiVector3t<TOther> () const;
 	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
 #ifdef __cplusplus
 #include "vector3.h"
 #include "vector3.h"
 
 
+#include <cmath>
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 /** Transformation of a vector by a 3x3 matrix */
 /** Transformation of a vector by a 3x3 matrix */
 template <typename TReal>
 template <typename TReal>
@@ -147,6 +149,14 @@ template <typename TReal>
 AI_FORCE_INLINE bool aiVector3t<TReal>::operator!= (const aiVector3t<TReal>& other) const {
 AI_FORCE_INLINE bool aiVector3t<TReal>::operator!= (const aiVector3t<TReal>& other) const {
 	return x != other.x || y != other.y || z != other.z;
 	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>
 template <typename TReal>
 AI_FORCE_INLINE const aiVector3t<TReal> aiVector3t<TReal>::SymMul(const aiVector3t<TReal>& o) {
 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"
 " -- Commandline toolchain --\n"
 "------------------------------------------------------ \n\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 = 
 const char* AICMD_MSG_HELP = 
 "assimp <verb> <parameters>\n\n"
 "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];
 	char szFileName[MAX_PATH*2];
 	DWORD dwTemp;
 	DWORD dwTemp;
 	if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,"ModelExportDest",NULL,NULL,(BYTE*)szFileName,&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 
 		// invent a nice default file name 
 		char* sz = std::max(strrchr(szFileName,'\\'),strrchr(szFileName,'/'));
 		char* sz = std::max(strrchr(szFileName,'\\'),strrchr(szFileName,'/'));
 		if (sz) {
 		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 {
 	else {
 		// Key was not found. Use the folder where the asset comes from
 		// 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
 	// fix file extension
 	{	char * const sz = strrchr(szFileName,'.');
 	{	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.
 	// build the stupid info string for GetSaveFileName() - can't use sprintf() because the string must contain binary zeros.
 	char desc[256] = {0};
 	char desc[256] = {0};
 	char* c = strcpy(desc,e->description) + strlen(e->description)+1;
 	char* c = strcpy(desc,e->description) + strlen(e->description)+1;
 	c += sprintf(c,"*.%s",e->fileExtension)+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);
 	const std::string ext = "."+std::string(e->fileExtension);
 	OPENFILENAME sFilename1 = {
 	OPENFILENAME sFilename1 = {
@@ -1084,7 +1092,15 @@ void DoExport(size_t formatId)
 	}
 	}
 
 
 	// export the file
 	// 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) {
 	if (res == aiReturn_SUCCESS) {
 		CLogDisplay::Instance().AddEntry("[INFO] Exported file " + sFinal,D3DCOLOR_ARGB(0xFF,0x00,0xFF,0x00));
 		CLogDisplay::Instance().AddEntry("[INFO] Exported file " + sFinal,D3DCOLOR_ARGB(0xFF,0x00,0xFF,0x00));
 		return;
 		return;