1 /*========================================================================= 2 3 Program: Visualization Toolkit 4 Module: vtkVolumeMask.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 vtkVolumeMask_h_ 17 #define vtkVolumeMask_h_ 18 19 #include <vtkDataArray.h> 20 #include <vtkImageData.h> 21 22 #include <map> // STL required 23 24 //---------------------------------------------------------------------------- 25 class vtkVolumeMask 26 { 27 public: vtkVolumeMask()28 vtkVolumeMask() 29 { 30 this->TextureId = 0; 31 this->Loaded = false; 32 this->LoadedExtent[0] = VTK_INT_MAX; 33 this->LoadedExtent[1] = VTK_INT_MIN; 34 this->LoadedExtent[2] = VTK_INT_MAX; 35 this->LoadedExtent[3] = VTK_INT_MIN; 36 this->LoadedExtent[4] = VTK_INT_MAX; 37 this->LoadedExtent[5] = VTK_INT_MIN; 38 } 39 ~vtkVolumeMask()40 ~vtkVolumeMask() 41 { 42 if(this->TextureId != 0) 43 { 44 glDeleteTextures(1, &this->TextureId); 45 this->TextureId = 0; 46 } 47 } 48 GetBuildTime()49 vtkTimeStamp GetBuildTime() 50 { 51 return this->BuildTime; 52 } 53 Bind()54 void Bind() 55 { 56 // Activate texture 6 57 glActiveTexture(GL_TEXTURE6); 58 glBindTexture(GL_TEXTURE_3D, this->TextureId); 59 } 60 Update(vtkImageData * input,int cellFlag,int textureExtent[6],int scalarMode,int arrayAccessMode,int arrayId,const char * arrayName,vtkIdType maxMemoryInBytes)61 void Update(vtkImageData *input, 62 int cellFlag, 63 int textureExtent[6], 64 int scalarMode, 65 int arrayAccessMode, 66 int arrayId, 67 const char* arrayName, 68 vtkIdType maxMemoryInBytes) 69 { 70 glActiveTexture(GL_TEXTURE6); 71 72 bool needUpdate = false; 73 bool modified = false; 74 if(this->TextureId == 0) 75 { 76 glGenTextures(1, &this->TextureId); 77 needUpdate = true; 78 } 79 glBindTexture(GL_TEXTURE_3D,this->TextureId); 80 81 int obsolete = needUpdate || !this->Loaded || 82 input->GetMTime()>this->BuildTime; 83 if(!obsolete) 84 { 85 obsolete = cellFlag != this->LoadedCellFlag; 86 int i = 0; 87 while(!obsolete && i<6) 88 { 89 obsolete = obsolete || this->LoadedExtent[i]>textureExtent[i]; 90 ++i; 91 obsolete = obsolete || this->LoadedExtent[i]<textureExtent[i]; 92 ++i; 93 } 94 } 95 96 if(obsolete) 97 { 98 this->Loaded = false; 99 int dim[3]; 100 input->GetDimensions(dim); 101 102 vtkDataArray *scalars = 103 vtkAbstractMapper::GetScalars(input,scalarMode,arrayAccessMode, 104 arrayId,arrayName, 105 this->LoadedCellFlag); 106 107 // DONT USE GetScalarType() or GetNumberOfScalarComponents() on 108 // ImageData as it deals only with point data... 109 int scalarType = scalars->GetDataType(); 110 if(scalarType != VTK_UNSIGNED_CHAR) 111 { 112 cout <<"Mask should be VTK_UNSIGNED_CHAR." << endl; 113 } 114 if(scalars->GetNumberOfComponents()!=1) 115 { 116 cout << "Mask should be a one-component scalar field." << endl; 117 } 118 119 GLint internalFormat = GL_ALPHA8; 120 GLenum format = GL_ALPHA; 121 GLenum type = GL_UNSIGNED_BYTE; 122 123 // Enough memory? 124 int textureSize[3]; 125 int i=0; 126 while(i<3) 127 { 128 textureSize[i] = textureExtent[2*i+1] - textureExtent[2*i] + 1; 129 ++i; 130 } 131 132 GLint width; 133 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &width); 134 this->Loaded = textureSize[0] <= width && textureSize[1] <= width && 135 textureSize[2] <= width; 136 if(this->Loaded) 137 { 138 // So far, so good but some cards always succeed with a proxy texture 139 // let's try to actually allocate.. 140 glTexImage3D(GL_TEXTURE_3D, 0, internalFormat, textureSize[0], 141 textureSize[1], textureSize[2], 0, format, type, 0); 142 GLenum errorCode = glGetError(); 143 this->Loaded = errorCode!= GL_OUT_OF_MEMORY; 144 if(this->Loaded) 145 { 146 // so far, so good, actual allocation succeeded. 147 if(errorCode != GL_NO_ERROR) 148 { 149 cout << "After try to load the texture"; 150 cout << "ERROR (x"<<hex<<errorCode<<") " << dec; 151 cout << endl; 152 } 153 // so far, so good but some cards don't report allocation error 154 this->Loaded = textureSize[0] * textureSize[1]* 155 textureSize[2]*vtkAbstractArray::GetDataTypeSize(scalarType)* 156 scalars->GetNumberOfComponents() <= maxMemoryInBytes; 157 if(this->Loaded) 158 { 159 // OK, we consider the allocation above succeeded... 160 // If it actually didn't the only to fix it for the user 161 // is to decrease the value of this->MaxMemoryInBytes. 162 163 // enough memory! We can load the scalars! 164 165 // we don't clamp to edge because for the computation of the 166 // gradient on the border we need some external value. 167 glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 168 glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 169 glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 170 171 GLfloat borderColor[4]={0.0,0.0,0.0,0.0}; 172 glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, borderColor); 173 174 glPixelTransferf(GL_ALPHA_SCALE, 1.0); 175 glPixelTransferf(GL_ALPHA_BIAS, 0.0); 176 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 177 178 if(!(textureExtent[1]-textureExtent[0]+cellFlag==dim[0])) 179 { 180 glPixelStorei(GL_UNPACK_ROW_LENGTH,dim[0]-cellFlag); 181 } 182 if(!(textureExtent[3]-textureExtent[2]+cellFlag==dim[1])) 183 { 184 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT_EXT, 185 dim[1]-cellFlag); 186 } 187 void* dataPtr = scalars->GetVoidPointer( 188 ((textureExtent[4]*(dim[1]-cellFlag)+textureExtent[2]) * 189 (dim[0]-cellFlag)+textureExtent[0]) * 190 scalars->GetNumberOfComponents()); 191 192 glTexImage3D(GL_TEXTURE_3D, 0, internalFormat, 193 textureSize[0], textureSize[1], textureSize[2], 194 0, format, type, dataPtr); 195 196 // Restore the default values. 197 glPixelStorei(GL_UNPACK_ROW_LENGTH,0); 198 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT_EXT,0); 199 glPixelTransferf(GL_ALPHA_SCALE,1.0); 200 glPixelTransferf(GL_ALPHA_BIAS,0.0); 201 202 this->LoadedCellFlag = cellFlag; 203 i = 0; 204 while(i < 6) 205 { 206 this->LoadedExtent[i] = textureExtent[i]; 207 ++i; 208 } 209 210 double spacing[3]; 211 double origin[3]; 212 input->GetSpacing(spacing); 213 input->GetOrigin(origin); 214 int swapBounds[3]; 215 swapBounds[0] = (spacing[0] < 0); 216 swapBounds[1] = (spacing[1] < 0); 217 swapBounds[2] = (spacing[2] < 0); 218 219 if(!this->LoadedCellFlag) // loaded extents represent points 220 { 221 // slabsPoints[i]=(slabsDataSet[i] - origin[i/2]) / spacing[i/2]; 222 // in general, x=o+i*spacing. 223 // if spacing is positive min extent match the min of the 224 // bounding box 225 // and the max extent match the max of the bounding box 226 // if spacing is negative min extent match the max of the 227 // bounding box 228 // and the max extent match the min of the bounding box 229 230 // if spacing is negative, we may have to rethink the equation 231 // between real point and texture coordinate... 232 this->LoadedBounds[0]=origin[0]+ 233 static_cast<double>(this->LoadedExtent[0+swapBounds[0]])*spacing[0]; 234 this->LoadedBounds[2]=origin[1]+ 235 static_cast<double>(this->LoadedExtent[2+swapBounds[1]])*spacing[1]; 236 this->LoadedBounds[4]=origin[2]+ 237 static_cast<double>(this->LoadedExtent[4+swapBounds[2]])*spacing[2]; 238 this->LoadedBounds[1]=origin[0]+ 239 static_cast<double>(this->LoadedExtent[1-swapBounds[0]])*spacing[0]; 240 this->LoadedBounds[3]=origin[1]+ 241 static_cast<double>(this->LoadedExtent[3-swapBounds[1]])*spacing[1]; 242 this->LoadedBounds[5]=origin[2]+ 243 static_cast<double>(this->LoadedExtent[5-swapBounds[2]])*spacing[2]; 244 245 } 246 else // loaded extents represent cells 247 { 248 int wholeTextureExtent[6]; 249 input->GetExtent(wholeTextureExtent); 250 i=1; 251 while(i<6) 252 { 253 wholeTextureExtent[i]--; 254 i+=2; 255 } 256 257 i=0; 258 while(i<3) 259 { 260 if(this->LoadedExtent[2*i]==wholeTextureExtent[2*i]) 261 { 262 this->LoadedBounds[2*i+swapBounds[i]]=origin[i]; 263 } 264 else 265 { 266 this->LoadedBounds[2*i+swapBounds[i]]=origin[i]+ 267 (static_cast<double>(this->LoadedExtent[2*i])+0.5)*spacing[i]; 268 } 269 270 if(this->LoadedExtent[2*i+1]==wholeTextureExtent[2*i+1]) 271 { 272 this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ 273 (static_cast<double>(this->LoadedExtent[2*i+1])+1.0)*spacing[i]; 274 } 275 else 276 { 277 this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ 278 (static_cast<double>(this->LoadedExtent[2*i+1])+0.5)*spacing[i]; 279 } 280 ++i; 281 } 282 } 283 modified=true; 284 } // if enough memory 285 } //load fail with out of memory 286 } 287 } 288 289 if(this->Loaded && (needUpdate || modified)) 290 { 291 glTexParameterf(GL_TEXTURE_3D,GL_TEXTURE_MIN_FILTER, 292 GL_NEAREST ); 293 glTexParameterf(GL_TEXTURE_3D,GL_TEXTURE_MAG_FILTER, 294 GL_NEAREST ); 295 modified=true; 296 } 297 if(modified) 298 { 299 this->BuildTime.Modified(); 300 } 301 glActiveTexture(GL_TEXTURE0); 302 } 303 GetLoadedBounds()304 double* GetLoadedBounds() 305 { 306 return this->LoadedBounds; 307 } 308 GetLoadedExtent()309 vtkIdType* GetLoadedExtent() 310 { 311 return this->LoadedExtent; 312 } 313 GetLoadedCellFlag()314 int GetLoadedCellFlag() 315 { 316 return this->LoadedCellFlag; 317 } 318 IsLoaded()319 bool IsLoaded() 320 { 321 return this->Loaded; 322 } 323 324 protected: 325 GLuint TextureId; 326 vtkTimeStamp BuildTime; 327 328 double LoadedBounds[6]; 329 vtkIdType LoadedExtent[6]; 330 331 int LoadedCellFlag; 332 bool Loaded; 333 }; 334 335 //---------------------------------------------------------------------------- 336 class vtkMapMaskTextureId 337 { 338 public: 339 std::map<vtkImageData *,vtkVolumeMask*> Map; vtkMapMaskTextureId()340 vtkMapMaskTextureId() 341 { 342 } 343 private: 344 vtkMapMaskTextureId(const vtkMapMaskTextureId &other); 345 vtkMapMaskTextureId &operator=(const vtkMapMaskTextureId &other); 346 }; 347 348 #endif // vtkVolumeMask_h_ 349 // VTK-HeaderTest-Exclude: vtkVolumeMask.h 350