Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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.