diff --git a/code/ColladaHelper.h b/code/ColladaHelper.h index 894ed773c..6351fc81c 100644 --- a/code/ColladaHelper.h +++ b/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 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 mTransforms; - std::vector mMeshes; ///< Meshes at this node + std::vector mMeshes; ///< Meshes at this node Node() { mParent = NULL; } ~Node() { for( std::vector::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 diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index c50320b16..21214fbf9 100644 --- a/code/ColladaLoader.cpp +++ b/code/ColladaLoader.cpp @@ -159,18 +159,18 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll std::vector 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::const_iterator dstMeshIt = mMeshIndexbyID.find( mid); + std::map::const_iterator dstMeshIt = mMeshIndexbyID.find( mid.mMesh); if( dstMeshIt != mMeshIndexbyID.end()) { newMeshRefs.push_back( dstMeshIt->second); diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index d412a129f..64cbda92c 100644 --- a/code/ColladaParser.cpp +++ b/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 has been consumed by ReadMesh() + // check for the closing tag of the outer element, the inner closing of 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); } // ------------------------------------------------------------------------------------------------ diff --git a/code/ColladaParser.h b/code/ColladaParser.h index a18c07799..c3f9a02ca 100644 --- a/code/ColladaParser.h +++ b/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 NodeLibrary; NodeLibrary mNodeLibrary; + /** Image library: stores texture properties by ID */ + typedef std::map ImageLibrary; + ImageLibrary mImageLibrary; + + /** Effect library: surface attributes by ID */ + typedef std::map EffectLibrary; + EffectLibrary mEffectLibrary; + + /** Material library: surface material by ID */ + typedef std::map 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; diff --git a/doc/dox.h b/doc/dox.h index 52db9f952..51f63e996 100644 --- a/doc/dox.h +++ b/doc/dox.h @@ -135,6 +135,7 @@ C++ example: @code #include // C++ importer interface #include // root structure of the imported data +#include // Post processing flags #include // 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 // Plain C importer interface #include // Root structure of the imported data +#include // Post processing flags #include // Example: mesh data structures. you'll propably need other includes, too bool DoTheImportThing( const char* pFile)