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