Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkVtkModel.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include "mitkVtkModel.h"
18 #include <mitkLogMacros.h>
19 #include <mitkRenderingManager.h>
20 #include <sofa/core/visual/VisualParams.h>
21 #include <vtkCellArray.h>
22 #include <vtkFloatArray.h>
23 #include <vtkImageData.h>
24 #include <vtkImageReader2.h>
25 #include <vtkImageReader2Factory.h>
26 #include <vtkPointData.h>
27 #include <vtkPolyData.h>
28 #include <vtkOpenGLTexture.h>
29 
30 // Defined in mitkExportMitkVisitor.cpp
31 void ApplyMaterial(mitk::DataNode::Pointer dataNode, const sofa::core::loader::Material& material);
32 
33 static bool InitGLEW()
34 {
35  static bool isInitialized = false;
36 
37  // If no render window is shown, OpenGL is potentially not initialized, e.g., the
38  // Display tab of the Workbench might be closed while loading a SOFA scene file.
39  // In this case initialization is deferred (see mitk::VtkModel::internalDraw()).
40  if (mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows().empty())
41  return false;
42 
43  if (!isInitialized)
44  {
45  GLenum error = glewInit();
46 
47  if (error != GLEW_OK)
48  {
49  MITK_ERROR("glewInit") << glewGetErrorString(error);
50  }
51  else
52  {
53  isInitialized = true;
54  }
55  }
56 
57  return isInitialized;
58 }
59 
60 mitk::VtkModel::VtkModel()
61  : m_GlewIsInitialized(InitGLEW()),
62  m_BuffersWereCreated(false),
63  m_LastNumberOfVertices(0),
64  m_LastNumberOfTriangles(0),
65  m_LastNumberOfQuads(0),
66  m_VertexBuffer(0),
67  m_IndexBuffer(0),
68  m_VtkRenderer(nullptr),
69  m_Mode(OpenGL)
70 {
71 }
72 
73 mitk::VtkModel::~VtkModel()
74 {
75  if (m_Mode == OpenGL && m_BuffersWereCreated)
76  {
77  glDeleteBuffers(1, &m_IndexBuffer);
78  glDeleteBuffers(1, &m_VertexBuffer);
79  }
80 }
81 
82 void mitk::VtkModel::CreateIndexBuffer()
83 {
84  if (m_Mode == OpenGL)
85  {
86  glGenBuffers(1, &m_IndexBuffer);
87  }
88  else if (m_Mode == Surface)
89  {
91  }
92 
93  this->InitIndexBuffer();
94 }
95 
96 void mitk::VtkModel::CreateVertexBuffer()
97 {
98  if (m_Mode == OpenGL)
99  {
100  glGenBuffers(1, &m_VertexBuffer);
101  }
102  else if (m_Mode == Surface)
103  {
104  m_Points = vtkSmartPointer<vtkPoints>::New();
106  m_TexCoords = vtkSmartPointer<vtkFloatArray>::New();
107  }
108 
109  this->InitVertexBuffer();
110 }
111 
112 void mitk::VtkModel::DrawGroup(int group, bool transparent)
113 {
114  if (m_Mode == OpenGL)
115  {
116  this->DrawOpenGLGroup(group, transparent);
117  }
118  else if (m_Mode == Surface)
119  {
120  this->DrawSurfaceGroup(group, transparent);
121  }
122 }
123 
124 void mitk::VtkModel::DrawOpenGLGroup(int group, bool)
125 {
126  using sofa::core::loader::Material;
127  using sofa::defaulttype::ResizableExtVector;
128  using sofa::defaulttype::Vec4f;
129 
130  const VecCoord& vertices = this->getVertices();
131  const ResizableExtVector<Deriv>& normals = this->getVnormals();
132  const ResizableExtVector<Triangle>& triangles = this->getTriangles();
133  const ResizableExtVector<Quad>& quads = this->getQuads();
134 
135  FaceGroup faceGroup;
136 
137  if (group == -1)
138  {
139  faceGroup.nbt = triangles.size();
140  faceGroup.nbq = quads.size();
141  }
142  else
143  {
144  faceGroup = groups.getValue()[group];
145  }
146 
147  Material material = faceGroup.materialId != -1
148  ? materials.getValue()[faceGroup.materialId]
149  : this->material.getValue();
150 
151  if (material.useTexture && material.activated)
152  {
153  m_Textures[faceGroup.materialId]->Load(m_VtkRenderer);
154 
155  glEnable(GL_TEXTURE_2D);
156  glTexCoordPointer(2, GL_FLOAT, 0, reinterpret_cast<const GLvoid*>(vertices.size() * sizeof(VecCoord::value_type) + normals.size() * sizeof(Deriv)));
157  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
158  }
159 
160  Vec4f ambient = material.useAmbient ? material.ambient : Vec4f();
161  Vec4f diffuse = material.useDiffuse ? material.diffuse : Vec4f();
162  Vec4f specular = material.useSpecular ? material.specular : Vec4f();
163  Vec4f emissive = material.useEmissive ? material.emissive : Vec4f();
164  float shininess = material.useShininess ? std::min(material.shininess, 128.0f) : 45.0f;
165 
166  if (shininess == 0.0f)
167  {
168  specular.clear();
169  shininess = 1.0f;
170  }
171 
172  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient.ptr());
173  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse.ptr());
174  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular.ptr());
175  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emissive.ptr());
176  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
177 
178  if (faceGroup.nbt != 0)
179  glDrawElements(GL_TRIANGLES, faceGroup.nbt * 3, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid*>(faceGroup.tri0 * sizeof(Triangle)));
180 
181  if (faceGroup.nbq != 0)
182  glDrawElements(GL_QUADS, faceGroup.nbq * 4, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid*>(triangles.size() * sizeof(Triangle) + faceGroup.quad0 * sizeof(Quad)));
183 
184  if (material.useTexture && material.activated)
185  {
186  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
187  glDisable(GL_TEXTURE_2D);
188 
189  m_Textures[faceGroup.materialId]->PostRender(m_VtkRenderer);
190  }
191 }
192 
193 void mitk::VtkModel::DrawSurfaceGroup(int group, bool)
194 {
195  m_PolyData->SetPoints(m_Points);
196  m_PolyData->SetPolys(m_Polys);
197 
198  vtkPointData* pointData = m_PolyData->GetPointData();
199 
200  pointData->SetNormals(m_Normals->GetSize() != 0
201  ? m_Normals
202  : nullptr);
203 
204  pointData->SetTCoords(m_TexCoords->GetSize() != 0
205  ? m_TexCoords
206  : nullptr);
207 
208  m_PolyData->Modified();
209 }
210 
211 void mitk::VtkModel::DrawGroups(bool transparent)
212 {
213  using sofa::core::objectmodel::Data;
214  using sofa::helper::ReadAccessor;
215  using sofa::helper::vector;
216 
217  ReadAccessor<Data<vector<FaceGroup> > > groups = this->groups;
218 
219  if (groups.empty())
220  {
221  this->DrawGroup(-1, transparent);
222  }
223  else
224  {
225  int numGroups = static_cast<int>(groups.size());
226 
227  for (int i = 0; i < numGroups; ++i)
228  this->DrawGroup(i, transparent);
229  }
230 }
231 
232 void mitk::VtkModel::InitIndexBuffer()
233 {
234  using sofa::defaulttype::ResizableExtVector;
235 
236  const ResizableExtVector<Triangle>& triangles = this->getTriangles();
237  const ResizableExtVector<Quad>& quads = this->getQuads();
238 
239  if (m_Mode == OpenGL)
240  {
241  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IndexBuffer);
242  glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangles.size() * sizeof(Triangle) + quads.size() * sizeof(Quad), nullptr, GL_DYNAMIC_DRAW);
243  }
244 
245  this->UpdateIndexBuffer();
246 }
247 
248 void mitk::VtkModel::InitVertexBuffer()
249 {
250  using sofa::defaulttype::ResizableExtVector;
251 
252  const VecCoord& vertices = this->getVertices();
253  const ResizableExtVector<Deriv> normals = this->getVnormals();
254  const VecTexCoord& texCoords = this->getVtexcoords();
255 
256  if (m_Mode == OpenGL)
257  {
258  glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
259  glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(VecCoord::value_type) + normals.size() * sizeof(Deriv) + texCoords.size() * sizeof(VecTexCoord::value_type), nullptr, GL_DYNAMIC_DRAW);
260  }
261  else if (m_Mode == Surface)
262  {
263  m_Points->SetNumberOfPoints(vertices.size());
264 
265  m_Normals->SetNumberOfComponents(3);
266  m_Normals->SetNumberOfTuples(normals.size());
267 
268  m_TexCoords->SetNumberOfComponents(2);
269  m_TexCoords->SetNumberOfTuples(texCoords.size());
270  }
271 
272  this->UpdateVertexBuffer();
273 }
274 
275 void mitk::VtkModel::internalDraw(const sofa::core::visual::VisualParams* vparams, bool transparent)
276 {
277  using sofa::core::visual::DisplayFlags;
278  using sofa::defaulttype::ResizableExtVector;
279 
280  if (m_Mode == OpenGL && !m_GlewIsInitialized)
281  {
282  // Try lazy initialization since initialization potentially failed so far
283  // due to missing render windows (see InitGLEW()).
284  m_GlewIsInitialized = InitGLEW();
285 
286  if (m_GlewIsInitialized)
287  {
288  this->updateBuffers();
289  }
290  else
291  {
292  return;
293  }
294  }
295 
296  const DisplayFlags& displayFlags = vparams->displayFlags();
297 
298  if (!displayFlags.getShowVisualModels())
299  return;
300 
301  if (m_BuffersWereCreated == false)
302  return;
303 
304  if (m_Mode == OpenGL)
305  {
306  glEnable(GL_LIGHTING);
307  glColor3f(1.0f, 1.0f, 1.0f);
308  glPolygonMode(GL_FRONT_AND_BACK, displayFlags.getShowWireFrame() ? GL_LINE : GL_FILL);
309 
310  const VecCoord& vertices = this->getVertices();
311 
312  glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
313  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IndexBuffer);
314 
315  this->ValidateBoundBuffers();
316 
317  glVertexPointer(3, GL_FLOAT, 0, nullptr);
318  glNormalPointer(GL_FLOAT, 0, reinterpret_cast<const GLvoid*>(vertices.size() * sizeof(VecCoord::value_type)));
319  glEnableClientState(GL_VERTEX_ARRAY);
320  glEnableClientState(GL_NORMAL_ARRAY);
321  }
322 
323  this->DrawGroups(transparent);
324 
325  if (m_Mode == OpenGL)
326  {
327  glDisableClientState(GL_NORMAL_ARRAY);
328  glDisableClientState(GL_VERTEX_ARRAY);
329 
330  if (displayFlags.getShowWireFrame())
331  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
332 
333  glDisable(GL_LIGHTING);
334  }
335 
336  if (displayFlags.getShowNormals())
337  this->DrawNormals();
338 }
339 
340 void mitk::VtkModel::DrawNormals()
341 {
342  using sofa::defaulttype::ResizableExtVector;
343 
344  if (m_Mode == OpenGL)
345  {
346  const VecCoord& vertices = this->getVertices();
347  const ResizableExtVector<Deriv>& normals = this->getVnormals();
348  size_t numVertices = vertices.size();
349  Coord normal;
350 
351  glBegin(GL_LINES);
352 
353  for (size_t i = 0; i < numVertices; ++i)
354  {
355  glVertex3fv(vertices[i].ptr());
356  normal = vertices[i] + normals[i];
357  glVertex3fv(normal.ptr());
358  }
359 
360  glEnd();
361  }
362 }
363 
365 {
366  using sofa::helper::system::DataRepository;
367  using sofa::helper::vector;
368  using sofa::core::loader::Material;
369 
370  m_Textures.clear();
371 
372  std::vector<unsigned int> materialIndices;
373 
374  const vector<Material>& materials = this->materials.getValue();
375  unsigned int numMaterials = materials.size();
376 
377  for (unsigned int i = 0; i < numMaterials; ++i)
378  {
379  const Material& material = materials[i];
380 
381  if (material.useTexture && material.activated)
382  materialIndices.push_back(i);
383  }
384 
385  bool retValue = true;
386  size_t numTextures = materialIndices.size();
387 
388  for (size_t i = 0; i < numTextures; ++i)
389  {
390  std::string filename = materials[materialIndices[i]].textureFilename;
391 
392  if (!DataRepository.findFile(filename))
393  {
394  MITK_ERROR("VtkModel") << "File \"" << filename << "\" not found!";
395  retValue = false;
396  continue;
397  }
398 
399  vtkSmartPointer<vtkImageReader2> imageReader = vtkSmartPointer<vtkImageReader2>::Take(vtkImageReader2Factory::CreateImageReader2(filename.c_str()));
400 
401  if (imageReader == nullptr)
402  {
403  MITK_ERROR("VtkModel") << "File \"" << filename << "\" has unknown image format!";
404  retValue = false;
405  continue;
406  }
407 
408  imageReader->SetFileName(filename.c_str());
409  imageReader->UpdateWholeExtent();
410 
411  vtkSmartPointer<vtkOpenGLTexture> texture = vtkSmartPointer<vtkOpenGLTexture>::New();
412  texture->SetInputConnection(imageReader->GetOutputPort());
413  texture->InterpolateOn();
414 
415  m_Textures.insert(std::make_pair(materialIndices[i], texture));
416  }
417 
418  return retValue;
419 }
420 
422 {
423  return m_DataNode;
424 }
425 
427 {
428  return m_Mode;
429 }
430 
432 {
433  if (m_Mode == mode)
434  return;
435 
436  if (mode == OpenGL)
437  {
438  m_DataNode = nullptr;
439  m_Surface = nullptr;
440  m_PolyData = nullptr;
441  m_TexCoords = nullptr;
442  m_Normals = nullptr;
443  m_Polys = nullptr;
444  m_Points = nullptr;
445  }
446  else if (mode == Surface)
447  {
448  if (m_Mode == OpenGL && m_BuffersWereCreated)
449  {
450  glDeleteBuffers(1, &m_IndexBuffer);
451  m_IndexBuffer = 0;
452 
453  glDeleteBuffers(1, &m_VertexBuffer);
454  m_VertexBuffer = 0;
455  }
456 
457  m_PolyData = vtkSmartPointer<vtkPolyData>::New();
458 
459  m_Surface = Surface::New();
460  m_Surface->SetVtkPolyData(m_PolyData);
461 
462  m_DataNode = DataNode::New();
463  m_DataNode->SetName(name.getValue());
464  m_DataNode->SetData(m_Surface);
465 
466  ApplyMaterial(m_DataNode, this->material.getValue());
467  }
468 
469  m_Mode = mode;
470 
471  m_BuffersWereCreated = false;
472  this->updateBuffers();
473 }
474 
475 void mitk::VtkModel::SetVtkRenderer(vtkRenderer* renderer)
476 {
477  m_VtkRenderer = renderer;
478 }
479 
481 {
482  using sofa::defaulttype::ResizableExtVector;
483 
484  if (m_Mode == OpenGL && !m_GlewIsInitialized)
485  return;
486 
487  const VecCoord& vertices = this->getVertices();
488  const ResizableExtVector<Triangle>& triangles = this->getTriangles();
489  const ResizableExtVector<Quad>& quads = this->getQuads();
490 
491  if (!m_BuffersWereCreated)
492  {
493  this->CreateVertexBuffer();
494  this->CreateIndexBuffer();
495 
496  m_BuffersWereCreated = true;
497  }
498  else
499  {
500  if (m_LastNumberOfVertices != vertices.size())
501  this->InitVertexBuffer();
502  else
503  this->UpdateVertexBuffer();
504 
505  if (m_LastNumberOfTriangles != triangles.size() || m_LastNumberOfQuads != quads.size())
506  this->InitIndexBuffer();
507  else
508  this->UpdateIndexBuffer();
509  }
510 
511  m_LastNumberOfVertices = vertices.size();
512  m_LastNumberOfTriangles = triangles.size();
513  m_LastNumberOfQuads = quads.size();
514 }
515 
516 void mitk::VtkModel::UpdateIndexBuffer()
517 {
518  using sofa::defaulttype::ResizableExtVector;
519 
520  const ResizableExtVector<Triangle>& triangles = this->getTriangles();
521  const ResizableExtVector<Quad>& quads = this->getQuads();
522 
523  GLsizeiptr sizeOfTriangleIndices = triangles.size() * sizeof(Triangle);
524  GLsizeiptr sizeOfQuadIndices = quads.size() * sizeof(Quad);
525 
526  if (m_Mode == OpenGL)
527  {
528  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IndexBuffer);
529  glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeOfTriangleIndices, triangles.getData());
530  glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sizeOfTriangleIndices, sizeOfQuadIndices, quads.getData());
531  }
532  else if (m_Mode == Surface)
533  {
534  m_Polys->Initialize();
535 
536  if (!triangles.empty())
537  {
538  ResizableExtVector<Triangle>::const_iterator trianglesEnd = triangles.end();
539 
540  for (ResizableExtVector<Triangle>::const_iterator it = triangles.begin(); it != trianglesEnd; ++it)
541  {
542  const Triangle& triangle = *it;
543 
544  m_Polys->InsertNextCell(3);
545  m_Polys->InsertCellPoint(triangle[0]);
546  m_Polys->InsertCellPoint(triangle[1]);
547  m_Polys->InsertCellPoint(triangle[2]);
548  }
549  }
550 
551  if (!quads.empty())
552  {
553  ResizableExtVector<Quad>::const_iterator quadsEnd = quads.end();
554 
555  for (ResizableExtVector<Quad>::const_iterator it = quads.begin(); it != quadsEnd; ++it)
556  {
557  const Quad& quad = *it;
558 
559  m_Polys->InsertNextCell(4);
560  m_Polys->InsertCellPoint(quad[0]);
561  m_Polys->InsertCellPoint(quad[1]);
562  m_Polys->InsertCellPoint(quad[2]);
563  m_Polys->InsertCellPoint(quad[3]);
564  }
565  }
566  }
567 }
568 
569 void mitk::VtkModel::UpdateVertexBuffer()
570 {
571  using sofa::defaulttype::ResizableExtVector;
572 
573  const VecCoord& vertices = this->getVertices();
574  const ResizableExtVector<Deriv> normals = this->getVnormals();
575  const VecTexCoord& texCoords = this->getVtexcoords();
576 
577  if (m_Mode == OpenGL)
578  {
579  GLsizeiptr sizeOfVertices = vertices.size() * sizeof(VecCoord::value_type);
580  GLsizeiptr sizeOfNormals = normals.size() * sizeof(Deriv);
581 
582  glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
583  glBufferSubData(GL_ARRAY_BUFFER, 0, sizeOfVertices, vertices.getData());
584  glBufferSubData(GL_ARRAY_BUFFER, sizeOfVertices, sizeOfNormals, normals.getData());
585 
586  if (!m_Textures.empty())
587  {
588  GLsizeiptr sizeOfTexCoords = texCoords.size() * sizeof(VecTexCoord::value_type);
589  glBufferSubData(GL_ARRAY_BUFFER, sizeOfVertices + sizeOfNormals, sizeOfTexCoords, texCoords.getData());
590  }
591  }
592  else if (m_Mode == Surface)
593  {
594  size_t numPoints = vertices.size();
595 
596  for (size_t i = 0; i < numPoints; ++i)
597  m_Points->SetPoint(i, vertices[i].elems);
598 
599  if (!normals.empty())
600  {
601  size_t numNormals = normals.size();
602 
603  for (size_t i = 0; i < numNormals; ++i)
604  m_Normals->SetTuple(i, normals[i].elems);
605  }
606 
607  if (!texCoords.empty())
608  {
609  size_t numTexCoords = texCoords.size();
610 
611  for (size_t i = 0; i < numTexCoords; ++i)
612  m_TexCoords->SetTuple(i, normals[i].elems);
613  }
614  }
615 }
616 
617 void mitk::VtkModel::ValidateBoundBuffers()
618 {
619  if (m_Mode != OpenGL)
620  return;
621 
622  GLint indexBufferSize;
623  glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &indexBufferSize);
624 
625  if (indexBufferSize == 0)
626  {
627  glDeleteBuffers(1, &m_IndexBuffer);
628  this->CreateIndexBuffer();
629 
630  glDeleteBuffers(1, &m_VertexBuffer);
631  this->CreateVertexBuffer();
632  }
633 }
Class for storing surfaces (vtkPolyData).
Definition: mitkSurface.h:32
bool loadTextures() override
#define MITK_ERROR
Definition: mitkLogMacros.h:24
void updateBuffers() override
static bool InitGLEW()
Mode GetMode() const
void SetMode(Mode mode)
void ApplyMaterial(mitk::DataNode::Pointer dataNode, const sofa::core::loader::Material &material)
static Pointer New()
static RenderingManager * GetInstance()
static const std::string filename
void SetVtkRenderer(vtkRenderer *renderer)
static T min(T x, T y)
Definition: svm.cpp:67
DataNode::Pointer GetDataNode() const
void internalDraw(const sofa::core::visual::VisualParams *vparams, bool transparent) override
static Pointer New()
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.