From 917db45b3c6696a37f524430a49c4ae25ce3aba3 Mon Sep 17 00:00:00 2001 From: ulfjorensen Date: Thu, 4 Dec 2008 17:06:26 +0000 Subject: [PATCH] - 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 --- code/AssimpPCH.h | 42 +-- code/ColladaHelper.h | 45 ++- code/ColladaLoader.cpp | 258 +++++++++++----- code/ColladaLoader.h | 35 ++- code/ColladaParser.cpp | 278 ++++++++++++++++-- code/ColladaParser.h | 13 +- code/Importer.cpp | 4 - code/SceneCombiner.cpp | 8 - .../boost/random/mersenne_twister.hpp | 4 - 9 files changed, 526 insertions(+), 161 deletions(-) diff --git a/code/AssimpPCH.h b/code/AssimpPCH.h index 4985bee19..3e5003bc9 100644 --- a/code/AssimpPCH.h +++ b/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 #include #include - +#include // ******************************************************************* // 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 # include # include diff --git a/code/ColladaHelper.h b/code/ColladaHelper.h index 6351fc81c..36cf9a135 100644 --- a/code/ColladaHelper.h +++ b/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 mFaceSize; + + // Submeshes in this mesh, each with a given material + std::vector 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 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; } }; diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index b23e13d5a..671903462 100644 --- a/code/ColladaLoader.cpp +++ b/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( &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::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; + const Collada::SubMesh& submesh = srcMesh->mSubMeshes[sm]; + // find material assigned to this submesh + std::map::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)); - // copy positions - dstMesh->mNumVertices = srcMesh->mPositions.size(); - dstMesh->mVertices = new aiVector3D[dstMesh->mNumVertices]; - std::copy( srcMesh->mPositions.begin(), srcMesh->mPositions.end(), dstMesh->mVertices); + // built lookup index of the Mesh-Submesh-Material combination + ColladaMeshIndex index( mid.mMesh, sm, meshMaterial); - // 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) + // 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( 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::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 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( &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( &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; +} diff --git a/code/ColladaLoader.h b/code/ColladaLoader.h index 0e5c6972d..d0ef2bc79 100644 --- a/code/ColladaLoader.h +++ b/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 mMeshIndexbyID; + std::map mMeshIndexByID; + + /** Which material was stored under which index in the scene */ + std::map mMaterialIndexByName; /** Accumulated meshes for the target scene */ std::vector mMeshes; diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index 64cbda92c..86ac5165c 100644 --- a/code/ColladaParser.cpp +++ b/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 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 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); + 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 + // 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) diff --git a/code/ColladaParser.h b/code/ColladaParser.h index c3f9a02ca..e80485e0f 100644 --- a/code/ColladaParser.h +++ b/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; } diff --git a/code/Importer.cpp b/code/Importer.cpp index e88ef2b81..993cdc0a9 100644 --- a/code/Importer.cpp +++ b/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; diff --git a/code/SceneCombiner.cpp b/code/SceneCombiner.cpp index 15d9afd28..e802046ce 100644 --- a/code/SceneCombiner.cpp +++ b/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 # include # include diff --git a/include/BoostWorkaround/boost/random/mersenne_twister.hpp b/include/BoostWorkaround/boost/random/mersenne_twister.hpp index 07695b4f5..e45a5a7e7 100644 --- a/include/BoostWorkaround/boost/random/mersenne_twister.hpp +++ b/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 {