VTK
dox/Charts/vtkOpenGLContextDevice2DPrivate.h
Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Program:   Visualization Toolkit
00004   Module:    vtkOpenGLContextDevice2DPrivate.h
00005 
00006   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
00007   All rights reserved.
00008   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
00009 
00010      This software is distributed WITHOUT ANY WARRANTY; without even
00011      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00012      PURPOSE.  See the above copyright notice for more information.
00013 
00014 =========================================================================*/
00015 
00032 #ifndef __vtkOpenGLContextDevice2DPrivate_h
00033 #define __vtkOpenGLContextDevice2DPrivate_h
00034 
00035 #include "vtkOpenGLContextDevice2D.h"
00036 
00037 #include "vtkFreeTypeTools.h"
00038 #include <algorithm>
00039 #include <list>
00040 #include <utility>
00041 
00042 // .NAME vtkTextureImageCache - store vtkTexture and vtkImageData identified by
00043 // a unique key.
00044 // .SECTION Description
00045 // Creating and initializing a texture can be time consuming,
00046 // vtkTextureImageCache offers the ability to reuse them as much as possible.
00047 template <class Key>
00048 class vtkTextureImageCache
00049 {
00050 public:
00051   struct CacheData
00052   {
00053     vtkSmartPointer<vtkImageData> ImageData;
00054     vtkSmartPointer<vtkTexture>   Texture;
00055   };
00056 
00058 
00059   struct CacheElement: public std::pair<Key, CacheData>
00060   {
00061     // Default constructor
00062     CacheElement()
00063       : std::pair<Key, CacheData>(Key(), CacheData()){}
00064     // Construct a partial CacheElement with no CacheData
00065     // This can be used for temporary CacheElement used to search a given
00066     // key into the cache list.
00067     CacheElement(const Key& key)
00068       : std::pair<Key, CacheData>(key, CacheData()){}
00069     // Standard constructor of CacheElement
00070     CacheElement(const Key& key, const CacheData& cacheData)
00071       : std::pair<Key, CacheData>(key, cacheData){}
00072     // Operator tuned to be used when searching into the cache list using
00073     // std::find()
00074     bool operator==(const CacheElement& other)const
00075     {
00076       // Here we cheat and make the comparison only on the key, this allows
00077       // us to use std::find() to search for a given key.
00078       return this->first == other.first;
00079     }
00080   };
00082 
00084 
00086   vtkTextureImageCache()
00087   {
00088     this->MaxSize = 50;
00089   }
00091 
00093 
00095   bool IsKeyInCache(const Key& key)const
00096   {
00097     return std::find(this->Cache.begin(), this->Cache.end(), key) != this->Cache.end();
00098   }
00100 
00105   CacheData& GetCacheData(const Key& key);
00106 
00108 
00110   void ReleaseGraphicsResources(vtkWindow* window)
00111   {
00112     typename std::list<CacheElement >::iterator it;
00113     for (it = this->Cache.begin(); it != this->Cache.end(); ++it)
00114       {
00115       it->second.Texture->ReleaseGraphicsResources(window);
00116       }
00117   }
00119 
00120 protected:
00122 
00124   CacheData& AddCacheData(const Key& key, const CacheData& cacheData)
00125   {
00126     assert(!this->IsKeyInCache(key));
00127     if (this->Cache.size() >= this->MaxSize)
00128       {
00129       this->Cache.pop_back();
00130       }
00131     this->Cache.push_front(CacheElement(key, cacheData));
00132     return this->Cache.begin()->second;
00133   }
00135 
00137 
00138   std::list<CacheElement > Cache;
00139   // Description:
00140   // Maximum size the cache list can be.
00141   size_t MaxSize;
00142 };
00144 
00145 template<class Key>
00146 typename vtkTextureImageCache<Key>::CacheData& vtkTextureImageCache<Key>
00147 ::GetCacheData(const Key& key)
00148 {
00149   typename std::list<CacheElement>::iterator it =
00150     std::find(this->Cache.begin(), this->Cache.end(), CacheElement(key));
00151   if (it != this->Cache.end())
00152     {
00153     return it->second;
00154     }
00155   CacheData cacheData;
00156   cacheData.ImageData = vtkSmartPointer<vtkImageData>::New();
00157   cacheData.Texture = vtkSmartPointer<vtkTexture>::New();
00158   cacheData.Texture->SetInput(cacheData.ImageData);
00159   return this->AddCacheData(key, cacheData);
00160 }
00161 
00162 // .NAME TextPropertyKey - unique key for a vtkTextProperty and text
00163 // .SECTION Description
00164 // Uniquely describe a pair of vtkTextProperty and text.
00165 struct TextPropertyKey
00166 {
00168 
00169   static unsigned long GetIdFromTextProperty(vtkTextProperty* textProperty)
00170   {
00171     unsigned long id;
00172     vtkFreeTypeTools::GetInstance()->MapTextPropertyToId(textProperty, &id);
00173     return id;
00174   }
00176 
00178 
00179   TextPropertyKey(vtkTextProperty* textProperty, const vtkStdString& text)
00180   {
00181     this->TextPropertyId = GetIdFromTextProperty(textProperty);
00182     this->Text = text;
00183   }
00185 
00187 
00189   bool operator==(const TextPropertyKey& other)const
00190   {
00191     return this->TextPropertyId == other.TextPropertyId &&
00192       this->Text == other.Text;
00193   }
00194   unsigned long TextPropertyId;
00195   vtkStdString Text;
00196 };
00198 
00199 class vtkOpenGLContextDevice2D::Private
00200 {
00201 public:
00202   Private()
00203   {
00204     this->Texture = NULL;
00205     this->TextureProperties = vtkContextDevice2D::Linear |
00206         vtkContextDevice2D::Stretch;
00207     this->SpriteTexture = NULL;
00208     this->SavedLighting = GL_TRUE;
00209     this->SavedDepthTest = GL_TRUE;
00210     this->SavedAlphaTest = GL_TRUE;
00211     this->SavedStencilTest = GL_TRUE;
00212     this->SavedBlend = GL_TRUE;
00213     this->SavedDrawBuffer = 0;
00214     this->SavedClearColor[0] = this->SavedClearColor[1] =
00215                                this->SavedClearColor[2] =
00216                                this->SavedClearColor[3] = 0.0f;
00217     this->TextCounter = 0;
00218     this->GLExtensionsLoaded = false;
00219     this->OpenGL15 = false;
00220     this->OpenGL20 = false;
00221     this->GLSL = false;
00222     this->PowerOfTwoTextures = true;
00223   }
00224 
00225   ~Private()
00226   {
00227     if (this->Texture)
00228       {
00229       this->Texture->Delete();
00230       this->Texture = NULL;
00231       }
00232     if (this->SpriteTexture)
00233       {
00234       this->SpriteTexture->Delete();
00235       this->SpriteTexture = NULL;
00236       }
00237   }
00238 
00239   void SaveGLState(bool colorBuffer = false)
00240   {
00241     this->SavedLighting = glIsEnabled(GL_LIGHTING);
00242     this->SavedDepthTest = glIsEnabled(GL_DEPTH_TEST);
00243 
00244     if (colorBuffer)
00245       {
00246       this->SavedAlphaTest = glIsEnabled(GL_ALPHA_TEST);
00247       this->SavedStencilTest = glIsEnabled(GL_STENCIL_TEST);
00248       this->SavedBlend = glIsEnabled(GL_BLEND);
00249       glGetFloatv(GL_COLOR_CLEAR_VALUE, this->SavedClearColor);
00250       glGetIntegerv(GL_DRAW_BUFFER, &this->SavedDrawBuffer);
00251       }
00252   }
00253 
00254   void RestoreGLState(bool colorBuffer = false)
00255   {
00256     this->SetGLCapability(GL_LIGHTING, this->SavedLighting);
00257     this->SetGLCapability(GL_DEPTH_TEST, this->SavedDepthTest);
00258 
00259     if (colorBuffer)
00260       {
00261       this->SetGLCapability(GL_ALPHA_TEST, this->SavedAlphaTest);
00262       this->SetGLCapability(GL_STENCIL_TEST, this->SavedStencilTest);
00263       this->SetGLCapability(GL_BLEND, this->SavedBlend);
00264 
00265       if(this->SavedDrawBuffer != GL_BACK_LEFT)
00266         {
00267         glDrawBuffer(this->SavedDrawBuffer);
00268         }
00269 
00270       int i = 0;
00271       bool colorDiffer = false;
00272       while(!colorDiffer && i < 4)
00273         {
00274         colorDiffer=this->SavedClearColor[i++] != 0.0;
00275         }
00276       if(colorDiffer)
00277         {
00278         glClearColor(this->SavedClearColor[0],
00279                      this->SavedClearColor[1],
00280                      this->SavedClearColor[2],
00281                      this->SavedClearColor[3]);
00282         }
00283       }
00284   }
00285 
00286   void SetGLCapability(GLenum capability, GLboolean state)
00287   {
00288     if (state)
00289       {
00290       glEnable(capability);
00291       }
00292     else
00293       {
00294       glDisable(capability);
00295       }
00296   }
00297 
00298   float* TexCoords(float* f, int n)
00299   {
00300     float* texCoord = new float[2*n];
00301     float minX = f[0]; float minY = f[1];
00302     float maxX = f[0]; float maxY = f[1];
00303     float* fptr = f;
00304     for(int i = 0; i < n; ++i)
00305       {
00306       minX = fptr[0] < minX ? fptr[0] : minX;
00307       maxX = fptr[0] > maxX ? fptr[0] : maxX;
00308       minY = fptr[1] < minY ? fptr[1] : minY;
00309       maxY = fptr[1] > maxY ? fptr[1] : maxY;
00310       fptr+=2;
00311       }
00312     fptr = f;
00313     if (this->TextureProperties & vtkContextDevice2D::Repeat)
00314       {
00315       double* textureBounds = this->Texture->GetInput()->GetBounds();
00316       float rangeX = (textureBounds[1] - textureBounds[0]) ?
00317         textureBounds[1] - textureBounds[0] : 1.;
00318       float rangeY = (textureBounds[3] - textureBounds[2]) ?
00319         textureBounds[3] - textureBounds[2] : 1.;
00320       for (int i = 0; i < n; ++i)
00321         {
00322         texCoord[i*2] = (fptr[0]-minX) / rangeX;
00323         texCoord[i*2+1] = (fptr[1]-minY) / rangeY;
00324         fptr+=2;
00325         }
00326       }
00327     else // this->TextureProperties & vtkContextDevice2D::Stretch
00328       {
00329       float rangeX = (maxX - minX)? maxX - minX : 1.f;
00330       float rangeY = (maxY - minY)? maxY - minY : 1.f;
00331       for (int i = 0; i < n; ++i)
00332         {
00333         texCoord[i*2] = (fptr[0]-minX)/rangeX;
00334         texCoord[i*2+1] = (fptr[1]-minY)/rangeY;
00335         fptr+=2;
00336         }
00337       }
00338     return texCoord;
00339   }
00340 
00341   vtkVector2i FindPowerOfTwo(const vtkVector2i& size)
00342     {
00343     vtkVector2i pow2(1, 1);
00344     for (int i = 0; i < 2; ++i)
00345       {
00346       while (pow2[i] < size[i])
00347         {
00348         pow2[i] *= 2;
00349         }
00350       }
00351     return pow2;
00352     }
00353 
00354   GLuint TextureFromImage(vtkImageData *image, vtkVector2f& texCoords)
00355     {
00356     if (image->GetScalarType() != VTK_UNSIGNED_CHAR)
00357       {
00358       cout << "Error = not an unsigned char..." << endl;
00359       return 0;
00360       }
00361     int bytesPerPixel = image->GetNumberOfScalarComponents();
00362     int size[3];
00363     image->GetDimensions(size);
00364     vtkVector2i newImg = this->FindPowerOfTwo(vtkVector2i(size[0], size[1]));
00365 
00366     for (int i = 0; i < 2; ++i)
00367       {
00368       texCoords[i] = size[i] / float(newImg[i]);
00369       }
00370 
00371     unsigned char *dataPtr =
00372         new unsigned char[newImg[0] * newImg[1] * bytesPerPixel];
00373     unsigned char *origPtr =
00374         static_cast<unsigned char*>(image->GetScalarPointer());
00375 
00376     for (int i = 0; i < newImg[0]; ++i)
00377       {
00378       for (int j = 0; j < newImg[1]; ++j)
00379         {
00380         for (int k = 0; k < bytesPerPixel; ++k)
00381           {
00382           if (i < size[0] && j < size[1])
00383             {
00384             dataPtr[i * newImg[0] * bytesPerPixel + j * bytesPerPixel + k] =
00385                 origPtr[i * size[0] * bytesPerPixel + j * bytesPerPixel + k];
00386             }
00387           else
00388             {
00389             dataPtr[i * newImg[0] * bytesPerPixel + j * bytesPerPixel + k] =
00390                 k == 3 ? 0 : 255;
00391             }
00392           }
00393         }
00394       }
00395 
00396     GLuint tmpIndex(0);
00397     GLint glFormat = bytesPerPixel == 3 ? GL_RGB : GL_RGBA;
00398     GLint glInternalFormat = bytesPerPixel == 3 ? GL_RGB8 : GL_RGBA8;
00399 
00400     glGenTextures(1, &tmpIndex);
00401     glBindTexture(GL_TEXTURE_2D, tmpIndex);
00402 
00403     glTexEnvf(GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_REPLACE);
00404     glTexEnvf(GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_REPLACE);
00405 
00406     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00407     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00408     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
00409                      vtkgl::CLAMP_TO_EDGE );
00410     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
00411                      vtkgl::CLAMP_TO_EDGE );
00412 
00413     glTexImage2D(GL_TEXTURE_2D, 0 , glInternalFormat,
00414                  newImg[0], newImg[1], 0, glFormat,
00415                  GL_UNSIGNED_BYTE, static_cast<const GLvoid *>(dataPtr));
00416     glAlphaFunc(GL_GREATER, static_cast<GLclampf>(0));
00417     glEnable(GL_ALPHA_TEST);
00418     glMatrixMode(GL_TEXTURE);
00419     glLoadIdentity();
00420     glMatrixMode(GL_MODELVIEW);
00421     glEnable(GL_TEXTURE_2D);
00422     delete [] dataPtr;
00423     return tmpIndex;
00424     }
00425 
00426   GLuint TextureFromImage(vtkImageData *image)
00427   {
00428     if (image->GetScalarType() != VTK_UNSIGNED_CHAR)
00429       {
00430       cout << "Error = not an unsigned char..." << endl;
00431       return 0;
00432       }
00433     int bytesPerPixel = image->GetNumberOfScalarComponents();
00434     int size[3];
00435     image->GetDimensions(size);
00436 
00437     unsigned char *dataPtr =
00438         static_cast<unsigned char*>(image->GetScalarPointer());
00439     GLuint tmpIndex(0);
00440     GLint glFormat = bytesPerPixel == 3 ? GL_RGB : GL_RGBA;
00441     GLint glInternalFormat = bytesPerPixel == 3 ? GL_RGB8 : GL_RGBA8;
00442 
00443     glGenTextures(1, &tmpIndex);
00444     glBindTexture(GL_TEXTURE_2D, tmpIndex);
00445 
00446     glTexEnvf(GL_TEXTURE_ENV, vtkgl::COMBINE_RGB, GL_REPLACE);
00447     glTexEnvf(GL_TEXTURE_ENV, vtkgl::COMBINE_ALPHA, GL_REPLACE);
00448 
00449     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00450     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00451     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
00452                      vtkgl::CLAMP_TO_EDGE );
00453     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
00454                      vtkgl::CLAMP_TO_EDGE );
00455 
00456     glTexImage2D(GL_TEXTURE_2D, 0 , glInternalFormat,
00457                  size[0], size[1], 0, glFormat,
00458                  GL_UNSIGNED_BYTE, static_cast<const GLvoid *>(dataPtr));
00459     glAlphaFunc(GL_GREATER, static_cast<GLclampf>(0));
00460     glEnable(GL_ALPHA_TEST);
00461     glMatrixMode(GL_TEXTURE);
00462     glLoadIdentity();
00463     glMatrixMode(GL_MODELVIEW);
00464     glEnable(GL_TEXTURE_2D);
00465     return tmpIndex;
00466   }
00467 
00468   vtkTexture *Texture;
00469   unsigned int TextureProperties;
00470   vtkTexture *SpriteTexture;
00471   // Store the previous GL state so that we can restore it when complete
00472   GLboolean SavedLighting;
00473   GLboolean SavedDepthTest;
00474   GLboolean SavedAlphaTest;
00475   GLboolean SavedStencilTest;
00476   GLboolean SavedBlend;
00477   GLint SavedDrawBuffer;
00478   GLfloat SavedClearColor[4];
00479 
00480   int TextCounter;
00481   vtkVector2i Dim;
00482   vtkVector2i Offset;
00483   bool GLExtensionsLoaded;
00484   bool OpenGL15;
00485   bool OpenGL20;
00486   bool GLSL;
00487   bool PowerOfTwoTextures;
00488 
00490 
00492   mutable vtkTextureImageCache<TextPropertyKey> TextTextureCache;
00493 };
00495 
00496 #endif // VTKOPENGLCONTEXTDEVICE2DPRIVATE_H