GLC_lib  2.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
glc_worldto3ds.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  *****************************************************************************/
23 
24 #include <QFile>
25 #include <QtDebug>
26 
27 #include "../geometry/glc_3drep.h"
28 #include "../geometry/glc_geometry.h"
29 #include "../geometry/glc_mesh.h"
30 
31 #include "../shading/glc_material.h"
32 
33 // Lib3ds Header
34 #include "3rdparty/lib3ds/file.h"
35 #include "3rdparty/lib3ds/mesh.h"
36 #include "3rdparty/lib3ds/node.h"
37 #include "3rdparty/lib3ds/matrix.h"
38 #include "3rdparty/lib3ds/material.h"
39 
40 #include "glc_worldto3ds.h"
41 
43 : QObject()
44 , m_World(world)
45 , m_pLib3dsFile(NULL)
46 , m_FileName()
47 , m_ReferenceToMesh()
48 , m_NameToMaterial()
49 , m_pRootLib3dsNode(NULL)
50 , m_CurrentNodeId(0)
51 , m_OccIdToNodeId()
52 , m_CurrentMeshIndex(0)
53 , m_UseAbsolutePosition(false)
54 , m_TextureToFileName()
55 {
56 
57 
58 }
59 
61 {
62 
63 }
64 
66 // Set Functions
68 bool GLC_WorldTo3ds::exportToFile(const QString& fileName, bool useAbsolutePosition)
69 {
70  m_ReferenceToMesh.clear();
71  m_NameToMaterial.clear();
72  m_pRootLib3dsNode= NULL;
73  m_CurrentNodeId= 0;
74  m_OccIdToNodeId.clear();
76  m_UseAbsolutePosition= useAbsolutePosition;
77  m_TextureToFileName.clear();
78 
79  m_FileName= fileName;
80  bool subject= false;
81  {
82  QFile exportFile(m_FileName);
83  subject= exportFile.open(QIODevice::WriteOnly);
84  exportFile.close();
85  }
86  if (subject)
87  {
88  m_pLib3dsFile= lib3ds_file_new();
89  saveWorld();
90  subject= lib3ds_file_save(m_pLib3dsFile, fileName.toLatin1().data());
91  }
92 
93  return subject;
94 }
95 
96 
98 // Private services functions
100 
102 {
104  {
105  saveMeshes();
106  }
107 
108  // Save node structure
110  const int childCount= pRoot->childCount();
111  for (int i= 0; i < childCount; ++i)
112  {
113  saveBranch(pRoot->child(i));
114  }
115 }
116 
118 {
119  // Retrieve the list of mesh and save them into the 3ds
120  QList<GLC_StructReference*> refList= m_World.references();
121  const int refCount= refList.count();
122  for (int i= 0; i < refCount; ++i)
123  {
124  GLC_StructReference* pRef= refList.at(i);
125  if (pRef->hasRepresentation())
126  {
127  GLC_3DRep* pRep= dynamic_cast<GLC_3DRep*>(pRef->representationHandle());
128  if (NULL != pRep)
129  {
130  // This reference has a mesh
131  const QString meshName= pRef->name() + '_' + QString::number(++m_CurrentMeshIndex);
132  QList<Lib3dsMesh*> meshes= createMeshsFrom3DRep(pRep, meshName);
133  {
134  const int count= meshes.count();
135  for (int i= 0; i < count; ++i)
136  {
137  lib3ds_file_insert_mesh(m_pLib3dsFile, meshes.at(i));
138  m_ReferenceToMesh.insertMulti(pRef, meshes.at(i));
139  }
140  }
141  }
142  }
143  }
144 }
145 
147 {
149 
150  const int childCount= pOcc->childCount();
151  for (int i= 0; i < childCount; ++i)
152  {
153  saveBranch(pOcc->child(i));
154  }
155 }
156 
158 {
159  Lib3dsNode* p3dsNode = lib3ds_node_new_object();
160  p3dsNode->node_id= m_CurrentNodeId;
161  m_OccIdToNodeId.insert(pOcc->id(), m_CurrentNodeId++);
162 
163  if (pOcc->parent() == m_World.rootOccurence())
164  {
165  p3dsNode->parent_id= LIB3DS_NO_PARENT;
166  }
167  else
168  {
169  Q_ASSERT(m_OccIdToNodeId.contains(pOcc->parent()->id()));
170  p3dsNode->parent_id= m_OccIdToNodeId.value(pOcc->parent()->id());
171  }
172 
173  lib3ds_file_insert_node(m_pLib3dsFile, p3dsNode);
174 
175  GLC_StructReference* pRef= pOcc->structReference();
177  {
178  if (pOcc->structReference()->hasRepresentation())
179  {
180  GLC_3DRep* pRep= dynamic_cast<GLC_3DRep*>(pOcc->structReference()->representationHandle());
181  if (NULL != pRep)
182  {
183  // This reference has a mesh
184  const GLC_Matrix4x4 matrix= pOcc->absoluteMatrix();
185  const QString meshName= pRef->name() + '_' + QString::number(++m_CurrentMeshIndex);
186  QList<Lib3dsMesh*> meshes= createMeshsFrom3DRep(pRep, meshName, matrix);
187 
188  const int meshCount= meshes.count();
189  for (int i= 0; i < meshCount; ++i)
190  {
191  lib3ds_file_insert_mesh(m_pLib3dsFile, meshes.at(i));
192  }
193 
194  if (meshCount > 1)
195  {
196  for (int i= 0; i < meshCount; ++i)
197  {
198 
199  Lib3dsNode* pCurrent3dsNode = lib3ds_node_new_object();
200  pCurrent3dsNode->node_id= m_CurrentNodeId++;
201  pCurrent3dsNode->parent_id= p3dsNode->node_id;
202 
203  strcpy(pCurrent3dsNode->name, meshes.at(i)->name);
204  lib3ds_file_insert_node(m_pLib3dsFile, pCurrent3dsNode);
205  }
206  }
207  else if (!meshes.isEmpty())
208  {
209  strcpy(p3dsNode->name, meshes.first()->name);
210  }
211  }
212  }
213  }
214  else
215  {
216  // Node matrix
217  const GLC_Matrix4x4 matrix= pOcc->structInstance()->relativeMatrix();
218  setNodePosition(p3dsNode, matrix);
219 
220  // Set mesh name if necessary
221  if (m_ReferenceToMesh.contains(pRef))
222  {
223 
224  QList<Lib3dsMesh*> meshes= m_ReferenceToMesh.values(pRef);
225  const int meshCount= meshes.count();
226  if (meshCount > 1)
227  {
228  for (int i= 0; i < meshCount; ++i)
229  {
230 
231  Lib3dsNode* pCurrent3dsNode = lib3ds_node_new_object();
232  pCurrent3dsNode->node_id= m_CurrentNodeId++;
233  pCurrent3dsNode->parent_id= p3dsNode->node_id;
234 
235  strcpy(pCurrent3dsNode->name, meshes.at(i)->name);
236  lib3ds_file_insert_node(m_pLib3dsFile, pCurrent3dsNode);
237  }
238  }
239  else
240  {
241  strcpy(p3dsNode->name, m_ReferenceToMesh.value(pRef)->name);
242  }
243 
244  }
245  }
246 }
247 
248 QList<Lib3dsMesh*> GLC_WorldTo3ds::createMeshsFrom3DRep(GLC_3DRep* pRep, const QString& name, const GLC_Matrix4x4& matrix)
249 {
250  QList<Lib3dsMesh*> subject;
251  int bodyIndex= 0;
252 
253  const int bodyCount= pRep->numberOfBody();
254  for (int i= 0; i < bodyCount; ++i)
255  {
256  GLC_Mesh* pCurrentMesh= dynamic_cast<GLC_Mesh*>(pRep->geomAt(i));
257  if ((NULL != pCurrentMesh) && !pCurrentMesh->isEmpty())
258  {
259  bool deleteCurrentMesh= false;
260  if (pCurrentMesh->lodCount() > 1)
261  {
262  // Keep only the first level of detail
263  pCurrentMesh= pCurrentMesh->createMeshOfGivenLod(0);
264  deleteCurrentMesh= true;
265  }
266  const QString bodyMeshName= name + '_' + QString::number(bodyIndex++);
267  if (matrix.type() != GLC_Matrix4x4::Identity)
268  {
269  if (!deleteCurrentMesh)
270  {
271  pCurrentMesh= new GLC_Mesh(*pCurrentMesh);
272  deleteCurrentMesh= true;
273  }
274  pCurrentMesh->transformVertice(matrix);
275  Q_ASSERT(!pCurrentMesh->isEmpty());
276  }
277  Lib3dsMesh* p3dsMesh= create3dsMeshFromGLC_Mesh(pCurrentMesh, bodyMeshName);
278 
279  if (deleteCurrentMesh) delete pCurrentMesh;
280  subject.append(p3dsMesh);
281  }
282  }
283 
284  return subject;
285 }
286 
287 Lib3dsMesh* GLC_WorldTo3ds::create3dsMeshFromGLC_Mesh(GLC_Mesh* pMesh, const QString& meshName)
288 {
289  // Create empty 3ds mesh with the given name
290  Lib3dsMesh* p3dsMesh= lib3ds_mesh_new(meshName.toLatin1().data());
291 
292  const int stride= 3;
293 
294  GLfloatVector vertice= pMesh->positionVector();
295  const uint pointsCount= vertice.count() / stride;
296 
297  // Add points to the 3DS mesh
298  lib3ds_mesh_new_point_list(p3dsMesh, pointsCount);
299 
300  for (uint i= 0; i < pointsCount; ++i)
301  {
302  Lib3dsPoint point;
303  point.pos[0]= vertice[i * 3];
304  point.pos[1]= vertice[i * 3 + 1];
305  point.pos[2]= vertice[i * 3 + 2];
306 
307  p3dsMesh->pointL[i]= point;
308  }
309 
310  // Add texel to the 3DS mesh
311  GLfloatVector texelVector= pMesh->texelVector();
312  if(!texelVector.isEmpty())
313  {
314  lib3ds_mesh_new_texel_list(p3dsMesh, pointsCount);
315  for (uint i= 0; i < pointsCount; ++i)
316  {
317  p3dsMesh->texelL[i][0]= texelVector[i * 2];
318  p3dsMesh->texelL[i][1]= texelVector[i * 2 + 1];
319  }
320  }
321 
322  // Add faces to the 3ds mesh
323  const uint totalFaceCount= pMesh->faceCount(0);
324  lib3ds_mesh_new_face_list(p3dsMesh, totalFaceCount);
325 
326  QSet<GLC_Material*> materialSet= pMesh->materialSet();
327  QSet<GLC_Material*>::iterator iMat= materialSet.begin();
328  uint currentFaceIndex= 0;
329  while(iMat != materialSet.end())
330  {
331  GLC_Material* pCurrentGLCMat= *iMat;
332  Lib3dsMaterial* pMaterial= get3dsMaterialFromGLC_Material(pCurrentGLCMat);
333  IndexList currentTriangleIndex= pMesh->getEquivalentTrianglesStripsFansIndex(0, pCurrentGLCMat->id());
334  const int faceCount= currentTriangleIndex.count() / 3;
335  for (int i= 0; i < faceCount; ++i)
336  {
337  Lib3dsFace face;
338  strcpy(face.material, pMaterial->name);
339 
340  face.points[0]= currentTriangleIndex.at(i * 3);
341  face.points[1]= currentTriangleIndex.at(i * 3 + 1);
342  face.points[2]= currentTriangleIndex.at(i * 3 + 2);
343 
344  p3dsMesh->faceL[currentFaceIndex++]= face;
345  Q_ASSERT(currentFaceIndex <= totalFaceCount);
346  }
347  ++iMat;
348  }
349 
350  return p3dsMesh;
351 }
352 
354 {
355  Lib3dsMaterial* pSubject= NULL;
356  const QString matName= materialName(pMat);
357  if (m_NameToMaterial.contains(matName))
358  {
359  pSubject= m_NameToMaterial.value(matName);
360  }
361  else
362  {
363  pSubject= create3dsMaterialFromGLC_Material(pMat, matName);
364  }
365 
366  return pSubject;
367 }
368 
369 Lib3dsMaterial* GLC_WorldTo3ds::create3dsMaterialFromGLC_Material(GLC_Material* pMat, const QString& matName)
370 {
371  Lib3dsMaterial* pSubject= lib3ds_material_new();
372  strcpy(pSubject->name, matName.toLatin1().data());
373 
374 
375  // Ambient Color
376  QColor ambient= pMat->ambientColor();
377  pSubject->ambient[0]= static_cast<float>(ambient.redF());
378  pSubject->ambient[1]= static_cast<float>(ambient.greenF());
379  pSubject->ambient[2]= static_cast<float>(ambient.blueF());
380  pSubject->ambient[3]= static_cast<float>(ambient.alphaF());
381 
382  // Diffuse Color
383  QColor diffuse= pMat->diffuseColor();
384  pSubject->diffuse[0]= static_cast<float>(diffuse.redF());
385  pSubject->diffuse[1]= static_cast<float>(diffuse.greenF());
386  pSubject->diffuse[2]= static_cast<float>(diffuse.blueF());
387  pSubject->diffuse[3]= static_cast<float>(diffuse.alphaF());
388 
389  // Specular Color
390  QColor specular= pMat->specularColor();
391  pSubject->specular[0]= static_cast<float>(specular.redF());
392  pSubject->specular[1]= static_cast<float>(specular.greenF());
393  pSubject->specular[2]= static_cast<float>(specular.blueF());
394  pSubject->specular[3]= static_cast<float>(specular.alphaF());
395 
396 
397  // Shininess
398  pSubject->shininess= pMat->shininess();
399 
400  // Transparency
401 
402  pSubject->transparency= 1.0f - static_cast<float>(pMat->opacity());
403 
404  // Texture
405  if (pMat->hasTexture())
406  {
407  if (!m_TextureToFileName.contains(pMat->textureHandle()))
408  {
409  QString filePath= QFileInfo(m_FileName).absolutePath();
410  QString textureName= matName;
411  QImage textureImage= pMat->textureHandle()->imageOfTexture();
412  if (!pMat->textureFileName().isEmpty())
413  {
414  textureName= QFileInfo(pMat->textureFileName()).fileName();
415  if (QFileInfo(pMat->textureFileName()).exists())
416  {
417  textureImage.load(pMat->textureFileName());
418  }
419  }
420  else
421  {
422  textureName= textureName + ".jpg";
423  }
424  textureName= textureName.right(63);
425 
426  if (!textureImage.isNull())
427  {
428  const QString type(QFileInfo(textureName).suffix());
429  QString newTextureFile= filePath + '/' + textureName;
430  textureImage.save(newTextureFile, type.toUpper().toLatin1().data());
431  strcpy(pSubject->texture1_map.name, textureName.toLatin1().data());
432  m_TextureToFileName.insert(pMat->textureHandle(), textureName);
433  }
434  }
435  else
436  {
437  QString textureName= m_TextureToFileName.value(pMat->textureHandle());
438  strcpy(pSubject->texture1_map.name, textureName.toLatin1().data());
439  }
440 
441  }
442 
443  lib3ds_file_insert_material(m_pLib3dsFile, pSubject);
444  m_NameToMaterial.insert(matName, pSubject);
445 
446  return pSubject;
447 }
448 
450 {
451  QString subject= pMat->name() + '_' + QString::number(pMat->id());
452  subject= subject.right(63);
453 
454  return subject;
455 }
456 
457 void GLC_WorldTo3ds::setNodePosition(Lib3dsNode* pNode, const GLC_Matrix4x4& matrix)
458 {
459  Lib3dsObjectData *pObjectData= &pNode->data.object;
460 
461  GLC_Matrix4x4 isoMatrix(matrix.isometricMatrix());
462  // Translation
463  Lib3dsLin3Key* pLin3Key= lib3ds_lin3_key_new();
464  pLin3Key->value[0]= isoMatrix.getData()[12];
465  pLin3Key->value[1]= isoMatrix.getData()[13];
466  pLin3Key->value[2]= isoMatrix.getData()[14];
467 
468  pLin3Key->tcb.frame= 1;
469  pObjectData->pos_track.keyL= pLin3Key;
470 
471 
472  // Scaling
473  Lib3dsLin3Key* pScale3Key= lib3ds_lin3_key_new();
474  pScale3Key->value[0]= static_cast<float>(matrix.scalingX());
475  pScale3Key->value[1]= static_cast<float>(matrix.scalingY());
476  pScale3Key->value[2]= static_cast<float>(matrix.scalingZ());
477 
478  pScale3Key->tcb.frame= 1;
479  pObjectData->scl_track.keyL= pScale3Key;
480 
481  // Rotation
482 
483  Lib3dsQuatKey* pQuatKey= lib3ds_quat_key_new();
484 
485  QQuaternion quaternion= matrix.quaternion();
486  QPair<GLC_Vector3d, double> pair= matrix.rotationVectorAndAngle();
487 
488  pQuatKey->angle= static_cast<float>(pair.second);
489  pQuatKey->axis[0]= static_cast<float>(pair.first.x());
490  pQuatKey->axis[1]= static_cast<float>(pair.first.y());
491  pQuatKey->axis[2]= static_cast<float>(pair.first.z());
492 
493  pQuatKey->tcb.frame= 1;
494 
495  pObjectData->rot_track.keyL= pQuatKey;
496 
497 }

©2005-2013 Laurent Ribon