glc_3dstoworld.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 
00003  This file is part of the GLC-lib library.
00004  Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
00005  http://glc-lib.sourceforge.net
00006 
00007  GLC-lib is free software; you can redistribute it and/or modify
00008  it under the terms of the GNU Lesser General Public License as published by
00009  the Free Software Foundation; either version 3 of the License, or
00010  (at your option) any later version.
00011 
00012  GLC-lib is distributed in the hope that it will be useful,
00013  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  GNU Lesser General Public License for more details.
00016 
00017  You should have received a copy of the GNU Lesser General Public License
00018  along with GLC-lib; if not, write to the Free Software
00019  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 *****************************************************************************/
00022 
00024 
00025 #include "glc_3dstoworld.h"
00026 
00027 #include "../geometry/glc_mesh.h"
00028 #include "../sceneGraph/glc_world.h"
00029 #include "../glc_fileformatexception.h"
00030 #include "../geometry/glc_circle.h"
00031 #include "../shading/glc_material.h"
00032 #include "../maths/glc_vector2df.h"
00033 #include "../maths/glc_vector3df.h"
00034 #include "../sceneGraph/glc_structreference.h"
00035 #include "../sceneGraph/glc_structinstance.h"
00036 #include "../sceneGraph/glc_structoccurence.h"
00037 
00038 // Lib3ds Header
00039 #include "3rdparty/lib3ds/file.h"
00040 #include "3rdparty/lib3ds/mesh.h"
00041 #include "3rdparty/lib3ds/node.h"
00042 #include "3rdparty/lib3ds/matrix.h"
00043 #include "3rdparty/lib3ds/material.h"
00044 
00045 #include <QFileInfo>
00046 #include <QGLContext>
00047 
00048 GLC_3dsToWorld::GLC_3dsToWorld()
00049 : m_pWorld(NULL)
00050 , m_FileName()
00051 , m_pCurrentMesh(NULL)
00052 , m_pLib3dsFile(NULL)
00053 , m_Materials()
00054 , m_NextMaterialIndex(0)
00055 , m_LoadedMeshes()
00056 , m_InitQuantumValue(50)
00057 , m_CurrentQuantumValue(0)
00058 , m_PreviousQuantumValue(0)
00059 , m_NumberOfMeshes(0)
00060 , m_CurrentMeshNumber(0)
00061 , m_ListOfAttachedFileName()
00062 {
00063 }
00064 
00065 GLC_3dsToWorld::~GLC_3dsToWorld()
00066 {
00067         clear();
00068 }
00069 
00070 // Create an GLC_World from an input 3DS File
00071 GLC_World* GLC_3dsToWorld::CreateWorldFrom3ds(QFile &file)
00072 {
00073         clear();
00074         m_FileName= file.fileName();
00075 
00077         // Test if the file exist and can be opened
00079         if (!file.open(QIODevice::ReadOnly))
00080         {
00081                 QString message(QString("GLC_3dsToWorld::CreateWorldFrom3ds File ") + m_FileName + QString(" doesn't exist"));
00082                 GLC_FileFormatException fileFormatException(message, m_FileName, GLC_FileFormatException::FileNotFound);
00083                 throw(fileFormatException);
00084         }
00085         // Close the file before open it with lib3ds
00086         file.close();
00087 
00089         // Init member
00091         m_pWorld= new GLC_World;
00092 
00093         //Load 3ds File
00094         m_pLib3dsFile=lib3ds_file_load(m_FileName.toLocal8Bit().data());
00095         if (!m_pLib3dsFile)
00096         {
00097                 QString message= "GLC_3dsToWorld::CreateWorldFrom3ds : Loading Failed";
00098                 GLC_FileFormatException fileFormatException(message, m_FileName, GLC_FileFormatException::FileNotSupported);
00099                 clear();
00100                 throw(fileFormatException);
00101         }
00102         // Evaluate Nodes Matrix for the first frame (Needed by instances)
00103         lib3ds_file_eval(m_pLib3dsFile, 0.0);
00104         m_CurrentQuantumValue= m_InitQuantumValue;
00105         m_PreviousQuantumValue= m_CurrentQuantumValue;
00106 
00107         emit currentQuantum(m_CurrentQuantumValue);
00108         // Count the number of meshes
00109         for(Lib3dsMesh *pMesh= m_pLib3dsFile->meshes; pMesh != NULL; pMesh = pMesh->next)
00110         {
00111                 ++m_NumberOfMeshes;
00112         }
00113         // Check if there is some meshes in the 3ds file
00114         if (0 == m_NumberOfMeshes)
00115         {
00116                 QString message= "GLC_3dsToWorld::CreateWorldFrom3ds : No mesh found !";
00117                 GLC_FileFormatException fileFormatException(message, m_FileName, GLC_FileFormatException::NoMeshFound);
00118                 clear();
00119                 throw(fileFormatException);
00120         }
00121 
00122         // Create GLC_3DViewInstance with Node
00123         for (Lib3dsNode *pNode=m_pLib3dsFile->nodes; pNode!=0; pNode=pNode->next)
00124         {
00125                 createMeshes(m_pWorld->rootOccurence(), pNode);
00126         }
00127 
00128         // Load unloaded mesh name
00129         for(Lib3dsMesh *pMesh= m_pLib3dsFile->meshes; pMesh != NULL; pMesh = pMesh->next)
00130         {
00131                 if (!m_LoadedMeshes.contains(QString(pMesh->name)))
00132                 {
00133                         //qDebug() << "Mesh without parent found" << QString(pMesh->name);
00134                         Lib3dsNode *pNode= lib3ds_node_new_object();
00135                         strcpy(pNode->name, pMesh->name);
00136                         pNode->parent_id= LIB3DS_NO_PARENT;
00137                         lib3ds_file_insert_node(m_pLib3dsFile, pNode);
00138                         createMeshes(m_pWorld->rootOccurence(), pNode);
00139                 }
00140         }
00141 
00142         // Free Lib3dsFile and all its ressources
00143         lib3ds_file_free(m_pLib3dsFile);
00144         m_pLib3dsFile= NULL;
00145         emit currentQuantum(100);
00146         // Create the world bounding box
00147         m_pWorld->collection()->boundingBox();
00148         return m_pWorld;
00149 }
00150 
00152 // Private services Functions
00154 
00155 // clear 3dsToWorld allocate memory and reset member
00156 void GLC_3dsToWorld::clear()
00157 {
00158         if (NULL != m_pCurrentMesh)
00159         {
00160                 delete m_pCurrentMesh;
00161                 m_pCurrentMesh= NULL;
00162         }
00163         m_pWorld= NULL;
00164         m_FileName.clear();
00165         if (NULL != m_pLib3dsFile)
00166         {
00167                 lib3ds_file_free(m_pLib3dsFile);
00168                 m_pLib3dsFile= NULL;
00169         }
00170 
00171         // Remove unused material
00172         QHash<QString, GLC_Material*>::iterator i;
00173         for (i= m_Materials.begin(); i != m_Materials.end(); ++i)
00174         {
00175                 if (i.value()->isUnused()) delete i.value();
00176         }
00177         m_Materials.clear();
00178         m_NextMaterialIndex= 0;
00179         // Clear the loaded meshes Set
00180         m_LoadedMeshes.clear();
00181         // Progress indicator
00182         m_CurrentQuantumValue= 0;
00183         m_PreviousQuantumValue= 0;
00184         m_NumberOfMeshes= 0;
00185         m_CurrentMeshNumber= 0;
00186         m_ListOfAttachedFileName.clear();
00187 }
00188 
00189 // Create meshes from the 3ds File
00190 void GLC_3dsToWorld::createMeshes(GLC_StructOccurence* pProduct, Lib3dsNode* pFatherNode)
00191 {
00192         GLC_StructOccurence* pChildProduct= NULL;
00193         Lib3dsMesh *pMesh= NULL;
00194 
00195         if (pFatherNode->type == LIB3DS_OBJECT_NODE)
00196         {
00197                 //qDebug() << "Node type LIB3DS_OBJECT_NODE is named : " << QString(pFatherNode->name);
00198                 //qDebug() << "Node Matrix :";
00199                 //qDebug() << GLC_Matrix4x4(&(pFatherNode->matrix[0][0])).toString();
00200 
00201                 // Check if the node is a mesh or dummy
00202                 if (!(strcmp(pFatherNode->name,"$$$DUMMY")==0))
00203                 {
00204                 pMesh = lib3ds_file_mesh_by_name(m_pLib3dsFile, pFatherNode->name);
00205                     if( pMesh != NULL )
00206                     {
00207                         GLC_3DRep representation(create3DRep(pMesh));
00208                         // Test if there is vertex in the mesh
00209                         if (0 != representation.vertexCount())
00210                         {
00211                                 m_LoadedMeshes.insert(representation.name());
00212                                 // Load node matrix
00213                                 GLC_Matrix4x4 nodeMat(&(pFatherNode->matrix[0][0]));
00214                                         // The mesh matrix to inverse
00215                                 GLC_Matrix4x4 matInv(&(pMesh->matrix[0][0]));
00216                                         matInv.invert();
00217                                         // Get the node pivot
00218                                         Lib3dsObjectData *pObjectData;
00219                                         pObjectData= &pFatherNode->data.object;
00220                                         GLC_Matrix4x4 trans(-pObjectData->pivot[0], -pObjectData->pivot[1], -pObjectData->pivot[2]);
00221                                         // Compute the part matrix
00222                                         nodeMat= nodeMat * trans * matInv; // I don't know why...
00223                                         nodeMat.optimise();
00224                                         // move the part by the matrix
00225                                         pProduct->addChild((new GLC_StructInstance(new GLC_3DRep(representation)))->move(nodeMat));
00226                         }
00227                         else
00228                         {
00229                                 // the instance will be deleted, check material usage
00230                                 QSet<GLC_Material*> meshMaterials= representation.materialSet();
00231                                 QSet<GLC_Material*>::const_iterator iMat= meshMaterials.constBegin();
00232                                 while (iMat != meshMaterials.constEnd())
00233                                 {
00234                                         if ((*iMat)->numberOfUsage() == 1)
00235                                         {
00236                                                 m_Materials.remove((*iMat)->name());
00237                                         }
00238                                         ++iMat;
00239                                 }
00240                         }
00241                     }
00242                 } // End If DUMMY
00243         }
00244         else return;
00245         // If there is a child, create a child product
00246         if (NULL != pFatherNode->childs)
00247         {
00248                 pChildProduct= new GLC_StructOccurence();
00249                 pProduct->addChild(pChildProduct);
00250 
00251                 pChildProduct->setName(QString("Product") + QString::number(pFatherNode->node_id));
00252 
00253                 //pChildProduct->move(GLC_Matrix4x4(&(pFatherNode->matrix[0][0])));
00254 
00255                 // Create Childs meshes if exists
00256                 for (Lib3dsNode* pNode= pFatherNode->childs; pNode!=0; pNode= pNode->next)
00257                 {
00258                         createMeshes(pChildProduct, pNode);
00259                 }
00260         }
00261 
00262 
00263 }
00265 GLC_3DRep GLC_3dsToWorld::create3DRep(Lib3dsMesh* p3dsMesh)
00266 {
00267         QString meshName(p3dsMesh->name);
00268         if (m_LoadedMeshes.contains(meshName))
00269         {
00270                 // This mesh as been already loaded
00271                 QList<GLC_3DViewInstance*> instancesList(m_pWorld->collection()->instancesHandle());
00272                 GLC_3DViewInstance* pCurrentInstance= NULL;
00273                 int currentIndex= -1;
00274                 do
00275                 {
00276                         pCurrentInstance= instancesList[++currentIndex];
00277                 } while (pCurrentInstance->name() != meshName);
00278                 // return an instance.
00279                 //qDebug() << "instance";
00280                 return pCurrentInstance->representation();
00281         }
00282         GLC_Mesh * pMesh= new GLC_Mesh();
00283         pMesh->setName(p3dsMesh->name);
00284         // The mesh normals
00285         const int normalsNumber= p3dsMesh->faces * 3;
00286 
00287         Lib3dsVector *normalL= static_cast<Lib3dsVector*>(malloc(normalsNumber * sizeof(Lib3dsVector)));
00288         lib3ds_mesh_calculate_normals(p3dsMesh, normalL);
00289 
00290         // Position vector
00291         QVector<float> position(normalsNumber * 3);
00292 
00293         // Normal Vector
00294         QVector<float> normal(normalsNumber * 3);
00295         memcpy((void*)normal.data(), normalL, normalsNumber * 3 * sizeof(float));
00296 
00297         // Texel Vector
00298         QVector<float> texel;
00299         if (p3dsMesh->texels > 0)
00300         {
00301                 texel.resize(normalsNumber * 2);
00302         }
00303 
00304         int normalIndex= 0;
00305         for (unsigned int i= 0; i < p3dsMesh->faces; ++i)
00306         {
00307                 IndexList triangleIndex;
00308                 Lib3dsFace *p3dsFace=&p3dsMesh->faceL[i];
00309                 for (int i=0; i < 3; ++i)
00310                 {
00311                         triangleIndex.append(normalIndex);
00312                         // Add vertex coordinate
00313                         memcpy((void*)&(position.data()[normalIndex * 3]), &p3dsMesh->pointL[p3dsFace->points[i]], 3 * sizeof(float));
00314 
00315                         // Add texel
00316                         if (p3dsMesh->texels > 0)
00317                         {
00318                                 memcpy((void*)&(texel.data()[normalIndex * 2]), &p3dsMesh->texelL[p3dsFace->points[i]], 2 * sizeof(float));
00319                         }
00320                         ++normalIndex;
00321                 }
00322 
00323                 // Load the material
00324                 // The material current face index
00325                 GLC_Material* pCurMaterial= NULL;
00326                 if (p3dsFace->material[0])
00327                 {
00328                         Lib3dsMaterial* p3dsMat=lib3ds_file_material_by_name(m_pLib3dsFile, p3dsFace->material);
00329                         if (NULL != p3dsMat)
00330                         {
00331                                 // Check it this material as already been loaded
00332                                 const QString materialName(p3dsFace->material);
00333 
00334                                 if (!m_Materials.contains(materialName))
00335                                 { // Material not already loaded, load it
00336                                         loadMaterial(p3dsMat);
00337                                 }
00338                                 pCurMaterial= m_Materials.value(materialName);
00339                         }
00340                 }
00341                 pMesh->addTriangles(pCurMaterial, triangleIndex);
00342         }
00343         pMesh->addVertice(position);
00344         pMesh->addNormals(normal);
00345         if (p3dsMesh->texels > 0)
00346         {
00347                 pMesh->addTexels(texel);
00348         }
00349 
00350         // free normal memmory
00351         delete[] normalL;
00352         // Compute loading progress
00353         ++m_CurrentMeshNumber;
00354         m_CurrentQuantumValue = static_cast<int>((static_cast<double>(m_CurrentMeshNumber) / m_NumberOfMeshes) * (100 - m_InitQuantumValue)) + m_InitQuantumValue;
00355         if (m_CurrentQuantumValue > m_PreviousQuantumValue)
00356         {
00357                 emit currentQuantum(m_CurrentQuantumValue);
00358         }
00359         m_PreviousQuantumValue= m_CurrentQuantumValue;
00360 
00361         pMesh->finish();
00362         return GLC_3DRep(pMesh);
00363 }
00364 
00365 // Load Material
00366 void GLC_3dsToWorld::loadMaterial(Lib3dsMaterial* p3dsMaterial)
00367 {
00368         GLC_Material* pMaterial= new GLC_Material;
00369         // Set the material name
00370         const QString materialName(p3dsMaterial->name);
00371         pMaterial->setName(materialName);
00372         // Check if there is a texture
00373         if (p3dsMaterial->texture1_map.name[0])
00374         {
00375                 const QString textureName(p3dsMaterial->texture1_map.name);
00376                 // Retrieve the .3ds file path
00377                 QFileInfo fileInfo(m_FileName);
00378                 QString textureFileName(fileInfo.absolutePath() + QDir::separator());
00379                 textureFileName.append(textureName);
00380 
00381                 // TGA file type are not supported
00382                 if (!textureName.right(3).contains("TGA", Qt::CaseInsensitive))
00383                 {
00384                         QFile textureFile(textureFileName);
00385 
00386                         if (textureFile.open(QIODevice::ReadOnly))
00387                         {
00388                                 // Create the texture and assign it to the material
00389                                 GLC_Texture *pTexture = new GLC_Texture(textureFile);
00390                                 pMaterial->setTexture(pTexture);
00391                                 m_ListOfAttachedFileName << textureFileName;
00392                                 textureFile.close();
00393                         }
00394                         else
00395                         {
00396                                 QStringList stringList(m_FileName);
00397                                 stringList.append("Open File : " + textureFileName + " failed");
00398                                 GLC_ErrorLog::addError(stringList);
00399                         }
00400 
00401                 }
00402                 else
00403                 {
00404                         QStringList stringList(m_FileName);
00405                         stringList.append("Image : " + textureFileName + " not suported");
00406                         GLC_ErrorLog::addError(stringList);
00407                 }
00408         }
00409 
00410         // Ambient Color
00411         QColor ambient;
00412         ambient.setRgbF(p3dsMaterial->ambient[0], p3dsMaterial->ambient[1], p3dsMaterial->ambient[2]);
00413         ambient.setAlphaF(p3dsMaterial->ambient[3]);
00414         pMaterial->setAmbientColor(ambient);
00415         // Diffuse Color
00416         QColor diffuse;
00417         diffuse.setRgbF(p3dsMaterial->diffuse[0], p3dsMaterial->diffuse[1], p3dsMaterial->diffuse[2]);
00418         diffuse.setAlphaF(p3dsMaterial->diffuse[3]);
00419         pMaterial->setDiffuseColor(diffuse);
00420         // Specular Color
00421         QColor specular;
00422         specular.setRgbF(p3dsMaterial->specular[0], p3dsMaterial->specular[1], p3dsMaterial->specular[2]);
00423         specular.setAlphaF(p3dsMaterial->specular[3]);
00424         pMaterial->setSpecularColor(specular);
00425         // Shininess
00426 
00427         if (0 != p3dsMaterial->shininess)
00428         {
00429                 float matShininess= p3dsMaterial->shininess * 128.0f;
00430                 if (matShininess > 128.0f) matShininess= 128.0f;
00431                 if (matShininess < 5.0f) matShininess= 20.0f;
00432                 pMaterial->setShininess(matShininess);
00433         }
00434         // Transparency
00435 
00436         pMaterial->setOpacity(1.0 - p3dsMaterial->transparency);
00437 
00438         // Add the material to the hash table
00439         m_Materials.insert(materialName, pMaterial);
00440 }
00441 

SourceForge.net Logo

©2005-2011 Laurent Ribon