Преглед изворни кода

- first draft of the Collada importer. Compiles and runs fine, but not functional yet.
- added a "rotation around arbitrary axis" function to the matrix class

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@238 67173fc5-114c-0410-ac8e-9d2fd5bffc1f

ulfjorensen пре 17 година
родитељ
комит
1083d85b2c

+ 116 - 0
code/ColladaLoader.cpp

@@ -0,0 +1,116 @@
+/** Implementation of the Collada loader */
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (ASSIMP)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development 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 Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#include "AssimpPCH.h"
+#include "../include/aiAnim.h"
+#include "ColladaLoader.h"
+#include "ColladaParser.h"
+
+using namespace Assimp;
+
+// ------------------------------------------------------------------------------------------------
+// Constructor to be privately used by Importer
+ColladaLoader::ColladaLoader()
+{
+}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor, private as well
+ColladaLoader::~ColladaLoader()
+{
+}
+
+// ------------------------------------------------------------------------------------------------
+// Returns whether the class can handle the format of the given file. 
+bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
+{
+	// check file extension 
+	std::string::size_type pos = pFile.find_last_of('.');
+	// no file extension - can't read
+	if( pos == std::string::npos)
+		return false;
+	std::string extension = pFile.substr( pos);
+	for( std::string::iterator it = extension.begin(); it != extension.end(); ++it)
+		*it = tolower( *it);
+
+	if( extension == ".dae")
+		return true;
+
+	return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Imports the given file into the given scene structure. 
+void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
+{
+	mFileName = pFile;
+
+	// parse the input file
+	ColladaParser parser( pFile);
+
+	// build the node hierarchy from it
+	pScene->mRootNode = BuildHierarchy( parser, parser.mRootNode);
+
+	pScene->mFlags = AI_SCENE_FLAGS_INCOMPLETE;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Recursively constructs a scene node for the given parser node and returns it.
+aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const ColladaParser::Node* pNode)
+{
+	// create a node for it
+	aiNode* node = new aiNode( pNode->mName);
+	
+	// calculate the transformation matrix for it
+	node->mTransformation = pParser.CalculateResultTransform( pNode->mTransforms);
+
+	// add children
+	node->mNumChildren = pNode->mChildren.size();
+	node->mChildren = new aiNode*[node->mNumChildren];
+	for( unsigned int a = 0; a < pNode->mChildren.size(); a++)
+	{
+		node->mChildren[a] = BuildHierarchy( pParser, pNode->mChildren[a]);
+		node->mChildren[a]->mParent = node;
+	}
+
+	return node;
+}

+ 95 - 0
code/ColladaLoader.h

@@ -0,0 +1,95 @@
+/** Defines the collada loader class */
+
+/*
+Open Asset Import Library (ASSIMP)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development 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 Development 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.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef AI_COLLADALOADER_H_INC
+#define AI_COLLADALOADER_H_INC
+
+#include "BaseImporter.h"
+#include "ColladaParser.h"
+
+namespace Assimp
+{
+
+/** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing
+ * more useless stuff, so I limited the data to what I think is useful for games. 
+*/
+class ColladaLoader : public BaseImporter
+{
+	friend class Importer;
+
+protected:
+	/** Constructor to be privately used by Importer */
+	ColladaLoader();
+
+	/** Destructor, private as well */
+	~ColladaLoader();
+
+public:
+	/** Returns whether the class can handle the format of the given file. 
+	 * See BaseImporter::CanRead() for details.	*/
+	bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const;
+
+protected:
+	/** Called by Importer::GetExtensionList() for each loaded importer.
+	 * See BaseImporter::GetExtensionList() for details
+	 */
+	void GetExtensionList( std::string& append)
+	{
+		append.append("*.dae");
+	}
+
+	/** Imports the given file into the given scene structure. 
+	 * See BaseImporter::InternReadFile() for details
+	 */
+	void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
+
+	/** Recursively constructs a scene node for the given parser node and returns it. */
+	aiNode* BuildHierarchy( const ColladaParser& pParser, const ColladaParser::Node* pNode);
+
+protected:
+	/** Filename, for a verbose error message */
+	std::string mFileName;
+};
+
+} // end of namespace Assimp
+
+#endif // AI_COLLADALOADER_H_INC

+ 484 - 0
code/ColladaParser.cpp

@@ -0,0 +1,484 @@
+/** Implementation of the Collada parser helper*/
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (ASSIMP)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development 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 Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#include "AssimpPCH.h"
+#include "ColladaParser.h"
+#include "fast_atof.h"
+#include "ParsingUtils.h"
+
+using namespace Assimp;
+
+// ------------------------------------------------------------------------------------------------
+// Constructor to be privately used by Importer
+ColladaParser::ColladaParser( const std::string& pFile)
+	: mFileName( pFile)
+{
+	mRootNode = NULL;
+	mUnitSize = 1.0f;
+	mUpDirection = UP_Z;
+
+	// generate a XML reader for it
+	mReader = irr::io::createIrrXMLReader( pFile.c_str());
+	if( !mReader)
+		ThrowException( "Unable to open file.");
+
+	// start reading
+	ReadContents();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor, private as well
+ColladaParser::~ColladaParser()
+{
+	delete mReader;
+	for( NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it)
+		delete it->second;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads the contents of the file
+void ColladaParser::ReadContents()
+{
+	while( mReader->read())
+	{
+		// handle the root element "COLLADA"
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "COLLADA"))
+			{
+				ReadStructure();
+			} else
+			{
+				DefaultLogger::get()->debug( boost::str( boost::format( "Ignoring global element \"%s\".") % mReader->getNodeName()));
+				SkipElement();
+			}
+		} else
+		{
+			// skip everything else silently
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads the structure of the file
+void ColladaParser::ReadStructure()
+{
+	while( mReader->read())
+	{
+		// beginning of elements
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "asset"))
+				ReadAssetInfo();
+			else if( IsElement( "library_geometries"))
+				ReadGeometryLibrary();
+			else if( IsElement( "library_visual_scenes"))
+				ReadSceneLibrary();
+			else if( IsElement( "scene"))
+				ReadScene();
+			else
+				SkipElement();
+		} 
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads asset informations such as coordinate system informations and legal blah
+void ColladaParser::ReadAssetInfo()
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "unit"))
+			{
+				// read unit data from the element's attributes
+				int attrIndex = GetAttribute( "meter");
+				mUnitSize = mReader->getAttributeValueAsFloat( attrIndex);
+
+				// consume the trailing stuff
+				if( !mReader->isEmptyElement())
+					SkipElement();
+			} 
+			else if( IsElement( "up_axis"))
+			{
+				// read content, strip whitespace, compare
+				const char* content = GetTextContent();
+				if( strncmp( content, "X_UP", 4) == 0)
+					mUpDirection = UP_X;
+				else if( strncmp( content, "Y_UP", 4) == 0)
+					mUpDirection = UP_Y;
+				else
+					mUpDirection = UP_Z;
+
+				// check element end
+				TestClosing( "up_axis");
+			} else
+			{
+				SkipElement();
+			}
+		} 
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads the geometry library contents
+void ColladaParser::ReadGeometryLibrary()
+{
+	SkipElement();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads the library of node hierarchies and scene parts
+void ColladaParser::ReadSceneLibrary()
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			// a visual scene - generate root node under its ID and let ReadNode() do the recursive work
+			if( IsElement( "visual_scene"))
+			{
+				// read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then?
+				int indexID = GetAttribute( "id");
+				const char* attrID = mReader->getAttributeValue( indexID);
+
+				// read name if given. 
+				int indexName = TestAttribute( "name");
+				const char* attrName = "unnamed";
+				if( indexName > -1)
+					attrName = mReader->getAttributeValue( indexName);
+
+				// TODO: (thom) support SIDs
+				assert( TestAttribute( "sid") == -1);
+
+				// create a node and store it in the library under its ID
+				Node* node = new Node;
+				node->mID = attrID;
+				node->mName = attrName;
+				mNodeLibrary[node->mID] = node;
+
+				ReadSceneNode( node);
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads a scene node's contents including children and stores it in the given node
+void ColladaParser::ReadSceneNode( Node* pNode)
+{
+	// quit immediately on <bla/> elements
+	if( mReader->isEmptyElement())
+		return;
+
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "lookat"))
+				ReadNodeTransformation( pNode, TF_LOOKAT);
+			else if( IsElement( "matrix"))
+				ReadNodeTransformation( pNode, TF_MATRIX);
+			else if( IsElement( "rotate"))
+				ReadNodeTransformation( pNode, TF_ROTATE);
+			else if( IsElement( "scale"))
+				ReadNodeTransformation( pNode, TF_SCALE);
+			else if( IsElement( "skew"))
+				ReadNodeTransformation( pNode, TF_SKEW);
+			else if( IsElement( "translate"))
+				ReadNodeTransformation( pNode, TF_TRANSLATE);
+			else if( IsElement( "node"))
+			{
+				Node* child = new Node;
+				int attrID = TestAttribute( "id");
+				if( attrID > -1)
+					child->mID = mReader->getAttributeValue( attrID);
+
+				int attrName = TestAttribute( "name");
+				if( attrName > -1)
+					child->mName = mReader->getAttributeValue( attrName);
+
+				// TODO: (thom) support SIDs
+				assert( TestAttribute( "sid") == -1);
+
+				pNode->mChildren.push_back( child);
+				child->mParent = pNode;
+
+				// read on recursively from there
+				ReadSceneNode( child);
+			} else if( IsElement( "instance_node"))
+			{
+				// test for it, in case we need to implement it
+				assert( false);
+				SkipElement();
+			} else
+			{
+				// skip everything else for the moment
+				SkipElement();
+			}
+		} 
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads a node transformation entry of the given type and adds it to the given node's transformation list.
+void ColladaParser::ReadNodeTransformation( Node* pNode, TransformType pType)
+{
+	std::string tagName = mReader->getNodeName();
+
+	// how many parameters to read per transformation type
+	static const unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
+	const char* content = GetTextContent();
+
+	// read as many parameters and store in the transformation
+	Transform tf;
+	tf.mType = pType;
+	for( unsigned int a = 0; a < sNumParameters[pType]; a++)
+	{
+		// read a number
+		content = fast_atof_move( content, tf.f[a]);
+		// skip whitespace after it
+		SkipSpacesAndLineEnd( &content);
+	}
+
+	// place the transformation at the queue of the node
+	pNode->mTransforms.push_back( tf);
+
+	// and consum the closing tag
+	TestClosing( tagName.c_str());
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads the collada scene
+void ColladaParser::ReadScene()
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "instance_visual_scene"))
+			{
+				// should be the first and only occurence
+				if( mRootNode)
+					ThrowException( "Invalid scene containing multiple root nodes");
+
+				// read the url of the scene to instance. Should be of format "#some_name"
+				int urlIndex = GetAttribute( "url");
+				const char* url = mReader->getAttributeValue( urlIndex);
+				if( url[0] != '#')
+					ThrowException( "Unknown reference format");
+
+				// find the referred scene, skip the leading # 
+				NodeLibrary::const_iterator sit = mNodeLibrary.find( url+1);
+				if( sit == mNodeLibrary.end())
+					ThrowException( boost::str( boost::format( "Unable to resolve visual_scene reference \"%s\".") % url));
+				mRootNode = sit->second;
+			} else
+			{
+				SkipElement();
+			}
+		} 
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			break;
+		} 
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Aborts the file reading with an exception
+void ColladaParser::ThrowException( const std::string& pError) const
+{
+	throw new ImportErrorException( boost::str( boost::format( "%s - %s") % mFileName % pError));
+}
+
+// ------------------------------------------------------------------------------------------------
+// Skips all data until the end node of the current element
+void ColladaParser::SkipElement()
+{
+	// nothing to skip if it's an <element />
+	if( mReader->isEmptyElement())
+		return;
+
+	// copy the current node's name because it'a pointer to the reader's internal buffer, 
+	// which is going to change with the upcoming parsing 
+	std::string element = mReader->getNodeName();
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+			if( mReader->getNodeName() == element)
+				break;
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Tests for the closing tag of the given element, throws an exception if not found
+void ColladaParser::TestClosing( const char* pName)
+{
+	// read closing tag
+	if( !mReader->read())
+		ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of \"%s\" element.") % pName));
+	if( mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp( mReader->getNodeName(), pName) != 0)
+		ThrowException( boost::str( boost::format( "Expected end of \"%s\" element.") % pName));
+}
+
+// ------------------------------------------------------------------------------------------------
+// Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes
+int ColladaParser::GetAttribute( const char* pAttr) const
+{
+	int index = TestAttribute( pAttr);
+	if( index != -1)
+		return index;
+
+	// attribute not found -> throw an exception
+	ThrowException( boost::str( boost::format( "Expected attribute \"%s\" at element \"%s\".") % pAttr % mReader->getNodeName()));
+	return -1;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Tests the present element for the presence of one attribute, returns its index or throws an exception if not found
+int ColladaParser::TestAttribute( const char* pAttr) const
+{
+	for( int a = 0; a < mReader->getAttributeCount(); a++)
+		if( strcmp( mReader->getAttributeName( a), pAttr) == 0)
+			return a;
+
+	return -1;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads the text contents of an element, throws an exception if not given. Skips leading whitespace.
+const char* ColladaParser::GetTextContent()
+{
+	// present node should be the beginning of an element
+	if( mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement())
+		ThrowException( "Expected opening element");
+
+	// read contents of the element
+	if( !mReader->read())
+		ThrowException( "Unexpected end of file while reading asset up_axis element.");
+	if( mReader->getNodeType() != irr::io::EXN_TEXT)
+		ThrowException( "Invalid contents in element \"up_axis\".");
+
+	// skip leading whitespace
+	const char* text = mReader->getNodeData();
+	SkipSpacesAndLineEnd( &text);
+
+	return text;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Calculates the resulting transformation fromm all the given transform steps
+aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform>& pTransforms) const
+{
+	aiMatrix4x4 res;
+
+	for( std::vector<Transform>::const_iterator it = pTransforms.begin(); it != pTransforms.end(); ++it)
+	{
+		const Transform& tf = *it;
+		switch( tf.mType)
+		{
+			case TF_LOOKAT:
+				// TODO: (thom)
+				assert( false);
+				break;
+			case TF_ROTATE:
+			{
+				aiMatrix4x4 rot;
+				aiMatrix4x4::Rotation( tf.f[3], aiVector3D( tf.f[0], tf.f[1], tf.f[2]), rot);
+				res *= rot;
+				break;
+			}
+			case TF_TRANSLATE:
+			{
+				aiMatrix4x4 trans;
+				aiMatrix4x4::Translation( aiVector3D( tf.f[0], tf.f[1], tf.f[2]), trans);
+				res *= trans;
+				break;
+			}
+			case TF_SCALE:
+			{
+				aiMatrix4x4 scale( tf.f[0], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[1], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[2], 0.0f, 
+					0.0f, 0.0f, 0.0f, 1.0f);
+				res *= scale;
+				break;
+			}
+			case TF_SKEW:
+				// TODO: (thom)
+				assert( false);
+				break;
+			case TF_MATRIX:
+			{
+				aiMatrix4x4 mat( tf.f[0], tf.f[1], tf.f[2], tf.f[3], tf.f[4], tf.f[5], tf.f[6], tf.f[7],
+					tf.f[8], tf.f[9], tf.f[10], tf.f[11], tf.f[12], tf.f[13], tf.f[14], tf.f[15]);
+				res *= mat;
+				break;
+			}
+			default: 
+				assert( false);
+				break;
+		}
+	}
+
+	return res;
+}

+ 194 - 0
code/ColladaParser.h

@@ -0,0 +1,194 @@
+/** Defines the parser helper class for the collada loader */
+
+/*
+Open Asset Import Library (ASSIMP)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development 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 Development 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.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef AI_COLLADAPARSER_H_INC
+#define AI_COLLADAPARSER_H_INC
+
+#include "./irrXML/irrXMLWrapper.h"
+
+namespace Assimp
+{
+
+/** Parser helper class for the Collada loader. Does all the XML reading and builds internal data structures from it, 
+ * but leaves the resolving of all the references to the loader.
+*/
+class ColladaParser
+{
+	friend class ColladaLoader;
+public:
+	/** Transformation types that can be applied to a node */
+	enum TransformType
+	{
+		TF_LOOKAT,
+		TF_ROTATE,
+		TF_TRANSLATE,
+		TF_SCALE,
+		TF_SKEW,
+		TF_MATRIX
+	};
+
+	/** Contains all data for one of the different transformation types */
+	struct Transform
+	{
+		TransformType mType;
+		float f[16]; ///< Interpretation of data depends on the type of the transformation 
+	};
+
+	/** A node in a scene hierarchy */
+	struct Node
+	{
+		std::string mName;
+		std::string mID;
+		Node* mParent;
+		std::vector<Node*> mChildren;
+
+		/** Operations in order to calculate the resulting transformation to parent. */
+		std::vector<Transform> mTransforms;
+
+		Node() { mParent = NULL; }
+		~Node() { for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) delete *it; }
+	};
+
+	/** Data source array */
+	struct Data
+	{
+		std::vector<float> mValues;
+	};
+
+	/** Accessor to a data array */
+	struct Accessor
+	{
+		unsigned int mCount;   // in number of objects
+		unsigned int mOffset;  // in number of values
+		unsigned int mStride;  // Stride in number of values
+		std::string mSource;   // URL of the source array
+	};
+
+	/** Contains data for a single mesh */
+	struct Mesh
+	{
+		
+	};
+
+protected:
+	/** Constructor from XML file */
+	ColladaParser( const std::string& pFile);
+
+	/** Destructor */
+	~ColladaParser();
+
+	/** Reads the contents of the file */
+	void ReadContents();
+
+	/** Reads the structure of the file */
+	void ReadStructure();
+
+	/** Reads asset informations such as coordinate system informations and legal blah */
+	void ReadAssetInfo();
+
+	/** Reads the geometry library contents */
+	void ReadGeometryLibrary();
+
+	/** Reads a mesh from the geometry library */
+	void ReadGeometry();
+
+	/** Reads the library of node hierarchies and scene parts */
+	void ReadSceneLibrary();
+
+	/** Reads a scene node's contents including children and stores it in the given node */
+	void ReadSceneNode( Node* pNode);
+
+	/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
+	void ReadNodeTransformation( Node* pNode, TransformType pType);
+
+	/** Reads the collada scene */
+	void ReadScene();
+
+protected:
+	/** Aborts the file reading with an exception */
+	void ThrowException( const std::string& pError) const;
+
+	/** Skips all data until the end node of the current element */
+	void SkipElement();
+
+	/** Compares the current xml element name to the given string and returns true if equal */
+	bool IsElement( const char* pName) const { assert( mReader->getNodeType() == irr::io::EXN_ELEMENT); return strcmp( mReader->getNodeName(), pName) == 0; }
+
+	/** Tests for the closing tag of the given element, throws an exception if not found */
+	void TestClosing( const char* pName);
+
+	/** Checks the present element for the presence of the attribute, returns its index or throws an exception if not found */
+	int GetAttribute( const char* pAttr) const;
+
+	/** Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes */
+	int TestAttribute( const char* pAttr) const;
+
+	/** Reads the text contents of an element, throws an exception if not given. Skips leading whitespace. */
+	const char* GetTextContent();
+
+	/** Calculates the resulting transformation fromm all the given transform steps */
+	aiMatrix4x4 CalculateResultTransform( const std::vector<Transform>& pTransforms) const;
+
+protected:
+	/** Filename, for a verbose error message */
+	std::string mFileName;
+
+	/** XML reader */
+	irr::io::IrrXMLReader* mReader;
+
+	/** node library: root node of the hierarchy part by ID */
+	typedef std::map<std::string, Node*> NodeLibrary;
+	NodeLibrary mNodeLibrary;
+
+	/** Pointer to the root node. Don't delete, it just points to one of the nodes in the node library. */
+	Node* mRootNode;
+
+	/** Size unit: how large compared to a meter */
+	float mUnitSize;
+
+	/** Which is the up vector */
+	enum { UP_X, UP_Y, UP_Z } mUpDirection;
+};
+
+} // end of namespace Assimp
+
+#endif // AI_COLLADAPARSER_H_INC

+ 6 - 0
code/Importer.cpp

@@ -129,6 +129,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_BUILD_NO_B3D_IMPORTER
 #	include "B3DImporter.h"
 #endif
+#ifndef AI_BUILD_NO_COLLADA_IMPORTER
+#	include "ColladaLoader.h"
+#endif
 
 
 // PostProcess-Steps
@@ -283,6 +286,9 @@ Importer::Importer() :
 #if (!defined AI_BUILD_NO_B3D_IMPORTER)
 	mImporter.push_back( new B3DImporter());
 #endif
+#if (!defined AI_BUILD_NO_COLLADA_IMPORTER)
+	mImporter.push_back( new ColladaLoader());
+#endif
 
 	// add an instance of each post processing step here in the order 
 	// of sequence it is executed. steps that are added here are not validated -

+ 8 - 0
include/aiMatrix4x4.h

@@ -142,6 +142,14 @@ struct aiMatrix4x4
 	 */
 	static aiMatrix4x4& RotationZ(float a, aiMatrix4x4& out);
 
+	/** Returns a rotation matrix for a rotation around an arbitrary axis.
+	 *  @param a Rotation angle, in radians
+	 *  @param axis Rotation axis, should be a normalized vector.
+	 *  @param out Receives the output matrix
+	 *  \return Reference to the output matrix
+	 */
+	static aiMatrix4x4& Rotation(float a, const aiVector3D& axis, aiMatrix4x4& out);
+
 	/** \brief Returns a translation matrix 
 	 *  \param v Translation vector
 	 *  \param out Receives the output matrix

+ 19 - 0
include/aiMatrix4x4.inl

@@ -282,6 +282,25 @@ inline aiMatrix4x4& aiMatrix4x4::RotationZ(float a, aiMatrix4x4& out)
 	out.a2 = -(out.b1 = sin(a));
 	return out;
 }
+
+// ---------------------------------------------------------------------------
+// Returns a rotation matrix for a rotation around an arbitrary axis.
+inline aiMatrix4x4& aiMatrix4x4::Rotation( float a, const aiVector3D& axis, aiMatrix4x4& out)
+{
+  float c = cos( a), s = sin( a), t = 1 - c;
+  float x = axis.x, y = axis.y, z = axis.z;
+
+  // Many thanks to MathWorld and Wikipedia
+  out.a1 = t*x*x + c;   out.a2 = t*x*y - s*z; out.a3 = t*x*z + s*y;
+  out.b1 = t*x*y + s*z; out.b2 = t*y*y + c;   out.b3 = t*y*z - s*x;
+  out.c1 = t*x*z - s*y; out.c2 = t*y*z + s*x; out.c3 = t*z*z + c;
+  out.a4 = out.b4 = out.c4 = 0.0f;
+  out.d1 = out.d2 = out.d3 = 0.0f;
+  out.d4 = 1.0f;
+
+  return out;
+}
+
 // ---------------------------------------------------------------------------
 inline aiMatrix4x4& aiMatrix4x4::Translation( const aiVector3D& v, aiMatrix4x4& out)
 {

+ 0 - 9
workspaces/vc8/assimp.sln

@@ -76,30 +76,21 @@ Global
 		{5691E159-2D9B-407F-971F-EA5C592DC524}.Release|x64.ActiveCfg = Release|x64
 		{5691E159-2D9B-407F-971F-EA5C592DC524}.Release|x64.Build.0 = Release|x64
 		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug_DLL|Win32.ActiveCfg = Debug_DLL|Win32
-		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug_DLL|Win32.Build.0 = Debug_DLL|Win32
 		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
-		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
 		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug|x64.ActiveCfg = Debug|x64
-		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug|x64.Build.0 = Debug|x64
 		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32
-		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Release_DLL|Win32.Build.0 = Release_DLL|Win32
 		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
-		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Release_DLL|x64.Build.0 = Release_DLL|x64
 		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Release|Win32.ActiveCfg = Release|Win32
-		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Release|Win32.Build.0 = Release|Win32
 		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Release|x64.ActiveCfg = Release|x64
-		{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Release|x64.Build.0 = Release|x64
 		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Debug_DLL|Win32.ActiveCfg = Debug|Win32
 		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Debug_DLL|x64.ActiveCfg = Debug|x64
 		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Debug|x64.ActiveCfg = Debug|x64
-		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Debug|x64.Build.0 = Debug|x64
 		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Release_DLL|Win32.ActiveCfg = Release|Win32
 		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Release_DLL|x64.ActiveCfg = Release|x64
 		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Release|Win32.ActiveCfg = Release|Win32
 		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Release|x64.ActiveCfg = Release|x64
-		{FE78BFBA-4BA5-457D-8602-B800D498102D}.Release|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 20 - 0
workspaces/vc8/assimp.vcproj

@@ -1422,6 +1422,26 @@
 						>
 					</File>
 				</Filter>
+				<Filter
+					Name="Collada"
+					>
+					<File
+						RelativePath="..\..\code\ColladaLoader.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ColladaLoader.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ColladaParser.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ColladaParser.h"
+						>
+					</File>
+				</Filter>
 			</Filter>
 			<Filter
 				Name="PostProcess"