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

Revision 10370, 65.4 kB (checked in by robert, 6 years ago)

From Wojciech Lewandowski, "Here are my changes:

- osg::Texture sets GL_MAX_TEXTURE_LEVEL if image uses fewer mipmaps than
number from computeNumberOfMipmaps (and it works!)
- DDS fix to read only available mipmaps
- DDS fixes to read / save 3D textures with mipmaps ( packing == 1 is
required)
- Few cosmetic DDS modifications and comments to make code cleaner (I hope)

Added _isTextureMaxLevelSupported variable to texture extensions. It
could be removed if OSG requires OpenGL version 1.2 by default.

Added simple ComputeImageSizeInBytes? function in DDSReaderWrites. In
my opinion it would be better if similar static method was defined for
Image. Then it could be used not only in DDS but other modules as well (I
noticed that Texture/Texture2D do similar computations).

Also attached is an example test.osg model with DDS without last mipmaps to
demonstrate the problem. When loaded into Viewer with current code and moved
far away, so that cube occupies 4 pixels, cube becomes red due to the issue
I described in earlier post. When you patch DDS reader writer with attched
code but no osg::Texture yet, cube becomes blank (at least on my
Windows/NVidia) When you also merge osg::Texture patch cube will look right
and mipmaps will be correct."

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