- 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-9d2fd5bffc1fpull/1/head
parent
d320a4bc64
commit
917db45b3c
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
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));
|
||||
|
||||
// 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<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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
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)
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
||||
|
|
Loading…
Reference in New Issue