1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkOpenGLImageGradient.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkOpenGLImageGradient.h"
16
17 #include "vtkOpenGLImageAlgorithmHelper.h"
18
19 #include "vtkCellData.h"
20 #include "vtkDataArray.h"
21 #include "vtkImageData.h"
22 #include "vtkInformation.h"
23 #include "vtkInformationVector.h"
24 #include "vtkObjectFactory.h"
25 #include "vtkPointData.h"
26 #include "vtkShaderProgram.h"
27 #include "vtkStreamingDemandDrivenPipeline.h"
28
29 #include <algorithm> // for std::nth_element
30
31 vtkStandardNewMacro(vtkOpenGLImageGradient);
32
33 //------------------------------------------------------------------------------
34 // Construct an instance of vtkOpenGLImageGradient filter.
vtkOpenGLImageGradient()35 vtkOpenGLImageGradient::vtkOpenGLImageGradient()
36 {
37 // for GPU we do not want threading
38 this->NumberOfThreads = 1;
39 this->EnableSMP = false;
40 this->Helper = vtkOpenGLImageAlgorithmHelper::New();
41 }
42
43 //------------------------------------------------------------------------------
~vtkOpenGLImageGradient()44 vtkOpenGLImageGradient::~vtkOpenGLImageGradient()
45 {
46 if (this->Helper)
47 {
48 this->Helper->Delete();
49 this->Helper = nullptr;
50 }
51 }
52
SetRenderWindow(vtkRenderWindow * renWin)53 void vtkOpenGLImageGradient::SetRenderWindow(vtkRenderWindow* renWin)
54 {
55 this->Helper->SetRenderWindow(renWin);
56 }
57
58 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)59 void vtkOpenGLImageGradient::PrintSelf(ostream& os, vtkIndent indent)
60 {
61 this->Superclass::PrintSelf(os, indent);
62
63 os << indent << "Helper: ";
64 this->Helper->PrintSelf(os, indent);
65 }
66
67 // this is used as a callback by the helper to set shader parameters
68 // before running and to update them on each slice
69 class vtkOpenGLGradientCB : public vtkOpenGLImageAlgorithmCallback
70 {
71 public:
72 // initialize the spacing
InitializeShaderUniforms(vtkShaderProgram * program)73 void InitializeShaderUniforms(vtkShaderProgram* program) override
74 {
75 float sp[3];
76 sp[0] = this->Spacing[0];
77 sp[1] = this->Spacing[1];
78 sp[2] = this->Spacing[2];
79 program->SetUniform3f("spacing", sp);
80 }
81
82 // no uniforms change on a per slice basis so empty
UpdateShaderUniforms(vtkShaderProgram *,int)83 void UpdateShaderUniforms(vtkShaderProgram* /* program */, int /* zExtent */) override {}
84
85 double* Spacing;
86 vtkOpenGLGradientCB() = default;
87 ~vtkOpenGLGradientCB() override = default;
88
89 private:
90 vtkOpenGLGradientCB(const vtkOpenGLGradientCB&) = delete;
91 void operator=(const vtkOpenGLGradientCB&) = delete;
92 };
93
94 //------------------------------------------------------------------------------
95 // This method contains the first switch statement that calls the correct
96 // templated function for the input and output region types.
ThreadedRequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector),vtkImageData *** inData,vtkImageData ** outData,int outExt[6],int vtkNotUsed (id))97 void vtkOpenGLImageGradient::ThreadedRequestData(vtkInformation* vtkNotUsed(request),
98 vtkInformationVector** inputVector, vtkInformationVector* vtkNotUsed(outputVector),
99 vtkImageData*** inData, vtkImageData** outData, int outExt[6], int vtkNotUsed(id))
100 {
101 vtkDataArray* inArray = this->GetInputArrayToProcess(0, inputVector);
102 outData[0]->GetPointData()->GetScalars()->SetName(inArray->GetName());
103
104 // The output scalar type must be double to store proper gradients.
105 if (outData[0]->GetScalarType() != VTK_DOUBLE)
106 {
107 vtkErrorMacro(
108 "Execute: output ScalarType is " << outData[0]->GetScalarType() << "but must be double.");
109 return;
110 }
111
112 // Gradient makes sense only with one input component. This is not
113 // a Jacobian filter.
114 if (inArray->GetNumberOfComponents() != 1)
115 {
116 vtkErrorMacro("Execute: input has more than one component. "
117 "The input to gradient should be a single component image. "
118 "Think about it. If you insist on using a color image then "
119 "run it though RGBToHSV then ExtractComponents to get the V "
120 "components. That's probably what you want anyhow.");
121 return;
122 }
123
124 vtkOpenGLGradientCB cb;
125 cb.Spacing = inData[0][0]->GetSpacing();
126
127 // build the fragment shader for 2D or 3D gradient
128 std::string fragShader =
129 "//VTK::System::Dec\n"
130 "varying vec2 tcoordVSOutput;\n"
131 "uniform sampler3D inputTex1;\n"
132 "uniform float zPos;\n"
133 "uniform vec3 spacing;\n"
134 "uniform float inputScale;\n"
135 "uniform float inputShift;\n"
136 "//VTK::Output::Dec\n"
137 "void main(void) {\n"
138 " float dx = textureOffset(inputTex1, vec3(tcoordVSOutput, zPos), ivec3(1,0,0)).r\n"
139 " - textureOffset(inputTex1, vec3(tcoordVSOutput, zPos), ivec3(-1,0,0)).r;\n"
140 " dx = inputScale*0.5*dx/spacing.x;\n"
141 " float dy = textureOffset(inputTex1, vec3(tcoordVSOutput, zPos), ivec3(0,1,0)).r\n"
142 " - textureOffset(inputTex1, vec3(tcoordVSOutput, zPos), ivec3(0,-1,0)).r;\n"
143 " dy = inputScale*0.5*dy/spacing.y;\n";
144
145 if (this->Dimensionality == 3)
146 {
147 fragShader +=
148 " float dz = textureOffset(inputTex1, vec3(tcoordVSOutput, zPos), ivec3(0,0,1)).r\n"
149 " - textureOffset(inputTex1, vec3(tcoordVSOutput, zPos), ivec3(0,0,-1)).r;\n"
150 " dz = inputScale*0.5*dz/spacing.z;\n"
151 " gl_FragData[0] = vec4(dx, dy, dz, 1.0);\n"
152 "}\n";
153 }
154 else
155 {
156 fragShader += " gl_FragData[0] = vec4(dx, dy, 0.0, 1.0);\n"
157 "}\n";
158 }
159
160 // call the helper to execte this code
161 this->Helper->Execute(&cb, inData[0][0], inArray, outData[0], outExt,
162
163 "//VTK::System::Dec\n"
164 "attribute vec4 vertexMC;\n"
165 "attribute vec2 tcoordMC;\n"
166 "varying vec2 tcoordVSOutput;\n"
167 "void main() {\n"
168 " tcoordVSOutput = tcoordMC;\n"
169 " gl_Position = vertexMC;\n"
170 "}\n",
171
172 fragShader.c_str(),
173
174 "");
175 }
176