CustusX  2023.01.05-dev+develop.0da12
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) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 
13 /*
14  * vmTextureSlicePainter.cpp
15  *
16  * Created on: Oct 13, 2009
17  * Author: petterw
18  */
19 
20 #include "cxTextureSlicePainter.h"
21 
22 //#ifndef WIN32
23 //#ifndef CX_VTK_OPENGL2
24 #if !defined(CX_VTK_OPENGL2) && !defined(WIN32)
25 #include <QtCore>
26 #include <vtkOpenGLExtensionManager.h>
27 #include <vtkRenderer.h>
28 #include <vtkShaderProgram2.h>
29 #include <vtkShader2.h>
30 #include <vtkShader2Collection.h>
31 #include <vtkUniformVariables.h>
32 #include <vtkObjectFactory.h>
33 #include <vtkOpenGLRenderWindow.h>
34 
35 #ifdef __APPLE__
36 #include <OpenGL/glu.h>
37 #include "X11/Xlib.h"
38 //#include "/usr/include/X11/Xlib.h"
39 #else
40 //#define GL_GLEXT_PROTOTYPES
41 #include <GL/glu.h>
42 #include <GL/glext.h>
43 #endif
44 
45 #ifdef WIN32
46 #include <windows.h>
47 #include <GL/glext.h>
48 #endif
49 
50 #include "cxGPUImageBuffer.h"
51 #include "cxTypeConversions.h"
52 #include "cxGLHelpers.h"
53 
54 
55 //---------------------------------------------------------
56 namespace cx
57 {
58 //---------------------------------------------------------
59 
60 vtkStandardNewMacro(TextureSlicePainter);
61 
63  mWindow(0.0),
64  mLevel(0.0),
65  mLLR(0.0),
66  mAlpha(1.0)
67 {
68  mIndex = index;
69 }
70 
72  mWindow(0.0),
73  mLevel(0.0),
74  mLLR(0.0),
75  mAlpha(1.0)
76 {
77  mIndex = -1;
78 }
79 
81 {
82 
83 }
84 
86 {
87  mVolumeBuffer = buffer;
88 }
89 
91 {
92  mLutBuffer = buffer;
93 }
94 
95 void SingleVolumePainterHelper::SetColorAttribute(float window, float level, float llr,float alpha)
96 {
97  mWindow = window;
98  mLevel = level;
99  mLLR = llr;
100  mAlpha = alpha;
101 }
102 
104 {
105  if (mVolumeBuffer)
106  mVolumeBuffer->allocate();
107  if (mLutBuffer)
108  mLutBuffer->allocate();
109 }
110 
111 void SingleVolumePainterHelper::setUniformiArray(vtkUniformVariables* uniforms, QString name, int val)
112 {
113  QString fullName = QString("%1[%2]").arg(name).arg(mIndex);
114  uniforms->SetUniformi(cstring_cast(fullName), 1, &val);
115 }
116 
117 void SingleVolumePainterHelper::setUniformfArray(vtkUniformVariables* uniforms, QString name, float val)
118 {
119  QString fullName = QString("%1[%2]").arg(name).arg(mIndex);
120  uniforms->SetUniformf(cstring_cast(fullName), 1, &val);
121 }
122 
123 void SingleVolumePainterHelper::eachRenderInternal(vtkSmartPointer<vtkShaderProgram2> shader)
124 {
125  if (!mVolumeBuffer)
126  return;
127 
128  mVolumeBuffer->bind(mIndex);
129 
130  int texture = 2*mIndex; //texture unit 1
131  int lut = 2*mIndex+1; //texture unit 1
132 
133  int lutsize = 0;
134  if (mLutBuffer)
135  {
136  mLutBuffer->bind(mIndex);
137  lutsize = mLutBuffer->getLutSize();
138  }
139 
140  vtkUniformVariables* uniforms = shader->GetUniformVariables();
141  this->setUniformiArray(uniforms, "texture", texture);
142  this->setUniformiArray(uniforms, "lut", lut);
143  this->setUniformiArray(uniforms, "lutsize", lutsize);
144  this->setUniformfArray(uniforms, "llr", mLLR);
145  this->setUniformfArray(uniforms, "level", mLevel);
146  this->setUniformfArray(uniforms, "window", mWindow);
147  this->setUniformfArray(uniforms, "alpha", mAlpha);
148 
149  report_gl_error();
150 }
151 
152 //---------------------------------------------------------
154  hasLoadedExtensions(false)
155 {
156 }
157 
159 {
160  mShaderPath = path;
161 }
162 
163 QString TextureSlicePainter::loadShaderFile()
164 {
165  QString filepath = mShaderPath + "/cxOverlay2D_frag.glsl";
166  QFile fp(filepath);
167  if (fp.exists())
168  {
169  fp.open(QFile::ReadOnly);
170  QTextStream shaderfile(&fp);
171  return shaderfile.readAll();
172  }
173  else
174  {
175  std::cout << "TextureSlicer can't read shaderfile [" << fp.fileName() << "]" << std::endl;
176  }
177  return "";
178 }
179 
181 {
182  if (this->LastContext)
183  {
184  this->ReleaseGraphicsResources(this->LastWindow);
185  }
186 }
187 
189 {
190  if (this->Shader != 0)
191  {
192  this->Shader->ReleaseGraphicsResources();
193  this->Shader = 0;
194  }
195 
196  this->ClearGraphicsResources(); //the shader
197  this->LastContext = 0;
198  this->Superclass::ReleaseGraphicsResources(win);
199 }
200 
201 void TextureSlicePainter::PrepareForRendering(vtkRenderer* renderer, vtkActor* actor)
202 {
203  report_gl_error();
204  if (!CanRender(renderer, actor))
205  {
206  this->ClearGraphicsResources();
207  this->LastContext = 0;
208  this->Superclass::PrepareForRendering(renderer, actor);
209  return;
210  }
211 
212  GLint oldTextureUnit;
213  glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit);
214 
215  vtkRenderWindow* renWin = renderer->GetRenderWindow();
216  if (this->LastContext != renWin)
217  {
218  this->ClearGraphicsResources();
219  hasLoadedExtensions = false; // force re-check
220  }
221  this->LastContext = renWin;
222 
223  vtkOpenGLRenderWindow *context = vtkOpenGLRenderWindow::SafeDownCast(renWin);
224  if (!hasLoadedExtensions)
225  {
226  if (!this->LoadRequiredExtensions(context->GetExtensionManager()))
227  {
228  return;
229  }
230  hasLoadedExtensions = true;
231  }
232 
233  for (unsigned i = 0; i < this->mElement.size(); ++i)
234  this->mElement[i].initializeRendering();
235 
236  if (!this->Shader)
237  {
238  report_gl_error();
239  QString shaderSource = this->loadShaderFile();
240  shaderSource = this->replaceShaderSourceMacros(shaderSource);
241 // int layers = this->mElement.size();
242 // shaderSource = shaderSource.replace("${LAYERS}", QString("%1").arg(layers));
243 
244  this->buildProgram(shaderSource, context);
245  }
246 
247  glPixelStorei(GL_PACK_ALIGNMENT, 1);
248  glPixelStorei(GL_PACK_ROW_LENGTH, 0);
249  glPixelStorei(GL_PACK_SKIP_ROWS, 0);
250  glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
251 
252  this->Superclass::PrepareForRendering(renderer, actor);
253  report_gl_error();
254  glActiveTexture(oldTextureUnit);
255 }
256 
257 QString TextureSlicePainter::replaceShaderSourceMacros(QString shaderSource)
258 {
259  // set constant layers
260  int layers = this->mElement.size();
261  shaderSource = shaderSource.replace("${LAYERS}", QString("%1").arg(layers));
262 
263  // fill function vec4 sampleLut(in int index, in float idx)
264  QString element = "\tif (index==%1) return texture1D(lut[%1], idx);\n";
265  QString sampleLutContent;
266  for (unsigned i=0; i<layers; ++i)
267  sampleLutContent += element.arg(i);
268  shaderSource = shaderSource.replace("${SAMPLE_LUT_CONTENT}", sampleLutContent);
269 
270  return shaderSource;
271 }
272 
273 
274 void TextureSlicePainter::RenderInternal(vtkRenderer* renderer, vtkActor* actor, unsigned long typeflags,
275  bool forceCompileOnly)
276 {
277  if (!CanRender(renderer, actor))
278  {
279  return;
280  }
281 
282  GLint oldTextureUnit;
283  glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit);
284 
285  int layers = this->mElement.size();
286  this->Shader->GetUniformVariables()->SetUniformi("layers", 1, &layers);
287 
288  for (unsigned i = 0; i < this->mElement.size(); ++i)
289  {
290  this->mElement[i].eachRenderInternal(this->Shader);
291  }
292 
293  this->Shader->Use();
294 
295  if (!this->Shader->IsValid())
296  {
297  vtkErrorMacro(<<" validation of the program failed: "<< this->Shader->GetLastValidateLog());
298  }
299 
300  this->Superclass::RenderInternal(renderer, actor, typeflags, forceCompileOnly);
301 
302  this->Shader->Restore();
303  report_gl_error();
304  glActiveTexture(oldTextureUnit);
305 }
306 
307 bool TextureSlicePainter::CanRender(vtkRenderer*, vtkActor*)
308 {
309  return !this->mElement.empty();
310 }
311 
312 bool TextureSlicePainter::LoadRequiredExtension(vtkOpenGLExtensionManager* mgr, QString id)
313 {
314  bool loaded = mgr->LoadSupportedExtension(cstring_cast(id));
315  if (!loaded)
316  std::cout << "TextureSlicePainter Error: GL extension " + id + " not found" << std::endl;
317  return loaded;
318 }
319 
320 bool TextureSlicePainter::LoadRequiredExtensions(vtkOpenGLExtensionManager* mgr)
321 {
322  return (LoadRequiredExtension(mgr, "GL_VERSION_2_0")
323  && LoadRequiredExtension(mgr, "GL_VERSION_1_5")
324  && LoadRequiredExtension(mgr, "GL_ARB_vertex_buffer_object"));
325 }
326 
328 {
329  this->safeIndex(index).SetBuffer(buffer);
330 }
331 
333 {
334  this->safeIndex(index).SetBuffer(buffer);
335 }
336 
337 void TextureSlicePainter::SetColorAttribute(int index, float window, float level, float llr,float alpha)
338 {
339  this->safeIndex(index).SetColorAttribute(window, level, llr, alpha);
340 }
341 
343 {
344 }
345 
346 void TextureSlicePainter::PrintSelf(ostream& os, vtkIndent indent)
347 {
348 }
349 
350 SingleVolumePainterHelper& TextureSlicePainter::safeIndex(int index)
351 {
352  if ((int)mElement.size() <= index)
353  {
354  mElement.resize(index+1);
355  mElement[index] = SingleVolumePainterHelper(index);
356  }
357  return mElement[index];
358 }
359 
360 void TextureSlicePainter::buildProgram(QString shaderSource, vtkOpenGLRenderWindow* renderWindow)
361 {
362  vtkShaderProgram2Ptr pgm = vtkShaderProgram2Ptr::New();
363  pgm->SetContext(renderWindow);
364 
365  vtkShader2Ptr s2 = vtkShader2Ptr::New();
366  s2->SetType(VTK_SHADER_TYPE_FRAGMENT);
367  s2->SetSourceCode(cstring_cast(shaderSource));
368  s2->SetContext(pgm->GetContext());
369  pgm->GetShaders()->AddItem(s2);
370  report_gl_error();
371  pgm->Build();
372 
373  if (pgm->GetLastBuildStatus() != VTK_SHADER_PROGRAM2_LINK_SUCCEEDED)
374  {
375  vtkErrorMacro("Pass Two failed.");
376  abort();
377  }
378 
379  this->Shader = pgm;
380 }
381 
383 {
384  if (this->Shader != 0)
385  {
386  this->Shader->ReleaseGraphicsResources();
387  this->Shader = 0;
388  }
389 }
390 
391 
392 //---------------------------------------------------------
393 }//end namespace
394 //---------------------------------------------------------
395 
396 #endif //CX_VTK_OPENGL2
397 //#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:28
Namespace for all CustusX production code.