root/OpenSceneGraph/trunk/src/osg/Texture.cpp @ 10409

Revision 10409, 65.4 kB (checked in by robert, 5 years ago)

From Mathias Froehlich, "put texturemanager into osg namespace."

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13#include <osg/GLExtensions>
14#include <osg/Image>
15#include <osg/Texture>
16#include <osg/State>
17#include <osg/Notify>
18#include <osg/GLU>
19#include <osg/Timer>
20#include <osg/ApplicationUsage>
21#include <osg/FrameBufferObject>
22#include <osg/TextureRectangle>
23
24#include <OpenThreads/ScopedLock>
25#include <OpenThreads/Mutex>
26
27using namespace osg;
28
29#ifndef GL_TEXTURE_WRAP_R
30#define GL_TEXTURE_WRAP_R                 0x8072
31#endif
32
33#ifndef GL_TEXTURE_MAX_LEVEL
34#define GL_TEXTURE_MAX_LEVEL              0x813D
35#endif
36
37
38#ifndef GL_UNPACK_CLIENT_STORAGE_APPLE
39#define GL_UNPACK_CLIENT_STORAGE_APPLE    0x85B2
40#endif
41
42#ifndef GL_APPLE_vertex_array_range
43#define GL_VERTEX_ARRAY_RANGE_APPLE       0x851D
44#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
45#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
46#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
47#define GL_STORAGE_CACHED_APPLE           0x85BE
48#define GL_STORAGE_SHARED_APPLE           0x85BF
49#endif
50
51//#define DO_TIMING
52
53namespace osg {
54
55ApplicationUsageProxy Texture_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAX_TEXTURE_SIZE","Set the maximum size of textures.");
56
57class TextureObjectManager : public osg::Referenced
58{
59public:
60
61    TextureObjectManager():
62        _expiryDelay(0.0)
63    {
64        // printf("Constructing TextureObjectManager\n");
65    }
66
67    ~TextureObjectManager()
68    {
69        // printf("Destructing TextureObjectManager\n");
70    }
71
72    virtual Texture::TextureObject* generateTextureObject(unsigned int contextID,GLenum target);
73
74    virtual Texture::TextureObject* generateTextureObject(unsigned int contextID,
75                                                 GLenum    target,
76                                                 GLint     numMipmapLevels,
77                                                 GLenum    internalFormat,
78                                                 GLsizei   width,
79                                                 GLsizei   height,
80                                                 GLsizei   depth,
81                                                 GLint     border);
82
83    virtual Texture::TextureObject* reuseTextureObject(unsigned int contextID,
84                                              GLenum    target,
85                                              GLint     numMipmapLevels,
86                                              GLenum    internalFormat,
87                                              GLsizei   width,
88                                              GLsizei   height,
89                                              GLsizei   depth,
90                                              GLint     border);
91
92    inline Texture::TextureObject* reuseOrGenerateTextureObject(unsigned int contextID,
93                                              GLenum    target,
94                                              GLint     numMipmapLevels,
95                                              GLenum    internalFormat,
96                                              GLsizei   width,
97                                              GLsizei   height,
98                                              GLsizei   depth,
99                                              GLint     border)
100    {
101        Texture::TextureObject* to = reuseTextureObject(contextID,target,numMipmapLevels,internalFormat,width,height,depth,border);
102        if (to) return to;
103        else return generateTextureObject(contextID,target,numMipmapLevels,internalFormat,width,height,depth,border);
104    }                                                     
105
106    void addTextureObjects(Texture::TextureObjectListMap& toblm);
107
108    void addTextureObjectsFrom(Texture& texture);
109
110    void flushAllTextureObjects(unsigned int contextID);
111
112    void discardAllTextureObjects(unsigned int contextID);
113
114    void flushTextureObjects(unsigned int contextID,double currentTime, double& availableTime);
115
116    void setExpiryDelay(double expiryDelay) { _expiryDelay = expiryDelay; }
117
118    double getExpiryDelay() const { return _expiryDelay; }
119
120    /** How long to keep unused texture objects before deletion. */
121    double                  _expiryDelay;
122
123    Texture::TextureObjectListMap    _textureObjectListMap;
124
125    // mutex to keep access serialized.
126    OpenThreads::Mutex      _mutex;
127};
128
129}
130
131unsigned int Texture::s_numberTextureReusedLastInLastFrame = 0;
132unsigned int Texture::s_numberNewTextureInLastFrame = 0;
133unsigned int Texture::s_numberDeletedTextureInLastFrame = 0;
134
135unsigned int s_minimumNumberOfTextureObjectsToRetainInCache = 0;
136
137typedef buffered_value< ref_ptr<Texture::Extensions> > BufferedExtensions;
138static BufferedExtensions s_extensions;
139
140static ref_ptr<TextureObjectManager> s_textureObjectManager = new TextureObjectManager;
141
142void Texture::setMinimumNumberOfTextureObjectsToRetainInCache(unsigned int minimum)
143{
144    s_minimumNumberOfTextureObjectsToRetainInCache = minimum;
145}
146
147unsigned int Texture::getMinimumNumberOfTextureObjectsToRetainInCache()
148{
149    return s_minimumNumberOfTextureObjectsToRetainInCache;
150}
151
152Texture::TextureObject* TextureObjectManager::generateTextureObject(unsigned int /*contextID*/,GLenum target)
153{
154    GLuint id;
155    glGenTextures( 1L, &id );
156
157    return new Texture::TextureObject(id,target);
158}
159
160static int s_number = 0;
161
162Texture::TextureObject* TextureObjectManager::generateTextureObject(unsigned int /*contextID*/,
163                                                                             GLenum    target,
164                                                                             GLint     numMipmapLevels,
165                                                                             GLenum    internalFormat,
166                                                                             GLsizei   width,
167                                                                             GLsizei   height,
168                                                                             GLsizei   depth,
169                                                                             GLint     border)
170{
171    ++s_number;
172    ++Texture::s_numberNewTextureInLastFrame;
173    // notify(NOTICE)<<"creating new texture object "<<s_number<<std::endl;
174
175    // no useable texture object found so return 0
176    GLuint id;
177    glGenTextures( 1L, &id );
178
179    return new Texture::TextureObject(id,target,numMipmapLevels,internalFormat,width,height,depth,border);
180}
181
182Texture::TextureObject* TextureObjectManager::reuseTextureObject(unsigned int contextID,
183                                                                             GLenum    target,
184                                                                             GLint     numMipmapLevels,
185                                                                             GLenum    internalFormat,
186                                                                             GLsizei   width,
187                                                                             GLsizei   height,
188                                                                             GLsizei   depth,
189                                                                             GLint     border)
190{
191    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
192
193    Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
194    for(Texture::TextureObjectList::iterator itr = tol.begin();
195        itr != tol.end();
196        ++itr)
197    {
198        if ((*itr)->match(target,numMipmapLevels,internalFormat,width,height,depth,border))
199        {
200            // found usable texture object.
201            Texture::TextureObject* textureObject = (*itr).release();
202            tol.erase(itr);
203           
204            // notify(NOTICE)<<"reusing texture object "<<std::endl;
205           
206            ++Texture::s_numberTextureReusedLastInLastFrame;
207
208            return textureObject;
209        }
210    }
211   
212    return 0;
213}
214
215   
216
217void TextureObjectManager::addTextureObjects(Texture::TextureObjectListMap& toblm)
218{
219    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
220
221    for(unsigned int i=0; i< toblm.size(); ++i)
222    {
223        Texture::TextureObjectList& tol = _textureObjectListMap[i];
224        tol.insert(tol.end(),toblm[i].begin(),toblm[i].end());
225    }
226}
227
228void TextureObjectManager::addTextureObjectsFrom(Texture& texture)
229{
230    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
231
232    texture.takeTextureObjects(_textureObjectListMap);
233}
234
235void TextureObjectManager::flushAllTextureObjects(unsigned int contextID)
236{
237    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
238
239    Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
240
241    // osg::notify(osg::INFO)<<"Flushing texture objects num="<<tol.size()<<" contextID="<<contextID<<std::endl;
242
243    for(Texture::TextureObjectList::iterator itr=tol.begin();
244        itr!=tol.end();
245        ++itr)
246    {
247        // osg::notify(osg::NOTICE)<<"  deleting texture object "<<(*itr)->_id<<std::endl;
248        glDeleteTextures( 1L, &((*itr)->_id));
249    }
250    tol.clear();
251}
252
253void TextureObjectManager::discardAllTextureObjects(unsigned int contextID)
254{
255    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
256
257    Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
258    tol.clear();
259}
260
261void TextureObjectManager::flushTextureObjects(unsigned int contextID,double currentTime, double& availableTime)
262{
263    // if no time available don't try to flush objects.
264    if (availableTime<=0.0) return;
265
266    unsigned int numObjectsDeleted = 0;
267    unsigned int maxNumObjectsToDelete = 4;
268
269    const osg::Timer& timer = *osg::Timer::instance();
270    osg::Timer_t start_tick = timer.tick();
271    double elapsedTime = 0.0;
272
273    unsigned int numTexturesDeleted = 0;
274    {   
275        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
276
277        Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
278
279        // reset the time of any uninitialized objects.
280        Texture::TextureObjectList::iterator itr;
281        for(itr=tol.begin();
282            itr!=tol.end();
283            ++itr)
284        {
285            if ((*itr)->_timeStamp==0.0) (*itr)->_timeStamp=currentTime;
286        }
287
288        double expiryTime = currentTime-_expiryDelay;
289
290        for(itr=tol.begin();
291            itr!=tol.end() && elapsedTime<availableTime && tol.size()>s_minimumNumberOfTextureObjectsToRetainInCache && numObjectsDeleted<maxNumObjectsToDelete;
292            )
293        {
294            if ((*itr)->_timeStamp<=expiryTime)
295            {
296                --s_number;
297                ++Texture::s_numberDeletedTextureInLastFrame;
298
299                glDeleteTextures( 1L, &((*itr)->_id));
300                itr = tol.erase(itr);
301                ++numTexturesDeleted;
302                ++numObjectsDeleted;
303            }
304            else
305            {
306                ++itr;
307            }
308            elapsedTime = timer.delta_s(start_tick,timer.tick());
309        }
310    }
311    elapsedTime = timer.delta_s(start_tick,timer.tick());
312    // if (numTexturesDeleted) notify(osg::NOTICE)<<"Number of Texture's deleted = "<<numTexturesDeleted<<" new total "<<s_number<<" elapsed time"<<elapsedTime<<std::endl;
313       
314    availableTime -= elapsedTime;
315}
316
317
318static TextureObjectManager* getTextureObjectManager()
319{
320    return s_textureObjectManager.get();
321}
322
323
324Texture::TextureObject* Texture::generateTextureObject(unsigned int contextID,GLenum target)
325{
326    if (getTextureObjectManager()) return getTextureObjectManager()->generateTextureObject(contextID,target);
327    else return 0;
328}
329
330Texture::TextureObject* Texture::generateTextureObject(unsigned int contextID,
331                                             GLenum    target,
332                                             GLint     numMipmapLevels,
333                                             GLenum    internalFormat,
334                                             GLsizei   width,
335                                             GLsizei   height,
336                                             GLsizei   depth,
337                                             GLint     border)
338{
339    if (getTextureObjectManager())   
340        return getTextureObjectManager()->reuseOrGenerateTextureObject(contextID,
341                                             target,
342                                             numMipmapLevels,
343                                             internalFormat,
344                                             width,
345                                             height,
346                                             depth,
347                                             border);
348    else
349        return 0;
350}                                             
351
352void Texture::flushAllDeletedTextureObjects(unsigned int contextID)
353{
354    if (getTextureObjectManager()) getTextureObjectManager()->flushAllTextureObjects(contextID);
355}
356
357void Texture::discardAllDeletedTextureObjects(unsigned int contextID)
358{
359    if (getTextureObjectManager()) getTextureObjectManager()->discardAllTextureObjects(contextID);
360}
361
362void Texture::flushDeletedTextureObjects(unsigned int contextID,double currentTime, double& availbleTime)
363{
364    if (getTextureObjectManager()) getTextureObjectManager()->flushTextureObjects(contextID, currentTime, availbleTime);
365}
366
367Texture::Texture():
368            _wrap_s(CLAMP),
369            _wrap_t(CLAMP),
370            _wrap_r(CLAMP),
371            _min_filter(LINEAR_MIPMAP_LINEAR), // trilinear
372            _mag_filter(LINEAR),
373            _maxAnisotropy(1.0f),
374            _useHardwareMipMapGeneration(true),
375            _unrefImageDataAfterApply(false),
376            _clientStorageHint(false),
377            _resizeNonPowerOfTwoHint(true),
378            _borderColor(0.0, 0.0, 0.0, 0.0),
379            _borderWidth(0),
380            _internalFormatMode(USE_IMAGE_DATA_FORMAT),
381            _internalFormatType(NORMALIZED),
382            _internalFormat(0),
383            _sourceFormat(0),
384            _sourceType(0),
385            _use_shadow_comparison(false),
386            _shadow_compare_func(LEQUAL),
387            _shadow_texture_mode(LUMINANCE),
388            _shadow_ambient(0)
389{
390}
391
392Texture::Texture(const Texture& text,const CopyOp& copyop):
393            StateAttribute(text,copyop),
394            _wrap_s(text._wrap_s),
395            _wrap_t(text._wrap_t),
396            _wrap_r(text._wrap_r),
397            _min_filter(text._min_filter),
398            _mag_filter(text._mag_filter),
399            _maxAnisotropy(text._maxAnisotropy),
400            _useHardwareMipMapGeneration(text._useHardwareMipMapGeneration),
401            _unrefImageDataAfterApply(text._unrefImageDataAfterApply),
402            _clientStorageHint(text._clientStorageHint),
403            _resizeNonPowerOfTwoHint(text._resizeNonPowerOfTwoHint),
404            _borderColor(text._borderColor),
405            _borderWidth(text._borderWidth),
406            _internalFormatMode(text._internalFormatMode),
407            _internalFormatType(text._internalFormatType),
408            _internalFormat(text._internalFormat),
409            _sourceFormat(text._sourceFormat),
410            _sourceType(text._sourceType),
411            _use_shadow_comparison(text._use_shadow_comparison),
412            _shadow_compare_func(text._shadow_compare_func),
413            _shadow_texture_mode(text._shadow_texture_mode),
414            _shadow_ambient(text._shadow_ambient)
415{
416}
417
418Texture::~Texture()
419{
420    // delete old texture objects.
421    dirtyTextureObject();
422}
423
424int Texture::compareTexture(const Texture& rhs) const
425{
426    COMPARE_StateAttribute_Parameter(_wrap_s)
427    COMPARE_StateAttribute_Parameter(_wrap_t)
428    COMPARE_StateAttribute_Parameter(_wrap_r)
429    COMPARE_StateAttribute_Parameter(_min_filter)
430    COMPARE_StateAttribute_Parameter(_mag_filter)
431    COMPARE_StateAttribute_Parameter(_maxAnisotropy)
432    COMPARE_StateAttribute_Parameter(_useHardwareMipMapGeneration)
433    COMPARE_StateAttribute_Parameter(_internalFormatMode)
434
435    // only compare _internalFomat is it has alrady been set in both lhs, and rhs
436    if (_internalFormat!=0 && rhs._internalFormat!=0)
437    {
438        COMPARE_StateAttribute_Parameter(_internalFormat)
439    }
440
441    COMPARE_StateAttribute_Parameter(_sourceFormat)
442    COMPARE_StateAttribute_Parameter(_sourceType)
443
444    COMPARE_StateAttribute_Parameter(_use_shadow_comparison)
445    COMPARE_StateAttribute_Parameter(_shadow_compare_func)
446    COMPARE_StateAttribute_Parameter(_shadow_texture_mode)
447    COMPARE_StateAttribute_Parameter(_shadow_ambient)
448
449    COMPARE_StateAttribute_Parameter(_unrefImageDataAfterApply)
450    COMPARE_StateAttribute_Parameter(_clientStorageHint)
451    COMPARE_StateAttribute_Parameter(_resizeNonPowerOfTwoHint)
452
453    COMPARE_StateAttribute_Parameter(_internalFormatType);
454   
455    return 0;
456}
457
458int Texture::compareTextureObjects(const Texture& rhs) const
459{
460    if (_textureObjectBuffer.size()<rhs._textureObjectBuffer.size()) return -1;
461    if (rhs._textureObjectBuffer.size()<_textureObjectBuffer.size()) return 1;
462    for(unsigned int i=0; i<_textureObjectBuffer.size(); ++i)
463    {
464        if (_textureObjectBuffer[i] < rhs._textureObjectBuffer[i]) return -1;
465        else if (rhs._textureObjectBuffer[i] < _textureObjectBuffer[i]) return 1;
466    }
467    return 0;
468}
469
470void Texture::setWrap(WrapParameter which, WrapMode wrap)
471{
472    switch( which )
473    {
474        case WRAP_S : _wrap_s = wrap; dirtyTextureParameters(); break;
475        case WRAP_T : _wrap_t = wrap; dirtyTextureParameters(); break;
476        case WRAP_R : _wrap_r = wrap; dirtyTextureParameters(); break;
477        default : notify(WARN)<<"Error: invalid 'which' passed Texture::setWrap("<<(unsigned int)which<<","<<(unsigned int)wrap<<")"<<std::endl; break;
478    }
479   
480}
481
482
483Texture::WrapMode Texture::getWrap(WrapParameter which) const
484{
485    switch( which )
486    {
487        case WRAP_S : return _wrap_s;
488        case WRAP_T : return _wrap_t;
489        case WRAP_R : return _wrap_r;
490        default : notify(WARN)<<"Error: invalid 'which' passed Texture::getWrap(which)"<<std::endl; return _wrap_s;
491    }
492}
493
494
495void Texture::setFilter(FilterParameter which, FilterMode filter)
496{
497    switch( which )
498    {
499        case MIN_FILTER : _min_filter = filter; dirtyTextureParameters(); break;
500        case MAG_FILTER : _mag_filter = filter; dirtyTextureParameters(); break;
501        default : notify(WARN)<<"Error: invalid 'which' passed Texture::setFilter("<<(unsigned int)which<<","<<(unsigned int)filter<<")"<<std::endl; break;
502    }
503}
504
505
506Texture::FilterMode Texture::getFilter(FilterParameter which) const
507{
508    switch( which )
509    {
510        case MIN_FILTER : return _min_filter;
511        case MAG_FILTER : return _mag_filter;
512        default : notify(WARN)<<"Error: invalid 'which' passed Texture::getFilter(which)"<< std::endl; return _min_filter;
513    }
514}
515
516void Texture::setMaxAnisotropy(float anis)
517{
518    if (_maxAnisotropy!=anis)
519    {
520        _maxAnisotropy = anis;
521        dirtyTextureParameters();
522    }
523}
524
525
526/** Force a recompile on next apply() of associated OpenGL texture objects.*/
527void Texture::dirtyTextureObject()
528{
529    if (getTextureObjectManager()) getTextureObjectManager()->addTextureObjectsFrom(*this);
530}
531
532void Texture::takeTextureObjects(Texture::TextureObjectListMap& toblm)
533{
534    for(unsigned int i = 0; i<_textureObjectBuffer.size();++i)
535    {
536        if (_textureObjectBuffer[i].valid())
537        {
538            //notify(INFO) << "releasing texture "<<toblm[i].size()<<std::endl;
539            toblm[i].push_back(_textureObjectBuffer[i]);
540        }
541    }
542    _textureObjectBuffer.setAllElementsTo(0);
543}
544
545void Texture::dirtyTextureParameters()
546{
547    _texParametersDirtyList.setAllElementsTo(1);
548}
549
550void Texture::allocateMipmapLevels()
551{
552    _texMipmapGenerationDirtyList.setAllElementsTo(1);
553}
554
555void Texture::computeInternalFormatWithImage(const osg::Image& image) const
556{
557    GLint internalFormat = image.getInternalTextureFormat();
558
559    if (_internalFormatMode==USE_IMAGE_DATA_FORMAT)
560    {
561        internalFormat = image.getInternalTextureFormat();
562    }
563    else if (_internalFormatMode==USE_USER_DEFINED_FORMAT)
564    {
565        internalFormat = _internalFormat;
566    }
567    else
568    {
569
570        const unsigned int contextID = 0; // state.getContextID();  // set to 0 right now, assume same parameters for each graphics context...
571        const Extensions* extensions = getExtensions(contextID,true);
572
573        switch(_internalFormatMode)
574        {
575        case(USE_ARB_COMPRESSION):
576            if (extensions->isTextureCompressionARBSupported())
577            {
578                switch(image.getPixelFormat())
579                {
580                    case(1): internalFormat = GL_COMPRESSED_ALPHA_ARB; break;
581                    case(2): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
582                    case(3): internalFormat = GL_COMPRESSED_RGB_ARB; break;
583                    case(4): internalFormat = GL_COMPRESSED_RGBA_ARB; break;
584                    case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_ARB; break;
585                    case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_ARB; break;
586                    case(GL_ALPHA): internalFormat = GL_COMPRESSED_ALPHA_ARB; break;
587                    case(GL_LUMINANCE): internalFormat = GL_COMPRESSED_LUMINANCE_ARB; break;
588                    case(GL_LUMINANCE_ALPHA): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
589                    case(GL_INTENSITY): internalFormat = GL_COMPRESSED_INTENSITY_ARB; break;
590                }
591            }
592            else internalFormat = image.getInternalTextureFormat();
593            break;
594
595        case(USE_S3TC_DXT1_COMPRESSION):
596            if (extensions->isTextureCompressionS3TCSupported())
597            {
598                switch(image.getPixelFormat())
599                {
600                    case(3):        internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
601                    case(4):        internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
602                    case(GL_RGB):   internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
603                    case(GL_RGBA):  internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
604                    default:        internalFormat = image.getInternalTextureFormat(); break;
605                }
606            }
607            else internalFormat = image.getInternalTextureFormat();
608            break;
609
610        case(USE_S3TC_DXT3_COMPRESSION):
611            if (extensions->isTextureCompressionS3TCSupported())
612            {
613                switch(image.getPixelFormat())
614                {
615                    case(3):
616                    case(GL_RGB):   internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
617                    case(4):
618                    case(GL_RGBA):  internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
619                    default:        internalFormat = image.getInternalTextureFormat(); break;
620                }
621            }
622            else internalFormat = image.getInternalTextureFormat();
623            break;
624
625        case(USE_S3TC_DXT5_COMPRESSION):
626            if (extensions->isTextureCompressionS3TCSupported())
627            {
628                switch(image.getPixelFormat())
629                {
630                    case(3):
631                    case(GL_RGB):   internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
632                    case(4):
633                    case(GL_RGBA):  internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
634                    default:        internalFormat = image.getInternalTextureFormat(); break;
635                }
636            }
637            else internalFormat = image.getInternalTextureFormat();
638            break;
639        default:
640            break;
641        }
642    }
643   
644    _internalFormat = internalFormat;
645    computeInternalFormatType();
646   
647    //osg::notify(osg::NOTICE)<<"Internal format="<<std::hex<<internalFormat<<std::dec<<std::endl;
648}
649
650void Texture::computeInternalFormatType() const
651{
652    // Here we could also precompute the _sourceFormat if it is not set,
653    // since it is different for different internal formats
654    // (i.e. rgba integer texture --> _sourceFormat = GL_RGBA_INTEGER_EXT)
655    // Should we do this?  ( Art, 09. Sept. 2007)
656   
657    // compute internal format type based on the internal format
658    switch(_internalFormat)
659    {
660        case GL_RGBA32UI_EXT:
661        case GL_RGBA16UI_EXT:
662        case GL_RGBA8UI_EXT:
663
664        case GL_RGB32UI_EXT:
665        case GL_RGB16UI_EXT:
666        case GL_RGB8UI_EXT:
667
668        case GL_LUMINANCE32UI_EXT
669        case GL_LUMINANCE16UI_EXT:   
670        case GL_LUMINANCE8UI_EXT:   
671
672        case GL_INTENSITY32UI_EXT:   
673        case GL_INTENSITY16UI_EXT:   
674        case GL_INTENSITY8UI_EXT:   
675
676        case GL_LUMINANCE_ALPHA32UI_EXT:   
677        case GL_LUMINANCE_ALPHA16UI_EXT:   
678        case GL_LUMINANCE_ALPHA8UI_EXT :   
679            _internalFormatType = UNSIGNED_INTEGER;
680            break;
681
682        case GL_RGBA32I_EXT:
683        case GL_RGBA16I_EXT:
684        case GL_RGBA8I_EXT:
685
686        case GL_RGB32I_EXT:
687        case GL_RGB16I_EXT:
688        case GL_RGB8I_EXT:
689
690        case GL_LUMINANCE32I_EXT:   
691        case GL_LUMINANCE16I_EXT:   
692        case GL_LUMINANCE8I_EXT:   
693
694        case GL_INTENSITY32I_EXT:   
695        case GL_INTENSITY16I_EXT:   
696        case GL_INTENSITY8I_EXT:   
697
698        case GL_LUMINANCE_ALPHA32I_EXT:   
699        case GL_LUMINANCE_ALPHA16I_EXT:   
700        case GL_LUMINANCE_ALPHA8I_EXT:   
701            _internalFormatType = SIGNED_INTEGER;
702            break;
703       
704        case GL_RGBA32F_ARB:
705        case GL_RGBA16F_ARB:
706
707        case GL_RGB32F_ARB:
708        case GL_RGB16F_ARB:
709
710        case GL_LUMINANCE32F_ARB:
711        case GL_LUMINANCE16F_ARB:   
712
713        case GL_INTENSITY32F_ARB:
714        case GL_INTENSITY16F_ARB:   
715
716        case GL_LUMINANCE_ALPHA32F_ARB:
717        case GL_LUMINANCE_ALPHA16F_ARB:   
718            _internalFormatType = FLOAT;
719            break;
720           
721        default:
722            _internalFormatType = NORMALIZED;
723            break;
724    };
725}
726
727bool Texture::isCompressedInternalFormat() const
728{
729    return isCompressedInternalFormat(getInternalFormat());
730}
731
732bool Texture::isCompressedInternalFormat(GLint internalFormat)
733{
734    switch(internalFormat)
735    {
736        case(GL_COMPRESSED_ALPHA_ARB):
737        case(GL_COMPRESSED_INTENSITY_ARB):
738        case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB):
739        case(GL_COMPRESSED_LUMINANCE_ARB):
740        case(GL_COMPRESSED_RGBA_ARB):
741        case(GL_COMPRESSED_RGB_ARB):
742        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
743        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
744        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
745        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
746            return true;
747        default:
748            return false;
749    }
750}
751
752void Texture::getCompressedSize(GLenum internalFormat, GLint width, GLint height, GLint depth, GLint& blockSize, GLint& size)
753{
754    if (internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
755        blockSize = 8;
756    else if (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT || internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
757        blockSize = 16;
758    else
759    {
760        notify(WARN)<<"Texture::getCompressedSize(...) : cannot compute correct size of compressed format ("<<internalFormat<<") returning 0."<<std::endl;
761        blockSize = 0;
762    }
763         
764    size = ((width+3)/4)*((height+3)/4)*depth*blockSize;       
765}
766
767void Texture::applyTexParameters(GLenum target, State& state) const
768{
769    // get the contextID (user defined ID of 0 upwards) for the
770    // current OpenGL context.
771    const unsigned int contextID = state.getContextID();
772    const Extensions* extensions = getExtensions(contextID,true);
773
774    WrapMode ws = _wrap_s, wt = _wrap_t, wr = _wrap_r;
775
776    // GL_IBM_texture_mirrored_repeat, fall-back REPEAT
777    if (!extensions->isTextureMirroredRepeatSupported())
778    {
779        if (ws == MIRROR)
780            ws = REPEAT;
781        if (wt == MIRROR)
782            wt = REPEAT;
783        if (wr == MIRROR)
784            wr = REPEAT;
785    }
786
787    // GL_EXT_texture_edge_clamp, fall-back CLAMP
788    if (!extensions->isTextureEdgeClampSupported())
789    {
790        if (ws == CLAMP_TO_EDGE)
791            ws = CLAMP;
792        if (wt == CLAMP_TO_EDGE)
793            wt = CLAMP;
794        if (wr == CLAMP_TO_EDGE)
795            wr = CLAMP;
796    }
797
798    if(!extensions->isTextureBorderClampSupported())
799    {
800        if(ws == CLAMP_TO_BORDER)
801            ws = CLAMP;
802        if(wt == CLAMP_TO_BORDER)
803            wt = CLAMP;
804        if(wr == CLAMP_TO_BORDER)
805            wr = CLAMP;
806    }
807   
808    const Image * image = getImage(0);
809    if( image &&
810        image->isMipmap() &&
811        extensions->isTextureMaxLevelSupported() &&
812        int( image->getNumMipmapLevels() ) <
813            Image::computeNumberOfMipmapLevels( image->s(), image->t(), image->r() ) )
814            glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, image->getNumMipmapLevels() - 1 );   
815
816
817    glTexParameteri( target, GL_TEXTURE_WRAP_S, ws );
818   
819    if (target!=GL_TEXTURE_1D) glTexParameteri( target, GL_TEXTURE_WRAP_T, wt );
820   
821    if (target==GL_TEXTURE_3D) glTexParameteri( target, GL_TEXTURE_WRAP_R, wr );
822
823   
824    glTexParameteri( target, GL_TEXTURE_MIN_FILTER, _min_filter);
825    glTexParameteri( target, GL_TEXTURE_MAG_FILTER, _mag_filter);
826
827    // Art: I think anisotropic filtering is not supported by the integer textures
828    if (extensions->isTextureFilterAnisotropicSupported() &&
829        _internalFormatType != SIGNED_INTEGER && _internalFormatType != UNSIGNED_INTEGER)
830    {
831        // note, GL_TEXTURE_MAX_ANISOTROPY_EXT will either be defined
832        // by gl.h (or via glext.h) or by include/osg/Texture.
833        glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, _maxAnisotropy);
834    }
835
836    if (extensions->isTextureBorderClampSupported())
837    {
838        if (_internalFormatType == SIGNED_INTEGER)
839        {
840            GLint color[4] = {(GLint)_borderColor.r(), (GLint)_borderColor.g(), (GLint)_borderColor.b(), (GLint)_borderColor.a()};
841            extensions->glTexParameterIiv(target, GL_TEXTURE_BORDER_COLOR, color);
842        }else if (_internalFormatType == UNSIGNED_INTEGER)
843        {
844            GLuint color[4] = {(GLuint)_borderColor.r(), (GLuint)_borderColor.g(), (GLuint)_borderColor.b(), (GLuint)_borderColor.a()};
845            extensions->glTexParameterIuiv(target, GL_TEXTURE_BORDER_COLOR, color);
846        }else{
847            GLfloat color[4] = {(GLfloat)_borderColor.r(), (GLfloat)_borderColor.g(), (GLfloat)_borderColor.b(), (GLfloat)_borderColor.a()};
848            glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color);
849        }
850    }
851
852    // integer texture are not supported by the shadow
853    if (extensions->isShadowSupported() && (target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE) &&
854        _internalFormatType != SIGNED_INTEGER && _internalFormatType != UNSIGNED_INTEGER)
855    {
856        if (_use_shadow_comparison)
857        {
858            glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
859            glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC_ARB, _shadow_compare_func);
860            glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, _shadow_texture_mode);
861
862            // if ambient value is 0 - it is default behaviour of GL_ARB_shadow
863            // no need for GL_ARB_shadow_ambient in this case
864            if (extensions->isShadowAmbientSupported() && _shadow_ambient > 0)
865            {
866                glTexParameterf(target, TEXTURE_COMPARE_FAIL_VALUE_ARB, _shadow_ambient);
867            }
868        }
869        else 
870        {
871            glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
872        }
873    }
874
875    getTextureParameterDirty(state.getContextID()) = false;
876
877}
878
879void Texture::computeRequiredTextureDimensions(State& state, const osg::Image& image,GLsizei& inwidth, GLsizei& inheight,GLsizei& numMipmapLevels) const
880{
881    const unsigned int contextID = state.getContextID();
882    const Extensions* extensions = getExtensions(contextID,true);
883
884    int width,height;
885
886    if( !_resizeNonPowerOfTwoHint && extensions->isNonPowerOfTwoTextureSupported(_min_filter) )
887    {
888        width = image.s();
889        height = image.t();
890    }
891    else
892    {
893        width = Image::computeNearestPowerOfTwo(image.s()-2*_borderWidth)+2*_borderWidth;
894        height = Image::computeNearestPowerOfTwo(image.t()-2*_borderWidth)+2*_borderWidth;
895    }
896
897    // cap the size to what the graphics hardware can handle.
898    if (width>extensions->maxTextureSize()) width = extensions->maxTextureSize();
899    if (height>extensions->maxTextureSize()) height = extensions->maxTextureSize();
900
901    inwidth = width;
902    inheight = height;
903   
904    bool useHardwareMipMapGeneration = !image.isMipmap() && isHardwareMipmapGenerationEnabled(state);
905
906    if( _min_filter == LINEAR || _min_filter == NEAREST || useHardwareMipMapGeneration )
907    {
908        numMipmapLevels = 1;
909    }
910    else if( image.isMipmap() )
911    {
912        numMipmapLevels = image.getNumMipmapLevels();
913    }
914    else
915    {
916        numMipmapLevels = 0;
917        for( ; (width || height) ;++numMipmapLevels)
918        {
919
920            if (width == 0)
921                width = 1;
922            if (height == 0)
923                height = 1;
924
925            width >>= 1;
926            height >>= 1;
927        }   
928    }
929   
930    // osg::notify(osg::NOTICE)<<"Texture::computeRequiredTextureDimensions() image.s() "<<image.s()<<" image.t()="<<image.t()<<" width="<<width<<" height="<<height<<" numMipmapLevels="<<numMipmapLevels<<std::endl;
931    // osg::notify(osg::NOTICE)<<"  _resizeNonPowerOfTwoHint="<<_resizeNonPowerOfTwoHint<<" extensions->isNonPowerOfTwoTextureSupported(_min_filter)="<<extensions->isNonPowerOfTwoTextureSupported(_min_filter) <<std::endl;
932}
933
934bool Texture::areAllTextureObjectsLoaded() const
935{
936    for(unsigned int i=0;i<DisplaySettings::instance()->getMaxNumberOfGraphicsContexts();++i)
937    {
938        if (_textureObjectBuffer[i]==0) return false;
939    }
940    return true;
941}
942
943
944void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight,GLsizei numMipmapLevels) const
945{
946    // if we don't have a valid image we can't create a texture!
947    if (!image || !image->data())
948        return;
949
950#ifdef DO_TIMING
951    osg::Timer_t start_tick = osg::Timer::instance()->tick();
952    osg::notify(osg::NOTICE)<<"glTexImage2D pixelFormat = "<<std::hex<<image->getPixelFormat()<<std::dec<<std::endl;
953#endif
954
955    // get the contextID (user defined ID of 0 upwards) for the
956    // current OpenGL context.
957    const unsigned int contextID = state.getContextID();
958    const Extensions* extensions = getExtensions(contextID,true);
959
960    // select the internalFormat required for the texture.
961    bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
962
963    // If the texture's internal format is a compressed type, then the
964    // user is requesting that the graphics card compress the image if it's
965    // not already compressed. However, if the image is not a multiple of
966    // four in each dimension the subsequent calls to glTexSubImage* will
967    // fail. Revert to uncompressed format in this case.
968    if (isCompressedInternalFormat(_internalFormat) &&
969        (((inwidth >> 2) << 2) != inwidth ||
970         ((inheight >> 2) << 2) != inheight))
971    {
972        osg::notify(osg::NOTICE)<<"Received a request to compress an image, but image size is not a multiple of four ("<<inwidth<<"x"<<inheight<<"). Reverting to uncompressed.\n";
973        switch(_internalFormat)
974        {
975            case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
976            case GL_COMPRESSED_RGB: _internalFormat = GL_RGB; break;
977            case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
978            case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
979            case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
980            case GL_COMPRESSED_RGBA: _internalFormat = GL_RGBA; break;
981            case GL_COMPRESSED_ALPHA: _internalFormat = GL_ALPHA; break;
982            case GL_COMPRESSED_LUMINANCE: _internalFormat = GL_LUMINANCE; break;
983            case GL_COMPRESSED_LUMINANCE_ALPHA: _internalFormat = GL_LUMINANCE_ALPHA; break;
984            case GL_COMPRESSED_INTENSITY: _internalFormat = GL_INTENSITY; break;
985        }
986    }
987   
988    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
989   
990    bool useClientStorage = extensions->isClientStorageSupported() && getClientStorageHint();
991    if (useClientStorage)
992    {
993        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_TRUE);
994        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_PRIORITY,0.0f);
995       
996        #ifdef GL_TEXTURE_STORAGE_HINT_APPLE   
997            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
998        #endif
999    }
1000   
1001    unsigned char* data = (unsigned char*)image->data();
1002 
1003    // osg::notify(osg::NOTICE)<<"inwidth="<<inwidth<<" inheight="<<inheight<<" image->getFileName()"<<image->getFileName()<<std::endl;
1004
1005    bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
1006    if (needImageRescale)
1007    {
1008
1009        // resize the image to power of two.
1010       
1011        if (image->isMipmap())
1012        {
1013            notify(WARN)<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
1014            return;
1015        }
1016        else if (compressed_image)
1017        {
1018            notify(WARN)<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
1019            return;
1020        }
1021       
1022        unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
1023        data = new unsigned char [newTotalSize];
1024       
1025        if (!data)
1026        {
1027            notify(WARN)<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
1028            return;
1029        }
1030
1031        if (!image->getFileName().empty()) notify(NOTICE) << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
1032        else notify(NOTICE) << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
1033
1034        // rescale the image to the correct size.
1035        glPixelStorei(GL_PACK_ALIGNMENT,image->getPacking());
1036        gluScaleImage(image->getPixelFormat(),
1037                      image->s(),image->t(),image->getDataType(),image->data(),
1038                      inwidth,inheight,image->getDataType(),data);
1039       
1040    }   
1041
1042    bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
1043    bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
1044    bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
1045
1046    unsigned char* dataMinusOffset = 0;
1047    unsigned char* dataPlusOffset = 0;
1048
1049    const PixelBufferObject* pbo = image->getPixelBufferObject();
1050    if (pbo && pbo->isPBOSupported(contextID) && !needImageRescale && !useGluBuildMipMaps)
1051    {
1052        state.bindPixelBufferObject(pbo);
1053        dataMinusOffset = data;
1054        dataPlusOffset = reinterpret_cast<unsigned char*>(pbo->offset());
1055#ifdef DO_TIMING
1056        osg::notify(osg::NOTICE)<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
1057#endif
1058    }
1059    else
1060    {
1061        pbo = 0;
1062    }
1063
1064    if( !mipmappingRequired || useHardwareMipMapGeneration)
1065    {
1066
1067        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
1068
1069        if ( !compressed_image)
1070        {
1071            numMipmapLevels = 1;
1072
1073            glTexImage2D( target, 0, _internalFormat,
1074                inwidth, inheight, _borderWidth,
1075                (GLenum)image->getPixelFormat(),
1076                (GLenum)image->getDataType(),
1077                data -dataMinusOffset+dataPlusOffset);
1078
1079        }
1080        else if (extensions->isCompressedTexImage2DSupported())
1081        {
1082            numMipmapLevels = 1;
1083
1084            GLint blockSize, size;
1085            getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size);
1086
1087            extensions->glCompressedTexImage2D(target, 0, _internalFormat,
1088                inwidth, inheight,0,
1089                size,
1090                data-dataMinusOffset+dataPlusOffset);               
1091        }
1092
1093        mipmapAfterTexImage(state, mipmapResult);
1094    }
1095    else
1096    {
1097        // we require mip mapping.
1098        if(image->isMipmap())
1099        {
1100
1101            // image is mip mapped so we take the mip map levels from the image.
1102       
1103            numMipmapLevels = image->getNumMipmapLevels();
1104
1105            int width  = inwidth;
1106            int height = inheight;
1107
1108            if( !compressed_image )
1109            {
1110                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
1111                {
1112
1113                    if (width == 0)
1114                        width = 1;
1115                    if (height == 0)
1116                        height = 1;
1117
1118                    glTexImage2D( target, k, _internalFormat,
1119                         width, height, _borderWidth,
1120                        (GLenum)image->getPixelFormat(),
1121                        (GLenum)image->getDataType(),
1122                        image->getMipmapData(k)-dataMinusOffset+dataPlusOffset);
1123
1124                    width >>= 1;
1125                    height >>= 1;
1126                }
1127            }
1128            else if (extensions->isCompressedTexImage2DSupported())
1129            {
1130                GLint blockSize, size;
1131
1132                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
1133                {
1134                    if (width == 0)
1135                        width = 1;
1136                    if (height == 0)
1137                        height = 1;
1138
1139                    getCompressedSize(_internalFormat, width, height, 1, blockSize,size);
1140                   
1141                    extensions->glCompressedTexImage2D(target, k, _internalFormat,
1142                                                       width, height, _borderWidth,
1143                                                       size, image->getMipmapData(k)-dataMinusOffset+dataPlusOffset);               
1144
1145                    width >>= 1;
1146                    height >>= 1;
1147                }
1148            }
1149        }
1150        else
1151        {
1152       
1153            if ( !compressed_image)
1154            {
1155                numMipmapLevels = 0;
1156
1157                gluBuild2DMipmaps( target, _internalFormat,
1158                    inwidth,inheight,
1159                    (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
1160                    data);
1161
1162                int width  = image->s();
1163                int height = image->t();
1164                for( numMipmapLevels = 0 ; (width || height) ; ++numMipmapLevels)
1165                {
1166                    width >>= 1;
1167                    height >>= 1;
1168                }
1169            }
1170            else 
1171            {
1172                notify(WARN)<<"Warning:: Compressed image cannot be mip mapped"<<std::endl;
1173            }
1174
1175        }
1176
1177    }
1178
1179    if (pbo)
1180    {
1181        state.unbindPixelBufferObject();
1182    }
1183   
1184#ifdef DO_TIMING
1185    static double s_total_time = 0.0;
1186    double delta_time = osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick());
1187    s_total_time += delta_time;
1188    osg::notify(osg::NOTICE)<<"glTexImage2D "<<delta_time<<"ms  total "<<s_total_time<<"ms"<<std::endl;
1189#endif
1190
1191    if (needImageRescale)
1192    {
1193        // clean up the resized image.
1194        delete [] data;
1195    }
1196   
1197    if (useClientStorage)
1198    {
1199        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_FALSE);
1200    }
1201}
1202
1203
1204
1205void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight, GLint inInternalFormat, GLint numMipmapLevels) const
1206{
1207    // if we don't have a valid image we can't create a texture!
1208    if (!image || !image->data())
1209        return;
1210
1211    // image size has changed so we have to re-load the image from scratch.
1212    if (image->s()!=inwidth || image->t()!=inheight || image->getInternalTextureFormat()!=inInternalFormat )
1213    {
1214        applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
1215        return;
1216    }
1217    // else image size the same as when loaded so we can go ahead and subload
1218   
1219    // If the texture's internal format is a compressed type, then the
1220    // user is requesting that the graphics card compress the image if it's
1221    // not already compressed. However, if the image is not a multiple of
1222    // four in each dimension the subsequent calls to glTexSubImage* will
1223    // fail. Revert to uncompressed format in this case.
1224    if (isCompressedInternalFormat(_internalFormat) &&
1225        (((inwidth >> 2) << 2) != inwidth ||
1226         ((inheight >> 2) << 2) != inheight))
1227    {
1228        applyTexImage2D_load(state, target, image, inwidth, inheight, numMipmapLevels);
1229        return;
1230    }
1231
1232#ifdef DO_TIMING
1233    osg::Timer_t start_tick = osg::Timer::instance()->tick();
1234    osg::notify(osg::NOTICE)<<"glTexSubImage2D pixelFormat = "<<std::hex<<image->getPixelFormat()<<std::dec<<std::endl;
1235#endif
1236   
1237
1238    // get the contextID (user defined ID of 0 upwards) for the
1239    // current OpenGL context.
1240    const unsigned int contextID = state.getContextID();
1241    const Extensions* extensions = getExtensions(contextID,true);
1242
1243    // select the internalFormat required for the texture.
1244    bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
1245   
1246    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
1247   
1248    unsigned char* data = (unsigned char*)image->data();
1249 
1250
1251    bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
1252    if (needImageRescale)
1253    {
1254
1255        // resize the image to power of two.
1256       
1257        if (image->isMipmap())
1258        {
1259            notify(WARN)<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
1260            return;
1261        }
1262        else if (compressed_image)
1263        {
1264            notify(WARN)<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
1265            return;
1266        }
1267       
1268        unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
1269        data = new unsigned char [newTotalSize];
1270       
1271        if (!data)
1272        {
1273            notify(WARN)<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
1274            return;
1275        }
1276
1277        if (!image->getFileName().empty()) notify(NOTICE) << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
1278        else notify(NOTICE) << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
1279
1280        // rescale the image to the correct size.
1281        glPixelStorei(GL_PACK_ALIGNMENT,image->getPacking());
1282        gluScaleImage(image->getPixelFormat(),
1283                      image->s(),image->t(),image->getDataType(),image->data(),
1284                      inwidth,inheight,image->getDataType(),data);
1285       
1286    }   
1287
1288
1289    bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
1290    bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
1291    bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
1292
1293    unsigned char* dataMinusOffset = 0;
1294    unsigned char* dataPlusOffset = 0;
1295   
1296    const PixelBufferObject* pbo = image->getPixelBufferObject();
1297    if (pbo && pbo->isPBOSupported(contextID) && !needImageRescale && !useGluBuildMipMaps)
1298    {
1299        state.bindPixelBufferObject(pbo);
1300        dataMinusOffset = data;
1301        dataPlusOffset = reinterpret_cast<unsigned char*>(pbo->offset());
1302#ifdef DO_TIMING
1303        osg::notify(osg::NOTICE)<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
1304#endif
1305    }
1306    else
1307    {
1308        pbo = 0;
1309    }
1310
1311    if( !mipmappingRequired || useHardwareMipMapGeneration)
1312    {
1313
1314        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
1315
1316        if (!compressed_image)
1317        {
1318            glTexSubImage2D( target, 0,
1319                0, 0,
1320                inwidth, inheight,
1321                (GLenum)image->getPixelFormat(),
1322                (GLenum)image->getDataType(),
1323                data - dataMinusOffset + dataPlusOffset);
1324
1325        }
1326        else if (extensions->isCompressedTexImage2DSupported())
1327        {       
1328            GLint blockSize,size;
1329            getCompressedSize(image->getInternalTextureFormat(), inwidth, inheight, 1, blockSize,size);
1330
1331            extensions->glCompressedTexSubImage2D(target, 0,
1332                0,0,
1333                inwidth, inheight,
1334                (GLenum)image->getPixelFormat(),
1335                size,
1336                data - dataMinusOffset + dataPlusOffset );               
1337        }
1338
1339        mipmapAfterTexImage(state, mipmapResult);
1340    }
1341    else
1342    {
1343        if (image->isMipmap())
1344        {
1345            numMipmapLevels = image->getNumMipmapLevels();
1346
1347            int width  = inwidth;
1348            int height = inheight;
1349
1350            if( !compressed_image )
1351            {
1352                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
1353                {
1354
1355                    if (width == 0)
1356                        width = 1;
1357                    if (height == 0)
1358                        height = 1;
1359
1360                    glTexSubImage2D( target, k,
1361                        0, 0,
1362                        width, height,
1363                        (GLenum)image->getPixelFormat(),
1364                        (GLenum)image->getDataType(),
1365                        image->getMipmapData(k) - dataMinusOffset + dataPlusOffset);
1366
1367                    width >>= 1;
1368                    height >>= 1;
1369                }
1370            }
1371            else if (extensions->isCompressedTexImage2DSupported())
1372            {
1373                GLint blockSize,size;
1374                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
1375                {
1376                    if (width == 0)
1377                        width = 1;
1378                    if (height == 0)
1379                        height = 1;
1380
1381                    getCompressedSize(image->getInternalTextureFormat(), width, height, 1, blockSize,size);
1382
1383                    //state.checkGLErrors("before extensions->glCompressedTexSubImage2D(");
1384
1385                    extensions->glCompressedTexSubImage2D(target, k, 
1386                                                       0, 0,
1387                                                       width, height,
1388                                                       (GLenum)image->getPixelFormat(),
1389                                                       size,
1390                                                        image->getMipmapData(k) - dataMinusOffset + dataPlusOffset);               
1391
1392                    //state.checkGLErrors("after extensions->glCompressedTexSubImage2D(");
1393
1394                    width >>= 1;
1395                    height >>= 1;
1396                }
1397
1398            }
1399        }
1400        else
1401        {
1402            //notify(WARN)<<"Warning:: cannot subload mip mapped texture from non mipmapped image."<<std::endl;
1403            applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
1404            return;
1405        }
1406    }
1407   
1408    if (pbo)
1409    {
1410        state.unbindPixelBufferObject();
1411    }
1412#ifdef DO_TIMING
1413    osg::notify(osg::NOTICE)<<"glTexSubImage2D "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
1414#endif
1415
1416    if (needImageRescale)
1417    {
1418        // clean up the resized image.
1419        delete [] data;
1420    }
1421}
1422
1423bool Texture::isHardwareMipmapGenerationEnabled(const State& state) const
1424{
1425    if (_useHardwareMipMapGeneration)
1426    {
1427        unsigned int contextID = state.getContextID();
1428        const Extensions* extensions = getExtensions(contextID,true);
1429
1430        if (extensions->isGenerateMipMapSupported())
1431        {
1432            return true;
1433        }
1434
1435        const FBOExtensions* fbo_ext = FBOExtensions::instance(contextID,true);
1436
1437        if (fbo_ext->glGenerateMipmapEXT)
1438        {
1439            return true;
1440        }
1441    }
1442
1443    return false;
1444}
1445
1446Texture::GenerateMipmapMode Texture::mipmapBeforeTexImage(const State& state, bool hardwareMipmapOn) const
1447{
1448    if (hardwareMipmapOn)
1449    {
1450        int width = getTextureWidth();
1451        int height = getTextureHeight();
1452
1453        //quick bithack to determine whether width or height are non-power-of-two
1454        if ((width & (width - 1)) || (height & (height - 1)))
1455        {
1456            //GL_GENERATE_MIPMAP_SGIS with non-power-of-two textures on NVIDIA hardware
1457            //is extremely slow. Use glGenerateMipmapEXT() instead if supported.
1458            if (_internalFormatType != SIGNED_INTEGER &&
1459                _internalFormatType != UNSIGNED_INTEGER)
1460            {
1461                if (FBOExtensions::instance(state.getContextID(), true)->glGenerateMipmapEXT)
1462                {
1463                    return GENERATE_MIPMAP;
1464                }
1465            }
1466        }
1467
1468        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1469        return GENERATE_MIPMAP_TEX_PARAMETER;
1470    }
1471    return GENERATE_MIPMAP_NONE;
1472}
1473
1474void Texture::mipmapAfterTexImage(State& state, GenerateMipmapMode beforeResult) const
1475{
1476    switch (beforeResult)
1477    {
1478    case GENERATE_MIPMAP:
1479        {
1480            unsigned int contextID = state.getContextID();
1481            TextureObject* textureObject = getTextureObject(contextID);
1482            if (textureObject)
1483            {
1484                osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(contextID, true);
1485                fbo_ext->glGenerateMipmapEXT(textureObject->_target);
1486            }
1487        }
1488        break;
1489    case GENERATE_MIPMAP_TEX_PARAMETER:
1490        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
1491        break;
1492    case GENERATE_MIPMAP_NONE:
1493        break;
1494    }
1495}
1496
1497void Texture::generateMipmap(State& state) const
1498{
1499    const unsigned int contextID = state.getContextID();
1500
1501    // get the texture object for the current contextID.
1502    TextureObject* textureObject = getTextureObject(contextID);
1503
1504    // if not initialized before, then do nothing
1505    if (textureObject == NULL) return;
1506
1507    _texMipmapGenerationDirtyList[contextID] = 0;
1508   
1509    // if internal format does not provide automatic mipmap generation, then do manual allocation
1510    if (_internalFormatType == SIGNED_INTEGER || _internalFormatType == UNSIGNED_INTEGER)
1511    {
1512        allocateMipmap(state);
1513        return;
1514    }
1515   
1516    // get fbo extension which provides us with the glGenerateMipmapEXT function
1517    osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(state.getContextID(), true);
1518
1519    // check if the function is supported
1520    if (fbo_ext->glGenerateMipmapEXT)
1521    {
1522        textureObject->bind();
1523        fbo_ext->glGenerateMipmapEXT(textureObject->_target);
1524       
1525        // inform state that this texture is the current one bound.
1526        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
1527   
1528    // if the function is not supported, then do manual allocation
1529    }else
1530    {
1531        allocateMipmap(state);
1532    }
1533   
1534}
1535
1536
1537///////////////////////////////////////////////////////////////////////////////////////////////
1538//  Static map to manage the deletion of texture objects are the right time.
1539//////////////////////////////////////////////////////////////////////////////////////////////
1540#include <map>
1541#include <set>
1542
1543
1544void Texture::compileGLObjects(State& state) const
1545{
1546    apply(state);
1547}
1548
1549void Texture::resizeGLObjectBuffers(unsigned int maxSize)
1550{
1551    _textureObjectBuffer.resize(maxSize);
1552}
1553
1554void Texture::releaseGLObjects(State* state) const
1555{
1556//    if (state) osg::notify(osg::NOTICE)<<"Texture::releaseGLObjects contextID="<<state->getContextID()<<std::endl;
1557//    else osg::notify(osg::NOTICE)<<"Texture::releaseGLObjects no State "<<std::endl;
1558
1559    if (!state) const_cast<Texture*>(this)->dirtyTextureObject();
1560    else
1561    {
1562        unsigned int contextID = state->getContextID();
1563        if (_textureObjectBuffer[contextID].valid() && getTextureObjectManager())
1564        {
1565            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getTextureObjectManager()->_mutex);
1566           
1567            getTextureObjectManager()->_textureObjectListMap[contextID].push_back(_textureObjectBuffer[contextID]);
1568            _textureObjectBuffer[contextID] = 0;
1569        }
1570    }
1571}
1572
1573Texture::Extensions* Texture::getExtensions(unsigned int contextID,bool createIfNotInitalized)
1574{
1575    if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID);
1576    return s_extensions[contextID].get();
1577}
1578
1579void Texture::setExtensions(unsigned int contextID,Extensions* extensions)
1580{
1581    s_extensions[contextID] = extensions;
1582}
1583
1584Texture::Extensions::Extensions(unsigned int contextID)
1585{
1586    setupGLExtensions(contextID);
1587}
1588
1589Texture::Extensions::Extensions(const Extensions& rhs):
1590    Referenced()
1591{
1592    _isMultiTexturingSupported = rhs._isMultiTexturingSupported;
1593    _isTextureFilterAnisotropicSupported = rhs._isTextureFilterAnisotropicSupported;
1594    _isTextureCompressionARBSupported = rhs._isTextureCompressionARBSupported;
1595    _isTextureCompressionS3TCSupported = rhs._isTextureCompressionS3TCSupported;
1596    _isTextureMirroredRepeatSupported = rhs._isTextureMirroredRepeatSupported;
1597    _isTextureEdgeClampSupported = rhs._isTextureEdgeClampSupported;
1598    _isTextureBorderClampSupported = rhs._isTextureBorderClampSupported;
1599    _isGenerateMipMapSupported = rhs._isGenerateMipMapSupported;
1600
1601    _maxTextureSize = rhs._maxTextureSize;
1602
1603    _glCompressedTexImage2D = rhs._glCompressedTexImage2D;
1604
1605    _isShadowSupported = rhs._isShadowSupported;
1606    _isShadowAmbientSupported = rhs._isShadowAmbientSupported;
1607
1608    _isClientStorageSupported = rhs._isClientStorageSupported;
1609
1610    _isNonPowerOfTwoTextureMipMappedSupported = rhs._isNonPowerOfTwoTextureMipMappedSupported;
1611    _isNonPowerOfTwoTextureNonMipMappedSupported = rhs._isNonPowerOfTwoTextureNonMipMappedSupported;
1612
1613    _isTextureIntegerEXTSupported = rhs._isTextureIntegerEXTSupported;
1614    _isTextureMaxLevelSupported = rhs._isTextureMaxLevelSupported;
1615}
1616
1617void Texture::Extensions::lowestCommonDenominator(const Extensions& rhs)
1618{
1619    if (!rhs._isMultiTexturingSupported) _isMultiTexturingSupported = false;
1620   
1621    if (!rhs._isTextureFilterAnisotropicSupported) _isTextureFilterAnisotropicSupported = false;
1622    if (!rhs._isTextureMirroredRepeatSupported) _isTextureMirroredRepeatSupported = false;
1623    if (!rhs._isTextureEdgeClampSupported) _isTextureEdgeClampSupported = false;
1624    if (!rhs._isTextureBorderClampSupported) _isTextureBorderClampSupported = false;
1625   
1626    if (!rhs._isTextureCompressionARBSupported) _isTextureCompressionARBSupported = false;
1627    if (!rhs._isTextureCompressionS3TCSupported) _isTextureCompressionS3TCSupported = false;
1628   
1629    if (!rhs._isGenerateMipMapSupported) _isGenerateMipMapSupported = false;
1630
1631    if (rhs._maxTextureSize<_maxTextureSize) _maxTextureSize = rhs._maxTextureSize;
1632    if (rhs._numTextureUnits<_numTextureUnits) _numTextureUnits = rhs._numTextureUnits;
1633
1634    if (!rhs._glCompressedTexImage2D) _glCompressedTexImage2D = 0;
1635    if (!rhs._glCompressedTexSubImage2D) _glCompressedTexSubImage2D = 0;
1636    if (!rhs._glGetCompressedTexImage) _glGetCompressedTexImage = 0;
1637
1638    if (!rhs._isShadowSupported) _isShadowSupported = false;
1639    if (!rhs._isShadowAmbientSupported) _isShadowAmbientSupported = false;
1640   
1641    if (!rhs._isClientStorageSupported) _isClientStorageSupported = false;
1642
1643    if (!rhs._isNonPowerOfTwoTextureMipMappedSupported) _isNonPowerOfTwoTextureMipMappedSupported = false;
1644    if (!rhs._isNonPowerOfTwoTextureNonMipMappedSupported) _isNonPowerOfTwoTextureNonMipMappedSupported = false;
1645
1646    if (!rhs._isTextureIntegerEXTSupported) _isTextureIntegerEXTSupported = false;
1647    if (!rhs._isTextureMaxLevelSupported) _isTextureMaxLevelSupported = false;
1648}
1649
1650void Texture::Extensions::setupGLExtensions(unsigned int contextID)
1651{
1652    const char* version = (const char*) glGetString( GL_VERSION );
1653    if (!version)
1654    {
1655        osg::notify(osg::FATAL)<<"Error: In Texture::Extensions::setupGLExtensions(..) OpenGL version test failed, requires valid graphics context."<<std::endl;
1656        return;
1657    }
1658   
1659    const char* renderer = (const char*) glGetString(GL_RENDERER);
1660    std::string rendererString(renderer ? renderer : "");
1661   
1662    _isMultiTexturingSupported = isGLExtensionOrVersionSupported( contextID,"GL_ARB_multitexture", 1.3f) ||
1663                                 isGLExtensionOrVersionSupported(contextID,"GL_EXT_multitexture", 1.3f);
1664                                 
1665    _isTextureFilterAnisotropicSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_filter_anisotropic");
1666   
1667    _isTextureCompressionARBSupported = isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_compression", 1.3f);
1668   
1669    _isTextureCompressionS3TCSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_compression_s3tc");
1670   
1671    _isTextureMirroredRepeatSupported = isGLExtensionOrVersionSupported(contextID,"GL_IBM_texture_mirrored_repeat", 1.4f) ||
1672                                        isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_mirrored_repeat", 1.4f);
1673                                       
1674    _isTextureEdgeClampSupported = isGLExtensionOrVersionSupported(contextID,"GL_EXT_texture_edge_clamp", 1.2f) ||
1675                                   isGLExtensionOrVersionSupported(contextID,"GL_SGIS_texture_edge_clamp", 1.2f);
1676                                   
1677    _isTextureBorderClampSupported = isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_border_clamp", 1.3f);
1678   
1679    _isGenerateMipMapSupported = isGLExtensionOrVersionSupported(contextID,"GL_SGIS_generate_mipmap", 1.4f);
1680                                 
1681    _isShadowSupported = isGLExtensionSupported(contextID,"GL_ARB_shadow");
1682   
1683    _isShadowAmbientSupported = isGLExtensionSupported(contextID,"GL_ARB_shadow_ambient");
1684
1685    _isClientStorageSupported = isGLExtensionSupported(contextID,"GL_APPLE_client_storage");
1686
1687    _isNonPowerOfTwoTextureNonMipMappedSupported = isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_non_power_of_two", 2.0);
1688
1689    _isNonPowerOfTwoTextureMipMappedSupported = _isNonPowerOfTwoTextureNonMipMappedSupported;
1690   
1691    _isTextureIntegerEXTSupported = isGLExtensionSupported(contextID, "GL_EXT_texture_integer");
1692
1693    if (rendererString.find("Radeon")!=std::string::npos || rendererString.find("RADEON")!=std::string::npos)
1694    {
1695        _isNonPowerOfTwoTextureMipMappedSupported = false;
1696        osg::notify(osg::INFO)<<"Disabling _isNonPowerOfTwoTextureMipMappedSupported for ATI hardware."<<std::endl;
1697    }
1698
1699    if (rendererString.find("GeForce FX")!=std::string::npos)
1700    {
1701        _isNonPowerOfTwoTextureMipMappedSupported = false;
1702        osg::notify(osg::INFO)<<"Disabling _isNonPowerOfTwoTextureMipMappedSupported for GeForce FX hardware."<<std::endl;
1703    }
1704
1705    glGetIntegerv(GL_MAX_TEXTURE_SIZE,&_maxTextureSize);
1706
1707    char *ptr;
1708    if( (ptr = getenv("OSG_MAX_TEXTURE_SIZE")) != 0)
1709    {
1710        GLint osg_max_size = atoi(ptr);
1711
1712        if (osg_max_size<_maxTextureSize)
1713        {
1714
1715            _maxTextureSize = osg_max_size;
1716        }
1717    }
1718
1719    if( _isMultiTexturingSupported )
1720    {
1721       glGetIntegerv(GL_MAX_TEXTURE_UNITS,&_numTextureUnits);
1722    }
1723    else
1724    {
1725       _numTextureUnits = 1;
1726    }
1727
1728    setGLExtensionFuncPtr(_glCompressedTexImage2D,"glCompressedTexImage2D","glCompressedTexImage2DARB");
1729    setGLExtensionFuncPtr(_glCompressedTexSubImage2D,"glCompressedTexSubImage2D","glCompressedTexSubImage2DARB");
1730    setGLExtensionFuncPtr(_glGetCompressedTexImage,"glGetCompressedTexImage","glGetCompressedTexImageARB");;
1731
1732    setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIiv", "glTexParameterIivARB");
1733    setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuiv", "glTexParameterIuivARB");
1734   
1735    if (_glTexParameterIiv == NULL) setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIivEXT");
1736    if (_glTexParameterIuiv == NULL) setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuivEXT");
1737
1738    _isTextureMaxLevelSupported = ( getGLVersionNumber() >= 1.2f );
1739}
1740
1741
1742void Texture::Extensions::glTexParameterIiv(GLenum target, GLenum pname, const GLint* data) const
1743{
1744    if (_glTexParameterIiv)
1745    {
1746        _glTexParameterIiv(target, pname, data);
1747    }
1748    else
1749    {
1750        notify(WARN)<<"Error: glTexParameterIiv not supported by OpenGL driver"<<std::endl;
1751    }
1752}
1753
1754void Texture::Extensions::glTexParameterIuiv(GLenum target, GLenum pname, const GLuint* data) const
1755{
1756    if (_glTexParameterIuiv)
1757    {
1758        _glTexParameterIuiv(target, pname, data);
1759    }
1760    else
1761    {
1762        notify(WARN)<<"Error: glTexParameterIuiv not supported by OpenGL driver"<<std::endl;
1763    }
1764}
1765
1766void Texture::Extensions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const
1767{
1768    if (_glCompressedTexImage2D)
1769    {
1770        _glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
1771    }
1772    else
1773    {
1774        notify(WARN)<<"Error: glCompressedTexImage2D not supported by OpenGL driver"<<std::endl;
1775    }
1776   
1777}
1778
1779void Texture::Extensions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) const
1780{
1781    if (_glCompressedTexSubImage2D)
1782    {
1783        _glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
1784    }
1785    else
1786    {
1787        notify(WARN)<<"Error: glCompressedTexImage2D not supported by OpenGL driver"<<std::endl;
1788    }
1789   
1790}
1791void Texture::Extensions::glGetCompressedTexImage(GLenum target, GLint level, GLvoid *data) const
1792{
1793    if (_glGetCompressedTexImage)
1794    {
1795        _glGetCompressedTexImage(target, level, data);
1796    }
1797    else
1798    {
1799        notify(WARN)<<"Error: glGetCompressedTexImage not supported by OpenGL driver"<<std::endl;
1800    }
1801}
Note: See TracBrowser for help on using the browser.