1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkOpenGLImageAlgorithmHelper.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
16 #include "vtkOpenGLImageAlgorithmHelper.h"
17 #include "vtkObjectFactory.h"
18 #include "vtkTextureObject.h"
19 #include "vtkOpenGLRenderWindow.h"
20 #include "vtkDataArray.h"
21 #include "vtkImageData.h"
22 #include "vtkNew.h"
23 #include "vtkOpenGLFramebufferObject.h"
24 #include "vtkOpenGLShaderCache.h"
25 #include "vtkOpenGLState.h"
26 #include "vtk_glew.h"
27 #include "vtkPixelTransfer.h"
28 #include "vtkPointData.h"
29 #include "vtkPixelBufferObject.h"
30 #include "vtkShaderProgram.h"
31 #include "vtkOpenGLVertexArrayObject.h"
32
33 vtkStandardNewMacro(vtkOpenGLImageAlgorithmHelper);
34
35 // ----------------------------------------------------------------------------
vtkOpenGLImageAlgorithmHelper()36 vtkOpenGLImageAlgorithmHelper::vtkOpenGLImageAlgorithmHelper()
37 {
38 this->RenderWindow = nullptr;
39 }
40
41 // ----------------------------------------------------------------------------
~vtkOpenGLImageAlgorithmHelper()42 vtkOpenGLImageAlgorithmHelper::~vtkOpenGLImageAlgorithmHelper()
43 {
44 this->SetRenderWindow(nullptr);
45 }
46
SetRenderWindow(vtkRenderWindow * renWin)47 void vtkOpenGLImageAlgorithmHelper::SetRenderWindow(vtkRenderWindow *renWin)
48 {
49 if (renWin == this->RenderWindow.GetPointer())
50 {
51 return;
52 }
53
54 vtkOpenGLRenderWindow *orw = nullptr;
55 if (renWin)
56 {
57 orw = vtkOpenGLRenderWindow::SafeDownCast(renWin);
58 }
59
60 this->RenderWindow = orw;
61 this->Modified();
62 }
63
Execute(vtkOpenGLImageAlgorithmCallback * cb,vtkImageData * inImage,vtkDataArray * inArray,vtkImageData * outImage,int outExt[6],const char * vertexCode,const char * fragmentCode,const char * geometryCode)64 void vtkOpenGLImageAlgorithmHelper::Execute(
65 vtkOpenGLImageAlgorithmCallback *cb,
66 vtkImageData *inImage, vtkDataArray *inArray,
67 vtkImageData *outImage, int outExt[6],
68 const char *vertexCode,
69 const char *fragmentCode,
70 const char *geometryCode
71 )
72 {
73 // make sure it is initialized
74 if (!this->RenderWindow)
75 {
76 this->SetRenderWindow(vtkRenderWindow::New());
77 this->RenderWindow->SetOffScreenRendering(true);
78 this->RenderWindow->UnRegister(this);
79 }
80 this->RenderWindow->Initialize();
81
82 // Is it a 2D or 3D image
83 int dims[3];
84 inImage->GetDimensions(dims);
85 int dimensions = 0;
86 for (int i = 0; i < 3; i ++)
87 {
88 if (dims[i] > 1)
89 {
90 dimensions++;
91 }
92 }
93
94 // no 1D or 2D support yet
95 if (dimensions < 3)
96 {
97 vtkErrorMacro("no 1D or 2D processing support yet");
98 return;
99 }
100
101 // send vector data to a texture
102 int inputExt[6];
103 inImage->GetExtent(inputExt);
104 void *inPtr = inArray->GetVoidPointer(0);
105
106 // could do shortcut here if the input volume is
107 // exactly what we want (updateExtent == wholeExtent)
108 // vtkIdType incX, incY, incZ;
109 // inImage->GetContinuousIncrements(inArray, extent, incX, incY, incZ);
110 // tmpImage->CopyAndCastFrom(inImage, inUpdateExtent)
111
112 vtkNew<vtkTextureObject> inputTex;
113 inputTex->SetContext(this->RenderWindow);
114 inputTex->Create3DFromRaw(
115 dims[0], dims[1], dims[2],
116 inArray->GetNumberOfComponents(),
117 inArray->GetDataType(), inPtr);
118
119 float shift = 0.0;
120 float scale = 1.0;
121 inputTex->GetShiftAndScale(shift, scale);
122
123 // now create the framebuffer for the output
124 int outDims[3];
125 outDims[0] = outExt[1] - outExt[0] + 1;
126 outDims[1] = outExt[3] - outExt[2] + 1;
127 outDims[2] = outExt[5] - outExt[4] + 1;
128
129 vtkNew<vtkTextureObject> outputTex;
130 outputTex->SetContext(this->RenderWindow);
131
132 vtkNew<vtkOpenGLFramebufferObject> fbo;
133 fbo->SetContext(this->RenderWindow);
134 vtkOpenGLState *ostate = this->RenderWindow->GetState();
135
136 outputTex->Create2D(outDims[0], outDims[1], 4, VTK_FLOAT, false);
137 fbo->AddColorAttachment(fbo->GetDrawMode(), 0, outputTex);
138
139 // because the same FBO can be used in another pass but with several color
140 // buffers, force this pass to use 1, to avoid side effects from the
141 // render of the previous frame.
142 fbo->ActivateDrawBuffer(0);
143
144 fbo->StartNonOrtho(outDims[0], outDims[1]);
145 ostate->vtkglViewport(0, 0, outDims[0], outDims[1]);
146 ostate->vtkglScissor(0, 0, outDims[0], outDims[1]);
147 ostate->vtkglDisable(GL_DEPTH_TEST);
148
149 vtkShaderProgram *prog =
150 this->RenderWindow->GetShaderCache()->ReadyShaderProgram(
151 vertexCode, fragmentCode, geometryCode);
152 if (prog != this->Quad.Program)
153 {
154 this->Quad.Program = prog;
155 this->Quad.VAO->ShaderProgramChanged();
156 }
157 cb->InitializeShaderUniforms(prog);
158
159 inputTex->Activate();
160 int inputTexId = inputTex->GetTextureUnit();
161 this->Quad.Program->SetUniformi("inputTex1", inputTexId);
162 // shift and scale to get the data backing into its original units
163 this->Quad.Program->SetUniformf("inputShift", shift);
164 this->Quad.Program->SetUniformf("inputScale", scale);
165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
167
168 // for each zslice in the output
169 vtkPixelExtent outputPixelExt(outExt);
170 for (int i = outExt[4]; i <= outExt[5]; i++)
171 {
172 cb->UpdateShaderUniforms(prog, i);
173 this->Quad.Program->SetUniformf("zPos", (i - outExt[4] + 0.5) / (outDims[2]));
174
175 fbo->RenderQuad(
176 0, outDims[0] - 1,
177 0, outDims[1] - 1,
178 this->Quad.Program, this->Quad.VAO);
179
180 vtkPixelBufferObject *outPBO = outputTex->Download();
181
182 vtkPixelTransfer::Blit<float, double>(
183 outputPixelExt,
184 outputPixelExt,
185 outputPixelExt,
186 outputPixelExt,
187 4,
188 (float*)outPBO->MapPackedBuffer(),
189 outImage->GetPointData()->GetScalars()->GetNumberOfComponents(),
190 static_cast<double *>(outImage->GetScalarPointer(outExt[0], outExt[2], i)));
191
192 outPBO->UnmapPackedBuffer();
193 outPBO->Delete();
194 }
195 }
196
197 // ----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)198 void vtkOpenGLImageAlgorithmHelper::PrintSelf(ostream& os, vtkIndent indent)
199 {
200 this->Superclass::PrintSelf(os,indent);
201
202 os << indent << "RenderWindow:";
203 if(this->RenderWindow != nullptr)
204 {
205 this->RenderWindow->PrintSelf(os,indent);
206 }
207 else
208 {
209 os << "(none)" <<endl;
210 }
211 }
212