1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkOpenGLVolumeOpacityTable.h
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 #ifndef vtkOpenGLVolumeOpacityTable_h
17 #define vtkOpenGLVolumeOpacityTable_h
18 #ifndef __VTK_WRAP__
19 
20 #include <vector>
21 
22 #include <vtkObjectFactory.h>
23 #include <vtkPiecewiseFunction.h>
24 #include <vtkTextureObject.h>
25 #include <vtkVolumeMapper.h>
26 #include <vtk_glew.h>
27 #include <vtkMath.h>
28 
29 
30 //----------------------------------------------------------------------------
31 class vtkOpenGLVolumeOpacityTable : public vtkObject
32 {
33 public:
34 
35   static vtkOpenGLVolumeOpacityTable* New();
36 
37   // Activate texture.
38   //--------------------------------------------------------------------------
Activate()39   void Activate()
40   {
41     if (!this->TextureObject)
42     {
43       return;
44     }
45     this->TextureObject->Activate();
46   }
47 
48   // Deactivate texture.
49   //--------------------------------------------------------------------------
Deactivate()50   void Deactivate()
51   {
52     if (!this->TextureObject)
53     {
54       return;
55     }
56     this->TextureObject->Deactivate();
57   }
58 
59   // Update opacity transfer function texture.
60   //--------------------------------------------------------------------------
Update(vtkPiecewiseFunction * scalarOpacity,int blendMode,double sampleDistance,double range[2],double unitDistance,int filterValue,vtkOpenGLRenderWindow * renWin)61   void Update(vtkPiecewiseFunction* scalarOpacity,
62               int blendMode,
63               double sampleDistance,
64               double range[2],
65               double unitDistance,
66               int filterValue,
67               vtkOpenGLRenderWindow* renWin)
68   {
69     bool needUpdate = false;
70     if (!this->TextureObject)
71     {
72       this->TextureObject = vtkTextureObject::New();
73     }
74 
75     this->TextureObject->SetContext(renWin);
76 
77     if (this->LastRange[0] != range[0] ||
78         this->LastRange[1] != range[1])
79     {
80       this->LastRange[0] = range[0];
81       this->LastRange[1] = range[1];
82       needUpdate = true;
83     }
84 
85     if(scalarOpacity->GetMTime() > this->BuildTime ||
86        this->TextureObject->GetMTime() > this->BuildTime ||
87        (this->LastBlendMode != blendMode) ||
88        (blendMode == vtkVolumeMapper::COMPOSITE_BLEND &&
89         this->LastSampleDistance != sampleDistance) ||
90        needUpdate || !this->TextureObject->GetHandle())
91     {
92       int const idealW = scalarOpacity->EstimateMinNumberOfSamples(this->LastRange[0],
93         this->LastRange[1]);
94       int const newWidth = this->GetMaximumSupportedTextureWidth(renWin, idealW);
95 
96       if(this->Table == nullptr || this->TextureWidth != newWidth)
97       {
98         this->TextureWidth = newWidth;
99         delete [] this->Table;
100         this->Table = new float[this->TextureWidth];
101       }
102 
103       scalarOpacity->GetTable(this->LastRange[0],
104                               this->LastRange[1],
105                               this->TextureWidth,
106                               this->Table);
107       this->LastBlendMode = blendMode;
108 
109       // Correct the opacity array for the spacing between the planes if we
110       // are using a composite blending operation
111       // TODO Fix this code for sample distance in three dimensions
112         if(blendMode == vtkVolumeMapper::COMPOSITE_BLEND)
113         {
114           float* ptr = this->Table;
115           double factor = sampleDistance/unitDistance;
116           int i=0;
117           while(i < this->TextureWidth)
118           {
119             if(*ptr > 0.0001f)
120             {
121               *ptr = static_cast<float>(1.0-pow(1.0-static_cast<double>(*ptr),
122                                         factor));
123             }
124             ++ptr;
125             ++i;
126           }
127           this->LastSampleDistance = sampleDistance;
128         }
129         else if (blendMode==vtkVolumeMapper::ADDITIVE_BLEND)
130         {
131           float* ptr = this->Table;
132           double factor = sampleDistance/unitDistance;
133           int i = 0;
134           while( i < this->TextureWidth)
135           {
136             if(*ptr > 0.0001f)
137             {
138               *ptr = static_cast<float>(static_cast<double>(*ptr)*factor);
139             }
140             ++ptr;
141             ++i;
142           }
143           this->LastSampleDistance = sampleDistance;
144         }
145 
146       this->TextureObject->SetWrapS(vtkTextureObject::ClampToEdge);
147       this->TextureObject->SetMagnificationFilter(filterValue);
148       this->TextureObject->SetMinificationFilter(filterValue);
149       this->TextureObject->Create2DFromRaw(this->TextureWidth, 1, 1,
150                                               VTK_FLOAT,
151                                               this->Table);
152       this->LastInterpolation = filterValue;
153       this->BuildTime.Modified();
154     }
155 
156     if(this->LastInterpolation != filterValue)
157     {
158       this->LastInterpolation = filterValue;
159       this->TextureObject->SetMagnificationFilter(filterValue);
160       this->TextureObject->SetMinificationFilter(filterValue);
161     }
162   }
163 
164   //--------------------------------------------------------------------------
GetMaximumSupportedTextureWidth(vtkOpenGLRenderWindow * renWin,int idealWidth)165   inline int GetMaximumSupportedTextureWidth(vtkOpenGLRenderWindow* renWin,
166     int idealWidth)
167   {
168     if (!this->TextureObject)
169     {
170       vtkErrorMacro("vtkTextureObject not initialized!");
171       return -1;
172     }
173 
174     // Try to match the next power of two.
175     idealWidth = vtkMath::NearestPowerOfTwo(idealWidth);
176     int const maxWidth = this->TextureObject->GetMaximumTextureSize(renWin);
177     if (maxWidth < 0)
178     {
179       vtkErrorMacro("Failed to query max texture size! using default 1024.");
180       return 1024;
181     }
182 
183     if (maxWidth >= idealWidth)
184     {
185       idealWidth = vtkMath::Max(1024, idealWidth);
186       return idealWidth;
187     }
188 
189     vtkWarningMacro("This OpenGL implementation does not support the required "
190       "texture size of " << idealWidth << ". Falling back to maximum allowed, "
191       << maxWidth << "." << "This may cause an incorrect color table mapping.");
192 
193     return maxWidth;
194   }
195 
196   // Get the texture unit
197   //--------------------------------------------------------------------------
GetTextureUnit(void)198   int GetTextureUnit(void)
199   {
200     if (!this->TextureObject)
201     {
202       return -1;
203     }
204     return this->TextureObject->GetTextureUnit();
205   }
206 
207   //--------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * window)208   void ReleaseGraphicsResources(vtkWindow *window)
209   {
210     if (this->TextureObject)
211     {
212       this->TextureObject->ReleaseGraphicsResources(window);
213       this->TextureObject->Delete();
214       this->TextureObject = nullptr;
215     }
216   }
217 
218 protected:
219 
220   //--------------------------------------------------------------------------
221   vtkOpenGLVolumeOpacityTable(int width = 1024)
222   {
223       this->TextureObject = nullptr;
224       this->LastBlendMode = vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND;
225       this->TextureWidth = width;
226       this->LastSampleDistance = 1.0;
227       this->Table = nullptr;
228       this->LastInterpolation = -1;
229       this->LastRange[0] = this->LastRange[1] = 0.0;
230   }
231 
232   //--------------------------------------------------------------------------
~vtkOpenGLVolumeOpacityTable()233   ~vtkOpenGLVolumeOpacityTable() override
234   {
235       if (this->TextureObject)
236       {
237         this->TextureObject->Delete();
238         this->TextureObject = nullptr;
239       }
240 
241       delete[] this->Table;
242   }
243 
244 
245   vtkTextureObject * TextureObject;
246   int LastBlendMode;
247   int TextureWidth;
248 
249   double LastSampleDistance;
250   vtkTimeStamp BuildTime;
251   float *Table;
252   int LastInterpolation;
253   double LastRange[2];
254 
255 private:
256   vtkOpenGLVolumeOpacityTable(const vtkOpenGLVolumeOpacityTable&)
257     = delete;
258   vtkOpenGLVolumeOpacityTable& operator=(const vtkOpenGLVolumeOpacityTable&)
259     = delete;
260 };
261 
262 ////////////////////////////////////////////////////////////////////////////////
263 class vtkOpenGLVolumeOpacityTables : public vtkObject
264 {
265 public:
266   static vtkOpenGLVolumeOpacityTables* New();
267 
268   //--------------------------------------------------------------------------
Create(unsigned int numberOfTables)269   void Create(unsigned int numberOfTables)
270   {
271     this->Tables.reserve(static_cast<size_t>(numberOfTables));
272 
273     for (unsigned int i = 0; i < numberOfTables; i++)
274     {
275       vtkOpenGLVolumeOpacityTable* table = vtkOpenGLVolumeOpacityTable::New();
276       this->Tables.push_back(table);
277     }
278   }
279 
280   //--------------------------------------------------------------------------
~vtkOpenGLVolumeOpacityTables()281   ~vtkOpenGLVolumeOpacityTables()
282   {
283     size_t const size = this->Tables.size();
284     for (size_t i = 0; i < size; i++)
285     {
286       this->Tables[i]->Delete();
287     }
288   }
289 
290   // brief Get opacity table at a given index.
291   //--------------------------------------------------------------------------
GetTable(unsigned int i)292   vtkOpenGLVolumeOpacityTable* GetTable(unsigned int i)
293   {
294     if (i >= this->Tables.size())
295     {
296       return nullptr;
297     }
298     return this->Tables[i];
299   }
300 
301   // Get number of opacity tables.
302   //--------------------------------------------------------------------------
GetNumberOfTables()303   size_t GetNumberOfTables()
304   {
305     return this->Tables.size();
306   }
307 
308   //--------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * window)309   void ReleaseGraphicsResources(vtkWindow *window)
310   {
311     size_t const size = this->Tables.size();
312     for (size_t i = 0; i < size; ++i)
313     {
314       this->Tables[i]->ReleaseGraphicsResources(window);
315     }
316   }
317 protected:
318   vtkOpenGLVolumeOpacityTables() = default;
319 
320 private:
321   std::vector<vtkOpenGLVolumeOpacityTable*> Tables;
322 
323   vtkOpenGLVolumeOpacityTables(
324     const vtkOpenGLVolumeOpacityTables &other) = delete;
325   vtkOpenGLVolumeOpacityTables &operator=(
326     const vtkOpenGLVolumeOpacityTables &other) = delete;
327 };
328 
329 #endif
330 #endif // vtkOpenGLVolumeOpacityTable_h
331 // VTK-HeaderTest-Exclude: vtkOpenGLVolumeOpacityTable.h
332