Bladeren bron

- corrected example code in the documentation. Thanks to Ingrater to point it out.
- Further work on the Collada loader. Halve way through the material import, I have to leave it here and continue at home.

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

ulfjorensen 17 jaren geleden
bovenliggende
commit
5639220859
5 gewijzigde bestanden met toevoegingen van 268 en 11 verwijderingen
  1. 50 1
      code/ColladaHelper.h
  2. 4 4
      code/ColladaLoader.cpp
  3. 181 5
      code/ColladaParser.cpp
  4. 30 0
      code/ColladaParser.h
  5. 3 1
      doc/dox.h

+ 50 - 1
code/ColladaHelper.h

@@ -66,6 +66,13 @@ struct Transform
 	float f[16]; ///< Interpretation of data depends on the type of the transformation 
 };
 
+/** A reference to a mesh inside a node, including materials assigned to the various subgroups */
+struct MeshInstance
+{
+	std::string mMesh; ///< ID of the mesh
+	std::map<std::string, std::string> mMaterials; ///< Map of materials by the subgroup ID they're applied to
+};
+
 /** A node in a scene hierarchy */
 struct Node
 {
@@ -77,7 +84,7 @@ struct Node
 	/** Operations in order to calculate the resulting transformation to parent. */
 	std::vector<Transform> mTransforms;
 
-	std::vector<std::string> mMeshes; ///< Meshes at this node
+	std::vector<MeshInstance> mMeshes; ///< Meshes at this node
 
 	Node() { mParent = NULL; }
 	~Node() { for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) delete *it; }
@@ -166,6 +173,48 @@ enum PrimitiveType
 	Prim_Polygon
 };
 
+/** A collada material. Pretty much the only member is a reference to an effect. */
+struct Material
+{
+	std::string mEffect;
+};
+
+/** Shading type supported by the standard effect spec of Collada */
+enum ShadeType
+{
+	Shade_Invalid,
+	Shade_Constant,
+	Shade_Lambert,
+	Shade_Phong,
+	Shade_Blinn
+};
+
+
+/** A collada effect. Can contain about anything according to the Collada spec, but we limit our version to a reasonable subset. */
+struct Effect
+{
+	ShadeType mShadeType;
+	aiColor4D mEmmisive, mAmbient, mDiffuse, mSpecular;
+	aiColor4D mReflectivity, mRefractivity;
+	std::string mTexEmmisive, mTexAmbient, mTexDiffuse, mTexSpecular;
+	float mShininess, mRefractIndex;
+
+	Effect() : mEmmisive( 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)
+	{ 
+		mShadeType = Shade_Phong; 
+		mShininess = 10;
+		mRefractIndex = 1;
+	}
+};
+
+/** An image, meaning texture */
+struct Image
+{
+	std::string mFileName;
+};
+
 } // end of namespace Collada
 } // end of namespace Assimp
 

+ 4 - 4
code/ColladaLoader.cpp

@@ -159,18 +159,18 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
 	std::vector<size_t> newMeshRefs;
 
 	// for the moment we simply ignore all material tags and transfer the meshes one by one
-	BOOST_FOREACH( const std::string& mid, pNode->mMeshes)
+	BOOST_FOREACH( const Collada::MeshInstance& mid, pNode->mMeshes)
 	{
 		// find the referred mesh
-		ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find( mid);
+		ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find( mid.mMesh);
 		if( srcMeshIt == pParser.mMeshLibrary.end())
 		{
-			DefaultLogger::get()->warn( boost::str( boost::format( "Unable to find geometry for ID \"%s\". Skipping.") % mid));
+			DefaultLogger::get()->warn( boost::str( boost::format( "Unable to find geometry for ID \"%s\". Skipping.") % mid.mMesh));
 			continue;
 		}
 
 		// 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);
+		std::map<std::string, size_t>::const_iterator dstMeshIt = mMeshIndexbyID.find( mid.mMesh);
 		if( dstMeshIt != mMeshIndexbyID.end())
 		{
 			newMeshRefs.push_back( dstMeshIt->second);

+ 181 - 5
code/ColladaParser.cpp

@@ -174,6 +174,152 @@ void ColladaParser::ReadAssetInfo()
 	}
 }
 
+// ------------------------------------------------------------------------------------------------
+// Reads the image library contents
+void ColladaParser::ReadImageLibrary()
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "image"))
+			{
+				// read ID. Another entry which is "optional" by design but obligatory in reality
+				int attrID = GetAttribute( "id");
+				std::string id = mReader->getAttributeValue( attrID);
+
+				// create an entry and store it in the library under its ID
+				mImageLibrary[id] = Image();
+
+				// read on from there
+				ReadImage( mImageLibrary[id]);
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "library_images") != 0)
+				ThrowException( "Expected end of \"library_images\" element.");
+
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads an image entry into the given image
+void ColladaParser::ReadImage( Collada::Image& pImage)
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "init_from"))
+			{
+				// element content is filename - hopefully
+				const char* content = GetTextContent();
+				pImage.mFileName = content;
+				TestClosing( "init_from");
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "image") != 0)
+				ThrowException( "Expected end of \"image\" element.");
+
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads the material library
+void ColladaParser::ReadMaterialLibrary()
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "material"))
+			{
+				// read ID. By now you propably know my opinion about this "specification"
+				int attrID = GetAttribute( "id");
+				std::string id = mReader->getAttributeValue( attrID);
+
+				// create an entry and store it in the library under its ID
+				mMaterialLibrary[id] = Material();
+				// read on from there
+				ReadMaterial( mMaterialLibrary[id]);
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "library_materials") != 0)
+				ThrowException( "Expected end of \"library_materials\" element.");
+
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads a material entry into the given material
+void ColladaParser::ReadMaterial( Collada::Material& pMaterial)
+{
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			if( IsElement( "instance_effect"))
+			{
+				// referred effect by URL
+				int attrUrl = GetAttribute( "url");
+				const char* url = mReader->getAttributeValue( attrUrl);
+				if( url[0] != '#')
+					ThrowException( "Unknown reference format");
+
+				pMaterial.mEffect = url;
+
+				SkipElement();
+			} else
+			{
+				// ignore the rest
+				SkipElement();
+			}
+		}
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "material") != 0)
+				ThrowException( "Expected end of \"image\" element.");
+
+			break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads the effect library
+void ColladaParser::ReadEffectLibrary()
+{
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads an effect entry into the given effect
+void ColladaParser::ReadEffect( Collada::Effect* pEffect)
+{
+}
+
 // ------------------------------------------------------------------------------------------------
 // Reads the geometry library contents
 void ColladaParser::ReadGeometryLibrary()
@@ -200,7 +346,7 @@ void ColladaParser::ReadGeometryLibrary()
 				// 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()
+				// check for the closing tag of the outer <geometry> element, the inner closing of <mesh> has been consumed by ReadMesh()
 				TestClosing( "geometry");
 			} else
 			{
@@ -871,11 +1017,41 @@ void ColladaParser::ReadNodeGeometry( Node* pNode)
 	if( url[0] != '#')
 		ThrowException( "Unknown reference format");
 	
-	// store the mesh ID
-	pNode->mMeshes.push_back( std::string( url+1));
+	Collada::MeshInstance instance;
+	instance.mMesh = url+1; // skipping the leading #
+
+	// read material associations. Ignore additional elements inbetween
+	while( mReader->read())
+	{
+		if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
+		{
+			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 = mReader->getAttributeValue( attrMaterial+1);
+
+				// store the association
+				instance.mMaterials[group] = mat;
+			} else
+			{
+				SkipElement();
+			}
+		} 
+		else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+		{
+			if( strcmp( mReader->getNodeName(), "instance_geometry") == 0)
+				break;
+		} 
+	}
 	
-	// for the moment, skip the rest
-	SkipElement();
+	// store it
+	pNode->mMeshes.push_back( instance);
 }
 
 // ------------------------------------------------------------------------------------------------

+ 30 - 0
code/ColladaParser.h

@@ -72,6 +72,24 @@ protected:
 	/** Reads asset informations such as coordinate system informations and legal blah */
 	void ReadAssetInfo();
 
+	/** Reads the image library contents */
+	void ReadImageLibrary();
+
+	/** Reads an image entry into the given image */
+	void ReadImage( Collada::Image& pImage);
+
+	/** Reads the material library */
+	void ReadMaterialLibrary();
+
+	/** Reads a material entry into the given material */
+	void ReadMaterial( Collada::Material& pMaterial);
+
+	/** Reads the effect library */
+	void ReadEffectLibrary();
+
+	/** Reads an effect entry into the given effect*/
+	void ReadEffect( Collada::Effect* pEffect);
+
 	/** Reads the geometry library contents */
 	void ReadGeometryLibrary();
 
@@ -174,6 +192,18 @@ protected:
 	typedef std::map<std::string, Collada::Node*> NodeLibrary;
 	NodeLibrary mNodeLibrary;
 
+	/** Image library: stores texture properties by ID */
+	typedef std::map<std::string, Collada::Image> ImageLibrary;
+	ImageLibrary mImageLibrary;
+
+	/** Effect library: surface attributes by ID */
+	typedef std::map<std::string, Collada::Effect> EffectLibrary;
+	EffectLibrary mEffectLibrary;
+
+	/** Material library: surface material by ID */
+	typedef std::map<std::string, Collada::Material> MaterialLibrary;
+	MaterialLibrary mMaterialLibrary;
+
 	/** Pointer to the root node. Don't delete, it just points to one of the nodes in the node library. */
 	Collada::Node* mRootNode;
 

+ 3 - 1
doc/dox.h

@@ -135,6 +135,7 @@ C++ example:
 @code
 #include <assimp.hpp>  // C++ importer interface
 #include <aiScene.h>   // root structure of the imported data
+#include <aiPostProcess.h> // Post processing flags
 #include <aiMesh.h>    // example: mesh data structures. you'll propably need other includes, too
 
 bool DoTheImportThing( const std::string& pFile)
@@ -148,7 +149,7 @@ bool DoTheImportThing( const std::string& pFile)
   // if the import failed, report it
   if( !scene)
   {
-    DoTheErrorLogging( importer.GetErrorText());
+    DoTheErrorLogging( importer.GetErrorString());
     return false;
   }
 
@@ -177,6 +178,7 @@ C example:
 @code
 #include <assimp.h>  // Plain C importer interface
 #include <aiScene.h> // Root structure of the imported data
+#include <aiPostProcess.h> // Post processing flags
 #include <aiMesh.h>  // Example: mesh data structures. you'll propably need other includes, too
 
 bool DoTheImportThing( const char* pFile)