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