Browse Source

- added another boost dependency.
- further work on the collada loader. Should load static geometry correctly now, but still not properly integrated
- added some Collada sample files. The license is hopefully fine with this.

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

ulfjorensen 17 years ago
parent
commit
fe3c008301

+ 1 - 0
code/AssimpPCH.h

@@ -117,6 +117,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #	include <boost/scoped_array.hpp>
 #	include <boost/format.hpp>
 #	include	<boost/math/common_factor_rt.hpp> 
+#	include <boost/foreach.hpp>
 
 #endif
 

+ 532 - 0
code/ColladaParser.cpp

@@ -72,6 +72,8 @@ ColladaParser::~ColladaParser()
 	delete mReader;
 	for( NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it)
 		delete it->second;
+	for( MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it)
+		delete it->second;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -163,6 +165,9 @@ void ColladaParser::ReadAssetInfo()
 		} 
 		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
 		{
+			if( strcmp( mReader->getNodeName(), "asset") != 0)
+				ThrowException( "Expected end of \"asset\" element.");
+
 			break;
 		}
 	}
@@ -172,9 +177,493 @@ void ColladaParser::ReadAssetInfo()
 // Reads the geometry library contents
 void ColladaParser::ReadGeometryLibrary()
 {
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "geometry"))
+			{
+				// read ID. Another entry which is "optional" by design but obligatory in reality
+				int indexID = GetAttribute( "id");
+				std::string id = mReader->getAttributeValue( indexID);
+
+				// TODO: (thom) support SIDs
+				assert( TestAttribute( "sid") == -1);
+
+				// a <geometry> always contains a single <mesh> element inside, so we just skip that element in advance
+				TestOpening( "mesh");
+
+				// create a mesh and store it in the library under its ID
+				Mesh* mesh = new Mesh;
+				mMeshLibrary[id] = mesh;
+				// read on from there
+				ReadMesh( mesh);
+
+				// check for the closing tag of the outer <geometry" element, the inner closing of <mesh> has been consumed by ReadMesh()
+				TestClosing( "geometry");
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "library_geometries") != 0)
+				ThrowException( "Expected end of \"library_geometries\" element.");
+
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads a mesh from the geometry library
+void ColladaParser::ReadMesh( Mesh* pMesh)
+{
+	// I'm doing a dirty state parsing here because I don't want to open another submethod for it.
+	// There's a <source> tag defining the name for the accessor inside, and possible a <float_array>
+	// with it's own ID. This string contains the current source's ID if parsing is inside a <source> element.
+	std::string presentSourceID;
+
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "source"))
+			{
+				// beginning of a source element - store ID for the inner elements
+				int attrID = GetAttribute( "id");
+				presentSourceID = mReader->getAttributeValue( attrID);
+			}
+			else if( IsElement( "float_array"))
+			{
+				ReadFloatArray();
+			}
+			else if( IsElement( "technique_common"))
+			{
+				// I don't fucking care for your profiles bullshit
+			}
+			else if( IsElement( "accessor"))
+			{
+				ReadAccessor( presentSourceID);
+			} 
+			else if( IsElement( "vertices"))
+			{
+				// read per-vertex mesh data
+				ReadVertexData( pMesh);
+			}
+			else if( IsElement( "polylist") || IsElement( "triangles"))
+			{
+				// read per-index mesh data and faces setup
+				ReadIndexData( pMesh);
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "source") == 0)
+			{
+				// end of <source> - reset present source ID
+				presentSourceID.clear();
+			}
+			else if( strcmp( mReader->getNodeName(), "technique_common") == 0)
+			{
+				// end of another meaningless element - read over it
+			} 
+			else if( strcmp( mReader->getNodeName(), "mesh") == 0)
+			{
+				// end of <mesh> element - we're done here
+				break;
+			} else
+			{
+				// everything else should be punished
+				ThrowException( "Expected end of \"mesh\" element.");
+			}
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads a data array holding a number of floats, and stores it in the global library
+void ColladaParser::ReadFloatArray()
+{
+	// read attributes
+	int indexID = GetAttribute( "id");
+	std::string id = mReader->getAttributeValue( indexID);
+	int indexCount = GetAttribute( "count");
+	unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( indexCount);
+	const char* content = GetTextContent();
+
+	// read values and store inside an array in the data library
+	mDataLibrary[id] = Data();
+	Data& data = mDataLibrary[id];
+	data.mValues.reserve( count);
+	for( unsigned int a = 0; a < count; a++)
+	{
+		if( *content == 0)
+			ThrowException( "Expected more values while reading float_array contents.");
+
+		float value;
+		// read a number
+		content = fast_atof_move( content, value);
+		data.mValues.push_back( value);
+		// skip whitespace after it
+		SkipSpacesAndLineEnd( &content);
+	}
+
+	// test for closing tag
+	TestClosing( "float_array");
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads an accessor and stores it in the global library
+void ColladaParser::ReadAccessor( const std::string& pID)
+{
+	// read accessor attributes
+	int attrSource = GetAttribute( "source");
+	const char* source = mReader->getAttributeValue( attrSource);
+	if( source[0] != '#')
+		ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\".") % source));
+	int attrCount = GetAttribute( "count");
+	unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( attrCount);
+	int attrOffset = TestAttribute( "offset");
+	unsigned int offset = 0;
+	if( attrOffset > -1)
+		offset = (unsigned int) mReader->getAttributeValueAsInt( attrOffset);
+	int attrStride = TestAttribute( "stride");
+	unsigned int stride = 1;
+	if( attrStride > -1)
+		stride = (unsigned int) mReader->getAttributeValueAsInt( attrStride);
+
+	// store in the library under the given ID
+	mAccessorLibrary[pID] = Accessor();
+	Accessor& acc = mAccessorLibrary[pID];
+	acc.mCount = count;
+	acc.mOffset = offset;
+	acc.mStride = stride;
+	acc.mSource = source+1; // ignore the leading '#'
+
+	// and read the components
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "param"))
+			{
+				// read data param
+				int attrName = TestAttribute( "name");
+				std::string name;
+				if( attrName > -1)
+				{
+					name = mReader->getAttributeValue( attrName);
+
+					// analyse for common type components and store it's sub-offset in the corresponding field
+					if( name == "X") acc.mSubOffset[0] = acc.mParams.size();
+					else if( name == "Y") acc.mSubOffset[1] = acc.mParams.size();
+					else if( name == "Z") acc.mSubOffset[2] = acc.mParams.size();
+					else if( name == "R") acc.mSubOffset[0] = acc.mParams.size();
+					else if( name == "G") acc.mSubOffset[1] = acc.mParams.size();
+					else if( name == "B") acc.mSubOffset[2] = acc.mParams.size();
+					else if( name == "A") acc.mSubOffset[3] = acc.mParams.size();
+					else if( name == "S") acc.mSubOffset[0] = acc.mParams.size();
+					else if( name == "T") acc.mSubOffset[1] = acc.mParams.size();
+					else
+						DefaultLogger::get()->warn( boost::str( boost::format( "Unknown accessor parameter \"%s\". Ignoring data channel.") % name));
+				}
+
+				acc.mParams.push_back( name);
+
+				// skip remaining stuff of this element, if any
+				SkipElement();
+			} else
+			{
+				ThrowException( "Unexpected sub element in tag \"accessor\".");
+			}
+		} 
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "accessor") != 0)
+				ThrowException( "Expected end of \"accessor\" element.");
+
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads input declarations of per-vertex mesh data into the given mesh
+void ColladaParser::ReadVertexData( Mesh* pMesh)
+{
+	// extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about
+	int attrID= GetAttribute( "id");
+	pMesh->mVertexID = mReader->getAttributeValue( attrID);
+
+	// a number of <input> elements
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "input"))
+			{
+				ReadInputChannel( pMesh->mPerVertexData);
+			} else
+			{
+				ThrowException( "Unexpected sub element in tag \"vertices\".");
+			}
+		} 
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "vertices") != 0)
+				ThrowException( "Expected end of \"vertices\" element.");
+
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads input declarations of per-index mesh data into the given mesh
+void ColladaParser::ReadIndexData( Mesh* pMesh)
+{
+	std::vector<size_t> vcount;
+	std::vector<InputChannel> perIndexData;
+
+	// read primitive count from the attribute
+	int attrCount = GetAttribute( "count");
+	size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount);
+
+	// distinguish between polys and triangles
+	std::string elementName = mReader->getNodeName();
+	bool isPolylist = IsElement( "polylist");
+
+	// also a number of <input> elements, but in addition a <p> primitive collection and propably index counts for all primitives
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "input"))
+			{
+				ReadInputChannel( perIndexData);
+			} 
+			else if( IsElement( "vcount"))
+			{
+				// case <polylist> - specifies the number of indices for each polygon
+				const char* content = GetTextContent();
+				vcount.reserve( numPrimitives);
+				for( unsigned int a = 0; a < numPrimitives; a++)
+				{
+					if( *content == 0)
+						ThrowException( "Expected more values while reading vcount contents.");
+					// read a number
+					vcount.push_back( (size_t) strtol10( content, &content));
+					// skip whitespace after it
+					SkipSpacesAndLineEnd( &content);
+				}
+				
+				TestClosing( "vcount");
+			}
+			else if( IsElement( "p"))
+			{
+				// now here the actual fun starts - these are the indices to construct the mesh data from
+				ReadPrimitives( pMesh, perIndexData, numPrimitives, vcount, isPolylist);
+			} else
+			{
+				ThrowException( "Unexpected sub element in tag \"vertices\".");
+			}
+		} 
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( mReader->getNodeName() != elementName)
+				ThrowException( boost::str( boost::format( "Expected end of \"%s\" element.") % elementName));
+
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads a single input channel element and stores it in the given array, if valid 
+void ColladaParser::ReadInputChannel( std::vector<InputChannel>& poChannels)
+{
+	InputChannel channel;
+	
+	// read semantic
+	int attrSemantic = GetAttribute( "semantic");
+	std::string semantic = mReader->getAttributeValue( attrSemantic);
+	channel.mType = GetTypeForSemantic( semantic);
+
+	// read source
+	int attrSource = GetAttribute( "source");
+	const char* source = mReader->getAttributeValue( attrSource);
+	if( source[0] != '#')
+		ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\".") % source));
+	channel.mAccessor = source+1; // skipping the leading #, hopefully the remaining text is the accessor ID only
+
+	// read index offset, if per-index <input>
+	int attrOffset = TestAttribute( "offset");
+	if( attrOffset > -1)
+		channel.mOffset = mReader->getAttributeValueAsInt( attrOffset);
+
+	// store, if valid type
+	if( channel.mType != IT_Invalid)
+		poChannels.push_back( channel);
+
+	// skip remaining stuff of this element, if any
 	SkipElement();
 }
 
+// ------------------------------------------------------------------------------------------------
+// Reads a <p> primitive index list and assembles the mesh data into the given mesh
+void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels, 
+								   size_t pNumPrimitives, const std::vector<size_t>& pVCount, bool pIsPolylist)
+{
+	// determine number of indices coming per vertex 
+	// find the offset index for all per-vertex channels
+	size_t numOffsets = 1;
+	size_t perVertexOffset = -1; // invalid value
+	BOOST_FOREACH( const InputChannel& channel, pPerIndexChannels)
+	{
+		numOffsets = std::max( numOffsets, channel.mOffset+1);
+		if( channel.mType == IT_Vertex)
+			perVertexOffset = channel.mOffset;
+	}
+
+	// determine the expected number of indices 
+	size_t expectedPointCount = 0;
+	if( pIsPolylist)
+	{
+		BOOST_FOREACH( size_t i, pVCount)
+			expectedPointCount += i;
+	} else
+	{
+		// everything triangles
+		expectedPointCount = 3 * pNumPrimitives;
+	}
+
+	// and read all indices into a temporary array
+	std::vector<size_t> indices( expectedPointCount * numOffsets);
+	const char* content = GetTextContent();
+	BOOST_FOREACH( size_t& value, indices)
+	{
+		if( *content == 0)
+			ThrowException( "Expected more values while reading primitive indices.");
+		// read a value in place
+		value = strtol10( content, &content);
+		// skip whitespace after it
+		SkipSpacesAndLineEnd( &content);
+	}
+
+	// find the data for all sources
+	BOOST_FOREACH( InputChannel& input, pMesh->mPerVertexData)
+	{
+		// find accessor
+		input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
+		// resolve accessor's data pointer as well, if neccessary
+		const Accessor* acc = input.mResolved;
+		if( !acc->mData)
+			acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
+	}
+	// and the same for the per-index channels
+	BOOST_FOREACH( InputChannel& input, pPerIndexChannels)
+	{
+		// ignore vertex pointer, it doesn't refer to an accessor
+		if( input.mType == IT_Vertex)
+		{
+			// warn if the vertex channel does not refer to the <vertices> element in the same mesh
+			if( input.mAccessor != pMesh->mVertexID)
+				ThrowException( "Unsupported vertex referencing scheme. I fucking hate Collada.");
+			continue;
+		}
+
+		// find accessor
+		input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
+		// resolve accessor's data pointer as well, if neccessary
+		const Accessor* acc = input.mResolved;
+		if( !acc->mData)
+			acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
+	}
+
+
+	// now assemble vertex data according to those indices
+	std::vector<size_t>::const_iterator idx = indices.begin();
+	for( size_t a = 0; a < pNumPrimitives; a++)
+	{
+		// determine number of points for this primitive
+		size_t numPoints = 3;
+		if( pIsPolylist)
+			numPoints = pVCount[a];
+
+		// store the face size to later reconstruct the face from
+		pMesh->mFaceSize.push_back( numPoints);
+
+		// gather that number of vertices
+		for( size_t b = 0; b < numPoints; b++)
+		{
+			// read all indices for this vertex. Yes, in a hacky static array
+			assert( numOffsets < 20);
+			static size_t vindex[20];
+			for( size_t offsets = 0; offsets < numOffsets; ++offsets)
+				vindex[offsets] = *idx++;
+
+			// extract per-vertex channels using the global per-vertex offset
+			BOOST_FOREACH( const InputChannel& input, pMesh->mPerVertexData)
+				ExtractDataObjectFromChannel( input, vindex[perVertexOffset], pMesh);
+			// and extract per-index channels using there specified offset
+			BOOST_FOREACH( const InputChannel& input, pPerIndexChannels)
+				ExtractDataObjectFromChannel( input, vindex[input.mOffset], pMesh);
+		}
+	}
+
+	// if I ever get my hands on that guy how invented this steaming pile of indirection...
+	TestClosing( "p");
+}
+
+// ------------------------------------------------------------------------------------------------
+// Extracts a single object from an input channel and stores it in the appropriate mesh data array 
+void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh)
+{
+	// ignore vertex referrer - we handle them that separate
+	if( pInput.mType == IT_Vertex)
+		return;
+
+	const Accessor& acc = *pInput.mResolved;
+	if( pLocalIndex >= acc.mCount)
+		ThrowException( boost::str( boost::format( "Invalid data index (%d/%d) in primitive specification") % pLocalIndex % acc.mCount));
+
+	// get a pointer to the start of the data object referred to by the accessor and the local index
+	const float* dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex* acc.mStride;
+	
+	// assemble according to the accessors component sub-offset list. We don't care, yet, what kind of object exactly we're extracting here
+	float obj[4];
+	for( size_t c = 0; c < 4; ++c)
+		obj[c] = dataObject[acc.mSubOffset[c]];
+
+	// now we reinterpret it according to the type we're reading here
+	switch( pInput.mType)
+	{
+		case IT_Position: // ignore all position streams except 0 - there can be only one position
+			if( pInput.mIndex == 0)
+				pMesh->mPositions.push_back( aiVector3D( obj[0], obj[1], obj[2])); 
+			break;
+		case IT_Normal: // ignore all normal streams except 0 - there can be only one normal
+			if( pInput.mIndex == 0)
+				pMesh->mNormals.push_back( aiVector3D( obj[0], obj[1], obj[2])); 
+			break;
+		case IT_Texcoord: // up to 4 texture coord sets are fine, ignore the others
+			if( pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS)
+				pMesh->mTexCoords[pInput.mIndex].push_back( aiVector2D( obj[0], obj[1])); 
+			break;
+		case IT_Color: // up to 4 color sets are fine, ignore the others
+			if( pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS)
+				pMesh->mColors[pInput.mIndex].push_back( aiColor4D( obj[0], obj[1], obj[2], obj[3])); 
+			break;
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // Reads the library of node hierarchies and scene parts
 void ColladaParser::ReadSceneLibrary()
@@ -214,6 +703,9 @@ void ColladaParser::ReadSceneLibrary()
 		}
 		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
 		{
+			if( strcmp( mReader->getNodeName(), "library_visual_scenes") != 0)
+				ThrowException( "Expected end of \"library_visual_scenes\" element.");
+
 			break;
 		}
 	}
@@ -371,6 +863,22 @@ void ColladaParser::SkipElement()
 	}
 }
 
+// ------------------------------------------------------------------------------------------------
+// Tests for an opening element of the given name, throws an exception if not found
+void ColladaParser::TestOpening( const char* pName)
+{
+	// read element start
+	if( !mReader->read())
+		ThrowException( boost::str( boost::format( "Unexpected end of file while beginning of \"%s\" element.") % pName));
+	// whitespace in front is ok, just read again if found
+	if( mReader->getNodeType() == irr::io::EXN_TEXT)
+		if( !mReader->read())
+			ThrowException( boost::str( boost::format( "Unexpected end of file while reading beginning of \"%s\" element.") % pName));
+
+	if( mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp( mReader->getNodeName(), pName) != 0)
+		ThrowException( boost::str( boost::format( "Expected start of \"%s\" element.") % pName));
+}
+
 // ------------------------------------------------------------------------------------------------
 // Tests for the closing tag of the given element, throws an exception if not found
 void ColladaParser::TestClosing( const char* pName)
@@ -378,6 +886,11 @@ 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));
+	// whitespace in front is ok, just read again if found
+	if( mReader->getNodeType() == irr::io::EXN_TEXT)
+		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));
 }
@@ -482,3 +995,22 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform
 
 	return res;
 }
+
+// ------------------------------------------------------------------------------------------------
+// Determines the input data type for the given semantic string
+ColladaParser::InputType ColladaParser::GetTypeForSemantic( const std::string& pSemantic)
+{
+	if( pSemantic == "POSITION")
+		return IT_Position;
+	else if( pSemantic == "TEXCOORD")
+		return IT_Texcoord;
+	else if( pSemantic == "NORMAL")
+		return IT_Normal;
+	else if( pSemantic == "COLOR")
+		return IT_Color;
+	else if( pSemantic == "VERTEX")
+		return IT_Vertex;
+
+	DefaultLogger::get()->warn( boost::str( boost::format( "Unknown vertex input type \"%s\". Ignoring.") % pSemantic));
+	return IT_Invalid;
+}

+ 110 - 5
code/ColladaParser.h

@@ -97,16 +97,65 @@ public:
 	/** 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
+		size_t mCount;   // in number of objects
+		size_t mOffset;  // in number of values
+		size_t mStride;  // Stride in number of values
+		std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore. 
+		size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
+							  // For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
 		std::string mSource;   // URL of the source array
+		mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
+
+		Accessor() 
+		{ 
+			mCount = 0; mOffset = 0; mStride = 0; mData = NULL; 
+			mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
+		}
+	};
+
+	/** A single face in a mesh */
+	struct Face
+	{
+		std::vector<size_t> mIndices;
+	};
+
+	/** Different types of input data to a vertex or face */
+	enum InputType
+	{
+		IT_Invalid,
+		IT_Vertex,  // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
+		IT_Position,
+		IT_Normal,
+		IT_Texcoord,
+		IT_Color
+	};
+
+	/** An input channel for mesh data, referring to a single accessor */
+	struct InputChannel
+	{
+		InputType mType;      // Type of the data
+		size_t mIndex;		  // Optional index, if multiple sets of the same data type are given
+		size_t mOffset;       // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
+		std::string mAccessor; // ID of the accessor where to read the actual values from.
+		mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
+
+		InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
 	};
 
 	/** Contains data for a single mesh */
 	struct Mesh
 	{
-		
+		std::string mVertexID; // just to check if there's some sophisticated addressing involved... which we don't support, and therefore should warn about.
+		std::vector<InputChannel> mPerVertexData; // Vertex data addressed by vertex indices
+
+		// actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
+		std::vector<aiVector3D> mPositions;
+		std::vector<aiVector3D> mNormals;
+		std::vector<aiVector2D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+		std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
+
+		// Faces. Stored are only the number of vertices for each face. 1 == point, 2 == line, 3 == triangle, 4+ == poly
+		std::vector<size_t> mFaceSize;
 	};
 
 protected:
@@ -129,7 +178,31 @@ protected:
 	void ReadGeometryLibrary();
 
 	/** Reads a mesh from the geometry library */
-	void ReadGeometry();
+	void ReadMesh( Mesh* pMesh);
+
+	/** Reads a data array holding a number of floats, and stores it in the global library */
+	void ReadFloatArray();
+
+	/** Reads an accessor and stores it in the global library under the given ID - 
+	 * accessors use the ID of the parent <source> element
+	 */
+	void ReadAccessor( const std::string& pID);
+
+	/** Reads input declarations of per-vertex mesh data into the given mesh */
+	void ReadVertexData( Mesh* pMesh);
+
+	/** Reads input declarations of per-index mesh data into the given mesh */
+	void ReadIndexData( Mesh* pMesh);
+
+	/** Reads a single input channel element and stores it in the given array, if valid */
+	void ReadInputChannel( std::vector<InputChannel>& poChannels);
+
+	/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
+	void ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels, 
+		size_t pNumPrimitives, const std::vector<size_t>& pVCount, bool pIsPolylist);
+
+	/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
+	void ExtractDataObjectFromChannel( const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh);
 
 	/** Reads the library of node hierarchies and scene parts */
 	void ReadSceneLibrary();
@@ -153,6 +226,9 @@ protected:
 	/** 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 opening tag of the given element, throws an exception if not found */
+	void TestOpening( const char* pName);
+
 	/** Tests for the closing tag of the given element, throws an exception if not found */
 	void TestClosing( const char* pName);
 
@@ -168,6 +244,12 @@ protected:
 	/** Calculates the resulting transformation fromm all the given transform steps */
 	aiMatrix4x4 CalculateResultTransform( const std::vector<Transform>& pTransforms) const;
 
+	/** Determines the input data type for the given semantic string */
+	InputType GetTypeForSemantic( const std::string& pSemantic);
+
+	/** Finds the item in the given library by its reference, throws if not found */
+	template <typename Type> const Type& ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
+
 protected:
 	/** Filename, for a verbose error message */
 	std::string mFileName;
@@ -175,6 +257,18 @@ protected:
 	/** XML reader */
 	irr::io::IrrXMLReader* mReader;
 
+	/** All data arrays found in the file by ID. Might be referred to by actually everyone. Collada, you are a steaming pile of indirection. */
+	typedef std::map<std::string, Data> DataLibrary;
+	DataLibrary mDataLibrary;
+
+	/** Same for accessors which define how the data in a data array is accessed. */
+	typedef std::map<std::string, Accessor> AccessorLibrary;
+	AccessorLibrary mAccessorLibrary;
+
+	/** Mesh library: mesh by ID */
+	typedef std::map<std::string, Mesh*> MeshLibrary;
+	MeshLibrary mMeshLibrary;
+
 	/** node library: root node of the hierarchy part by ID */
 	typedef std::map<std::string, Node*> NodeLibrary;
 	NodeLibrary mNodeLibrary;
@@ -189,6 +283,17 @@ protected:
 	enum { UP_X, UP_Y, UP_Z } mUpDirection;
 };
 
+// ------------------------------------------------------------------------------------------------
+// Finds the item in the given library by its reference, throws if not found
+template <typename Type> 
+const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const
+{
+	std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
+	if( it == pLibrary.end())
+		ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL));
+	return it->second;
+}
+
 } // end of namespace Assimp
 
 #endif // AI_COLLADAPARSER_H_INC

File diff suppressed because it is too large
+ 202 - 0
test/Collada/COLLADA.dae


File diff suppressed because it is too large
+ 201 - 0
test/Collada/COLLADA_triangulate.dae


BIN
test/Collada/Collada_Sample.jpg


+ 210 - 0
test/Collada/cube.dae

@@ -0,0 +1,210 @@
+<?xml version="1.0"?>
+<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
+    <asset>
+        <contributor>
+            <author>alorino</author>
+            <authoring_tool>Maya 7.0 | ColladaMaya v2.01 Jun  9 2006 at 16:08:19 | FCollada v1.11</authoring_tool>
+            <comments>Collada Maya Export Options: bakeTransforms=0;exportPolygonMeshes=1;bakeLighting=0;isSampling=0;
+curveConstrainSampling=0;exportCameraAsLookat=0;
+exportLights=1;exportCameras=1;exportJointsAndSkin=1;
+exportAnimations=1;exportTriangles=0;exportInvisibleNodes=0;
+exportNormals=1;exportTexCoords=1;exportVertexColors=1;exportTangents=0;
+exportTexTangents=0;exportConstraints=0;exportPhysics=0;exportXRefs=1;
+dereferenceXRefs=0;cameraXFov=0;cameraYFov=1</comments>
+            <copyright>
+Copyright 2006 Sony Computer Entertainment Inc.
+Licensed under the SCEA Shared Source License, Version 1.0 (the
+&quot;License&quot;); you may not use this file except in compliance with the
+License. You may obtain a copy of the License at:
+http://research.scea.com/scea_shared_source_license.html 
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+</copyright>
+        </contributor>
+        <created>2006-06-21T21:23:22Z</created>
+        <modified>2006-06-21T21:23:22Z</modified>
+        <unit meter="0.01" name="centimeter"/>
+        <up_axis>Y_UP</up_axis>
+    </asset>
+    <library_cameras>
+        <camera id="PerspCamera" name="PerspCamera">
+            <optics>
+                <technique_common>
+                    <perspective>
+                        <yfov>37.8493</yfov>
+                        <aspect_ratio>1</aspect_ratio>
+                        <znear>10</znear>
+                        <zfar>1000</zfar>
+                    </perspective>
+                </technique_common>
+            </optics>
+        </camera>
+        <camera id="testCameraShape" name="testCameraShape">
+            <optics>
+                <technique_common>
+                    <perspective>
+                        <yfov>37.8501</yfov>
+                        <aspect_ratio>1</aspect_ratio>
+                        <znear>0.01</znear>
+                        <zfar>1000</zfar>
+                    </perspective>
+                </technique_common>
+            </optics>
+        </camera>
+    </library_cameras>
+    <library_lights>
+        <light id="light-lib" name="light">
+            <technique_common>
+                <point>
+                    <color>1 1 1</color>
+                    <constant_attenuation>1</constant_attenuation>
+                    <linear_attenuation>0</linear_attenuation>
+                    <quadratic_attenuation>0</quadratic_attenuation>
+                </point>
+            </technique_common>
+            <technique profile="MAX3D">
+                <intensity>1.000000</intensity>
+            </technique>
+        </light>
+        <light id="pointLightShape1-lib" name="pointLightShape1">
+            <technique_common>
+                <point>
+                    <color>1 1 1</color>
+                    <constant_attenuation>1</constant_attenuation>
+                    <linear_attenuation>0</linear_attenuation>
+                    <quadratic_attenuation>0</quadratic_attenuation>
+                </point>
+            </technique_common>
+        </light>
+    </library_lights>
+    <library_materials>
+        <material id="Blue" name="Blue">
+            <instance_effect url="#Blue-fx"/>
+        </material>
+    </library_materials>
+    <library_effects>
+        <effect id="Blue-fx">
+            <profile_COMMON>
+                <technique sid="common">
+                    <phong>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <color>0.137255 0.403922 0.870588 1</color>
+                        </diffuse>
+                        <specular>
+                            <color>0.5 0.5 0.5 1</color>
+                        </specular>
+                        <shininess>
+                            <float>16</float>
+                        </shininess>
+                        <reflective>
+                            <color>0 0 0 1</color>
+                        </reflective>
+                        <reflectivity>
+                            <float>0.5</float>
+                        </reflectivity>
+                        <transparent>
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                        <index_of_refraction>
+                            <float>0</float>
+                        </index_of_refraction>
+                    </phong>
+                </technique>
+            </profile_COMMON>
+        </effect>
+    </library_effects>
+    <library_geometries>
+        <geometry id="box-lib" name="box">
+            <mesh>
+                <source id="box-lib-positions" name="position">
+                    <float_array id="box-lib-positions-array" count="24">-50 50 50 50 50 50 -50 -50 50 50 -50 50 -50 50 -50 50 50 -50 -50 -50 -50 50 -50 -50</float_array>
+                    <technique_common>
+                        <accessor count="8" offset="0" source="#box-lib-positions-array" stride="3">
+                            <param name="X" type="float"></param>
+                            <param name="Y" type="float"></param>
+                            <param name="Z" type="float"></param>
+                        </accessor>
+                    </technique_common>
+                </source>
+                <source id="box-lib-normals" name="normal">
+                    <float_array id="box-lib-normals-array" count="72">0 0 1 0 0 1 0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0 0 -1 0 0 -1 0 0 -1 0 0 -1</float_array>
+                    <technique_common>
+                        <accessor count="24" offset="0" source="#box-lib-normals-array" stride="3">
+                            <param name="X" type="float"></param>
+                            <param name="Y" type="float"></param>
+                            <param name="Z" type="float"></param>
+                        </accessor>
+                    </technique_common>
+                </source>
+                <vertices id="box-lib-vertices">
+                    <input semantic="POSITION" source="#box-lib-positions"/>
+                </vertices>
+                <polylist count="6" material="BlueSG">
+                    <input offset="0" semantic="VERTEX" source="#box-lib-vertices"/>
+                    <input offset="1" semantic="NORMAL" source="#box-lib-normals"/>
+                    <vcount>4 4 4 4 4 4</vcount>
+                    <p>0 0 2 1 3 2 1 3 0 4 1 5 5 6 4 7 6 8 7 9 3 10 2 11 0 12 4 13 6 14 2 15 3 16 7 17 5 18 1 19 5 20 7 21 6 22 4 23</p>
+                </polylist>
+            </mesh>
+        </geometry>
+    </library_geometries>
+    <library_visual_scenes>
+        <visual_scene id="VisualSceneNode" name="untitled">
+            <node id="Camera" name="Camera">
+                <translate sid="translate">-427.749 333.855 655.017</translate>
+                <rotate sid="rotateY">0 1 0 -33</rotate>
+                <rotate sid="rotateX">1 0 0 -22.1954</rotate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <instance_camera url="#PerspCamera"/>
+            </node>
+            <node id="Light" name="Light">
+                <translate sid="translate">-500 1000 400</translate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <rotate sid="rotateY">0 1 0 0</rotate>
+                <rotate sid="rotateX">1 0 0 0</rotate>
+                <instance_light url="#light-lib"/>
+            </node>
+            <node id="Box" name="Box">
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <rotate sid="rotateY">0 1 0 0</rotate>
+                <rotate sid="rotateX">1 0 0 0</rotate>
+                <instance_geometry url="#box-lib">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="BlueSG" target="#Blue"/>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+            </node>
+            <node id="testCamera" name="testCamera">
+                <translate sid="translate">-427.749 333.855 655.017</translate>
+                <rotate sid="rotateY">0 1 0 -33</rotate>
+                <rotate sid="rotateX">1 0 0 -22.1954</rotate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <instance_camera url="#testCameraShape"/>
+            </node>
+            <node id="pointLight1" name="pointLight1">
+                <translate sid="translate">3 4 10</translate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <rotate sid="rotateY">0 1 0 0</rotate>
+                <rotate sid="rotateX">1 0 0 0</rotate>
+                <instance_light url="#pointLightShape1-lib"/>
+            </node>
+        </visual_scene>
+    </library_visual_scenes>
+    <scene>
+        <instance_visual_scene url="#VisualSceneNode"/>
+    </scene>
+</COLLADA>

+ 210 - 0
test/Collada/cube_triangulate.dae

@@ -0,0 +1,210 @@
+<?xml version="1.0"?>
+<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
+    <asset>
+        <contributor>
+            <author>alorino</author>
+            <authoring_tool>Maya 7.0 | ColladaMaya v2.01 Jun  9 2006 at 16:08:19 | FCollada v1.11</authoring_tool>
+            <comments>Collada Maya Export Options: bakeTransforms=0;exportPolygonMeshes=1;bakeLighting=0;isSampling=0;
+curveConstrainSampling=0;exportCameraAsLookat=0;
+exportLights=1;exportCameras=1;exportJointsAndSkin=1;
+exportAnimations=1;exportTriangles=0;exportInvisibleNodes=0;
+exportNormals=1;exportTexCoords=1;exportVertexColors=1;exportTangents=0;
+exportTexTangents=0;exportConstraints=0;exportPhysics=0;exportXRefs=1;
+dereferenceXRefs=0;cameraXFov=0;cameraYFov=1</comments>
+            <copyright>
+Copyright 2006 Sony Computer Entertainment Inc.
+Licensed under the SCEA Shared Source License, Version 1.0 (the
+&quot;License&quot;); you may not use this file except in compliance with the
+License. You may obtain a copy of the License at:
+http://research.scea.com/scea_shared_source_license.html 
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+</copyright>
+          
+        </contributor>
+        <created>2006-06-21T21:23:22Z</created>
+        <modified>2006-06-21T21:23:22Z</modified>
+        <unit meter="0.01" name="centimeter"/>
+        <up_axis>Y_UP</up_axis>
+    </asset>
+    <library_cameras>
+        <camera id="PerspCamera" name="PerspCamera">
+            <optics>
+                <technique_common>
+                    <perspective>
+                        <yfov>37.8493</yfov>
+                        <aspect_ratio>1</aspect_ratio>
+                        <znear>10</znear>
+                        <zfar>1000</zfar>
+                    </perspective>
+                </technique_common>
+            </optics>
+        </camera>
+        <camera id="testCameraShape" name="testCameraShape">
+            <optics>
+                <technique_common>
+                    <perspective>
+                        <yfov>37.8501</yfov>
+                        <aspect_ratio>1</aspect_ratio>
+                        <znear>0.01</znear>
+                        <zfar>1000</zfar>
+                    </perspective>
+                </technique_common>
+            </optics>
+        </camera>
+    </library_cameras>
+    <library_lights>
+        <light id="light-lib" name="light">
+            <technique_common>
+                <point>
+                    <color>1 1 1</color>
+                    <constant_attenuation>1</constant_attenuation>
+                    <linear_attenuation>0</linear_attenuation>
+                    <quadratic_attenuation>0</quadratic_attenuation>
+                </point>
+            </technique_common>
+            <technique profile="MAX3D">
+                <intensity>1.000000</intensity>
+            </technique>
+        </light>
+        <light id="pointLightShape1-lib" name="pointLightShape1">
+            <technique_common>
+                <point>
+                    <color>1 1 1</color>
+                    <constant_attenuation>1</constant_attenuation>
+                    <linear_attenuation>0</linear_attenuation>
+                    <quadratic_attenuation>0</quadratic_attenuation>
+                </point>
+            </technique_common>
+        </light>
+    </library_lights>
+    <library_materials>
+        <material id="Blue" name="Blue">
+            <instance_effect url="#Blue-fx"/>
+        </material>
+    </library_materials>
+    <library_effects>
+        <effect id="Blue-fx">
+            <profile_COMMON>
+                <technique sid="common">
+                    <phong>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <color>0.137255 0.403922 0.870588 1</color>
+                        </diffuse>
+                        <specular>
+                            <color>0.5 0.5 0.5 1</color>
+                        </specular>
+                        <shininess>
+                            <float>16</float>
+                        </shininess>
+                        <reflective>
+                            <color>0 0 0 1</color>
+                        </reflective>
+                        <reflectivity>
+                            <float>0.5</float>
+                        </reflectivity>
+                        <transparent>
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                        <index_of_refraction>
+                            <float>0</float>
+                        </index_of_refraction>
+                    </phong>
+                </technique>
+            </profile_COMMON>
+        </effect>
+    </library_effects>
+    <library_geometries>
+        <geometry id="box-lib" name="box">
+            <mesh>
+                <source id="box-lib-positions" name="position">
+                    <float_array id="box-lib-positions-array" count="24">-50 50 50 50 50 50 -50 -50 50 50 -50 50 -50 50 -50 50 50 -50 -50 -50 -50 50 -50 -50</float_array>
+                    <technique_common>
+                        <accessor count="8" offset="0" source="#box-lib-positions-array" stride="3">
+                            <param name="X" type="float"></param>
+                            <param name="Y" type="float"></param>
+                            <param name="Z" type="float"></param>
+                        </accessor>
+                    </technique_common>
+                </source>
+                <source id="box-lib-normals" name="normal">
+                    <float_array id="box-lib-normals-array" count="72">0 0 1 0 0 1 0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0 0 -1 0 0 -1 0 0 -1 0 0 -1</float_array>
+                    <technique_common>
+                        <accessor count="24" offset="0" source="#box-lib-normals-array" stride="3">
+                            <param name="X" type="float"></param>
+                            <param name="Y" type="float"></param>
+                            <param name="Z" type="float"></param>
+                        </accessor>
+                    </technique_common>
+                </source>
+                <vertices id="box-lib-vertices">
+                    <input semantic="POSITION" source="#box-lib-positions"/>
+                </vertices>
+                <triangles count="12" material="BlueSG">
+                    <input offset="0" semantic="VERTEX" source="#box-lib-vertices"/>
+                    <input offset="1" semantic="NORMAL" source="#box-lib-normals"/>
+                    <p>0 0 2 1 3 2 0 0 3 2 1 3 0 4 1 5 5 6 0 4 5 6 4 7 6 8 7 9 3 10 6 8 3 10 2 11 0 12 4 13 6 14 0 12 6 14 2 15 3 16 7 17 5 18 3 16 5 18 1 19 5 20 7 21 6 22 5 20 6 22 4 23</p>
+                </triangles>
+            </mesh>
+        </geometry>
+    </library_geometries>
+    <library_visual_scenes>
+        <visual_scene id="VisualSceneNode" name="untitled">
+            <node id="Camera" name="Camera">
+                <translate sid="translate">-427.749 333.855 655.017</translate>
+                <rotate sid="rotateY">0 1 0 -33</rotate>
+                <rotate sid="rotateX">1 0 0 -22.1954</rotate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <instance_camera url="#PerspCamera"/>
+            </node>
+            <node id="Light" name="Light">
+                <translate sid="translate">-500 1000 400</translate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <rotate sid="rotateY">0 1 0 0</rotate>
+                <rotate sid="rotateX">1 0 0 0</rotate>
+                <instance_light url="#light-lib"/>
+            </node>
+            <node id="Box" name="Box">
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <rotate sid="rotateY">0 1 0 0</rotate>
+                <rotate sid="rotateX">1 0 0 0</rotate>
+                <instance_geometry url="#box-lib">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="BlueSG" target="#Blue"/>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+            </node>
+            <node id="testCamera" name="testCamera">
+                <translate sid="translate">-427.749 333.855 655.017</translate>
+                <rotate sid="rotateY">0 1 0 -33</rotate>
+                <rotate sid="rotateX">1 0 0 -22.1954</rotate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <instance_camera url="#testCameraShape"/>
+            </node>
+            <node id="pointLight1" name="pointLight1">
+                <translate sid="translate">3 4 10</translate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <rotate sid="rotateY">0 1 0 0</rotate>
+                <rotate sid="rotateX">1 0 0 0</rotate>
+                <instance_light url="#pointLightShape1-lib"/>
+            </node>
+        </visual_scene>
+    </library_visual_scenes>
+    <scene>
+        <instance_visual_scene url="#VisualSceneNode"/>
+    </scene>
+</COLLADA>

File diff suppressed because it is too large
+ 122 - 0
test/Collada/duck.dae


BIN
test/Collada/duckCM.tga


BIN
test/Collada/duck_sample.jpg


File diff suppressed because it is too large
+ 122 - 0
test/Collada/duck_triangulate.dae


File diff suppressed because it is too large
+ 74 - 0
test/Collada/sphere.dae


BIN
test/Collada/sphere_sample.jpg


File diff suppressed because it is too large
+ 74 - 0
test/Collada/sphere_triangulate.dae


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