VTK
|
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