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