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