Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
AssimpPlugin.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen *
5 * www.openflipper.org *
6 * *
7 *--------------------------------------------------------------------------- *
8 * This file is part of OpenFlipper. *
9 * *
10 * OpenFlipper is free software: you can redistribute it and/or modify *
11 * it under the terms of the GNU Lesser General Public License as *
12 * published by the Free Software Foundation, either version 3 of *
13 * the License, or (at your option) any later version with the *
14 * following exceptions: *
15 * *
16 * If other files instantiate templates or use macros *
17 * or inline functions from this file, or you compile this file and *
18 * link it with other files to produce an executable, this file does *
19 * not by itself cause the resulting executable to be covered by the *
20 * GNU Lesser General Public License. This exception does not however *
21 * invalidate any other reasons why the executable file might be *
22 * covered by the GNU Lesser General Public License. *
23 * *
24 * OpenFlipper is distributed in the hope that it will be useful, *
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
27 * GNU Lesser General Public License for more details. *
28 * *
29 * You should have received a copy of the GNU LesserGeneral Public *
30 * License along with OpenFlipper. If not, *
31 * see <http://www.gnu.org/licenses/>. *
32 * *
33 \*===========================================================================*/
34 
35 /*===========================================================================*\
36 * *
37 * $Revision: 13361 $ *
38 * $LastChangedBy: moebius $ *
39 * $Date: 2012-01-12 16:33:16 +0100 (Thu, 12 Jan 2012) $ *
40 * *
41 \*===========================================================================*/
42 
43 
44 
45 
46 #include "AssimpPlugin.hh"
47 
48 /*
49  * we have to implement our own aiScene and aiMaterial constructor/destructor
50  * since the linker cannot find the corresponding symbols from the
51  * assimp library
52  */
53 
54 aiMaterial::aiMaterial() {
55  mNumAllocated = 0;
56  mNumProperties = 0;
57  mProperties = NULL;
58 }
59 aiMaterial::~aiMaterial() {
60  for (unsigned int i = 0; i < mNumProperties; ++i)
61  delete mProperties[i];
62  delete[] mProperties;
63 }
64 
65 aiScene::aiScene() {
66  mFlags = 0;
67  mRootNode = NULL;
68  mNumMeshes = 0;
69  mMeshes = NULL;
70  mNumMaterials = 0;
71  mMaterials = NULL;
72  mNumAnimations = 0;
73  mAnimations = NULL;
74  mNumTextures = 0;
75  mTextures = NULL;
76  mNumLights = 0;
77  mLights = NULL;
78  mNumCameras = 0;
79  mCameras = NULL;
80 }
81 aiScene::~aiScene() {
82  delete mRootNode;
83 
84  for (unsigned int i = 0; i < mNumMeshes; ++i)
85  delete mMeshes[i];
86  delete[] mMeshes;
87 
88  for (unsigned int i = 0; i < mNumMaterials; ++i)
89  delete mMaterials[i];
90  delete[] mMaterials;
91 
92  for (unsigned int i = 0; i < mNumAnimations; ++i)
93  delete mAnimations[i];
94  delete[] mAnimations;
95 
96  for (unsigned int i = 0; i < mNumTextures; ++i)
97  delete mTextures[i];
98  delete[] mTextures;
99 
100  for (unsigned int i = 0; i < mNumLights; ++i)
101  delete mLights[i];
102  delete[] mLights;
103 
104  for (unsigned int i = 0; i < mNumCameras; ++i)
105  delete mCameras[i];
106  delete[] mCameras;
107 }
108 
109 
110 AssimpPlugin::AssimpPlugin()
111  :
112  loadOptions_(0),
113  saveOptions_(0),
114  type_(DATA_TRIANGLE_MESH)
115 {
116 }
117 
118 void AssimpPlugin::initializePlugin() {
119 
120  QString info =
121  " Copyright (c) 2006-2012 assimp team<br>"
122  " All rights reserved.<br>"
123  " Redistribution and use in source and binary forms, with or without modification, are "
124  " permitted provided that the following conditions are met: <br> "
125  " <br> "
126  " Redistributions of source code must retain the above copyright notice, this list of "
127  " conditions and the following disclaimer.<br> "
128  " <br> "
129  " Redistributions in binary form must reproduce the above copyright notice, this list "
130  " of conditions and the following disclaimer in the documentation and/or other "
131  " materials provided with the distribution.<br> "
132  " <br> "
133  " Neither the name of the assimp team nor the names of its contributors may be used to "
134  " endorse or promote products derived from this software without specific prior written "
135  " permission.<br> "
136  " <br> "
137  " THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY "
138  " EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF"
139  " MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL "
140  " THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, "
141  " SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, "
142  " PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS"
143  " INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, "
144  " STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF"
145  " THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "
146  " <br> ";
147 
148  emit addAboutInfo(info,"File-Assimp Plugin");
149 }
150 
151 int AssimpPlugin::convertAiSceneToOpenMesh(const aiScene *_scene, QString _objectName) {
152  int returnId = -1;
153  std::vector<int> ids;
154 
155  if (_scene->mNumMeshes == 0)
156  emit log(LOGWARN, tr("aiScene contains no meshes"));
157 
158  for (unsigned int i = 0; i < _scene->mNumMeshes; ++i) {
159  int objectId = -1;
160  emit addEmptyObject(type_, objectId);
161 
162  BaseObject* object(0);
163  if(!PluginFunctions::getObject( objectId, object )) {
164  emit log(LOGERR, tr("Could not create new object!"));
165  return -1;
166  }
167 
168  if (i == 0)
169  returnId = objectId;
170 
171  object->setName(_objectName);
172 
173  PolyMeshObject* polyMeshObj = dynamic_cast< PolyMeshObject* > (object);
174  TriMeshObject* triMeshObj = dynamic_cast< TriMeshObject* > (object);
175 
176  if (polyMeshObj) {
177  convertPolyMeshToAiMesh(polyMeshObj->mesh(), _scene->mMeshes[i]);
178 
179  emit updatedObject(polyMeshObj->id(), UPDATE_ALL);
180 
181  ids.push_back(object->id());
182  } else if (triMeshObj) {
183  convertAiMeshToTriMesh(triMeshObj->mesh(), _scene->mMeshes[i]);
184 
185  emit updatedObject(triMeshObj->id(), UPDATE_ALL);
186 
187  ids.push_back(object->id());
188  }
189 
190  emit openedFile( object->id() );
191  }
192 
193  if (_scene->mNumMeshes > 1) {
194  bool dataControlExists = false;
195  pluginExists( "datacontrol", dataControlExists );
196 
197  if ( dataControlExists ){
198  returnId = RPC::callFunctionValue<int>("datacontrol","groupObjects", ids, _objectName);
199  }
200  }
201 
202  return returnId;
203 }
204 
206  _scene->mMeshes = new aiMesh*[1];
207  _scene->mMeshes[0] = new aiMesh();
208  _scene->mNumMeshes = 1;
209  _scene->mRootNode = new aiNode();
210  _scene->mRootNode->mNumChildren = 0;
211  _scene->mRootNode->mNumMeshes = 1;
212  _scene->mRootNode->mMeshes = new unsigned int[1];
213  _scene->mRootNode->mMeshes[0] = 0;
214 
215  // assimp requires at least one material
216  _scene->mMaterials = new aiMaterial*[1];
217  _scene->mMaterials[0] = new aiMaterial();
218  _scene->mNumMaterials = 1;
219 
220  if ( _object->dataType( DATA_POLY_MESH ) ) {
221  return convertPolyMeshToAiMesh(dynamic_cast<PolyMeshObject*>(_object)->mesh(), _scene->mMeshes[0]);
222  }
223  else if ( _object->dataType( DATA_TRIANGLE_MESH ) ) {
224  return convertTriMeshToAiMesh(dynamic_cast<TriMeshObject*>(_object)->mesh(), _scene->mMeshes[0]);
225  }
226  else {
227  emit log(LOGERR, tr("Unable to save (object is not a compatible mesh type)"));
228  return false;
229  }
230 }
231 
232 void AssimpPlugin::convertAiMeshToPolyMesh(PolyMesh *_polyMesh, aiMesh *_mesh) {
233  mapVertices(_polyMesh, _mesh);
234 
235  std::vector<OpenMesh::VertexHandle> vhandles;
236  for (unsigned int i = 0; i < _mesh->mNumFaces; ++i) {
237  aiFace& face = _mesh->mFaces[i];
238  for (unsigned int j = 0; j < face.mNumIndices; ++j) {
239  vhandles.push_back(vertexHandles_[face.mIndices[j]]);
240  if (_mesh->HasNormals()) {
241  aiVector3D& aiNormal = _mesh->mNormals[face.mIndices[j]];
242  _polyMesh->set_normal(vhandles.back(), ACG::Vec3d(aiNormal.x, aiNormal.y, aiNormal.z));
243  }
244  }
245 
246  _polyMesh->add_face(vhandles);
247  vhandles.clear();
248  }
249 
250  if (!_mesh->HasNormals())
251  _polyMesh->update_normals();
252  else
253  _polyMesh->update_face_normals();
254 }
255 
256 void AssimpPlugin::convertAiMeshToTriMesh(TriMesh *_triMesh, aiMesh *_mesh) {
257  mapVertices(_triMesh, _mesh);
258 
259  std::vector<OpenMesh::VertexHandle> vhandles;
260  for (unsigned int i = 0; i < _mesh->mNumFaces; ++i) {
261  aiFace& face = _mesh->mFaces[i];
262  for (unsigned int j = 0; j < face.mNumIndices; ++j) {
263  vhandles.push_back(vertexHandles_[face.mIndices[j]]);
264  if (_mesh->HasNormals()) {
265  aiVector3D& aiNormal = _mesh->mNormals[face.mIndices[j]];
266  _triMesh->set_normal(vhandles.back(), ACG::Vec3d(aiNormal.x, aiNormal.y, aiNormal.z));
267  }
268  }
269 
270  _triMesh->add_face(vhandles);
271  vhandles.clear();
272  }
273 
274  if (!_mesh->HasNormals())
275  _triMesh->update_normals();
276  else
277  _triMesh->update_face_normals();
278 }
279 
280 bool AssimpPlugin::convertPolyMeshToAiMesh(PolyMesh *_polyMesh, aiMesh *_mesh) {
281  _mesh->mPrimitiveTypes = aiPrimitiveType_POLYGON;
282  _mesh->mNumVertices = _polyMesh->n_vertices();
283  _mesh->mNumFaces = _polyMesh->n_faces();
284 
285  _mesh->mVertices = new aiVector3D[_mesh->mNumVertices];
286  _mesh->mNormals = new aiVector3D[_mesh->mNumVertices];
287  _mesh->mFaces = new aiFace[_mesh->mNumFaces];
288 
289  std::map<OpenMesh::VertexHandle, int> vertexHandles;
290  int i = 0;
291  for (PolyMesh::ConstVertexIter v_it = _polyMesh->vertices_begin(); v_it != _polyMesh->vertices_end(); ++v_it, ++i) {
292  ACG::Vec3d pos = _polyMesh->point(*v_it);
293  ACG::Vec3d normal = _polyMesh->normal(*v_it);
294  _mesh->mVertices[i] = aiVector3D(pos[0], pos[1], pos[2]);
295  _mesh->mNormals[i] = aiVector3D(normal[0], normal[1], normal[2]);
296  vertexHandles[*v_it] = i;
297  }
298 
299  i = 0;
300  for (PolyMesh::ConstFaceIter f_it = _polyMesh->faces_begin(); f_it != _polyMesh->faces_end(); ++f_it, ++i) {
301  int nVertices = 0;
302  for (PolyMesh::ConstFaceVertexIter fv_it = _polyMesh->fv_iter(*f_it); fv_it.is_valid(); ++fv_it) {
303  ++nVertices;
304  }
305 
306  _mesh->mFaces[i].mNumIndices = nVertices;
307  _mesh->mFaces[i].mIndices = new unsigned int[nVertices];
308  int j = 0;
309  for (PolyMesh::ConstFaceVertexIter fv_it = _polyMesh->fv_iter(*f_it); fv_it.is_valid(); ++fv_it, ++j) {
310  _mesh->mFaces[i].mIndices[j] = vertexHandles[*fv_it];
311  }
312  }
313 
314  return true;
315 }
316 
317 bool AssimpPlugin::convertTriMeshToAiMesh(TriMesh *_triMesh, aiMesh *_mesh) {
318  _mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
319  _mesh->mNumVertices = _triMesh->n_vertices();
320  _mesh->mNumFaces = _triMesh->n_faces();
321 
322  _mesh->mVertices = new aiVector3D[_mesh->mNumVertices];
323  _mesh->mNormals = new aiVector3D[_mesh->mNumVertices];
324  _mesh->mFaces = new aiFace[_mesh->mNumFaces];
325 
326  std::map<OpenMesh::VertexHandle, int> vertexHandles;
327  int i = 0;
328  for (TriMesh::ConstVertexIter v_it = _triMesh->vertices_begin(); v_it != _triMesh->vertices_end(); ++v_it, ++i) {
329  ACG::Vec3d pos = _triMesh->point(*v_it);
330  ACG::Vec3d normal = _triMesh->normal(*v_it);
331  _mesh->mVertices[i] = aiVector3D(pos[0], pos[1], pos[2]);
332  _mesh->mNormals[i] = aiVector3D(normal[0], normal[1], normal[2]);
333  vertexHandles[*v_it] = i;
334  }
335 
336  i = 0;
337  for (TriMesh::ConstFaceIter f_it = _triMesh->faces_begin(); f_it != _triMesh->faces_end(); ++f_it, ++i) {
338  _mesh->mFaces[i].mNumIndices = 3;
339  _mesh->mFaces[i].mIndices = new unsigned int[3];
340  int j = 0;
341  for (PolyMesh::ConstFaceVertexIter fv_it = _triMesh->fv_iter(*f_it); fv_it.is_valid(); ++fv_it, ++j) {
342  _mesh->mFaces[i].mIndices[j] = vertexHandles[*fv_it];
343  }
344  }
345 
346  return true;
347 }
348 
349 void AssimpPlugin::mapVertices(PolyMesh *_polyMesh, aiMesh *_mesh) {
350  vertexHandles_.clear();
351 
352  for (unsigned int i = 0; i < _mesh->mNumVertices; ++i) {
353  vertexHandles_[i] = _polyMesh->add_vertex(ACG::Vec3d(_mesh->mVertices[i].x, _mesh->mVertices[i].y, _mesh->mVertices[i].z));
354  }
355 }
356 
357 void AssimpPlugin::mapVertices(TriMesh *_triMesh, aiMesh *_mesh) {
358  vertexHandles_.clear();
359 
360  for (unsigned int i = 0; i < _mesh->mNumVertices; ++i) {
361  vertexHandles_[i] = _triMesh->add_vertex(ACG::Vec3d(_mesh->mVertices[i].x, _mesh->mVertices[i].y, _mesh->mVertices[i].z));
362  }
363 }
364 
367  return type;
368 }
369 
370 
372  return QString( tr("Alias/Wavefront ( *.obj );;Collada ( *.dae );;Stereolithography files ( *.stl );;Polygon File Format files ( *.ply )" ) );
373 }
374 
376  return QString( tr("Alias/Wavefront ( *.obj );;AutoCAD DXF ( *.dxf );;Collada ( *.dae );;Stereolithography files ( *.stl );;Polygon File Format files ( *.ply );;Blender 3D( *.blend );;3ds Max 3DS ( *.3ds );;3ds Max ASE( *.ase );;Industry Foundation Classes ( *.ifc );;XGL ( *.xgl *.zgl );;Lightwave ( *.lwo );;Lightwave Scene ( *.lws );;Modo ( *.lxo );;DirectX X ( *.x );;AC3D ( *.ac );;Milkshape 3D ( *.ms3d );;TrueSpace ( *.cob *.scn )") );
377 }
378 
380  if (!saveOptions_) {
381  saveOptions_ = new QWidget();
382  }
383 
384  return saveOptions_;
385 }
386 
388  if (!loadOptions_) {
389  loadOptions_ = new QWidget();
390  }
391 
392  return loadOptions_;
393 }
394 
395 int AssimpPlugin::loadObject(QString _filename) {
396  Assimp::Importer importer;
397 
398  const aiScene* scene = NULL;
399  if (type_ == DATA_TRIANGLE_MESH)
400  scene = importer.ReadFile(_filename.toStdString(), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate);
401  else
402  scene = importer.ReadFile(_filename.toStdString(), aiProcess_JoinIdenticalVertices);
403 
404  if (!scene) {
405  emit log(LOGERR, tr(importer.GetErrorString()));
406  return -1;
407  }
408 
409  QFileInfo f(_filename);
410  return convertAiSceneToOpenMesh(scene, f.fileName());
411 }
412 
413 int AssimpPlugin::loadObject(QString _filename, DataType _type) {
414  if (_type != DATA_GROUP) //if equal => autodetect data
415  type_ = _type;
416  return loadObject(_filename);
417 }
418 
419 bool AssimpPlugin::saveObject(int _id, QString _filename) {
420  BaseObjectData* object;
421  PluginFunctions::getObject(_id,object);
422 
423  if (!object) {
424  emit log(LOGERR, tr("Could not get the object with the given id"));
425  return false;
426  }
427 
428  object->setFromFileName(_filename);
429  object->setName(object->filename());
430 
431  aiScene scene;
432 
433  if (!convertOpenMeshToAiScene(&scene, object))
434  return false;
435 
436  Assimp::Exporter exporter;
437 
438  QFileInfo f(_filename);
439 
440  std::string formatId = (f.suffix() == "dae") ? "collada" : f.suffix().toStdString();
441  bool ok = exporter.Export(&scene, formatId, _filename.toStdString()) == AI_SUCCESS;
442  if (!ok)
443  emit log(LOGERR, exporter.GetErrorString());
444 
445  return ok;
446 }
447 
448 #if QT_VERSION < 0x050000
449  Q_EXPORT_PLUGIN2( assimpplugin , AssimpPlugin )
450 #endif
bool dataType(DataType _type) const
Definition: BaseObject.cc:232
bool convertPolyMeshToAiMesh(PolyMesh *_polyMesh, aiMesh *_mesh)
converts a polymesh to an aiMesh
int loadObject(QString _filename)
Loads Object and converts it to a triangle mesh if possible.
bool getObject(int _identifier, BSplineCurveObject *&_object)
bool convertOpenMeshToAiScene(aiScene *_scene, BaseObjectData *_object)
converts a polymesh or trimesh to an aiScene
int id() const
Definition: BaseObject.cc:201
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:73
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:70
int convertAiSceneToOpenMesh(const aiScene *_scene, QString _objectName)
converts an aiScene to a polymesh or trimesh
std::map< unsigned int, OpenMesh::VertexHandle > vertexHandles_
maps indices of vertices in an aiMesh to OpenMesh VertexHandles
QWidget * loadOptionsWidget(QString)
QString filename() const
return the filename of the object
Definition: BaseObject.cc:717
QWidget * saveOptionsWidget(QString)
#define DATA_POLY_MESH
Definition: PolyMesh.hh:65
void convertAiMeshToTriMesh(TriMesh *_triMesh, aiMesh *_mesh)
converts _mesh into _triMesh
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:66
bool convertTriMeshToAiMesh(TriMesh *_triMesh, aiMesh *_mesh)
converts a trimesh to an aiMesh
Predefined datatypes.
Definition: DataTypes.hh:96
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
const DataType DATA_GROUP(1)
Items used for Grouping.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void convertAiMeshToPolyMesh(PolyMesh *_polyMesh, aiMesh *_mesh)
converts _mesh into _polyMesh
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
MeshT * mesh()
return a pointer to the mesh
Definition: MeshObjectT.cc:351
QString getLoadFilters()
QString getSaveFilters()
Kernel::ConstFaceVertexIter ConstFaceVertexIter
Circulator.
Definition: PolyMeshT.hh:180
void mapVertices(PolyMesh *_polyMesh, aiMesh *_mesh)
add a vertex from _mesh to _polyMesh and stores the index to handle mapping