GLC_lib  2.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
glc_3dstoworld.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 
3  This file is part of the GLC-lib library.
4  Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
5  http://glc-lib.sourceforge.net
6 
7  GLC-lib is free software; you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as published by
9  the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version.
11 
12  GLC-lib is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public License
18  along with GLC-lib; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21 *****************************************************************************/
22 
24 
25 #include "glc_3dstoworld.h"
26 
27 #include "../geometry/glc_mesh.h"
28 #include "../sceneGraph/glc_world.h"
29 #include "../glc_fileformatexception.h"
30 #include "../geometry/glc_circle.h"
31 #include "../shading/glc_material.h"
32 #include "../maths/glc_vector2df.h"
33 #include "../maths/glc_vector3df.h"
34 #include "../sceneGraph/glc_structreference.h"
35 #include "../sceneGraph/glc_structinstance.h"
36 #include "../sceneGraph/glc_structoccurence.h"
37 
38 // Lib3ds Header
39 #include "3rdparty/lib3ds/file.h"
40 #include "3rdparty/lib3ds/mesh.h"
41 #include "3rdparty/lib3ds/node.h"
42 #include "3rdparty/lib3ds/matrix.h"
43 #include "3rdparty/lib3ds/material.h"
44 
45 #include <QFileInfo>
46 #include <QGLContext>
47 
49 : m_pWorld(NULL)
50 , m_FileName()
51 , m_pCurrentMesh(NULL)
52 , m_pLib3dsFile(NULL)
53 , m_Materials()
54 , m_NextMaterialIndex(0)
55 , m_LoadedMeshes()
56 , m_InitQuantumValue(50)
57 , m_CurrentQuantumValue(0)
58 , m_PreviousQuantumValue(0)
59 , m_NumberOfMeshes(0)
60 , m_CurrentMeshNumber(0)
61 , m_ListOfAttachedFileName()
62 {
63 }
64 
66 {
67  clear();
68 }
69 
70 // Create an GLC_World from an input 3DS File
72 {
73  clear();
74  m_FileName= file.fileName();
75 
77  // Test if the file exist and can be opened
79  if (!file.open(QIODevice::ReadOnly))
80  {
81  QString message(QString("GLC_3dsToWorld::CreateWorldFrom3ds File ") + m_FileName + QString(" doesn't exist"));
83  throw(fileFormatException);
84  }
85  // Close the file before open it with lib3ds
86  file.close();
87 
89  // Init member
91  m_pWorld= new GLC_World;
92 
93  //Load 3ds File
94  m_pLib3dsFile=lib3ds_file_load(m_FileName.toLocal8Bit().data());
95  if (!m_pLib3dsFile)
96  {
97  QString message= "GLC_3dsToWorld::CreateWorldFrom3ds : Loading Failed";
99  clear();
100  throw(fileFormatException);
101  }
102  // Evaluate Nodes Matrix for the first frame (Needed by instances)
103  lib3ds_file_eval(m_pLib3dsFile, 0.0);
106 
108  // Count the number of meshes
109  for(Lib3dsMesh *pMesh= m_pLib3dsFile->meshes; pMesh != NULL; pMesh = pMesh->next)
110  {
112  }
113  // Check if there is some meshes in the 3ds file
114  if (0 == m_NumberOfMeshes)
115  {
116  QString message= "GLC_3dsToWorld::CreateWorldFrom3ds : No mesh found !";
118  clear();
119  throw(fileFormatException);
120  }
121 
122  // Create GLC_3DViewInstance with Node
123  for (Lib3dsNode *pNode=m_pLib3dsFile->nodes; pNode!=0; pNode=pNode->next)
124  {
126  }
127 
128  // Load unloaded mesh name
129  for(Lib3dsMesh *pMesh= m_pLib3dsFile->meshes; pMesh != NULL; pMesh = pMesh->next)
130  {
131  if (!m_LoadedMeshes.contains(QString(pMesh->name)))
132  {
133  //qDebug() << "Mesh without parent found" << QString(pMesh->name);
134  Lib3dsNode *pNode= lib3ds_node_new_object();
135  strcpy(pNode->name, pMesh->name);
136  pNode->parent_id= LIB3DS_NO_PARENT;
137  lib3ds_file_insert_node(m_pLib3dsFile, pNode);
139  }
140  }
141 
142  // Free Lib3dsFile and all its ressources
143  lib3ds_file_free(m_pLib3dsFile);
144  m_pLib3dsFile= NULL;
145  emit currentQuantum(100);
146  // Create the world bounding box
148  return m_pWorld;
149 }
150 
152 // Private services Functions
154 
155 // clear 3dsToWorld allocate memory and reset member
157 {
158  if (NULL != m_pCurrentMesh)
159  {
160  delete m_pCurrentMesh;
161  m_pCurrentMesh= NULL;
162  }
163  m_pWorld= NULL;
164  m_FileName.clear();
165  if (NULL != m_pLib3dsFile)
166  {
167  lib3ds_file_free(m_pLib3dsFile);
168  m_pLib3dsFile= NULL;
169  }
170 
171  // Remove unused material
172  QHash<QString, GLC_Material*>::iterator i;
173  for (i= m_Materials.begin(); i != m_Materials.end(); ++i)
174  {
175  if (i.value()->isUnused()) delete i.value();
176  }
177  m_Materials.clear();
179  // Clear the loaded meshes Set
180  m_LoadedMeshes.clear();
181  // Progress indicator
184  m_NumberOfMeshes= 0;
186  m_ListOfAttachedFileName.clear();
187 }
188 
189 // Create meshes from the 3ds File
190 void GLC_3dsToWorld::createMeshes(GLC_StructOccurence* pProduct, Lib3dsNode* pFatherNode)
191 {
192  GLC_StructOccurence* pChildProduct= NULL;
193  Lib3dsMesh *pMesh= NULL;
194 
195  if (pFatherNode->type == LIB3DS_OBJECT_NODE)
196  {
197  //qDebug() << "Node type LIB3DS_OBJECT_NODE is named : " << QString(pFatherNode->name);
198  //qDebug() << "Node Matrix :";
199  //qDebug() << GLC_Matrix4x4(&(pFatherNode->matrix[0][0])).toString();
200 
201  // Check if the node is a mesh or dummy
202  if (!(strcmp(pFatherNode->name,"$$$DUMMY")==0))
203  {
204  pMesh = lib3ds_file_mesh_by_name(m_pLib3dsFile, pFatherNode->name);
205  if( pMesh != NULL )
206  {
207  GLC_3DRep representation(create3DRep(pMesh));
208  // Test if there is vertex in the mesh
209  if (0 != representation.vertexCount())
210  {
211  m_LoadedMeshes.insert(representation.name());
212  // Load node matrix
213  GLC_Matrix4x4 nodeMat(&(pFatherNode->matrix[0][0]));
214  // The mesh matrix to inverse
215  GLC_Matrix4x4 matInv(&(pMesh->matrix[0][0]));
216  matInv.invert();
217  // Get the node pivot
218  Lib3dsObjectData *pObjectData;
219  pObjectData= &pFatherNode->data.object;
220  GLC_Matrix4x4 trans(-pObjectData->pivot[0], -pObjectData->pivot[1], -pObjectData->pivot[2]);
221  // Compute the part matrix
222  nodeMat= nodeMat * trans * matInv; // I don't know why...
223  nodeMat.optimise();
224  // move the part by the matrix
225  pProduct->addChild((new GLC_StructInstance(new GLC_3DRep(representation)))->move(nodeMat));
226  }
227  else
228  {
229  // the instance will be deleted, check material usage
230  QSet<GLC_Material*> meshMaterials= representation.materialSet();
231  QSet<GLC_Material*>::const_iterator iMat= meshMaterials.constBegin();
232  while (iMat != meshMaterials.constEnd())
233  {
234  if ((*iMat)->numberOfUsage() == 1)
235  {
236  m_Materials.remove((*iMat)->name());
237  }
238  ++iMat;
239  }
240  }
241  }
242  } // End If DUMMY
243  }
244  else return;
245  // If there is a child, create a child product
246  if (NULL != pFatherNode->childs)
247  {
248  pChildProduct= new GLC_StructOccurence();
249  pProduct->addChild(pChildProduct);
250 
251  pChildProduct->setName(QString("Product") + QString::number(pFatherNode->node_id));
252 
253  //pChildProduct->move(GLC_Matrix4x4(&(pFatherNode->matrix[0][0])));
254 
255  // Create Childs meshes if exists
256  for (Lib3dsNode* pNode= pFatherNode->childs; pNode!=0; pNode= pNode->next)
257  {
258  createMeshes(pChildProduct, pNode);
259  }
260  }
261 
262 
263 }
266 {
267  QString meshName(p3dsMesh->name);
268  if (m_LoadedMeshes.contains(meshName))
269  {
270  // This mesh as been already loaded
271  QList<GLC_3DViewInstance*> instancesList(m_pWorld->collection()->instancesHandle());
272  GLC_3DViewInstance* pCurrentInstance= NULL;
273  int currentIndex= -1;
274  do
275  {
276  pCurrentInstance= instancesList[++currentIndex];
277  } while (pCurrentInstance->name() != meshName);
278  // return an instance.
279  //qDebug() << "instance";
280  return pCurrentInstance->representation();
281  }
282  GLC_Mesh * pMesh= new GLC_Mesh();
283  pMesh->setName(p3dsMesh->name);
284  // The mesh normals
285  const int normalsNumber= p3dsMesh->faces * 3;
286 
287  Lib3dsVector *normalL= static_cast<Lib3dsVector*>(malloc(normalsNumber * sizeof(Lib3dsVector)));
288  lib3ds_mesh_calculate_normals(p3dsMesh, normalL);
289 
290  // Position vector
291  QVector<float> position(normalsNumber * 3);
292 
293  // Normal Vector
294  QVector<float> normal(normalsNumber * 3);
295  memcpy((void*)normal.data(), normalL, normalsNumber * 3 * sizeof(float));
296 
297  // Texel Vector
298  QVector<float> texel;
299  if (p3dsMesh->texels > 0)
300  {
301  texel.resize(normalsNumber * 2);
302  }
303 
304  int normalIndex= 0;
305  for (unsigned int i= 0; i < p3dsMesh->faces; ++i)
306  {
307  IndexList triangleIndex;
308  Lib3dsFace *p3dsFace=&p3dsMesh->faceL[i];
309  for (int i=0; i < 3; ++i)
310  {
311  triangleIndex.append(normalIndex);
312  // Add vertex coordinate
313  memcpy((void*)&(position.data()[normalIndex * 3]), &p3dsMesh->pointL[p3dsFace->points[i]], 3 * sizeof(float));
314 
315  // Add texel
316  if (p3dsMesh->texels > 0)
317  {
318  memcpy((void*)&(texel.data()[normalIndex * 2]), &p3dsMesh->texelL[p3dsFace->points[i]], 2 * sizeof(float));
319  }
320  ++normalIndex;
321  }
322 
323  // Load the material
324  // The material current face index
325  GLC_Material* pCurMaterial= NULL;
326  if (p3dsFace->material[0])
327  {
328  Lib3dsMaterial* p3dsMat=lib3ds_file_material_by_name(m_pLib3dsFile, p3dsFace->material);
329  if (NULL != p3dsMat)
330  {
331  // Check it this material as already been loaded
332  const QString materialName(p3dsFace->material);
333 
334  if (!m_Materials.contains(materialName))
335  { // Material not already loaded, load it
336  loadMaterial(p3dsMat);
337  }
338  pCurMaterial= m_Materials.value(materialName);
339  }
340  }
341  pMesh->addTriangles(pCurMaterial, triangleIndex);
342  }
343  pMesh->addVertice(position);
344  pMesh->addNormals(normal);
345  if (p3dsMesh->texels > 0)
346  {
347  pMesh->addTexels(texel);
348  }
349 
350  // free normal memmory
351  delete[] normalL;
352  // Compute loading progress
354  m_CurrentQuantumValue = static_cast<int>((static_cast<double>(m_CurrentMeshNumber) / m_NumberOfMeshes) * (100 - m_InitQuantumValue)) + m_InitQuantumValue;
356  {
358  }
360 
361  pMesh->finish();
362  return GLC_3DRep(pMesh);
363 }
364 
365 // Load Material
366 void GLC_3dsToWorld::loadMaterial(Lib3dsMaterial* p3dsMaterial)
367 {
368  GLC_Material* pMaterial= new GLC_Material;
369  // Set the material name
370  const QString materialName(p3dsMaterial->name);
371  pMaterial->setName(materialName);
372  // Check if there is a texture
373  if (p3dsMaterial->texture1_map.name[0])
374  {
375  const QString textureName(p3dsMaterial->texture1_map.name);
376  // Retrieve the .3ds file path
377  QFileInfo fileInfo(m_FileName);
378  QString textureFileName(fileInfo.absolutePath() + QDir::separator());
379  textureFileName.append(textureName);
380 
381  // TGA file type are not supported
382  if (!textureName.right(3).contains("TGA", Qt::CaseInsensitive))
383  {
384  QFile textureFile(textureFileName);
385 
386  if (textureFile.open(QIODevice::ReadOnly))
387  {
388  // Create the texture and assign it to the material
389  GLC_Texture *pTexture = new GLC_Texture(textureFile);
390  pMaterial->setTexture(pTexture);
391  m_ListOfAttachedFileName << textureFileName;
392  textureFile.close();
393  }
394  else
395  {
396  QStringList stringList(m_FileName);
397  stringList.append("Open File : " + textureFileName + " failed");
398  GLC_ErrorLog::addError(stringList);
399  }
400 
401  }
402  else
403  {
404  QStringList stringList(m_FileName);
405  stringList.append("Image : " + textureFileName + " not suported");
406  GLC_ErrorLog::addError(stringList);
407  }
408  }
409 
410  // Ambient Color
411  QColor ambient;
412  ambient.setRgbF(p3dsMaterial->ambient[0], p3dsMaterial->ambient[1], p3dsMaterial->ambient[2]);
413  ambient.setAlphaF(p3dsMaterial->ambient[3]);
414  pMaterial->setAmbientColor(ambient);
415  // Diffuse Color
416  QColor diffuse;
417  diffuse.setRgbF(p3dsMaterial->diffuse[0], p3dsMaterial->diffuse[1], p3dsMaterial->diffuse[2]);
418  diffuse.setAlphaF(p3dsMaterial->diffuse[3]);
419  pMaterial->setDiffuseColor(diffuse);
420  // Specular Color
421  QColor specular;
422  specular.setRgbF(p3dsMaterial->specular[0], p3dsMaterial->specular[1], p3dsMaterial->specular[2]);
423  specular.setAlphaF(p3dsMaterial->specular[3]);
424  pMaterial->setSpecularColor(specular);
425  // Shininess
426 
427  if (0 != p3dsMaterial->shininess)
428  {
429  float matShininess= p3dsMaterial->shininess * 128.0f;
430  if (matShininess > 128.0f) matShininess= 128.0f;
431  if (matShininess < 5.0f) matShininess= 20.0f;
432  pMaterial->setShininess(matShininess);
433  }
434  // Transparency
435 
436  pMaterial->setOpacity(1.0 - p3dsMaterial->transparency);
437 
438  // Add the material to the hash table
439  m_Materials.insert(materialName, pMaterial);
440 }
441 

©2005-2013 Laurent Ribon