Forráskód Böngészése

- further Collada work: materials are now loaded from profile_COMMON, meshes are properly split up at material borders

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@260 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
ulfjorensen 17 éve
szülő
commit
917db45b3c

+ 1 - 41
code/AssimpPCH.h

@@ -44,38 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #define ASSIMP_INTERNAL_BUILD
 
-#ifdef ASSIMP_BUILD_DLL_EXPORT
-#	if _MSC_VER >= 1400
-#		pragma message( "AssimpBuild: Building Windows DLL" )
-#	endif
-#endif
-
-// *******************************************************************
-// Print detailled memory allocation statistics? In this case we'll
-// need to overload all C++ memory management functions. It is assumed
-// that old C routines, such as malloc(), are NOT used in Assimp.
-// *******************************************************************
-#ifdef ASSIMP_BUILD_MEMORY_STATISTICS
-
-	void *operator new (size_t);
-	void operator delete (void *);
-	void *operator new[] (size_t);     
-	void operator delete[] (void *);
-
-#	if _MSC_VER >= 1400
-#		pragma message( "AssimpBuild: Memory tracking enabled" )
-#	endif
-
-#endif
-
-#if _MSC_VER >= 1400
-#	ifdef _DEBUG
-#		pragma message( "AssimpBuild: Debug build" )
-#	else
-#		pragma message( "AssimpBuild: Release build" )
-#	endif
-#endif
-
 // *******************************************************************
 // If we have at least VC8 some C string manipulation functions
 // are mapped to their safe _s counterparts (e.g. _itoa_s).
@@ -98,7 +66,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <queue>
 #include <iostream>
 #include <algorithm>
-
+#include <numeric>
 
 // *******************************************************************
 // public ASSIMP headers
@@ -124,10 +92,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // *******************************************************************
 #ifdef ASSIMP_BUILD_BOOST_WORKAROUND
 
-#if _MSC_VER >= 1400
-#	pragma message( "AssimpBuild: Using -noBoost workaround" )
-#endif
-
 #	include "../include/BoostWorkaround/boost/scoped_ptr.hpp"
 #	include "../include/BoostWorkaround/boost/scoped_array.hpp"
 #	include "../include/BoostWorkaround/boost/format.hpp"
@@ -135,10 +99,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #else
 
-#if _MSC_VER >= 1400
-#	pragma message( "AssimpBuild: Using standard boost headers" )
-#endif
-
 #	include <boost/scoped_ptr.hpp>
 #	include <boost/scoped_array.hpp>
 #	include <boost/format.hpp>

+ 38 - 7
code/ColladaHelper.h

@@ -144,6 +144,13 @@ struct InputChannel
 	InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
 };
 
+/** Subset of a mesh with a certain material */
+struct SubMesh
+{
+	std::string mMaterial; ///< subgroup identifier
+	size_t mNumFaces; ///< number of faces in this submesh
+};
+
 /** Contains data for a single mesh */
 struct Mesh
 {
@@ -158,6 +165,9 @@ struct Mesh
 
 	// Faces. Stored are only the number of vertices for each face. 1 == point, 2 == line, 3 == triangle, 4+ == poly
 	std::vector<size_t> mFaceSize;
+
+	// Submeshes in this mesh, each with a given material
+	std::vector<SubMesh> mSubMeshes;
 };
 
 /** Which type of primitives the ReadPrimitives() function is going to read */
@@ -179,6 +189,20 @@ struct Material
 	std::string mEffect;
 };
 
+/** Type of the effect param */
+enum ParamType
+{
+	Param_Sampler,
+	Param_Surface
+};
+
+/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
+struct EffectParam
+{
+	ParamType mType;
+	std::string mReference; // to which other thing the param is referring to. 
+};
+
 /** Shading type supported by the standard effect spec of Collada */
 enum ShadeType
 {
@@ -194,18 +218,25 @@ enum ShadeType
 struct Effect
 {
 	ShadeType mShadeType;
-	aiColor4D mEmmisive, mAmbient, mDiffuse, mSpecular;
-	aiColor4D mReflectivity, mRefractivity;
-	std::string mTexEmmisive, mTexAmbient, mTexDiffuse, mTexSpecular;
+	aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular;
+	aiColor4D mReflective, mRefractive;
+	std::string mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular;
 	float mShininess, mRefractIndex;
+	float mReflectivity, mRefractivity;
 
-	Effect() : mEmmisive( 0, 0, 0, 1), mAmbient( 0.1f, 0.1f, 0.1f, 1),
+	// local params referring to each other by their SID
+	typedef std::map<std::string, Collada::EffectParam> ParamLibrary;
+	ParamLibrary mParams;
+	
+	Effect() : mEmissive( 0, 0, 0, 1), mAmbient( 0.1f, 0.1f, 0.1f, 1),
 		mDiffuse( 0.6f, 0.6f, 0.6f, 1), mSpecular( 0.4f, 0.4f, 0.4f, 1),
-		mReflectivity( 0, 0, 0, 0), mRefractivity( 0, 0, 0, 0)
+		mReflective( 0, 0, 0, 0), mRefractive( 0, 0, 0, 0)
 	{ 
 		mShadeType = Shade_Phong; 
-		mShininess = 10;
-		mRefractIndex = 1;
+		mShininess = 10.0f;
+		mRefractIndex = 1.0f;
+		mReflectivity = 0.0f;
+		mRefractivity = 0.0f;
 	}
 };
 

+ 192 - 70
code/ColladaLoader.cpp

@@ -87,6 +87,12 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
 	// parse the input file
 	ColladaParser parser( pFile);
 
+	if( !parser.mRootNode)
+		throw new ImportErrorException( "File came out empty. Somethings wrong here.");
+
+	// create the materials first, for the meshes to find
+	BuildMaterials( parser, pScene);
+
 	// build the node hierarchy from it
 	pScene->mRootNode = BuildHierarchy( parser, parser.mRootNode);
 
@@ -107,23 +113,6 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
 
 	// store all meshes
 	StoreSceneMeshes( pScene);
-
-	// create dummy material
-	Assimp::MaterialHelper* mat = new Assimp::MaterialHelper;
-	aiString name( std::string( "dummy"));
-	mat->AddProperty( &name, AI_MATKEY_NAME);
-
-	int shadeMode = aiShadingMode_Phong;
-	mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
-	aiColor4D colAmbient( 0.2f, 0.2f, 0.2f, 1.0f), colDiffuse( 0.8f, 0.8f, 0.8f, 1.0f), colSpecular( 0.5f, 0.5f, 0.5f, 0.5f);
-	mat->AddProperty( &colAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
-	mat->AddProperty( &colDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
-	mat->AddProperty( &colSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
-	float specExp = 5.0f;
-	mat->AddProperty( &specExp, 1, AI_MATKEY_SHININESS);
-	pScene->mNumMaterials = 1;
-	pScene->mMaterials = new aiMaterial*[1];
-	pScene->mMaterials[0] = mat;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -168,70 +157,100 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
 			DefaultLogger::get()->warn( boost::str( boost::format( "Unable to find geometry for ID \"%s\". Skipping.") % mid.mMesh));
 			continue;
 		}
+		const Collada::Mesh* srcMesh = srcMeshIt->second;
 
-		// if we already have the mesh at the library, just add its index to the node's array
-		std::map<std::string, size_t>::const_iterator dstMeshIt = mMeshIndexbyID.find( mid.mMesh);
-		if( dstMeshIt != mMeshIndexbyID.end())
+		// build a mesh for each of its subgroups
+		size_t vertexStart = 0, faceStart = 0;
+		for( size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm)
 		{
-			newMeshRefs.push_back( dstMeshIt->second);
-		} else
-		{
-			// else we have to add the mesh to the collection and store its newly assigned index at the node
-			aiMesh* dstMesh = new aiMesh;
-			const Collada::Mesh* srcMesh = srcMeshIt->second;
-
-			// copy positions
-			dstMesh->mNumVertices = srcMesh->mPositions.size();
-			dstMesh->mVertices = new aiVector3D[dstMesh->mNumVertices];
-			std::copy( srcMesh->mPositions.begin(), srcMesh->mPositions.end(), dstMesh->mVertices);
-
-			// normals, if given. HACK: (thom) Due to the fucking Collada spec we never know if we have the same
-			// number of normals as there are positions. So we also ignore any vertex attribute if it has a different count
-			if( srcMesh->mNormals.size() == dstMesh->mNumVertices)
+			const Collada::SubMesh& submesh = srcMesh->mSubMeshes[sm];
+			// find material assigned to this submesh
+			std::map<std::string, std::string>::const_iterator meshMatIt = mid.mMaterials.find( submesh.mMaterial);
+			std::string meshMaterial;
+			if( meshMatIt != mid.mMaterials.end())
+				meshMaterial = meshMatIt->second;
+			else
+				DefaultLogger::get()->warn( boost::str( boost::format( "No material specified for subgroup \"%s\" in geometry \"%s\".") % submesh.mMaterial % mid.mMesh));
+
+			// built lookup index of the Mesh-Submesh-Material combination
+			ColladaMeshIndex index( mid.mMesh, sm, meshMaterial);
+
+			// if we already have the mesh at the library, just add its index to the node's array
+			std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find( index);
+			if( dstMeshIt != mMeshIndexByID.end())
 			{
-				dstMesh->mNormals = new aiVector3D[dstMesh->mNumVertices];
-				std::copy( srcMesh->mNormals.begin(), srcMesh->mNormals.end(), dstMesh->mNormals);
-			}
-
-			// same for texturecoords, as many as we have
-			for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)
+				newMeshRefs.push_back( dstMeshIt->second);
+			} else
 			{
-				if( srcMesh->mTexCoords[a].size() == dstMesh->mNumVertices)
+				// else we have to add the mesh to the collection and store its newly assigned index at the node
+				aiMesh* dstMesh = new aiMesh;
+
+				// count the vertices addressed by its faces
+				size_t numVertices = 
+					std::accumulate( srcMesh->mFaceSize.begin() + faceStart, srcMesh->mFaceSize.begin() + faceStart + submesh.mNumFaces, 0);
+
+				// copy positions
+				dstMesh->mNumVertices = numVertices;
+				dstMesh->mVertices = new aiVector3D[numVertices];
+				std::copy( srcMesh->mPositions.begin() + vertexStart, srcMesh->mPositions.begin() + vertexStart + numVertices, dstMesh->mVertices);
+
+				// normals, if given. HACK: (thom) Due to the fucking Collada spec we never know if we have the same
+				// number of normals as there are positions. So we also ignore any vertex attribute if it has a different count
+				if( srcMesh->mNormals.size() == srcMesh->mPositions.size())
 				{
-					dstMesh->mTextureCoords[a] = new aiVector3D[dstMesh->mNumVertices];
-					for( size_t b = 0; b < dstMesh->mNumVertices; ++b)
-						dstMesh->mTextureCoords[a][b].Set( srcMesh->mTexCoords[a][b].x, srcMesh->mTexCoords[a][b].y, 0.0f);
-					dstMesh->mNumUVComponents[a] = 2;
+					dstMesh->mNormals = new aiVector3D[numVertices];
+					std::copy( srcMesh->mNormals.begin() + vertexStart, srcMesh->mNormals.begin() + vertexStart + numVertices, dstMesh->mNormals);
 				}
-			}
 
-			// same for vertex colors, as many as we have
-			for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++)
-			{
-				if( srcMesh->mColors[a].size() == dstMesh->mNumVertices)
+				// same for texturecoords, as many as we have
+				for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)
 				{
-					dstMesh->mColors[a] = new aiColor4D[dstMesh->mNumVertices];
-					std::copy( srcMesh->mColors[a].begin(), srcMesh->mColors[a].end(), dstMesh->mColors[a]);
+					if( srcMesh->mTexCoords[a].size() == srcMesh->mPositions.size())
+					{
+						dstMesh->mTextureCoords[a] = new aiVector3D[numVertices];
+						for( size_t b = vertexStart; b < vertexStart + numVertices; ++b)
+							dstMesh->mTextureCoords[a][b].Set( srcMesh->mTexCoords[a][b].x, srcMesh->mTexCoords[a][b].y, 0.0f);
+						dstMesh->mNumUVComponents[a] = 2;
+					}
 				}
-			}
 
-			// create faces. Due to the fact that each face uses unique vertices, we can simply count up on each vertex
-			size_t vertex = 0;
-			dstMesh->mNumFaces = srcMesh->mFaceSize.size();
-			dstMesh->mFaces = new aiFace[dstMesh->mNumFaces];
-			for( size_t a = 0; a < dstMesh->mNumFaces; ++a)
-			{
-				size_t s = srcMesh->mFaceSize[a];
-				aiFace& face = dstMesh->mFaces[a];
-				face.mNumIndices = s;
-				face.mIndices = new unsigned int[s];
-				for( size_t b = 0; b < s; ++b)
-					face.mIndices[b] = vertex++;
-			}
+				// same for vertex colors, as many as we have
+				for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++)
+				{
+					if( srcMesh->mColors[a].size() == srcMesh->mPositions.size())
+					{
+						dstMesh->mColors[a] = new aiColor4D[numVertices];
+						std::copy( srcMesh->mColors[a].begin() + vertexStart, srcMesh->mColors[a].begin() + vertexStart + numVertices, dstMesh->mColors[a]);
+					}
+				}
 
-			// store the mesh, and store its new index in the node
-			newMeshRefs.push_back( mMeshes.size());
-			mMeshes.push_back( dstMesh);
+				// create faces. Due to the fact that each face uses unique vertices, we can simply count up on each vertex
+				size_t vertex = 0;
+				dstMesh->mNumFaces = submesh.mNumFaces;
+				dstMesh->mFaces = new aiFace[dstMesh->mNumFaces];
+				for( size_t a = 0; a < dstMesh->mNumFaces; ++a)
+				{
+					size_t s = srcMesh->mFaceSize[ faceStart + a];
+					aiFace& face = dstMesh->mFaces[a];
+					face.mNumIndices = s;
+					face.mIndices = new unsigned int[s];
+					for( size_t b = 0; b < s; ++b)
+						face.mIndices[b] = vertex++;
+				}
+
+				// store the mesh, and store its new index in the node
+				newMeshRefs.push_back( mMeshes.size());
+				mMeshIndexByID[index] = mMeshes.size();
+				mMeshes.push_back( dstMesh);
+				vertexStart += numVertices; faceStart += submesh.mNumFaces;
+
+				// assign the material index
+				std::map<std::string, size_t>::const_iterator matIt = mMaterialIndexByName.find( meshMaterial);
+				if( matIt != mMaterialIndexByName.end())
+					dstMesh->mMaterialIndex = matIt->second;
+				else
+					dstMesh->mMaterialIndex = 0;
+			}
 		}
 	}
 
@@ -255,3 +274,106 @@ void ColladaLoader::StoreSceneMeshes( aiScene* pScene)
 		std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes);
 	}
 }
+
+// ------------------------------------------------------------------------------------------------
+// Constructs materials from the collada material definitions
+void ColladaLoader::BuildMaterials( const ColladaParser& pParser, aiScene* pScene)
+{
+	std::vector<aiMaterial*> newMats;
+
+	for( ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin(); matIt != pParser.mMaterialLibrary.end(); ++matIt)
+	{
+		const Collada::Material& material = matIt->second;
+		// a material is only a reference to an effect
+		ColladaParser::EffectLibrary::const_iterator effIt = pParser.mEffectLibrary.find( material.mEffect);
+		if( effIt == pParser.mEffectLibrary.end())
+			continue;
+		const Collada::Effect& effect = effIt->second;
+
+		// create material
+		Assimp::MaterialHelper* mat = new Assimp::MaterialHelper;
+		aiString name( matIt->first);
+		mat->AddProperty( &name, AI_MATKEY_NAME);
+
+		int shadeMode;
+		switch( effect.mShadeType)
+		{
+			case Collada::Shade_Constant: shadeMode = aiShadingMode_NoShading; break;
+			case Collada::Shade_Lambert: shadeMode = aiShadingMode_Gouraud; break;
+			case Collada::Shade_Blinn: shadeMode = aiShadingMode_Blinn; break;
+			default: shadeMode = aiShadingMode_Phong; break;
+		}
+		mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
+
+		mat->AddProperty( &effect.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
+		mat->AddProperty( &effect.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
+		mat->AddProperty( &effect.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
+		mat->AddProperty( &effect.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
+		mat->AddProperty( &effect.mShininess, 1, AI_MATKEY_SHININESS);
+		mat->AddProperty( &effect.mRefractIndex, 1, AI_MATKEY_REFRACTI);
+		
+		// add textures, if given
+		if( !effect.mTexAmbient.empty())
+			mat->AddProperty( &FindFilenameForEffectTexture( pParser, effect, effect.mTexAmbient), AI_MATKEY_TEXTURE_AMBIENT( 0));
+		if( !effect.mTexDiffuse.empty())
+			mat->AddProperty( &FindFilenameForEffectTexture( pParser, effect, effect.mTexDiffuse), AI_MATKEY_TEXTURE_DIFFUSE( 0));
+		if( !effect.mTexEmissive.empty())
+			mat->AddProperty( &FindFilenameForEffectTexture( pParser, effect, effect.mTexEmissive), AI_MATKEY_TEXTURE_EMISSIVE( 0));
+		if( !effect.mTexSpecular.empty())
+			mat->AddProperty( &FindFilenameForEffectTexture( pParser, effect, effect.mTexSpecular), AI_MATKEY_TEXTURE_SPECULAR( 0));
+
+		// store the material
+		mMaterialIndexByName[matIt->first] = newMats.size();
+		newMats.push_back( mat);
+	}
+
+	// store a dummy material if none were given
+	if( newMats.size() == 0)
+	{
+		Assimp::MaterialHelper* mat = new Assimp::MaterialHelper;
+		aiString name( std::string( "dummy"));
+		mat->AddProperty( &name, AI_MATKEY_NAME);
+
+		int shadeMode = aiShadingMode_Phong;
+		mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
+		aiColor4D colAmbient( 0.2f, 0.2f, 0.2f, 1.0f), colDiffuse( 0.8f, 0.8f, 0.8f, 1.0f), colSpecular( 0.5f, 0.5f, 0.5f, 0.5f);
+		mat->AddProperty( &colAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
+		mat->AddProperty( &colDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
+		mat->AddProperty( &colSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
+		float specExp = 5.0f;
+		mat->AddProperty( &specExp, 1, AI_MATKEY_SHININESS);
+	}
+
+	// store the materials in the scene
+	pScene->mNumMaterials = newMats.size();
+	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
+	std::copy( newMats.begin(), newMats.end(), pScene->mMaterials);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Resolves the texture name for the given effect texture entry
+const aiString& ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser, const Collada::Effect& pEffect, const std::string& pName)
+{
+	// recurse through the param references until we end up at an image
+	std::string name = pName;
+	while( 1)
+	{
+		// the given string is a param entry. Find it
+		Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find( name);
+		// if not found, we're at the end of the recursion. The resulting string should be the image ID
+		if( it == pEffect.mParams.end())
+			break;
+
+		// else recurse on
+		name = it->second.mReference;
+	}
+
+	// find the image referred by this name in the image library of the scene
+	ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name);
+	if( imIt == pParser.mImageLibrary.end())
+		throw new ImportErrorException( boost::str( boost::format( "Unable to resolve effect texture entry \"%s\", ended up at ID \"%s\".") % pName % name));
+
+	static aiString result;
+	result.Set( imIt->second.mFileName);
+	return result;
+}

+ 34 - 1
code/ColladaLoader.h

@@ -49,6 +49,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp
 {
 
+struct ColladaMeshIndex
+{
+	std::string mMeshID;
+	size_t mSubMesh;
+	std::string mMaterial;
+	ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial) 
+		: mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial)
+	{   }
+
+	bool operator < (const ColladaMeshIndex& p) const
+	{
+		if( mMeshID == p.mMeshID) 
+		{
+			if( mSubMesh == p.mSubMesh)
+				return mMaterial < p.mMaterial;
+			else 
+				return mSubMesh < p.mSubMesh;
+		} else
+		{
+			return mMeshID < p.mMeshID;
+		}
+	}
+};
+
 /** 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. 
 */
@@ -91,12 +115,21 @@ protected:
 	/** Stores all meshes in the given scene */
 	void StoreSceneMeshes( aiScene* pScene);
 
+	/** Constructs materials from the collada material definitions */
+	void BuildMaterials( const ColladaParser& pParser, aiScene* pScene);
+
+	/** Resolves the texture name for the given effect texture entry */
+	const aiString& FindFilenameForEffectTexture( const ColladaParser& pParser, const Collada::Effect& pEffect, const std::string& pName);
+
 protected:
 	/** Filename, for a verbose error message */
 	std::string mFileName;
 
 	/** Which mesh-material compound was stored under which mesh ID */
-	std::map<std::string, size_t> mMeshIndexbyID;
+	std::map<ColladaMeshIndex, size_t> mMeshIndexByID;
+
+	/** Which material was stored under which index in the scene */
+	std::map<std::string, size_t> mMaterialIndexByName;
 
 	/** Accumulated meshes for the target scene */
 	std::vector<aiMesh*> mMeshes;

+ 252 - 28
code/ColladaParser.cpp

@@ -112,6 +112,12 @@ void ColladaParser::ReadStructure()
 		{
 			if( IsElement( "asset"))
 				ReadAssetInfo();
+			else if( IsElement( "library_images"))
+				ReadImageLibrary();
+			else if( IsElement( "library_materials"))
+				ReadMaterialLibrary();
+			else if( IsElement( "library_effects"))
+				ReadEffectLibrary();
 			else if( IsElement( "library_geometries"))
 				ReadGeometryLibrary();
 			else if( IsElement( "library_visual_scenes"))
@@ -289,7 +295,7 @@ void ColladaParser::ReadMaterial( Collada::Material& pMaterial)
 				if( url[0] != '#')
 					ThrowException( "Unknown reference format");
 
-				pMaterial.mEffect = url;
+				pMaterial.mEffect = url+1;
 
 				SkipElement();
 			} else
@@ -312,12 +318,214 @@ void ColladaParser::ReadMaterial( Collada::Material& pMaterial)
 // Reads the effect library
 void ColladaParser::ReadEffectLibrary()
 {
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "effect"))
+			{
+				// read ID. Do I have to repeat my ranting about "optional" attributes?
+				int attrID = GetAttribute( "id");
+				std::string id = mReader->getAttributeValue( attrID);
+
+				// create an entry and store it in the library under its ID
+				mEffectLibrary[id] = Effect();
+				// read on from there
+				ReadEffect( mEffectLibrary[id]);
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "library_effects") != 0)
+				ThrowException( "Expected end of \"library_effects\" element.");
+
+			break;
+		}
+	}
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads an effect entry into the given effect
-void ColladaParser::ReadEffect( Collada::Effect* pEffect)
+void ColladaParser::ReadEffect( Collada::Effect& pEffect)
 {
+	// for the moment we don't support any other type of effect.
+	// TODO: (thom) Rewrite this so that it ignores the whole effect instead of bailing out
+	TestOpening( "profile_COMMON");
+
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "newparam"))
+			{
+				// save ID
+				int attrSID = GetAttribute( "sid");
+				std::string sid = mReader->getAttributeValue( attrSID);
+				pEffect.mParams[sid] = EffectParam();
+				ReadEffectParam( pEffect.mParams[sid]);
+			} 
+			else if( IsElement( "technique"))
+			{
+				// just syntactic sugar
+			}
+			else if( IsElement( "phong"))
+				pEffect.mShadeType = Shade_Phong;
+			else if( IsElement( "constant"))
+				pEffect.mShadeType = Shade_Constant;
+			else if( IsElement( "lambert"))
+				pEffect.mShadeType = Shade_Lambert;
+			else if( IsElement( "blinn"))
+				pEffect.mShadeType = Shade_Blinn;
+			else if( IsElement( "emission"))
+				ReadEffectColor( pEffect.mEmissive, pEffect.mTexEmissive);
+			else if( IsElement( "ambient"))
+				ReadEffectColor( pEffect.mAmbient, pEffect.mTexAmbient);
+			else if( IsElement( "diffuse"))
+				ReadEffectColor( pEffect.mDiffuse, pEffect.mTexDiffuse);
+			else if( IsElement( "specular"))
+				ReadEffectColor( pEffect.mSpecular, pEffect.mTexSpecular);
+			else if( IsElement( "reflective"))
+				ReadEffectColor( pEffect.mReflective, std::string());
+			else if( IsElement( "transparent"))
+				ReadEffectColor( pEffect.mRefractive, std::string());
+			else if( IsElement( "shininess"))
+				ReadEffectFloat( pEffect.mShininess);
+			else if( IsElement( "reflectivity"))
+				ReadEffectFloat( pEffect.mReflectivity);
+			else if( IsElement( "transparency"))
+				ReadEffectFloat( pEffect.mRefractivity);
+			else if( IsElement( "index_of_refraction"))
+				ReadEffectFloat( pEffect.mRefractIndex);
+			else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "effect") == 0)
+				break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads an effect entry containing a color or a texture defining that color
+void ColladaParser::ReadEffectColor( aiColor4D& pColor, std::string& pSampler)
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "color"))
+			{
+				// text content contains 4 floats
+				const char* content = GetTextContent();
+				content = fast_atof_move( content, pColor.r);
+				SkipSpacesAndLineEnd( &content);
+				content = fast_atof_move( content, pColor.g);
+				SkipSpacesAndLineEnd( &content);
+				content = fast_atof_move( content, pColor.b);
+				SkipSpacesAndLineEnd( &content);
+				content = fast_atof_move( content, pColor.a);
+				SkipSpacesAndLineEnd( &content);
+
+				TestClosing( "color");
+			} 
+			else if( IsElement( "texture"))
+			{
+				int attrTex = GetAttribute( "texture");
+				pSampler = mReader->getAttributeValue( attrTex);
+				SkipElement();
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads an effect entry containing a float
+void ColladaParser::ReadEffectFloat( float& pFloat)
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "float"))
+			{
+				// text content contains a single floats
+				const char* content = GetTextContent();
+				content = fast_atof_move( content, pFloat);
+				SkipSpacesAndLineEnd( &content);
+
+				TestClosing( "float");
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads an effect parameter specification of any kind 
+void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "surface"))
+			{
+				// image ID given inside <init_from> tags
+				TestOpening( "init_from");
+				const char* content = GetTextContent();
+				pParam.mType = Param_Surface;
+				pParam.mReference = content;
+				TestClosing( "init_from");
+
+				// don't care for remaining stuff
+				SkipElement( "surface");
+			} 
+			else if( IsElement( "sampler2D"))
+			{
+				// surface ID is given inside <source> tags
+				TestOpening( "source");
+				const char* content = GetTextContent();
+				pParam.mType = Param_Sampler;
+				pParam.mReference = content;
+				TestClosing( "source");
+
+				// don't care for remaining stuff
+				SkipElement( "sampler2D");
+			} else
+			{
+				// ignore unknown element
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			break;
+		}
+	}
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -584,6 +792,14 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
 	int attrCount = GetAttribute( "count");
 	size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount);
 
+	// material subgroup 
+	int attrMaterial = TestAttribute( "material");
+	SubMesh subgroup;
+	if( attrMaterial > -1)
+		subgroup.mMaterial = mReader->getAttributeValue( attrMaterial);
+	subgroup.mNumFaces = numPrimitives;
+	pMesh->mSubMeshes.push_back( subgroup);
+
 	// distinguish between polys and triangles
 	std::string elementName = mReader->getNodeName();
 	PrimitiveType primType = Prim_Invalid;
@@ -1020,36 +1236,36 @@ void ColladaParser::ReadNodeGeometry( Node* pNode)
 	Collada::MeshInstance instance;
 	instance.mMesh = url+1; // skipping the leading #
 
-	// read material associations. Ignore additional elements inbetween
-	while( mReader->read())
+	if( !mReader->isEmptyElement())
 	{
-		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		// read material associations. Ignore additional elements inbetween
+		while( mReader->read())
 		{
-			if( IsElement( "instance_material"))
+			if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
 			{
-				// read ID of the geometry subgroup and the target material
-				int attrGroup = GetAttribute( "symbol");
-				std::string group = mReader->getAttributeValue( attrGroup);
-				int attrMaterial = GetAttribute( "target");
-				const char* urlMat = mReader->getAttributeValue( attrMaterial);
-				if( urlMat[0] != '#')
-					ThrowException( "Unknown reference format");
-				std::string mat = mReader->getAttributeValue( attrMaterial+1);
-
-				// store the association
-				instance.mMaterials[group] = mat;
-			} else
+				if( IsElement( "instance_material"))
+				{
+					// read ID of the geometry subgroup and the target material
+					int attrGroup = GetAttribute( "symbol");
+					std::string group = mReader->getAttributeValue( attrGroup);
+					int attrMaterial = GetAttribute( "target");
+					const char* urlMat = mReader->getAttributeValue( attrMaterial);
+					if( urlMat[0] != '#')
+						ThrowException( "Unknown reference format");
+					std::string mat = urlMat+1;
+
+					// store the association
+					instance.mMaterials[group] = mat;
+				} 
+			} 
+			else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
 			{
-				SkipElement();
-			}
-		} 
-		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
-		{
-			if( strcmp( mReader->getNodeName(), "instance_geometry") == 0)
-				break;
-		} 
+				if( strcmp( mReader->getNodeName(), "instance_geometry") == 0)
+					break;
+			} 
+		}
 	}
-	
+
 	// store it
 	pNode->mMeshes.push_back( instance);
 }
@@ -1106,9 +1322,17 @@ void ColladaParser::SkipElement()
 	if( mReader->isEmptyElement())
 		return;
 
+	// reroute
+	SkipElement( mReader->getNodeName());
+}
+
+// ------------------------------------------------------------------------------------------------
+// Skips all data until the end node of the given element
+void ColladaParser::SkipElement( const char* pElement)
+{
 	// 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();
+	std::string element = pElement;
 	while( mReader->read())
 	{
 		if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)

+ 12 - 1
code/ColladaParser.h

@@ -88,7 +88,15 @@ protected:
 	void ReadEffectLibrary();
 
 	/** Reads an effect entry into the given effect*/
-	void ReadEffect( Collada::Effect* pEffect);
+	void ReadEffect( Collada::Effect& pEffect);
+
+	/** Reads an effect entry containing a color or a texture defining that color */
+	void ReadEffectColor( aiColor4D& pColor, std::string& pSampler);
+	/** Reads an effect entry containing a float */
+	void ReadEffectFloat( float& pFloat);
+
+	/** Reads an effect parameter specification of any kind */
+	void ReadEffectParam( Collada::EffectParam& pParam);
 
 	/** Reads the geometry library contents */
 	void ReadGeometryLibrary();
@@ -142,6 +150,9 @@ protected:
 	/** Skips all data until the end node of the current element */
 	void SkipElement();
 
+	/** Skips all data until the end node of the given element */
+	void SkipElement( const char* pElement);
+
 	/** 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; }
 

+ 0 - 4
code/Importer.cpp

@@ -541,10 +541,8 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
 	// put a large try block around everything to catch all std::exception's
 	// that might be thrown by STL containers or by new(). 
 	// ImportErrorException's are throw by ourselves and caught elsewhere.
-#ifndef _DEBUG
 	try
 	{
-#endif 
 		// check whether this Importer instance has already loaded
 		// a scene. In this case we need to delete the old one
 		if (this->mScene)
@@ -644,7 +642,6 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
 
 		// clear any data allocated by post-process steps
 		mPPShared->Clean();
-#ifndef _DEBUG
 	}
 	catch (std::exception &e)
 	{
@@ -659,7 +656,6 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
 		DefaultLogger::get()->error(mErrorString);
 		delete mScene;mScene = NULL;
 	}
-#endif
 
 	// either successful or failure - the pointer expresses it anyways
 	return mScene;

+ 0 - 8
code/SceneCombiner.cpp

@@ -59,20 +59,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // ----------------------------------------------------------------------------
 #ifdef ASSIMP_BUILD_BOOST_WORKAROUND
 
-#if _MSC_VER >= 1400
-#	pragma message( "AssimpBuild: Using -noBoost workaround for boost::random" )
-#endif
-
 #	include "../include/BoostWorkaround/boost/random/uniform_int.hpp"
 #	include "../include/BoostWorkaround/boost/random/variate_generator.hpp"
 #	include "../include/BoostWorkaround/boost/random/mersenne_twister.hpp"
 
 #else
 
-#if _MSC_VER >= 1400
-#	pragma message( "AssimpBuild: Using standard boost headers for boost::random" )
-#endif
-
 #	include <boost/random/uniform_int.hpp>
 #	include <boost/random/variate_generator.hpp>
 #	include <boost/random/mersenne_twister.hpp>

+ 0 - 4
include/BoostWorkaround/boost/random/mersenne_twister.hpp

@@ -2,10 +2,6 @@
 #ifndef BOOST_MT_INCLUDED
 #define BOOST_MT_INCLUDED
 
-#if _MSC_VER >= 1400
-#	pragma message( "AssimpBuild: Using CRT's rand() as replacement for mt19937" )
-#endif
-
 namespace boost
 {