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

Revision 9539, 64.7 kB (checked in by robert, 5 years ago)

Warning fixes for VS, and removal of associated warning disables

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