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