]> SALOME platform Git repositories - modules/gui.git/blob - src/VTKViewer/VTKViewer_Texture.cxx
Salome HOME
2a54a03ee893b4739657e55f9b3e798981e12a50
[modules/gui.git] / src / VTKViewer / VTKViewer_Texture.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 #include "VTKViewer_Texture.h"
23
24 #include "vtkHomogeneousTransform.h"
25 #include "vtkImageData.h"
26 #include "vtkLookupTable.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkOpenGLRenderer.h"
29 #include "vtkPointData.h"
30 #include "vtkRenderWindow.h"
31 #include "vtkOpenGLExtensionManager.h"
32 #include "vtkOpenGLRenderWindow.h"
33 #include "vtkTransform.h"
34 #include "vtkPixelBufferObject.h"
35 #include "vtkOpenGL.h"
36 #include "vtkgl.h" // vtkgl namespace
37 #include <vtkObjectFactory.h>
38
39 vtkStandardNewMacro(VTKViewer_Texture);
40
41
42 // ----------------------------------------------------------------------------
43 VTKViewer_Texture::VTKViewer_Texture()
44 {
45   myWidth = 0;
46   myHeight = 0;
47   myPosition = VTKViewer_Texture::Centered;
48 }
49
50 // ----------------------------------------------------------------------------
51 VTKViewer_Texture::~VTKViewer_Texture()
52 {
53 }
54
55 // ----------------------------------------------------------------------------
56 // Implement base class method.
57 void VTKViewer_Texture::Load(vtkRenderer *ren)
58 {
59   GLenum format = GL_LUMINANCE;
60   vtkImageData *input = this->GetInput();
61
62   this->Initialize(ren);
63
64   // Need to reload the texture.
65   // There used to be a check on the render window's mtime, but
66   // this is too broad of a check (e.g. it would cause all textures
67   // to load when only the desired update rate changed).
68   // If a better check is required, check something more specific,
69   // like the graphics context.
70   vtkOpenGLRenderWindow* renWin = 
71     static_cast<vtkOpenGLRenderWindow*>(ren->GetRenderWindow());
72
73   if(this->BlendingMode != VTK_TEXTURE_BLENDING_MODE_NONE
74      && vtkgl::ActiveTexture)
75     {
76     glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, vtkgl::COMBINE);
77
78     switch(this->BlendingMode)
79       {
80       case VTK_TEXTURE_BLENDING_MODE_REPLACE:
81         {
82         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_REPLACE);
83         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_REPLACE);
84         break;
85         }
86       case VTK_TEXTURE_BLENDING_MODE_MODULATE:
87         {
88         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_MODULATE);
89         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_MODULATE);
90         break;
91         }
92       case VTK_TEXTURE_BLENDING_MODE_ADD:
93         {
94         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_ADD);
95         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_ADD);
96         break;
97         }
98       case VTK_TEXTURE_BLENDING_MODE_ADD_SIGNED:
99         {
100         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, vtkgl::ADD_SIGNED);
101         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, vtkgl::ADD_SIGNED);
102         break;
103         }
104       case VTK_TEXTURE_BLENDING_MODE_INTERPOLATE:
105         {
106         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, vtkgl::INTERPOLATE);
107         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, vtkgl::INTERPOLATE);
108         break;
109         }
110       case VTK_TEXTURE_BLENDING_MODE_SUBTRACT:
111         {
112         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, vtkgl::SUBTRACT);
113         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, vtkgl::SUBTRACT);
114         break;
115         }
116       default:
117         {
118         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_ADD);
119         glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_ADD);
120         }
121       }
122     }
123
124   if (this->GetMTime() > this->LoadTime.GetMTime() ||
125       input->GetMTime() > this->LoadTime.GetMTime() ||
126       (this->GetLookupTable() && this->GetLookupTable()->GetMTime () >  
127        this->LoadTime.GetMTime()) || 
128        renWin != this->RenderWindow.GetPointer() ||
129        renWin->GetContextCreationTime() > this->LoadTime)
130     {
131     int bytesPerPixel;
132     int size[3];
133     vtkDataArray *scalars;
134     unsigned char *dataPtr;
135     unsigned char *resultData=NULL;
136     int xsize, ysize;
137     unsigned int xs,ys;
138     GLuint tempIndex=0;
139
140     // Get the scalars the user choose to color with.
141     scalars = this->GetInputArrayToProcess(0, input);
142
143     // make sure scalars are non null
144     if (!scalars) 
145       {
146       vtkErrorMacro(<< "No scalar values found for texture input!");
147       return;
148       }
149
150     // get some info
151     input->GetDimensions(size);
152
153     if (input->GetNumberOfCells() == scalars->GetNumberOfTuples())
154       {
155       // we are using cell scalars. Adjust image size for cells.
156       for (int kk=0; kk < 3; kk++)
157         {
158         if (size[kk]>1)
159           {
160           size[kk]--;
161           }
162         }
163       }
164
165     bytesPerPixel = scalars->GetNumberOfComponents();
166
167     // make sure using unsigned char data of color scalars type
168     if (this->MapColorScalarsThroughLookupTable ||
169        scalars->GetDataType() != VTK_UNSIGNED_CHAR )
170       {
171       dataPtr = this->MapScalarsToColors (scalars);
172       bytesPerPixel = 4;
173       }
174     else
175       {
176       dataPtr = static_cast<vtkUnsignedCharArray *>(scalars)->GetPointer(0);
177       }
178
179     // we only support 2d texture maps right now
180     // so one of the three sizes must be 1, but it 
181     // could be any of them, so lets find it
182     if (size[0] == 1)
183       {
184       xsize = size[1]; ysize = size[2];
185       }
186     else
187       {
188       xsize = size[0];
189       if (size[1] == 1)
190         {
191         ysize = size[2];
192         }
193       else
194         {
195         ysize = size[1];
196         if (size[2] != 1)
197           {
198           vtkErrorMacro(<< "3D texture maps currently are not supported!");
199           return;
200           }
201         }
202       }
203     
204     
205     if(!this->CheckedHardwareSupport)
206       {
207       vtkOpenGLExtensionManager *m=renWin->GetExtensionManager();
208       this->CheckedHardwareSupport=true;
209       this->SupportsNonPowerOfTwoTextures=
210         m->ExtensionSupported("GL_VERSION_2_0")
211         || m->ExtensionSupported("GL_ARB_texture_non_power_of_two");
212       this->SupportsPBO=vtkPixelBufferObject::IsSupported(renWin);
213       }
214     
215     // -- decide whether the texture needs to be resampled --
216     
217     GLint maxDimGL;
218     glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxDimGL);
219     // if larger than permitted by the graphics library then must resample
220     bool resampleNeeded=xsize > maxDimGL || ysize > maxDimGL;
221     if(resampleNeeded)
222       {
223       vtkDebugMacro( "Texture too big for gl, maximum is " << maxDimGL);
224       }
225     
226     if(!resampleNeeded && !this->SupportsNonPowerOfTwoTextures)
227       {
228       // xsize and ysize must be a power of 2 in OpenGL
229       xs = static_cast<unsigned int>(xsize);
230       ys = static_cast<unsigned int>(ysize);
231       while (!(xs & 0x01))
232         {
233         xs = xs >> 1;
234         }
235       while (!(ys & 0x01))
236         {
237         ys = ys >> 1;
238         }
239       // if not a power of two then resampling is required
240       resampleNeeded= (xs>1) || (ys>1);
241       }
242
243     if(resampleNeeded)
244       {
245       vtkDebugMacro(<< "Resampling texture to power of two for OpenGL");
246       resultData = this->ResampleToPowerOfTwo(xsize, ysize, dataPtr, 
247                                               bytesPerPixel);
248       }
249
250     if ( resultData == NULL )
251         {
252         resultData = dataPtr;
253         }
254
255     // free any old display lists (from the old context)
256     if (this->RenderWindow)
257       {
258       this->ReleaseGraphicsResources(this->RenderWindow);
259       }
260     
261      this->RenderWindow = ren->GetRenderWindow();
262      
263     // make the new context current before we mess with opengl
264     this->RenderWindow->MakeCurrent();
265  
266     // define a display list for this texture
267     // get a unique display list id
268
269 #ifdef GL_VERSION_1_1
270     glGenTextures(1, &tempIndex);
271     this->Index = static_cast<long>(tempIndex);
272     glBindTexture(GL_TEXTURE_2D, this->Index);
273 #else
274     this->Index = glGenLists(1);
275     glDeleteLists (static_cast<GLuint>(this->Index), static_cast<GLsizei>(0));
276     glNewList (static_cast<GLuint>(this->Index), GL_COMPILE);
277 #endif
278     //seg fault protection for those wackos that don't use an
279     //opengl render window
280     if(this->RenderWindow->IsA("vtkOpenGLRenderWindow"))
281       {
282       static_cast<vtkOpenGLRenderWindow *>(ren->GetRenderWindow())->
283         RegisterTextureResource( this->Index );
284       }
285
286     if (this->Interpolate)
287       {
288       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
289                        GL_LINEAR);
290       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
291                        GL_LINEAR );
292       }
293     else
294       {
295       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
296       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
297       }
298     if (this->Repeat)
299       {
300       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     GL_REPEAT );
301       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     GL_REPEAT );
302       }
303     else
304       {
305       vtkOpenGLExtensionManager* manager = renWin->GetExtensionManager();
306       if (this->EdgeClamp &&
307            (manager->ExtensionSupported("GL_VERSION_1_2") ||
308             manager->ExtensionSupported("GL_EXT_texture_edge_clamp")))
309         {
310         glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
311                          vtkgl::CLAMP_TO_EDGE );
312         glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
313                          vtkgl::CLAMP_TO_EDGE );
314         }
315       else
316         {
317         glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     GL_CLAMP );
318         glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     GL_CLAMP );
319         }
320       }
321     int internalFormat = bytesPerPixel;
322     switch (bytesPerPixel)
323       {
324       case 1: format = GL_LUMINANCE; break;
325       case 2: format = GL_LUMINANCE_ALPHA; break;
326       case 3: format = GL_RGB; break;
327       case 4: format = GL_RGBA; break;
328       }
329     // if we are using OpenGL 1.1, you can force 32 or16 bit textures
330 #ifdef GL_VERSION_1_1
331     if (this->Quality == VTK_TEXTURE_QUALITY_32BIT)
332       {
333       switch (bytesPerPixel)
334         {
335         case 1: internalFormat = GL_LUMINANCE8; break;
336         case 2: internalFormat = GL_LUMINANCE8_ALPHA8; break;
337         case 3: internalFormat = GL_RGB8; break;
338         case 4: internalFormat = GL_RGBA8; break;
339         }
340       }
341     else if (this->Quality == VTK_TEXTURE_QUALITY_16BIT)
342       {
343       switch (bytesPerPixel)
344         {
345         case 1: internalFormat = GL_LUMINANCE4; break;
346         case 2: internalFormat = GL_LUMINANCE4_ALPHA4; break;
347         case 3: internalFormat = GL_RGB4; break;
348         case 4: internalFormat = GL_RGBA4; break;
349         }
350       }
351 #endif
352     if(this->SupportsPBO)
353       {
354       if(this->PBO==0)
355         {
356         this->PBO=vtkPixelBufferObject::New();
357         this->PBO->SetContext(renWin);
358         }
359       unsigned int dims[2];
360       vtkIdType increments[2];
361       dims[0]=static_cast<unsigned int>(xsize);
362       dims[1]=static_cast<unsigned int>(ysize);
363       increments[0]=0;
364       increments[1]=0;
365       this->PBO->Upload2D(VTK_UNSIGNED_CHAR,resultData,dims,bytesPerPixel,
366         increments);
367       // non-blocking call
368       this->PBO->Bind(vtkPixelBufferObject::UNPACKED_BUFFER);
369       glTexImage2D( GL_TEXTURE_2D, 0 , internalFormat,
370                     xsize, ysize, 0, format, 
371                     GL_UNSIGNED_BYTE,0);
372       myWidth = xsize;
373       myHeight = ysize;
374       this->PBO->UnBind();
375       }
376     else
377       {
378       // blocking call
379       glTexImage2D( GL_TEXTURE_2D, 0 , internalFormat,
380                     xsize, ysize, 0, format, 
381                     GL_UNSIGNED_BYTE,
382                     static_cast<const GLvoid *>(resultData) );
383         myWidth = xsize;
384         myHeight = ysize;
385       }
386 #ifndef GL_VERSION_1_1
387     glEndList ();
388 #endif
389     // modify the load time to the current time
390     this->LoadTime.Modified();
391     
392     // free memory
393     if (resultData != dataPtr)
394       {
395       delete [] resultData;
396       }
397     }
398
399   // execute the display list that uses creates the texture
400 #ifdef GL_VERSION_1_1
401   glBindTexture(GL_TEXTURE_2D, this->Index);
402 #else
403   glCallList(this->Index);
404 #endif
405   
406   // don't accept fragments if they have zero opacity. this will stop the
407   // zbuffer from be blocked by totally transparent texture fragments.
408   glAlphaFunc (GL_GREATER, static_cast<GLclampf>(0));
409   glEnable (GL_ALPHA_TEST);
410
411   if (this->PremultipliedAlpha)
412     {
413     // save the blend function.
414     glPushAttrib(GL_COLOR_BUFFER_BIT);
415
416     // make the blend function correct for textures premultiplied by alpha.
417     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
418     }
419
420   // now bind it
421   glEnable(GL_TEXTURE_2D);
422
423   // clear any texture transform
424   glMatrixMode(GL_TEXTURE);
425   glLoadIdentity();
426
427   // build transformation 
428   if (this->Transform)
429     {
430     double *mat = this->Transform->GetMatrix()->Element[0];
431     double mat2[16];
432     mat2[0] = mat[0];
433     mat2[1] = mat[4];
434     mat2[2] = mat[8];
435     mat2[3] = mat[12];
436     mat2[4] = mat[1];
437     mat2[5] = mat[5];
438     mat2[6] = mat[9];
439     mat2[7] = mat[13];
440     mat2[8] = mat[2];
441     mat2[9] = mat[6];
442     mat2[10] = mat[10];
443     mat2[11] = mat[14];
444     mat2[12] = mat[3];
445     mat2[13] = mat[7];
446     mat2[14] = mat[11];
447     mat2[15] = mat[15];
448     
449     // insert texture transformation 
450     glMultMatrixd(mat2);
451     }
452   glMatrixMode(GL_MODELVIEW);
453   
454   GLint uUseTexture=-1;
455   GLint uTexture=-1;
456   
457   vtkOpenGLRenderer *oRenderer=static_cast<vtkOpenGLRenderer *>(ren);
458  
459 /*  if(oRenderer->GetDepthPeelingHigherLayer())
460     {
461     uUseTexture=oRenderer->GetUseTextureUniformVariable();
462     uTexture=oRenderer->GetTextureUniformVariable();
463     vtkgl::Uniform1i(uUseTexture,1);
464     vtkgl::Uniform1i(uTexture,0); // active texture 0
465     }
466     */
467 }
468
469 void VTKViewer_Texture::Initialize(vtkRenderer * vtkNotUsed(ren))
470 {
471 }
472
473 int VTKViewer_Texture::GetWidth() const
474 {
475   return myWidth;
476 }
477
478 int VTKViewer_Texture::GetHeight() const
479 {
480   return myHeight;
481 }
482
483 void VTKViewer_Texture::SetPosition(int pos)
484 {
485   myPosition = pos;
486 }
487
488 int VTKViewer_Texture::GetPosition() const
489 {
490   return myPosition;
491 }