BUGFIX : Fix handling of multiple materials per object definition in Obj-Loader.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@745 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
kimmi 2010-05-30 12:45:38 +00:00
parent 31ff5d27eb
commit f3310b0f36
4 changed files with 120 additions and 60 deletions

View File

@ -107,14 +107,20 @@ struct Face
//! \brief Stores all objects of an objfile object definition //! \brief Stores all objects of an objfile object definition
struct Object struct Object
{ {
enum ObjectType
{
ObjType,
GroupType
};
//! Object name //! Object name
std::string m_strObjName; std::string m_strObjName;
//! Assigend face instances
std::vector<Face*> m_Faces;
//! Transformation matrix, stored in OpenGL format //! Transformation matrix, stored in OpenGL format
aiMatrix4x4 m_Transformation; aiMatrix4x4 m_Transformation;
//! All sub-objects referenced by this object //! All sub-objects referenced by this object
std::vector<Object*> m_SubObjects; std::vector<Object*> m_SubObjects;
/// Assigned meshes
std::vector<unsigned int> m_Meshes;
//! \brief Default constructor //! \brief Default constructor
Object() : Object() :
@ -189,6 +195,8 @@ struct Material
//! \brief Data structure to store a mesh //! \brief Data structure to store a mesh
struct Mesh struct Mesh
{ {
static const unsigned int NoMaterial = 999999999;
/// Array with pointer to all stored faces /// Array with pointer to all stored faces
std::vector<Face*> m_Faces; std::vector<Face*> m_Faces;
/// Assigned material /// Assigned material
@ -205,7 +213,7 @@ struct Mesh
Mesh() : Mesh() :
m_pMaterial(NULL), m_pMaterial(NULL),
m_uiNumIndices(0), m_uiNumIndices(0),
m_uiMaterialIndex(0), m_uiMaterialIndex( NoMaterial ),
m_hasNormals(false) m_hasNormals(false)
{ {
memset(m_uiUVCoordinates, 0, sizeof( unsigned int ) * AI_MAX_NUMBER_OF_TEXTURECOORDS); memset(m_uiUVCoordinates, 0, sizeof( unsigned int ) * AI_MAX_NUMBER_OF_TEXTURECOORDS);
@ -305,7 +313,6 @@ struct Model
} }
m_Groups.clear(); m_Groups.clear();
} }
}; };

View File

@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER #ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
#include "DefaultIOSystem.h" #include "DefaultIOSystem.h"
#include "ObjFileImporter.h" #include "ObjFileImporter.h"
#include "ObjFileParser.h" #include "ObjFileParser.h"
#include "ObjFileData.h" #include "ObjFileData.h"
@ -140,8 +139,8 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene
return; return;
// Create the root node of the scene // Create the root node of the scene
pScene->mRootNode = new aiNode(); pScene->mRootNode = new aiNode;
if (!pModel->m_ModelName.empty()) if ( !pModel->m_ModelName.empty() )
{ {
// Set the name of the scene // Set the name of the scene
pScene->mRootNode->mName.Set(pModel->m_ModelName); pScene->mRootNode->mName.Set(pModel->m_ModelName);
@ -175,40 +174,46 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Creates all nodes of the model // Creates all nodes of the model
aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pData, aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pObject,
unsigned int uiMeshIndex, unsigned int uiMeshIndex,
aiNode *pParent, aiScene* pScene, aiNode *pParent, aiScene* pScene,
std::vector<aiMesh*> &MeshArray) std::vector<aiMesh*> &MeshArray )
{ {
ai_assert( NULL != pModel ); ai_assert( NULL != pModel );
if (NULL == pData) if ( NULL == pObject )
return NULL; return NULL;
// Store older mesh size to be able to computate mesh offsets for new mesh instances // Store older mesh size to be able to computate mesh offsets for new mesh instances
const size_t oldMeshSize = MeshArray.size(); const size_t oldMeshSize = MeshArray.size();
aiNode *pNode = new aiNode(); aiNode *pNode = new aiNode;
if (pParent != NULL) if (pParent != NULL)
this->appendChildToParentNode(pParent, pNode); appendChildToParentNode(pParent, pNode);
aiMesh *pMesh = new aiMesh;
createTopology( pModel, pData, uiMeshIndex, pMesh ); for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ )
if ( pMesh->mNumVertices > 0 )
{ {
MeshArray.push_back( pMesh ); unsigned int meshId = pObject->m_Meshes[ i ];
} aiMesh *pMesh = new aiMesh;
else createTopology( pModel, pObject, meshId, pMesh );
{ if ( pMesh->mNumVertices > 0 )
delete pMesh; {
MeshArray.push_back( pMesh );
}
else
{
delete pMesh;
}
} }
// Create all nodes from the subobjects stored in the current object // Create all nodes from the sub-objects stored in the current object
if ( !pData->m_SubObjects.empty() ) if ( !pObject->m_SubObjects.empty() )
{ {
pNode->mNumChildren = (unsigned int)pData->m_SubObjects.size(); size_t numChilds = pObject->m_SubObjects.size();
pNode->mChildren = new aiNode*[pData->m_SubObjects.size()]; pNode->mNumChildren = static_cast<unsigned int>( numChilds );
pNode->mChildren = new aiNode*[ numChilds ];
pNode->mNumMeshes = 1; pNode->mNumMeshes = 1;
pNode->mMeshes = new unsigned int[1]; pNode->mMeshes = new unsigned int[ 1 ];
} }
// Set mesh instances into scene- and node-instances // Set mesh instances into scene- and node-instances
@ -216,7 +221,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
if ( meshSizeDiff > 0 ) if ( meshSizeDiff > 0 )
{ {
pNode->mMeshes = new unsigned int[ meshSizeDiff ]; pNode->mMeshes = new unsigned int[ meshSizeDiff ];
pNode->mNumMeshes = (unsigned int)meshSizeDiff; pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
size_t index = 0; size_t index = 0;
for (size_t i = oldMeshSize; i < MeshArray.size(); i++) for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
{ {
@ -248,7 +253,10 @@ void ObjFileImporter::createTopology(const ObjFile::Model* pModel,
if ( pMesh->mNumFaces > 0 ) if ( pMesh->mNumFaces > 0 )
{ {
pMesh->mFaces = new aiFace[ pMesh->mNumFaces ]; pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex; if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial )
{
pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
}
// Copy all data from all stored meshes // Copy all data from all stored meshes
for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
@ -278,7 +286,7 @@ void ObjFileImporter::createTopology(const ObjFile::Model* pModel,
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Creates a vretex array // Creates a vertex array
void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
const ObjFile::Object* pCurrentObject, const ObjFile::Object* pCurrentObject,
unsigned int uiMeshIndex, unsigned int uiMeshIndex,
@ -288,7 +296,7 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
ai_assert( NULL != pCurrentObject ); ai_assert( NULL != pCurrentObject );
// Break, if no faces are stored in object // Break, if no faces are stored in object
if (pCurrentObject->m_Faces.empty()) if ( pCurrentObject->m_Meshes.empty() )
return; return;
// Get current mesh // Get current mesh
@ -366,10 +374,10 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
void ObjFileImporter::countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes) void ObjFileImporter::countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes)
{ {
iNumMeshes = 0; iNumMeshes = 0;
if (rObjects.empty()) if ( rObjects.empty() )
return; return;
iNumMeshes += (unsigned int)rObjects.size(); iNumMeshes += static_cast<unsigned int>( rObjects.size() );
for (std::vector<ObjFile::Object*>::const_iterator it = rObjects.begin(); for (std::vector<ObjFile::Object*>::const_iterator it = rObjects.begin();
it != rObjects.end(); it != rObjects.end();
++it) ++it)
@ -400,17 +408,18 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc
Assimp::MaterialHelper* mat = new Assimp::MaterialHelper(); Assimp::MaterialHelper* mat = new Assimp::MaterialHelper();
// Store material name // Store material name
std::map<std::string, ObjFile::Material*>::const_iterator it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] ); std::map<std::string, ObjFile::Material*>::const_iterator it;
it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] );
// No material found, use the default material // No material found, use the default material
if ( pModel->m_MaterialMap.end() == it) if ( pModel->m_MaterialMap.end() == it )
continue; continue;
ObjFile::Material *pCurrentMaterial = (*it).second; ObjFile::Material *pCurrentMaterial = (*it).second;
mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME ); mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME );
// convert illumination model // convert illumination model
int sm; int sm = 0;
switch (pCurrentMaterial->illumination_model) switch (pCurrentMaterial->illumination_model)
{ {
case 0: case 0:
@ -474,8 +483,8 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc
void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild) void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild)
{ {
// Checking preconditions // Checking preconditions
ai_assert (NULL != pParent); ai_assert( NULL != pParent );
ai_assert (NULL != pChild); ai_assert( NULL != pChild );
// Assign parent to child // Assign parent to child
pChild->mParent = pParent; pChild->mParent = pParent;
@ -486,7 +495,7 @@ void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild)
if (pParent->mChildren != NULL) if (pParent->mChildren != NULL)
{ {
sNumChildren = pParent->mNumChildren; sNumChildren = pParent->mNumChildren;
ai_assert (0 != sNumChildren); ai_assert( 0 != sNumChildren );
for (size_t index = 0; index < pParent->mNumChildren; index++) for (size_t index = 0; index < pParent->mNumChildren; index++)
{ {
temp.push_back(pParent->mChildren [ index ] ); temp.push_back(pParent->mChildren [ index ] );

View File

@ -50,7 +50,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/aiTypes.h" #include "../include/aiTypes.h"
#include "DefaultIOSystem.h" #include "DefaultIOSystem.h"
namespace Assimp { namespace Assimp
{
// ------------------------------------------------------------------- // -------------------------------------------------------------------
const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME; const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME;
// fix: changed that to our standard default name // fix: changed that to our standard default name
@ -78,6 +80,7 @@ ObjFileParser::ObjFileParser(std::vector<char> &Data,const std::string &strModel
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Destrcutor.
ObjFileParser::~ObjFileParser() ObjFileParser::~ObjFileParser()
{ {
delete m_pModel->m_pDefaultMaterial; delete m_pModel->m_pDefaultMaterial;
@ -88,12 +91,14 @@ ObjFileParser::~ObjFileParser()
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Returns a pointer to the model instance.
ObjFile::Model *ObjFileParser::GetModel() const ObjFile::Model *ObjFileParser::GetModel() const
{ {
return m_pModel; return m_pModel;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// File parsing method.
void ObjFileParser::parseFile() void ObjFileParser::parseFile()
{ {
if (m_DataIt == m_DataItEnd) if (m_DataIt == m_DataItEnd)
@ -201,7 +206,6 @@ void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
size_t index = 0; size_t index = 0;
while (m_DataIt != m_DataItEnd) while (m_DataIt != m_DataItEnd)
{ {
// (Aramis) removed assertion (index<length-1) in favour of an explicit check
if (*m_DataIt == '\n' || *m_DataIt == '\r' || index == length-1) if (*m_DataIt == '\n' || *m_DataIt == '\r' || index == length-1)
break; break;
@ -265,7 +269,6 @@ void ObjFileParser::getFace()
std::vector<unsigned int> *pTexID = new std::vector<unsigned int>; std::vector<unsigned int> *pTexID = new std::vector<unsigned int>;
std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>; std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>;
bool hasNormal = false; bool hasNormal = false;
bool vt = (!m_pModel->m_TextureCoord.empty()); bool vt = (!m_pModel->m_TextureCoord.empty());
bool vn = (!m_pModel->m_Normals.empty()); bool vn = (!m_pModel->m_Normals.empty());
@ -329,7 +332,7 @@ void ObjFileParser::getFace()
++pPtr; ++pPtr;
} }
ObjFile::Face *face = new ObjFile::Face(pIndices, pNormalID, pTexID); ObjFile::Face *face = new ObjFile::Face( pIndices, pNormalID, pTexID );
// Set active material, if one set // Set active material, if one set
if (NULL != m_pModel->m_pCurrentMaterial) if (NULL != m_pModel->m_pCurrentMaterial)
@ -339,23 +342,20 @@ void ObjFileParser::getFace()
// Create a default object, if nothing there // Create a default object, if nothing there
if ( NULL == m_pModel->m_pCurrent ) if ( NULL == m_pModel->m_pCurrent )
createObject("defaultobject"); createObject( "defaultobject" );
// Store the new instance
m_pModel->m_pCurrent->m_Faces.push_back(face);
// Assign face to mesh // Assign face to mesh
if ( NULL == m_pModel->m_pCurrentMesh ) if ( NULL == m_pModel->m_pCurrentMesh )
{ {
m_pModel->m_pCurrentMesh = new ObjFile::Mesh(); createMesh();
m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
} }
// Store the face // Store the face
m_pModel->m_pCurrentMesh->m_Faces.push_back( face ); m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size(); m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size();
m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size(); m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size();
if(!m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal) { if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal )
{
m_pModel->m_pCurrentMesh->m_hasNormals = true; m_pModel->m_pCurrentMesh->m_hasNormals = true;
} }
// Skip the rest of the line // Skip the rest of the line
@ -391,6 +391,10 @@ void ObjFileParser::getMaterialDesc()
{ {
// Found, using detected material // Found, using detected material
m_pModel->m_pCurrentMaterial = (*it).second; m_pModel->m_pCurrentMaterial = (*it).second;
if ( needsNewMesh( strName ))
{
createMesh();
}
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName ); m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName );
} }
@ -460,11 +464,11 @@ void ObjFileParser::getNewMaterial()
return; return;
char *pStart = &(*m_DataIt); char *pStart = &(*m_DataIt);
std::string strMat(pStart, *m_DataIt); std::string strMat( pStart, *m_DataIt );
while ( isSeparator( *m_DataIt ) ) while ( isSeparator( *m_DataIt ) )
m_DataIt++; m_DataIt++;
std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat ); std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
if (it == m_pModel->m_MaterialMap.end()) if ( it == m_pModel->m_MaterialMap.end() )
{ {
// Show a warning, if material was not found // Show a warning, if material was not found
DefaultLogger::get()->warn("OBJ: Unsupported material requested: " + strMat); DefaultLogger::get()->warn("OBJ: Unsupported material requested: " + strMat);
@ -473,7 +477,10 @@ void ObjFileParser::getNewMaterial()
else else
{ {
// Set new material // Set new material
m_pModel->m_pCurrentMaterial = (*it).second; if ( needsNewMesh( strMat ) )
{
createMesh();
}
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat ); m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat );
} }
@ -514,13 +521,12 @@ void ObjFileParser::getGroupName()
std::string strGroupName(pStart, &(*m_DataIt)); std::string strGroupName(pStart, &(*m_DataIt));
// Change active group, if necessary // Change active group, if necessary
if (m_pModel->m_strActiveGroup != strGroupName) if ( m_pModel->m_strActiveGroup != strGroupName )
{ {
// Search for already existing entry // Search for already existing entry
ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(&strGroupName); ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(&strGroupName);
// We are mapping groups into the object structure // We are mapping groups into the object structure
/// TODO: Is this the right way to do it????
createObject( strGroupName ); createObject( strGroupName );
// New group name, creating a new entry // New group name, creating a new entry
@ -557,8 +563,8 @@ void ObjFileParser::getObjectName()
if (m_DataIt == m_DataItEnd) if (m_DataIt == m_DataItEnd)
return; return;
char *pStart = &(*m_DataIt); char *pStart = &(*m_DataIt);
while (!isSeparator(*m_DataIt)) while ( !isSeparator( *m_DataIt ) )
m_DataIt++; ++m_DataIt;
std::string strObjectName(pStart, &(*m_DataIt)); std::string strObjectName(pStart, &(*m_DataIt));
if (!strObjectName.empty()) if (!strObjectName.empty())
@ -588,15 +594,15 @@ void ObjFileParser::getObjectName()
// Creates a new object instance // Creates a new object instance
void ObjFileParser::createObject(const std::string &strObjectName) void ObjFileParser::createObject(const std::string &strObjectName)
{ {
ai_assert (NULL != m_pModel); ai_assert( NULL != m_pModel );
ai_assert (!strObjectName.empty()); ai_assert( !strObjectName.empty() );
m_pModel->m_pCurrent = new ObjFile::Object(); m_pModel->m_pCurrent = new ObjFile::Object;
m_pModel->m_pCurrent->m_strObjName = strObjectName; m_pModel->m_pCurrent->m_strObjName = strObjectName;
m_pModel->m_Objects.push_back( m_pModel->m_pCurrent ); m_pModel->m_Objects.push_back( m_pModel->m_pCurrent );
m_pModel->m_pCurrentMesh = new ObjFile::Mesh();
m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh ); createMesh();
if( m_pModel->m_pCurrentMaterial ) if( m_pModel->m_pCurrentMaterial )
{ {
@ -605,6 +611,39 @@ void ObjFileParser::createObject(const std::string &strObjectName)
m_pModel->m_pCurrentMesh->m_pMaterial = m_pModel->m_pCurrentMaterial; m_pModel->m_pCurrentMesh->m_pMaterial = m_pModel->m_pCurrentMaterial;
} }
} }
// -------------------------------------------------------------------
// Creates a new mesh
void ObjFileParser::createMesh()
{
ai_assert( NULL != m_pModel );
m_pModel->m_pCurrentMesh = new ObjFile::Mesh;
m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
unsigned int meshId = m_pModel->m_Meshes.size()-1;
if ( NULL != m_pModel->m_pCurrent )
{
m_pModel->m_pCurrent->m_Meshes.push_back( meshId );
}
else
{
DefaultLogger::get()->error("OBJ: No object detected to attach a new mesh instance.");
}
}
// -------------------------------------------------------------------
// Returns true, if a new mesh must be created.
bool ObjFileParser::needsNewMesh( const std::string &rMaterialName )
{
bool newMat = false;
int matIdx = getMaterialIndex( rMaterialName );
int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex;
if ( curMatIdx != ObjFile::Mesh::NoMaterial || curMatIdx != matIdx )
{
// New material -> only one material per mesh, so we need to create a new
// material
newMat = true;
}
return newMat;
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Shows an error in parsing process. // Shows an error in parsing process.
@ -613,6 +652,7 @@ void ObjFileParser::reportErrorTokenInFace()
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
DefaultLogger::get()->error("OBJ: Not supported token in face description detected"); DefaultLogger::get()->error("OBJ: Not supported token in face description detected");
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
} // Namespace Assimp } // Namespace Assimp

View File

@ -108,6 +108,10 @@ private:
void getObjectName(); void getObjectName();
/// Creates a new object. /// Creates a new object.
void createObject(const std::string &strObjectName); void createObject(const std::string &strObjectName);
/// Creates a new mesh.
void createMesh();
/// Returns true, if a new mesh instance must be created.
bool needsNewMesh( const std::string &rMaterialName );
/// Error report in token /// Error report in token
void reportErrorTokenInFace(); void reportErrorTokenInFace();