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

SourceForge.net Logo

©2005 Laurent Ribon