CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxShaderCallback.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 #include "cxShaderCallback.h"
13 
14 #include <vtkShaderProgram.h>
15 #include <vtkShader.h>
16 #include <vtkOpenGLHelper.h>
17 #include <vtkOpenGLVertexArrayObject.h>
18 #include <vtkOpenGLBufferObject.h>
19 #include <vtkTextureObject.h>
20 #include <vtkOpenGLIndexBufferObject.h>
21 #include <vtkOpenGLRenderWindow.h>
22 
23 #include "cxGLHelpers.h"
24 #include "cxLogger.h"
25 #include "GL/glew.h"
26 
27 #ifdef __APPLE__
28 #include <glu.h>
29 #else
30 #include <GL/glu.h>
31 #endif
32 
33 #include "cxOpenGLShaders.h"
34 
35 namespace cx
36 {
37 
38 
40 {
41 }
42 
44 {
45 }
46 
48 {
49  return new ShaderCallback;
50 }
51 
52 void ShaderCallback::printDebugInfo(vtkOpenGLHelper *OpenGLHelper)
53 {
54  if(!OpenGLHelper)
55  {
56  return;
57  }
58 
59  vtkShaderProgram *program = OpenGLHelper->Program;
60  std::cout << "Program is compiled? " << program->GetCompiled() << std::endl;
61  std::cout << "Program is bound? " << program->isBound() << std::endl;
62  std::cout << "IBO index count " << OpenGLHelper->IBO->IndexCount << std::endl;
63  std::string vertexshader = program->GetVertexShader()->GetSource();
64  std::cout << "Vertexshader:\n " << vertexshader << std::endl;
65  std::string fragmentshader = program->GetFragmentShader()->GetSource();
66  std::cout << "Fragmentshader:\n " << fragmentshader << std::endl;
68 }
69 
70 void ShaderCallback::Execute(vtkObject *, unsigned long eventId, void *cbo)
71 {
73 
74  vtkOpenGLHelper *OpenGLHelper = reinterpret_cast<vtkOpenGLHelper*>(cbo);
75 
76  if(!OpenGLHelper || !OpenGLHelper->VAO || !OpenGLHelper->Program)
77  {
78  return;
79  }
80 
81 
82  if(eventId == vtkCommand::UpdateShaderEvent)
83  {
85 
86 
87  int textures_to_add = this->getNumberOfUploadedTextures();
88 
89  //Bind fragmentshader output variable
90  // (glsl: vec4)
91  if(textures_to_add != 0)
92  {
93  this->bindFSOutputVariable(OpenGLHelper->Program);
94  }
95 
97 
98  //Bind VAO (Vertext Array Object - aka saved input to the vertex shader)
99  OpenGLHelper->VAO->Bind();
100  report_gl_error();
101 
102  for(int i=0; i< textures_to_add; ++i)
103  {
104  ShaderItemPtr shaderItem = mShaderItems.at(i);
105  // texture coordinates (glsl: vec3)
106  vtkOpenGLBufferObjectPtr texture_coordinates = shaderItem->mTextureCoordinates;
107 
108  if(texture_coordinates)
109  {
110  if(!texture_coordinates->Bind())
111  {
112  CX_LOG_WARNING() << "Could not bind texture coordinates";
113  }
114 
115  this->addArrayToAttributeArray(OpenGLHelper->Program, texture_coordinates, VS_In_Vec3_TextureCoordinate, i);
116  }
117  else
118  {
119  CX_LOG_WARNING() << "NO TEXTURE COORDINATES!";
120  }
121 
122  report_gl_error();
123 
124  // 3D texture pointer (glsl: sampler3D)
125  vtkTextureObjectPtr texture = shaderItem->mTexture;
126 
127  if(texture)
128  {
129  texture->Activate();
130  this->addUniformiArray(OpenGLHelper->Program, getVectorNameFromName(FS_Uniform_3DTexture_Volume, i), texture->GetTextureUnit());
131  }
132  else
133  {
134  CX_LOG_WARNING() << "NO 3D TEXTURE!";
135  }
136 
137  report_gl_error();
138 
139  // 1D texture pointer (glsl: sampler1D)
140  vtkTextureObjectPtr lut = shaderItem->mLUT;
141 
142  if(lut)
143  {
144  lut->Activate();
145  this->addUniformiArray(OpenGLHelper->Program, getVectorNameFromName(FS_Uniform_1DTexture_LUT, i), lut->GetTextureUnit());
146  }
147  else
148  {
149  CX_LOG_WARNING() << "NO 1D TEXTURE!";
150  }
151 
152  report_gl_error();
153 
154  this->addUniformfArray(OpenGLHelper->Program, getVectorNameFromName(FS_Uniform_Window,i), shaderItem->mWindow);
155  this->addUniformfArray(OpenGLHelper->Program, getVectorNameFromName(FS_Uniform_Level,i), shaderItem->mLevel);
156  this->addUniformfArray(OpenGLHelper->Program, getVectorNameFromName(FS_Uniform_LLR,i), shaderItem->mLLR);
157  this->addUniformfArray(OpenGLHelper->Program, getVectorNameFromName(FS_Uniform_Alpha,i), shaderItem->mAlpha);
158  }
159  }
160 
161  report_gl_error();
162 
163 }
164 
166 {
167  ShaderItemPtr item;
168 
169  for(int i=0; i<mShaderItems.size(); ++i)
170  {
171  item = mShaderItems.at(i);
172 
173  if(item->mTextureUid == image_uid)
174  {
175  return item;
176  }
177  }
178 
179  CX_LOG_ERROR() << "COULD NOT FIND THE SHADERITEM";
180  return item;
181 }
182 
184 {
185  return mShaderItems.size();
186 }
187 
189 {
190  mShaderItems.push_back(item);
191 }
192 
194 {
195  mShaderItems.clear();
196 }
197 
206 void ShaderCallback::addArrayToAttributeArray(vtkShaderProgram *program, vtkOpenGLBufferObjectPtr buffer, std::string name, int vector_index)
207 {
208  //--------
209  //This is information about how the texture coordinates are uploaded.
210  int offset = 0;
211  int vec_size = 3;
212  size_t stride = sizeof(float)*vec_size; //is this correct? was *3;
213  int elementType = GL_FLOAT; //VTK_FLOAT
214  bool normalize = false;
215 
216  //CX_LOG_DEBUG() << "Adding attribute called: " << name << " to vector_index: " << vector_index;
217  //--------
218 
219  const GLchar *namePtr = static_cast<const GLchar *>(name.c_str());
220  GLint start_of_vector_index = glGetAttribLocation(program->GetHandle(), namePtr);
221  report_gl_error();
222 
223 
224  if(start_of_vector_index != -1)
225  {
226  GLint position_in_vector_index = start_of_vector_index + vector_index;
227  buffer->Bind();
228 
229  glEnableVertexAttribArray(position_in_vector_index);
230 
231  glVertexAttribPointer(position_in_vector_index,
232  vec_size,
233  elementType,
234  normalize,
235  static_cast<GLsizei>(stride),
236  ((char *)NULL + (offset))
237  );
238  report_gl_error();
239  }
240  else
241  {
242  CX_LOG_ERROR() << "Error setting attribute " << name << " with vector_index " << vector_index;
243  }
244 
245 }
246 
247 void ShaderCallback::addUniformiArray(vtkShaderProgram *program, std::string name, int value)
248 {
249  //Note: Set uniform will fail if the uniform is not present OR active (used inside the program).
250  report_gl_error();
251 
252  //CX_LOG_DEBUG() << "Adding uniform called: " << name << " with value " << value;
253  if(!program->SetUniform1iv(name.c_str(), 1, &value))
254  {
255  CX_LOG_ERROR() << "Could not set uniform named " << name;
256  }
257 
258  report_gl_error();
259 }
260 
261 void ShaderCallback::addUniformfArray(vtkShaderProgram *program, std::string name, float value)
262 {
263  //Note: Set uniform will fail if the uniform is not present OR active (used inside the program).
264  report_gl_error();
265 
266  //CX_LOG_DEBUG() << "Adding uniform called: " << name << " with value " << value;
267  if(!program->SetUniform1fv(name.c_str(), 1, &value))
268  {
269  CX_LOG_ERROR() << "Could not set uniform named " << name;
270  }
271 
272  report_gl_error();
273 }
274 
275 void ShaderCallback::bindFSOutputVariable(vtkShaderProgram *program)
276 {
277  GLint color_frag_out_index = glGetFragDataLocation(program->GetHandle(), FS_Out_Vec4_Color.c_str());
278 
279  if(color_frag_out_index != -1)
280  {
281  glBindFragDataLocation(program->GetHandle(), color_frag_out_index, FS_Out_Vec4_Color.c_str()); //setting output of fragment shader
282  //CX_LOG_DEBUG() << "Binding fragmentshader output to " << FS_Out_Vec4_Color << " at index "<< color_frag_out_index;
283  }
284  else
285  {
286  CX_LOG_ERROR() << "Could not find glGetFragDataLocation for " << FS_Out_Vec4_Color;
287  }
288 }
289 
290 std::string ShaderCallback::getVectorNameFromName(std::string name, int index_of_vector) const
291 {
292  QString fullName = QString("%1[%2]").arg(QString(name.c_str())).arg(index_of_vector);
293  return fullName.toStdString();
294 }
295 
296 }//namespace cx
297 
vtkSmartPointer< class vtkTextureObject > vtkTextureObjectPtr
virtual void Execute(vtkObject *, unsigned long eventId, void *cbo)
vtkSmartPointer< class vtkOpenGLBufferObject > vtkOpenGLBufferObjectPtr
The ShaderCallback class is used to update information sent to our custom OpenGL shaders.
#define CX_LOG_ERROR
Definition: cxLogger.h:99
int getNumberOfUploadedTextures() const
boost::shared_ptr< ShaderItem > ShaderItemPtr
static ShaderCallback * New()
#define CX_LOG_WARNING
Definition: cxLogger.h:98
void add(ShaderItemPtr item)
ShaderItemPtr getShaderItem(QString image_uid) const
#define report_gl_error()
Definition: cxGLHelpers.h:28
Namespace for all CustusX production code.