Fraxinus  17.12-rc1
An IGT application
cxTextureSlicePainter.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 
34 /*
35  * vmTextureSlicePainter.cpp
36  *
37  * Created on: Oct 13, 2009
38  * Author: petterw
39  */
40 
41 #include "cxTextureSlicePainter.h"
42 
43 //#ifndef WIN32
44 //#ifndef CX_VTK_OPENGL2
45 #if !defined(CX_VTK_OPENGL2) && !defined(WIN32)
46 #include <QtCore>
47 #include <vtkOpenGLExtensionManager.h>
48 #include <vtkRenderer.h>
49 #include <vtkShaderProgram2.h>
50 #include <vtkShader2.h>
51 #include <vtkShader2Collection.h>
52 #include <vtkUniformVariables.h>
53 #include <vtkObjectFactory.h>
54 #include <vtkOpenGLRenderWindow.h>
55 
56 #ifdef __APPLE__
57 #include <OpenGL/glu.h>
58 #include "X11/Xlib.h"
59 //#include "/usr/include/X11/Xlib.h"
60 #else
61 //#define GL_GLEXT_PROTOTYPES
62 #include <GL/glu.h>
63 #include <GL/glext.h>
64 #endif
65 
66 #ifdef WIN32
67 #include <windows.h>
68 #include <GL/glext.h>
69 #endif
70 
71 #include "cxGPUImageBuffer.h"
72 #include "cxTypeConversions.h"
73 #include "cxGLHelpers.h"
74 
75 
76 //---------------------------------------------------------
77 namespace cx
78 {
79 //---------------------------------------------------------
80 
81 vtkStandardNewMacro(TextureSlicePainter);
82 
84  mWindow(0.0),
85  mLevel(0.0),
86  mLLR(0.0),
87  mAlpha(1.0)
88 {
89  mIndex = index;
90 }
91 
93  mWindow(0.0),
94  mLevel(0.0),
95  mLLR(0.0),
96  mAlpha(1.0)
97 {
98  mIndex = -1;
99 }
100 
102 {
103 
104 }
105 
107 {
108  mVolumeBuffer = buffer;
109 }
110 
112 {
113  mLutBuffer = buffer;
114 }
115 
116 void SingleVolumePainterHelper::SetColorAttribute(float window, float level, float llr,float alpha)
117 {
118  mWindow = window;
119  mLevel = level;
120  mLLR = llr;
121  mAlpha = alpha;
122 }
123 
125 {
126  if (mVolumeBuffer)
127  mVolumeBuffer->allocate();
128  if (mLutBuffer)
129  mLutBuffer->allocate();
130 }
131 
132 void SingleVolumePainterHelper::setUniformiArray(vtkUniformVariables* uniforms, QString name, int val)
133 {
134  QString fullName = QString("%1[%2]").arg(name).arg(mIndex);
135  uniforms->SetUniformi(cstring_cast(fullName), 1, &val);
136 }
137 
138 void SingleVolumePainterHelper::setUniformfArray(vtkUniformVariables* uniforms, QString name, float val)
139 {
140  QString fullName = QString("%1[%2]").arg(name).arg(mIndex);
141  uniforms->SetUniformf(cstring_cast(fullName), 1, &val);
142 }
143 
144 void SingleVolumePainterHelper::eachRenderInternal(vtkSmartPointer<vtkShaderProgram2> shader)
145 {
146  if (!mVolumeBuffer)
147  return;
148 
149  mVolumeBuffer->bind(mIndex);
150 
151  int texture = 2*mIndex; //texture unit 1
152  int lut = 2*mIndex+1; //texture unit 1
153 
154  int lutsize = 0;
155  if (mLutBuffer)
156  {
157  mLutBuffer->bind(mIndex);
158  lutsize = mLutBuffer->getLutSize();
159  }
160 
161  vtkUniformVariables* uniforms = shader->GetUniformVariables();
162  this->setUniformiArray(uniforms, "texture", texture);
163  this->setUniformiArray(uniforms, "lut", lut);
164  this->setUniformiArray(uniforms, "lutsize", lutsize);
165  this->setUniformfArray(uniforms, "llr", mLLR);
166  this->setUniformfArray(uniforms, "level", mLevel);
167  this->setUniformfArray(uniforms, "window", mWindow);
168  this->setUniformfArray(uniforms, "alpha", mAlpha);
169 
170  report_gl_error();
171 }
172 
173 //---------------------------------------------------------
175  hasLoadedExtensions(false)
176 {
177 }
178 
180 {
181  mShaderPath = path;
182 }
183 
184 QString TextureSlicePainter::loadShaderFile()
185 {
186  QString filepath = mShaderPath + "/cxOverlay2D_frag.glsl";
187  QFile fp(filepath);
188  if (fp.exists())
189  {
190  fp.open(QFile::ReadOnly);
191  QTextStream shaderfile(&fp);
192  return shaderfile.readAll();
193  }
194  else
195  {
196  std::cout << "TextureSlicer can't read shaderfile [" << fp.fileName() << "]" << std::endl;
197  }
198  return "";
199 }
200 
202 {
203  if (this->LastContext)
204  {
205  this->ReleaseGraphicsResources(this->LastWindow);
206  }
207 }
208 
210 {
211  if (this->Shader != 0)
212  {
213  this->Shader->ReleaseGraphicsResources();
214  this->Shader = 0;
215  }
216 
217  this->ClearGraphicsResources(); //the shader
218  this->LastContext = 0;
219  this->Superclass::ReleaseGraphicsResources(win);
220 }
221 
222 void TextureSlicePainter::PrepareForRendering(vtkRenderer* renderer, vtkActor* actor)
223 {
224  report_gl_error();
225  if (!CanRender(renderer, actor))
226  {
227  this->ClearGraphicsResources();
228  this->LastContext = 0;
229  this->Superclass::PrepareForRendering(renderer, actor);
230  return;
231  }
232 
233  GLint oldTextureUnit;
234  glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit);
235 
236  vtkRenderWindow* renWin = renderer->GetRenderWindow();
237  if (this->LastContext != renWin)
238  {
239  this->ClearGraphicsResources();
240  hasLoadedExtensions = false; // force re-check
241  }
242  this->LastContext = renWin;
243 
244  vtkOpenGLRenderWindow *context = vtkOpenGLRenderWindow::SafeDownCast(renWin);
245  if (!hasLoadedExtensions)
246  {
247  if (!this->LoadRequiredExtensions(context->GetExtensionManager()))
248  {
249  return;
250  }
251  hasLoadedExtensions = true;
252  }
253 
254  for (unsigned i = 0; i < this->mElement.size(); ++i)
255  this->mElement[i].initializeRendering();
256 
257  if (!this->Shader)
258  {
259  report_gl_error();
260  QString shaderSource = this->loadShaderFile();
261  shaderSource = this->replaceShaderSourceMacros(shaderSource);
262 // int layers = this->mElement.size();
263 // shaderSource = shaderSource.replace("${LAYERS}", QString("%1").arg(layers));
264 
265  this->buildProgram(shaderSource, context);
266  }
267 
268  glPixelStorei(GL_PACK_ALIGNMENT, 1);
269  glPixelStorei(GL_PACK_ROW_LENGTH, 0);
270  glPixelStorei(GL_PACK_SKIP_ROWS, 0);
271  glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
272 
273  this->Superclass::PrepareForRendering(renderer, actor);
274  report_gl_error();
275  glActiveTexture(oldTextureUnit);
276 }
277 
278 QString TextureSlicePainter::replaceShaderSourceMacros(QString shaderSource)
279 {
280  // set constant layers
281  int layers = this->mElement.size();
282  shaderSource = shaderSource.replace("${LAYERS}", QString("%1").arg(layers));
283 
284  // fill function vec4 sampleLut(in int index, in float idx)
285  QString element = "\tif (index==%1) return texture1D(lut[%1], idx);\n";
286  QString sampleLutContent;
287  for (unsigned i=0; i<layers; ++i)
288  sampleLutContent += element.arg(i);
289  shaderSource = shaderSource.replace("${SAMPLE_LUT_CONTENT}", sampleLutContent);
290 
291  return shaderSource;
292 }
293 
294 
295 void TextureSlicePainter::RenderInternal(vtkRenderer* renderer, vtkActor* actor, unsigned long typeflags,
296  bool forceCompileOnly)
297 {
298  if (!CanRender(renderer, actor))
299  {
300  return;
301  }
302 
303  GLint oldTextureUnit;
304  glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit);
305 
306  int layers = this->mElement.size();
307  this->Shader->GetUniformVariables()->SetUniformi("layers", 1, &layers);
308 
309  for (unsigned i = 0; i < this->mElement.size(); ++i)
310  {
311  this->mElement[i].eachRenderInternal(this->Shader);
312  }
313 
314  this->Shader->Use();
315 
316  if (!this->Shader->IsValid())
317  {
318  vtkErrorMacro(<<" validation of the program failed: "<< this->Shader->GetLastValidateLog());
319  }
320 
321  this->Superclass::RenderInternal(renderer, actor, typeflags, forceCompileOnly);
322 
323  this->Shader->Restore();
324  report_gl_error();
325  glActiveTexture(oldTextureUnit);
326 }
327 
328 bool TextureSlicePainter::CanRender(vtkRenderer*, vtkActor*)
329 {
330  return !this->mElement.empty();
331 }
332 
333 bool TextureSlicePainter::LoadRequiredExtension(vtkOpenGLExtensionManager* mgr, QString id)
334 {
335  bool loaded = mgr->LoadSupportedExtension(cstring_cast(id));
336  if (!loaded)
337  std::cout << "TextureSlicePainter Error: GL extension " + id + " not found" << std::endl;
338  return loaded;
339 }
340 
341 bool TextureSlicePainter::LoadRequiredExtensions(vtkOpenGLExtensionManager* mgr)
342 {
343  return (LoadRequiredExtension(mgr, "GL_VERSION_2_0")
344  && LoadRequiredExtension(mgr, "GL_VERSION_1_5")
345  && LoadRequiredExtension(mgr, "GL_ARB_vertex_buffer_object"));
346 }
347 
349 {
350  this->safeIndex(index).SetBuffer(buffer);
351 }
352 
354 {
355  this->safeIndex(index).SetBuffer(buffer);
356 }
357 
358 void TextureSlicePainter::SetColorAttribute(int index, float window, float level, float llr,float alpha)
359 {
360  this->safeIndex(index).SetColorAttribute(window, level, llr, alpha);
361 }
362 
364 {
365 }
366 
367 void TextureSlicePainter::PrintSelf(ostream& os, vtkIndent indent)
368 {
369 }
370 
371 SingleVolumePainterHelper& TextureSlicePainter::safeIndex(int index)
372 {
373  if ((int)mElement.size() <= index)
374  {
375  mElement.resize(index+1);
376  mElement[index] = SingleVolumePainterHelper(index);
377  }
378  return mElement[index];
379 }
380 
381 void TextureSlicePainter::buildProgram(QString shaderSource, vtkOpenGLRenderWindow* renderWindow)
382 {
383  vtkShaderProgram2Ptr pgm = vtkShaderProgram2Ptr::New();
384  pgm->SetContext(renderWindow);
385 
386  vtkShader2Ptr s2 = vtkShader2Ptr::New();
387  s2->SetType(VTK_SHADER_TYPE_FRAGMENT);
388  s2->SetSourceCode(cstring_cast(shaderSource));
389  s2->SetContext(pgm->GetContext());
390  pgm->GetShaders()->AddItem(s2);
391  report_gl_error();
392  pgm->Build();
393 
394  if (pgm->GetLastBuildStatus() != VTK_SHADER_PROGRAM2_LINK_SUCCEEDED)
395  {
396  vtkErrorMacro("Pass Two failed.");
397  abort();
398  }
399 
400  this->Shader = pgm;
401 }
402 
404 {
405  if (this->Shader != 0)
406  {
407  this->Shader->ReleaseGraphicsResources();
408  this->Shader = 0;
409  }
410 }
411 
412 
413 //---------------------------------------------------------
414 }//end namespace
415 //---------------------------------------------------------
416 
417 #endif //CX_VTK_OPENGL2
418 //#endif //WIN32
vtkSmartPointer< class vtkShaderProgram2 > vtkShaderProgram2Ptr
bool CanRender(vtkRenderer *, vtkActor *)
void PrintSelf(ostream &os, vtkIndent indent)
void SetLutBuffer(int index, GPUImageLutBufferPtr buffer)
void setUniformiArray(vtkUniformVariables *uniforms, QString name, int val)
void eachRenderInternal(vtkSmartPointer< vtkShaderProgram2 > shader)
void SetColorAttribute(float window, float level, float llr, float alpha)
cstring_cast_Placeholder cstring_cast(const T &val)
void releaseGraphicsResources(int index)
virtual void PrepareForRendering(vtkRenderer *, vtkActor *)
static bool LoadRequiredExtension(vtkOpenGLExtensionManager *mgr, QString id)
vtkStandardNewMacro(TextureSlicePainter)
static bool LoadRequiredExtensions(vtkOpenGLExtensionManager *mgr)
void SetVolumeBuffer(int index, GPUImageDataBufferPtr buffer)
void setUniformfArray(vtkUniformVariables *uniforms, QString name, float val)
boost::shared_ptr< class GPUImageDataBuffer > GPUImageDataBufferPtr
void RenderInternal(vtkRenderer *renderer, vtkActor *actor, unsigned long typeflags, bool forceCompileOnly)
boost::shared_ptr< class GPUImageLutBuffer > GPUImageLutBufferPtr
vtkSmartPointer< class vtkShader2 > vtkShader2Ptr
void SetBuffer(GPUImageDataBufferPtr buffer)
void SetColorAttribute(int index, float window, float level, float llr, float alpha)
virtual void ReleaseGraphicsResources(vtkWindow *)
#define report_gl_error()
Definition: cxGLHelpers.h:49
Namespace for all CustusX production code.