1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 #include "VTKViewer_Texture.h"
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"
32 #include "vtkOpenGLExtensionManager.h"
33 #include "vtkgl.h" // vtkgl namespace
35 #include "vtkTextureObject.h"
36 #include "vtkOpenGLError.h"
38 #include "vtkOpenGLRenderWindow.h"
39 #include "vtkTransform.h"
40 #include "vtkPixelBufferObject.h"
41 #include "vtkOpenGL.h"
42 #include <vtkObjectFactory.h>
44 vtkStandardNewMacro(VTKViewer_Texture);
47 // ----------------------------------------------------------------------------
48 VTKViewer_Texture::VTKViewer_Texture()
52 myPosition = VTKViewer_Texture::Centered;
55 // ----------------------------------------------------------------------------
56 VTKViewer_Texture::~VTKViewer_Texture()
60 // ----------------------------------------------------------------------------
61 // Implement base class method.
62 void VTKViewer_Texture::Load(vtkRenderer *ren)
65 GLenum format = GL_LUMINANCE;
66 vtkImageData *input = this->GetInput();
68 this->Initialize(ren);
70 // Need to reload the texture.
71 // There used to be a check on the render window's mtime, but
72 // this is too broad of a check (e.g. it would cause all textures
73 // to load when only the desired update rate changed).
74 // If a better check is required, check something more specific,
75 // like the graphics context.
76 vtkOpenGLRenderWindow* renWin =
77 static_cast<vtkOpenGLRenderWindow*>(ren->GetRenderWindow());
79 if(this->BlendingMode != VTK_TEXTURE_BLENDING_MODE_NONE
80 && vtkgl::ActiveTexture)
82 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, vtkgl::COMBINE);
84 switch(this->BlendingMode)
86 case VTK_TEXTURE_BLENDING_MODE_REPLACE:
88 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_REPLACE);
89 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_REPLACE);
92 case VTK_TEXTURE_BLENDING_MODE_MODULATE:
94 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_MODULATE);
95 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_MODULATE);
98 case VTK_TEXTURE_BLENDING_MODE_ADD:
100 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_ADD);
101 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_ADD);
104 case VTK_TEXTURE_BLENDING_MODE_ADD_SIGNED:
106 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, vtkgl::ADD_SIGNED);
107 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, vtkgl::ADD_SIGNED);
110 case VTK_TEXTURE_BLENDING_MODE_INTERPOLATE:
112 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, vtkgl::INTERPOLATE);
113 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, vtkgl::INTERPOLATE);
116 case VTK_TEXTURE_BLENDING_MODE_SUBTRACT:
118 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, vtkgl::SUBTRACT);
119 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, vtkgl::SUBTRACT);
124 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_ADD);
125 glTexEnvf (GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_ADD);
130 if (this->GetMTime() > this->LoadTime.GetMTime() ||
131 input->GetMTime() > this->LoadTime.GetMTime() ||
132 (this->GetLookupTable() && this->GetLookupTable()->GetMTime () >
133 this->LoadTime.GetMTime()) ||
134 renWin != this->RenderWindow.GetPointer() ||
135 renWin->GetContextCreationTime() > this->LoadTime)
139 vtkDataArray *scalars;
140 unsigned char *dataPtr;
141 unsigned char *resultData=NULL;
146 // Get the scalars the user choose to color with.
147 scalars = this->GetInputArrayToProcess(0, input);
149 // make sure scalars are non null
152 vtkErrorMacro(<< "No scalar values found for texture input!");
157 input->GetDimensions(size);
159 if (input->GetNumberOfCells() == scalars->GetNumberOfTuples())
161 // we are using cell scalars. Adjust image size for cells.
162 for (int kk=0; kk < 3; kk++)
171 bytesPerPixel = scalars->GetNumberOfComponents();
173 // make sure using unsigned char data of color scalars type
174 if (this->MapColorScalarsThroughLookupTable ||
175 scalars->GetDataType() != VTK_UNSIGNED_CHAR )
177 dataPtr = this->MapScalarsToColors (scalars);
182 dataPtr = static_cast<vtkUnsignedCharArray *>(scalars)->GetPointer(0);
185 // we only support 2d texture maps right now
186 // so one of the three sizes must be 1, but it
187 // could be any of them, so lets find it
190 xsize = size[1]; ysize = size[2];
204 vtkErrorMacro(<< "3D texture maps currently are not supported!");
211 if(!this->CheckedHardwareSupport)
213 vtkOpenGLExtensionManager *m=renWin->GetExtensionManager();
214 this->CheckedHardwareSupport=true;
215 this->SupportsNonPowerOfTwoTextures=
216 m->ExtensionSupported("GL_VERSION_2_0")
217 || m->ExtensionSupported("GL_ARB_texture_non_power_of_two");
218 this->SupportsPBO=vtkPixelBufferObject::IsSupported(renWin);
221 // -- decide whether the texture needs to be resampled --
224 glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxDimGL);
225 // if larger than permitted by the graphics library then must resample
226 bool resampleNeeded=xsize > maxDimGL || ysize > maxDimGL;
229 vtkDebugMacro( "Texture too big for gl, maximum is " << maxDimGL);
232 if(!resampleNeeded && !this->SupportsNonPowerOfTwoTextures)
234 // xsize and ysize must be a power of 2 in OpenGL
235 xs = static_cast<unsigned int>(xsize);
236 ys = static_cast<unsigned int>(ysize);
245 // if not a power of two then resampling is required
246 resampleNeeded= (xs>1) || (ys>1);
251 vtkDebugMacro(<< "Resampling texture to power of two for OpenGL");
252 resultData = this->ResampleToPowerOfTwo(xsize, ysize, dataPtr,
256 if ( resultData == NULL )
258 resultData = dataPtr;
261 // free any old display lists (from the old context)
262 if (this->RenderWindow)
264 this->ReleaseGraphicsResources(this->RenderWindow);
267 this->RenderWindow = ren->GetRenderWindow();
269 // make the new context current before we mess with opengl
270 this->RenderWindow->MakeCurrent();
272 // define a display list for this texture
273 // get a unique display list id
275 #ifdef GL_VERSION_1_1
276 glGenTextures(1, &tempIndex);
277 this->Index = static_cast<long>(tempIndex);
278 glBindTexture(GL_TEXTURE_2D, this->Index);
280 this->Index = glGenLists(1);
281 glDeleteLists (static_cast<GLuint>(this->Index), static_cast<GLsizei>(0));
282 glNewList (static_cast<GLuint>(this->Index), GL_COMPILE);
284 //seg fault protection for those wackos that don't use an
285 //opengl render window
286 if(this->RenderWindow->IsA("vtkOpenGLRenderWindow"))
288 static_cast<vtkOpenGLRenderWindow *>(ren->GetRenderWindow())->
289 RegisterTextureResource( this->Index );
292 if (this->Interpolate)
294 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
296 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
301 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
302 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
306 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
307 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
311 vtkOpenGLExtensionManager* manager = renWin->GetExtensionManager();
312 if (this->EdgeClamp &&
313 (manager->ExtensionSupported("GL_VERSION_1_2") ||
314 manager->ExtensionSupported("GL_EXT_texture_edge_clamp")))
316 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
317 vtkgl::CLAMP_TO_EDGE );
318 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
319 vtkgl::CLAMP_TO_EDGE );
323 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
324 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
327 int internalFormat = bytesPerPixel;
328 switch (bytesPerPixel)
330 case 1: format = GL_LUMINANCE; break;
331 case 2: format = GL_LUMINANCE_ALPHA; break;
332 case 3: format = GL_RGB; break;
333 case 4: format = GL_RGBA; break;
335 // if we are using OpenGL 1.1, you can force 32 or16 bit textures
336 #ifdef GL_VERSION_1_1
337 if (this->Quality == VTK_TEXTURE_QUALITY_32BIT)
339 switch (bytesPerPixel)
341 case 1: internalFormat = GL_LUMINANCE8; break;
342 case 2: internalFormat = GL_LUMINANCE8_ALPHA8; break;
343 case 3: internalFormat = GL_RGB8; break;
344 case 4: internalFormat = GL_RGBA8; break;
347 else if (this->Quality == VTK_TEXTURE_QUALITY_16BIT)
349 switch (bytesPerPixel)
351 case 1: internalFormat = GL_LUMINANCE4; break;
352 case 2: internalFormat = GL_LUMINANCE4_ALPHA4; break;
353 case 3: internalFormat = GL_RGB4; break;
354 case 4: internalFormat = GL_RGBA4; break;
358 if(this->SupportsPBO)
362 this->PBO=vtkPixelBufferObject::New();
363 this->PBO->SetContext(renWin);
365 unsigned int dims[2];
366 vtkIdType increments[2];
367 dims[0]=static_cast<unsigned int>(xsize);
368 dims[1]=static_cast<unsigned int>(ysize);
371 this->PBO->Upload2D(VTK_UNSIGNED_CHAR,resultData,dims,bytesPerPixel,
374 this->PBO->Bind(vtkPixelBufferObject::UNPACKED_BUFFER);
375 glTexImage2D( GL_TEXTURE_2D, 0 , internalFormat,
376 xsize, ysize, 0, format,
385 glTexImage2D( GL_TEXTURE_2D, 0 , internalFormat,
386 xsize, ysize, 0, format,
388 static_cast<const GLvoid *>(resultData) );
392 #ifndef GL_VERSION_1_1
395 // modify the load time to the current time
396 this->LoadTime.Modified();
399 if (resultData != dataPtr)
401 delete [] resultData;
405 // execute the display list that uses creates the texture
406 #ifdef GL_VERSION_1_1
407 glBindTexture(GL_TEXTURE_2D, this->Index);
409 glCallList(this->Index);
412 // don't accept fragments if they have zero opacity. this will stop the
413 // zbuffer from be blocked by totally transparent texture fragments.
414 glAlphaFunc (GL_GREATER, static_cast<GLclampf>(0));
415 glEnable (GL_ALPHA_TEST);
417 if (this->PremultipliedAlpha)
419 // save the blend function.
420 glPushAttrib(GL_COLOR_BUFFER_BIT);
422 // make the blend function correct for textures premultiplied by alpha.
423 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
427 glEnable(GL_TEXTURE_2D);
429 // clear any texture transform
430 glMatrixMode(GL_TEXTURE);
433 // build transformation
436 double *mat = this->Transform->GetMatrix()->Element[0];
455 // insert texture transformation
458 glMatrixMode(GL_MODELVIEW);
460 GLint uUseTexture=-1;
463 vtkOpenGLRenderer *oRenderer=static_cast<vtkOpenGLRenderer *>(ren);
465 /* if(oRenderer->GetDepthPeelingHigherLayer())
467 uUseTexture=oRenderer->GetUseTextureUniformVariable();
468 uTexture=oRenderer->GetTextureUniformVariable();
469 vtkgl::Uniform1i(uUseTexture,1);
470 vtkgl::Uniform1i(uTexture,0); // active texture 0
474 if (!this->ExternalTextureObject)
476 vtkImageData *input = this->GetInput();
478 // Need to reload the texture.
479 // There used to be a check on the render window's mtime, but
480 // this is too broad of a check (e.g. it would cause all textures
481 // to load when only the desired update rate changed).
482 // If a better check is required, check something more specific,
483 // like the graphics context.
484 vtkOpenGLRenderWindow* renWin =
485 static_cast<vtkOpenGLRenderWindow*>(ren->GetRenderWindow());
487 // has something changed so that we need to rebuild the texture?
488 if (this->GetMTime() > this->LoadTime.GetMTime() ||
489 input->GetMTime() > this->LoadTime.GetMTime() ||
490 (this->GetLookupTable() && this->GetLookupTable()->GetMTime () >
491 this->LoadTime.GetMTime()) ||
492 renWin != this->RenderWindow.GetPointer() ||
493 renWin->GetContextCreationTime() > this->LoadTime)
496 unsigned char *dataPtr;
497 unsigned char *resultData = 0;
500 this->RenderWindow = renWin;
501 if (this->TextureObject == 0)
503 this->TextureObject = vtkTextureObject::New();
505 this->TextureObject->ResetFormatAndType();
506 this->TextureObject->SetContext(renWin);
508 // Get the scalars the user choose to color with.
509 vtkDataArray* scalars = this->GetInputArrayToProcess(0, input);
511 // make sure scalars are non null
514 vtkErrorMacro(<< "No scalar values found for texture input!");
519 input->GetDimensions(size);
521 if (input->GetNumberOfCells() == scalars->GetNumberOfTuples())
523 // we are using cell scalars. Adjust image size for cells.
524 for (int kk = 0; kk < 3; kk++)
533 int bytesPerPixel = scalars->GetNumberOfComponents();
535 // make sure using unsigned char data of color scalars type
536 if (this->IsDepthTexture != 1 &&
537 (this->MapColorScalarsThroughLookupTable ||
538 scalars->GetDataType() != VTK_UNSIGNED_CHAR ))
540 dataPtr = this->MapScalarsToColors (scalars);
545 dataPtr = static_cast<vtkUnsignedCharArray *>(scalars)->GetPointer(0);
548 // we only support 2d texture maps right now
549 // so one of the three sizes must be 1, but it
550 // could be any of them, so lets find it
553 xsize = size[1]; ysize = size[2];
567 vtkErrorMacro(<< "3D texture maps currently are not supported!");
573 // -- decide whether the texture needs to be resampled --
575 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxDimGL);
576 vtkOpenGLCheckErrorMacro("failed at glGetIntegerv");
577 // if larger than permitted by the graphics library then must resample
578 bool resampleNeeded = xsize > maxDimGL || ysize > maxDimGL;
581 vtkDebugMacro( "Texture too big for gl, maximum is " << maxDimGL);
586 vtkDebugMacro(<< "Resampling texture to power of two for OpenGL");
587 resultData = this->ResampleToPowerOfTwo(xsize, ysize, dataPtr,
593 resultData = dataPtr;
596 // create the texture
597 if (this->IsDepthTexture)
599 this->TextureObject->CreateDepthFromRaw(
600 xsize, ysize, vtkTextureObject::Float32, scalars->GetDataType(), resultData);
604 this->TextureObject->Create2DFromRaw(
605 xsize, ysize, bytesPerPixel, VTK_UNSIGNED_CHAR, resultData);
609 // activate a free texture unit for this texture
610 this->TextureObject->Activate();
613 if (this->Interpolate)
615 this->TextureObject->SetMinificationFilter(vtkTextureObject::Linear);
616 this->TextureObject->SetMagnificationFilter(vtkTextureObject::Linear);
620 this->TextureObject->SetMinificationFilter(vtkTextureObject::Nearest);
621 this->TextureObject->SetMagnificationFilter(vtkTextureObject::Nearest);
625 this->TextureObject->SetWrapS(vtkTextureObject::Repeat);
626 this->TextureObject->SetWrapT(vtkTextureObject::Repeat);
627 this->TextureObject->SetWrapR(vtkTextureObject::Repeat);
631 this->TextureObject->SetWrapS(vtkTextureObject::ClampToEdge);
632 this->TextureObject->SetWrapT(vtkTextureObject::ClampToEdge);
633 this->TextureObject->SetWrapR(vtkTextureObject::ClampToEdge);
636 // modify the load time to the current time
637 this->LoadTime.Modified();
640 if (resultData != dataPtr)
642 delete [] resultData;
649 vtkOpenGLRenderWindow* renWin =
650 static_cast<vtkOpenGLRenderWindow*>(ren->GetRenderWindow());
652 // has something changed so that we need to rebuild the texture?
653 if (this->GetMTime() > this->LoadTime.GetMTime() ||
654 renWin != this->RenderWindow.GetPointer() ||
655 renWin->GetContextCreationTime() > this->LoadTime)
657 this->RenderWindow = renWin;
658 this->TextureObject->SetContext(renWin);
661 // activate a free texture unit for this texture
662 this->TextureObject->Activate();
664 if (this->PremultipliedAlpha)
666 // make the blend function correct for textures premultiplied by alpha.
667 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
669 vtkOpenGLCheckErrorMacro("failed after Load");
673 void VTKViewer_Texture::Initialize(vtkRenderer * vtkNotUsed(ren))
677 int VTKViewer_Texture::GetWidth() const
682 int VTKViewer_Texture::GetHeight() const
687 void VTKViewer_Texture::SetPosition(int pos)
692 int VTKViewer_Texture::GetPosition() const