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

Revision 10598, 90.1 kB (checked in by robert, 5 years ago)

Fixed warning about max texture size being smaller than the currently used texture pool size

  • 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
27#ifndef GL_TEXTURE_WRAP_R
28#define GL_TEXTURE_WRAP_R                 0x8072
29#endif
30
31#ifndef GL_TEXTURE_MAX_LEVEL
32#define GL_TEXTURE_MAX_LEVEL              0x813D
33#endif
34
35
36#ifndef GL_UNPACK_CLIENT_STORAGE_APPLE
37#define GL_UNPACK_CLIENT_STORAGE_APPLE    0x85B2
38#endif
39
40#ifndef GL_APPLE_vertex_array_range
41#define GL_VERTEX_ARRAY_RANGE_APPLE       0x851D
42#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
43#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
44#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
45#define GL_STORAGE_CACHED_APPLE           0x85BE
46#define GL_STORAGE_SHARED_APPLE           0x85BF
47#endif
48
49//#define DO_TIMING
50
51namespace osg {
52
53ApplicationUsageProxy Texture_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAX_TEXTURE_SIZE","Set the maximum size of textures.");
54
55typedef buffered_value< ref_ptr<Texture::Extensions> > BufferedExtensions;
56static BufferedExtensions s_extensions;
57
58unsigned int s_minimumNumberOfTextureObjectsToRetainInCache = 0;
59
60void Texture::setMinimumNumberOfTextureObjectsToRetainInCache(unsigned int minimum)
61{
62    s_minimumNumberOfTextureObjectsToRetainInCache = minimum;
63}
64
65unsigned int Texture::getMinimumNumberOfTextureObjectsToRetainInCache()
66{
67    return s_minimumNumberOfTextureObjectsToRetainInCache;
68}
69
70
71#define USE_NEW_TEXTURE_POOL 1
72
73void Texture::TextureObject::bind()
74{
75    glBindTexture( _profile._target, _id);
76    if (_set) _set->moveToBack(this);
77}
78
79void Texture::TextureObject::setAllocated(GLint     numMipmapLevels,
80                                          GLenum    internalFormat,
81                                          GLsizei   width,
82                                          GLsizei   height,
83                                          GLsizei   depth,
84                                          GLint     border)
85{
86    _allocated=true;
87    if (!match(_profile._target,numMipmapLevels,internalFormat,width,height,depth,border))
88    {
89        _profile.set(numMipmapLevels,internalFormat,width,height,depth,border);
90
91        if (_set)
92        {
93            // remove self from original set
94            _set->remove(this);
95
96            // get the new set for the new profile
97            _set = _set->getParent()->getTextureObjectSet(_profile);
98
99            // register self with new set.
100            _set->addToBack(this);
101        }
102    }
103}
104
105void Texture::TextureProfile::computeSize()
106{
107    unsigned int numBitsPerTexel = 32;
108
109    switch(_internalFormat)
110    {
111        case(1): numBitsPerTexel = 8; break;
112        case(GL_ALPHA): numBitsPerTexel = 8; break;
113        case(GL_LUMINANCE): numBitsPerTexel = 8; break;
114        case(GL_INTENSITY): numBitsPerTexel = 8; break;
115
116        case(GL_LUMINANCE_ALPHA): numBitsPerTexel = 16; break;
117        case(2): numBitsPerTexel = 16; break;
118
119        case(GL_RGB): numBitsPerTexel = 24; break;
120        case(GL_BGR): numBitsPerTexel = 24; break;
121        case(3): numBitsPerTexel = 24; break;
122
123        case(GL_RGBA): numBitsPerTexel = 32; break;
124        case(4): numBitsPerTexel = 32; break;
125
126        case(GL_COMPRESSED_ALPHA_ARB):           numBitsPerTexel = 4; break;
127        case(GL_COMPRESSED_INTENSITY_ARB):       numBitsPerTexel = 4; break;
128        case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB): numBitsPerTexel = 4; break;
129        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):   numBitsPerTexel = 4; break;
130        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):  numBitsPerTexel = 4; break;
131
132        case(GL_COMPRESSED_RGB_ARB):             numBitsPerTexel = 8; break;
133        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):  numBitsPerTexel = 8; break;
134        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):  numBitsPerTexel = 8; break;
135    }
136
137    _size = (unsigned int)(ceil(double(_width * _height * _depth * numBitsPerTexel)/8.0));
138
139    if (_numMipmapLevels>1)
140    {
141        unsigned int mipmapSize = _size / 4;
142        for(GLint i=0; i<_numMipmapLevels && mipmapSize!=0; ++i)
143        {
144            _size += mipmapSize;
145            mipmapSize /= 4;
146        }
147    }
148
149    // osg::notify(osg::NOTICE)<<"TO ("<<_width<<", "<<_height<<", "<<_depth<<") size="<<_size<<" numBitsPerTexel="<<numBitsPerTexel<<std::endl;
150}
151
152///////////////////////////////////////////////////////////////////////////////////////////////////////////
153//
154//  New texture object manager
155//
156Texture::TextureObjectSet::TextureObjectSet(TextureObjectManager* parent, const TextureProfile& profile):
157    _parent(parent),
158    _contextID(parent->getContextID()),
159    _profile(profile),
160    _numOfTextureObjects(0),
161    _head(0),
162    _tail(0)
163{
164}
165
166Texture::TextureObjectSet::~TextureObjectSet()
167{
168#if 0
169    osg::notify(osg::NOTICE)<<"TextureObjectSet::~TextureObjectSet(), _numOfTextureObjects="<<_numOfTextureObjects<<std::endl;
170    osg::notify(osg::NOTICE)<<"     _orphanedTextureObjects = "<<_orphanedTextureObjects.size()<<std::endl;
171    osg::notify(osg::NOTICE)<<"     _head = "<<_head<<std::endl;
172    osg::notify(osg::NOTICE)<<"     _tail = "<<_tail<<std::endl;
173#endif
174}
175
176bool Texture::TextureObjectSet::checkConsistency() const
177{
178    return true;
179
180    // osg::notify(osg::NOTICE)<<"TextureObjectSet::checkConsistency()"<<std::endl;
181    // check consistency of linked list.
182    unsigned int numInList = 0;
183    Texture::TextureObject* to = _head;
184    while(to!=0)
185    {
186        ++numInList;
187
188        if (to->_next)
189        {
190            if ((to->_next)->_previous != to)
191            {
192                osg::notify(osg::NOTICE)<<"Error (to->_next)->_previous != to "<<std::endl;
193                throw "Error (to->_next)->_previous != to ";
194            }
195        }
196        else
197        {
198            if (_tail != to)
199            {
200                osg::notify(osg::NOTICE)<<"Error _trail != to"<<std::endl;
201                throw "Error _trail != to";
202            }
203        }
204
205        to = to->_next;
206    }
207
208    unsigned int totalNumber = numInList + _orphanedTextureObjects.size();
209    if (totalNumber != _numOfTextureObjects)
210    {
211        osg::notify(osg::NOTICE)<<"Error numInList + _orphanedTextureObjects.size() != _numOfTextureObjects"<<std::endl;
212        osg::notify(osg::NOTICE)<<"    numInList = "<<numInList<<std::endl;
213        osg::notify(osg::NOTICE)<<"    _orphanedTextureObjects.size() = "<<_orphanedTextureObjects.size()<<std::endl;
214        osg::notify(osg::NOTICE)<<"    _pendingOrphanedTextureObjects.size() = "<<_pendingOrphanedTextureObjects.size()<<std::endl;
215        osg::notify(osg::NOTICE)<<"    _numOfTextureObjects = "<<_numOfTextureObjects<<std::endl;
216        throw "Error numInList + _orphanedTextureObjects.size() != _numOfTextureObjects";
217    }
218
219    return true;
220}
221
222void Texture::TextureObjectSet::handlePendingOrphandedTextureObjects()
223{
224    // osg::notify(osg::NOTICE)<<"handlePendingOrphandedTextureObjects()"<<_pendingOrphanedTextureObjects.size()<<std::endl;
225
226    if (_pendingOrphanedTextureObjects.empty()) return;
227
228    unsigned int numOrphaned = _pendingOrphanedTextureObjects.size();
229
230    for(TextureObjectList::iterator itr = _pendingOrphanedTextureObjects.begin();
231        itr != _pendingOrphanedTextureObjects.end();
232        ++itr)
233    {
234        TextureObject* to = itr->get();
235
236        _orphanedTextureObjects.push_back(to);
237
238        remove(to);
239
240#if 0
241        osg::notify(osg::NOTICE)<<"  HPOTO  after  _head = "<<_head<<std::endl;
242        osg::notify(osg::NOTICE)<<"  HPOTO  after _tail = "<<_tail<<std::endl;
243        osg::notify(osg::NOTICE)<<"  HPOTO  after to->_previous = "<<to->_previous<<std::endl;
244        osg::notify(osg::NOTICE)<<"  HPOTO  after to->_next = "<<to->_next<<std::endl;
245#endif
246
247    }
248
249
250    // update the TextureObjectManager's running total of active + orphaned TextureObjects
251    _parent->getNumberOrphanedTextureObjects() += numOrphaned;
252    _parent->getNumberActiveTextureObjects() -= numOrphaned;
253
254    _pendingOrphanedTextureObjects.clear();
255
256    checkConsistency();
257}
258
259void Texture::TextureObjectSet::flushAllDeletedTextureObjects()
260{
261    for(TextureObjectList::iterator itr = _orphanedTextureObjects.begin();
262        itr != _orphanedTextureObjects.end();
263        ++itr)
264    {
265
266        GLuint id = (*itr)->id();
267
268        // osg::notify(osg::NOTICE)<<"Deleting textureobject id="<<id<<std::endl;
269
270        glDeleteTextures( 1L, &id);
271    }
272
273    unsigned int numDeleted = _orphanedTextureObjects.size();
274    _numOfTextureObjects -= numDeleted;
275
276    // update the TextureObjectManager's running total of current pool size
277    _parent->getCurrTexturePoolSize() -= numDeleted*_profile._size;
278    _parent->getNumberOrphanedTextureObjects() -= numDeleted;
279    _parent->getNumberDeleted() += numDeleted;
280
281    _orphanedTextureObjects.clear();
282}
283
284void Texture::TextureObjectSet::discardAllDeletedTextureObjects()
285{
286    unsigned int numDiscarded = _orphanedTextureObjects.size();
287
288    _numOfTextureObjects -= numDiscarded;
289
290    // update the TextureObjectManager's running total of current pool size
291    _parent->setCurrTexturePoolSize( _parent->getCurrTexturePoolSize() - numDiscarded*_profile._size );
292
293    // update the number of active and orphaned TextureOjects
294    _parent->getNumberOrphanedTextureObjects() -= 1;
295    _parent->getNumberActiveTextureObjects() += 1;
296    _parent->getNumberDeleted() += 1;
297
298
299    // just clear the list as there is nothing else we can do with them when discarding them
300    _orphanedTextureObjects.clear();
301}
302
303void Texture::TextureObjectSet::flushDeletedTextureObjects(double currentTime, double& availableTime)
304{
305    // osg::notify(osg::NOTICE)<<"Texture::TextureObjectSet::flushDeletedTextureObjects(..) Not properly implemented yet"<<std::endl;
306
307    // if nothing to delete return
308    if (_orphanedTextureObjects.empty()) return;
309
310    // if no time available don't try to flush objects.
311    if (availableTime<=0.0) return;
312
313    // if we don't have too many orphaned texture objects then don't bother deleting them, as we can potentially reuse them later.
314    if (_parent->getNumberOrphanedTextureObjects()<=s_minimumNumberOfTextureObjectsToRetainInCache) return;
315
316    unsigned int numDeleted = 0;
317    unsigned int maxNumObjectsToDelete = _parent->getNumberOrphanedTextureObjects()-s_minimumNumberOfTextureObjectsToRetainInCache;
318    if (maxNumObjectsToDelete>4) maxNumObjectsToDelete = 4;
319
320    ElapsedTime timer;
321
322    TextureObjectList::iterator itr = _orphanedTextureObjects.begin();
323    for(;
324        itr != _orphanedTextureObjects.end() && timer.elapsedTime()<availableTime && numDeleted<maxNumObjectsToDelete;
325        ++itr)
326    {
327
328        GLuint id = (*itr)->id();
329
330        // osg::notify(osg::NOTICE)<<"Deleting textureobject id="<<id<<std::endl;
331
332        glDeleteTextures( 1L, &id);
333
334        ++numDeleted;
335    }
336
337    // osg::notify(osg::NOTICE)<<"Size before = "<<_orphanedTextureObjects.size();
338    _orphanedTextureObjects.erase(_orphanedTextureObjects.begin(), itr);
339    // osg::notify(osg::NOTICE)<<", after = "<<_orphanedTextureObjects.size()<<" numDeleted = "<<numDeleted<<std::endl;
340
341    // update the number of TO's in this TextureObjectSet
342    _numOfTextureObjects -= numDeleted;
343
344    _parent->setCurrTexturePoolSize( _parent->getCurrTexturePoolSize() - numDeleted*_profile._size );
345
346    // update the number of active and orphaned TextureOjects
347    _parent->getNumberOrphanedTextureObjects() -= numDeleted;
348    _parent->getNumberActiveTextureObjects() += numDeleted;
349    _parent->getNumberDeleted() += numDeleted;
350
351    availableTime -= timer.elapsedTime();
352}
353
354bool Texture::TextureObjectSet::makeSpace(unsigned int& size)
355{
356    if (!_orphanedTextureObjects.empty())
357    {
358        unsigned int sizeAvailable = _orphanedTextureObjects.size() * _profile._size;
359        if (size>sizeAvailable) size -= sizeAvailable;
360        else size = 0;
361
362        flushAllDeletedTextureObjects();
363    }
364
365    return size==0;
366}
367
368Texture::TextureObject* Texture::TextureObjectSet::takeFromOrphans(Texture* texture)
369{
370    // take front of orphaned list.
371    ref_ptr<TextureObject> to = _orphanedTextureObjects.front();
372
373    // remove from orphan list.
374    _orphanedTextureObjects.pop_front();
375
376    // assign to new texture
377    to->setTexture(texture);
378
379    // update the number of active and orphaned TextureOjects
380    _parent->getNumberOrphanedTextureObjects() -= 1;
381    _parent->getNumberActiveTextureObjects() += 1;
382
383    // place at back of active list
384    addToBack(to.get());
385
386    // osg::notify(osg::NOTICE)<<"Reusing orhpahned TextureObject, _numOfTextureObjects="<<_numOfTextureObjects<<std::endl;
387
388    return to.release();
389}
390
391
392Texture::TextureObject* Texture::TextureObjectSet::takeOrGenerate(Texture* texture)
393{
394    // see if we can recyle TextureObject from the orphane list
395    if (!_pendingOrphanedTextureObjects.empty())
396    {
397        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
398        handlePendingOrphandedTextureObjects();
399        return takeFromOrphans(texture);
400    }
401    else if (!_orphanedTextureObjects.empty())
402    {
403        return takeFromOrphans(texture);
404    }
405
406    unsigned int minFrameNumber = _parent->getFrameNumber();
407
408    // see if we can reuse TextureObject by taking the least recently used active TextureObject
409    if ((_parent->getMaxTexturePoolSize()!=0) &&
410        (!_parent->hasSpace(_profile._size)) &&
411        (_numOfTextureObjects>1) &&
412        (_head != 0) &&
413        (_head->_frameLastUsed<minFrameNumber))
414    {
415
416        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
417
418        ref_ptr<TextureObject> to = _head;
419
420        ref_ptr<Texture> original_texture = to->getTexture();
421
422        if (original_texture.valid())
423        {
424            original_texture->setTextureObject(_contextID,0);
425            // osg::notify(osg::NOTICE)<<"TextureObjectSet="<<this<<": Reusing an active TextureObject "<<to.get()<<" _numOfTextureObjects="<<_numOfTextureObjects<<" width="<<_profile._width<<" height="<<_profile._height<<std::endl;
426        }
427        else
428        {
429            // osg::notify(osg::NOTICE)<<"Reusing a recently orphaned active TextureObject "<<to.get()<<std::endl;
430        }
431
432        moveToBack(to.get());
433
434        // assign to new texture
435        to->setTexture(texture);
436
437        return to.release();
438    }
439
440    //
441    // no TextureObjects available to recyle so have to create one from scratch
442    //
443    GLuint id;
444    glGenTextures( 1L, &id );
445
446    TextureObject* to = new Texture::TextureObject(const_cast<Texture*>(texture),id,_profile);
447    to->_set = this;
448    ++_numOfTextureObjects;
449
450    // update the current texture pool size
451    _parent->getCurrTexturePoolSize() += _profile._size;
452    _parent->getNumberActiveTextureObjects() += 1;
453
454    addToBack(to);
455
456    // osg::notify(osg::NOTICE)<<"Created new TextureObject, _numOfTextureObjects "<<_numOfTextureObjects<<std::endl;
457
458    return to;
459}
460
461void Texture::TextureObjectSet::moveToBack(Texture::TextureObject* to)
462{
463#if 0
464    osg::notify(osg::NOTICE)<<"TextureObjectSet::moveToBack("<<to<<")"<<std::endl;
465    osg::notify(osg::NOTICE)<<"    before _head = "<<_head<<std::endl;
466    osg::notify(osg::NOTICE)<<"    before _tail = "<<_tail<<std::endl;
467    osg::notify(osg::NOTICE)<<"    before to->_previous = "<<to->_previous<<std::endl;
468    osg::notify(osg::NOTICE)<<"    before to->_next = "<<to->_next<<std::endl;
469#endif
470
471    to->_frameLastUsed = _parent->getFrameNumber();
472
473    // nothing to do if we are already tail
474    if (to==_tail) return;
475
476    // if no tail exists then assign 'to' as tail and head
477    if (_tail==0)
478    {
479        osg::notify(osg::NOTICE)<<"Error ***************** Should not get here !!!!!!!!!"<<std::endl;
480        _head = to;
481        _tail = to;
482        return;
483    }
484
485    if (to->_next==0)
486    {
487        osg::notify(osg::NOTICE)<<"Error ***************** Should not get here either !!!!!!!!!"<<std::endl;
488        return;
489    }
490
491
492    if (to->_previous)
493    {
494        (to->_previous)->_next = to->_next;
495    }
496    else
497    {
498        // 'to' is the head, so moving it to the back will mean we need a new head
499        if (to->_next)
500        {
501            _head = to->_next;
502        }
503    }
504
505    (to->_next)->_previous = to->_previous;
506
507    _tail->_next = to;
508
509    to->_previous = _tail;
510    to->_next = 0;
511
512    _tail = to;
513
514#if 0
515    osg::notify(osg::NOTICE)<<"  m2B   after  _head = "<<_head<<std::endl;
516    osg::notify(osg::NOTICE)<<"  m2B   after _tail = "<<_tail<<std::endl;
517    osg::notify(osg::NOTICE)<<"  m2B   after to->_previous = "<<to->_previous<<std::endl;
518    osg::notify(osg::NOTICE)<<"  m2B   after to->_next = "<<to->_next<<std::endl;
519#endif
520    checkConsistency();
521}
522
523void Texture::TextureObjectSet::addToBack(Texture::TextureObject* to)
524{
525#if 0
526    osg::notify(osg::NOTICE)<<"TextureObjectSet::addToBack("<<to<<")"<<std::endl;
527    osg::notify(osg::NOTICE)<<"    before _head = "<<_head<<std::endl;
528    osg::notify(osg::NOTICE)<<"    before _tail = "<<_tail<<std::endl;
529    osg::notify(osg::NOTICE)<<"    before to->_previous = "<<to->_previous<<std::endl;
530    osg::notify(osg::NOTICE)<<"    before to->_next = "<<to->_next<<std::endl;
531#endif
532
533    if (to->_previous !=0 || to->_next !=0)
534    {
535        moveToBack(to);
536    }
537    else
538    {
539        to->_frameLastUsed = _parent->getFrameNumber();
540
541        if (_tail) _tail->_next = to;
542        to->_previous = _tail;
543
544        if (!_head) _head = to;
545        _tail = to;
546    }
547#if 0
548    osg::notify(osg::NOTICE)<<"  a2B  after  _head = "<<_head<<std::endl;
549    osg::notify(osg::NOTICE)<<"  a2B   after _tail = "<<_tail<<std::endl;
550    osg::notify(osg::NOTICE)<<"  a2B   after to->_previous = "<<to->_previous<<std::endl;
551    osg::notify(osg::NOTICE)<<"  a2B   after to->_next = "<<to->_next<<std::endl;
552#endif
553    checkConsistency();
554}
555
556void Texture::TextureObjectSet::orphan(Texture::TextureObject* to)
557{
558    // osg::notify(osg::NOTICE)<<"TextureObjectSet::orphan("<<to<<")"<<std::endl;
559
560    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
561
562    // disconnect from original texture
563    to->setTexture(0);
564
565    // add orphan 'to' to the pending list of orphans, these will then be
566    // handled in the handlePendingOrphandedTextureObjects() where the TO's
567    // will be removed from the active list, and then placed in the orhpanTextureObject
568    // list.  This double buffered approach to handling orphaned TO's is used
569    // to avoid having to mutex the process of appling active TO's.
570    _pendingOrphanedTextureObjects.push_back(to);
571
572#if 0
573    osg::notify(osg::NOTICE)<<"TextureObjectSet::orphan("<<to<<")  _pendingOrphanedTextureObjects.size()="<<_pendingOrphanedTextureObjects.size()<<std::endl;
574    osg::notify(osg::NOTICE)<<"                                    _orphanedTextureObjects.size()="<<_orphanedTextureObjects.size()<<std::endl;
575#endif
576}
577
578void Texture::TextureObjectSet::remove(Texture::TextureObject* to)
579{
580    if (to->_previous!=0)
581    {
582        (to->_previous)->_next = to->_next;
583    }
584    else
585    {
586        // 'to' was head so assign _head to the next in list
587        _head = to->_next;
588    }
589
590    if (to->_next!=0)
591    {
592        (to->_next)->_previous = to->_previous;
593    }
594    else
595    {
596        // 'to' was tail so assing tail to the previous in list
597        _tail = to->_previous;
598    }
599
600    // reset the 'to' list pointers as it's no longer in the active list.
601    to->_next = 0;
602    to->_previous = 0;
603}
604
605
606Texture::TextureObjectManager::TextureObjectManager(unsigned int contextID):
607    _contextID(contextID),
608    _numActiveTextureObjects(0),
609    _numOrphanedTextureObjects(0),
610    _currTexturePoolSize(0),
611    _maxTexturePoolSize(0),
612    _frameNumber(0),
613    _numFrames(0),
614    _numDeleted(0),
615    _deleteTime(0.0),
616    _numGenerated(0),
617    _generateTime(0.0),
618    _numApplied(0),
619    _applyTime(0.0)
620{
621}
622
623void Texture::TextureObjectManager::setMaxTexturePoolSize(unsigned int size)
624{
625    if (_maxTexturePoolSize == size) return;
626
627    if (size<_currTexturePoolSize)
628    {
629        osg::notify(osg::NOTICE)<<"Warning: new MaxTexturePoolSize="<<size<<" is smaller than current TexturePoolSize="<<_currTexturePoolSize<<std::endl;
630    }
631
632    _maxTexturePoolSize = size;
633}
634
635bool Texture::TextureObjectManager::makeSpace(unsigned int size)
636{
637    for(TextureSetMap::iterator itr = _textureSetMap.begin();
638        itr != _textureSetMap.end() && size>0;
639        ++itr)
640    {
641        if ((*itr).second->makeSpace(size)) return true;
642    }
643
644    return size==0;
645}
646
647
648Texture::TextureObject* Texture::TextureObjectManager::generateTextureObject(const Texture* texture, GLenum target)
649{
650    return generateTextureObject(texture, target, 0, 0, 0, 0, 0, 0);
651}
652
653Texture::TextureObject* Texture::TextureObjectManager::generateTextureObject(const Texture* texture,
654                                             GLenum    target,
655                                             GLint     numMipmapLevels,
656                                             GLenum    internalFormat,
657                                             GLsizei   width,
658                                             GLsizei   height,
659                                             GLsizei   depth,
660                                             GLint     border)
661{
662    ElapsedTime elapsedTime(&(getGenerateTime()));
663    ++getNumberGenerated();
664
665    Texture::TextureProfile profile(target,numMipmapLevels,internalFormat,width,height,depth,border);
666    TextureObjectSet* tos = getTextureObjectSet(profile);
667    return tos->takeOrGenerate(const_cast<Texture*>(texture));
668}
669
670Texture::TextureObjectSet* Texture::TextureObjectManager::getTextureObjectSet(const TextureProfile& profile)
671{
672    osg::ref_ptr<Texture::TextureObjectSet>& tos = _textureSetMap[profile];
673    if (!tos) tos = new Texture::TextureObjectSet(this, profile);
674    return tos.get();
675}
676
677void Texture::TextureObjectManager::handlePendingOrphandedTextureObjects()
678{
679    for(TextureSetMap::iterator itr = _textureSetMap.begin();
680        itr != _textureSetMap.end();
681        ++itr)
682    {
683        (*itr).second->handlePendingOrphandedTextureObjects();
684    }
685}
686
687void Texture::TextureObjectManager::flushAllDeletedTextureObjects()
688{
689    ElapsedTime elapsedTime(&(getDeleteTime()));
690
691    for(TextureSetMap::iterator itr = _textureSetMap.begin();
692        itr != _textureSetMap.end();
693        ++itr)
694    {
695        (*itr).second->flushAllDeletedTextureObjects();
696    }
697}
698
699void Texture::TextureObjectManager::discardAllDeletedTextureObjects()
700{
701    for(TextureSetMap::iterator itr = _textureSetMap.begin();
702        itr != _textureSetMap.end();
703        ++itr)
704    {
705        (*itr).second->discardAllDeletedTextureObjects();
706    }
707}
708
709void Texture::TextureObjectManager::flushDeletedTextureObjects(double currentTime, double& availableTime)
710{
711    ElapsedTime elapsedTime(&(getDeleteTime()));
712
713    for(TextureSetMap::iterator itr = _textureSetMap.begin();
714        (itr != _textureSetMap.end()) && (availableTime > 0.0);
715        ++itr)
716    {
717        (*itr).second->flushDeletedTextureObjects(currentTime, availableTime);
718    }
719}
720
721void Texture::TextureObjectManager::releaseTextureObject(Texture::TextureObject* to)
722{
723    if (to->_set) to->_set->orphan(to);
724    else osg::notify(osg::NOTICE)<<"TextureObjectManager::releaseTextureObject(Texture::TextureObject* to) Not implemented yet"<<std::endl;
725}
726
727
728void Texture::TextureObjectManager::newFrame(osg::FrameStamp* fs)
729{
730    if (fs) _frameNumber = fs->getFrameNumber();
731    else ++_frameNumber;
732
733    ++_numFrames;
734}
735
736void Texture::TextureObjectManager::reportStats()
737{
738    double numFrames(_numFrames==0 ? 1.0 : _numFrames);
739    osg::notify(osg::NOTICE)<<"TextureObjectMananger::reportStats()"<<std::endl;
740    osg::notify(osg::NOTICE)<<"   total _numOfTextureObjects="<<_numActiveTextureObjects<<", _numOrphanedTextureObjects="<<_numOrphanedTextureObjects<<" _currTexturePoolSize="<<_currTexturePoolSize<<std::endl;
741    osg::notify(osg::NOTICE)<<"   total _numGenerated="<<_numGenerated<<", _generateTime="<<_generateTime<<", averagePerFrame="<<_generateTime/numFrames*1000.0<<"ms"<<std::endl;
742    osg::notify(osg::NOTICE)<<"   total _numDeleted="<<_numDeleted<<", _deleteTime="<<_deleteTime<<", averagePerFrame="<<_deleteTime/numFrames*1000.0<<"ms"<<std::endl;
743    osg::notify(osg::NOTICE)<<"   total _numApplied="<<_numApplied<<", _applyTime="<<_applyTime<<", averagePerFrame="<<_applyTime/numFrames*1000.0<<"ms"<<std::endl;
744}
745
746void Texture::TextureObjectManager::resetStats()
747{
748    _numFrames = 0;
749    _numDeleted = 0;
750    _deleteTime = 0;
751
752    _numGenerated = 0;
753    _generateTime = 0;
754
755    _numApplied = 0;
756    _applyTime = 0;
757}
758
759
760
761osg::ref_ptr<Texture::TextureObjectManager>& Texture::getTextureObjectManager(unsigned int contextID)
762{
763    typedef osg::buffered_object< ref_ptr<Texture::TextureObjectManager> > TextureObjectManagerBuffer;
764    static TextureObjectManagerBuffer s_TextureObjectManager;
765    if (!s_TextureObjectManager[contextID]) s_TextureObjectManager[contextID] = new Texture::TextureObjectManager(contextID);
766    return s_TextureObjectManager[contextID];
767}
768
769
770#if USE_NEW_TEXTURE_POOL
771
772Texture::TextureObject* Texture::generateTextureObject(const Texture* texture, unsigned int contextID, GLenum target)
773{
774    return getTextureObjectManager(contextID)->generateTextureObject(texture, target);
775}
776
777Texture::TextureObject* Texture::generateTextureObject(const Texture* texture, unsigned int contextID,
778                                             GLenum    target,
779                                             GLint     numMipmapLevels,
780                                             GLenum    internalFormat,
781                                             GLsizei   width,
782                                             GLsizei   height,
783                                             GLsizei   depth,
784                                             GLint     border)
785{
786    return getTextureObjectManager(contextID)->generateTextureObject(texture,target,numMipmapLevels,internalFormat,width,height,depth,border);
787}
788
789void Texture::flushAllDeletedTextureObjects(unsigned int contextID)
790{
791    getTextureObjectManager(contextID)->flushAllDeletedTextureObjects();
792}
793
794void Texture::discardAllDeletedTextureObjects(unsigned int contextID)
795{
796    getTextureObjectManager(contextID)->discardAllDeletedTextureObjects();
797}
798
799void Texture::flushDeletedTextureObjects(unsigned int contextID,double currentTime, double& availbleTime)
800{
801    getTextureObjectManager(contextID)->flushDeletedTextureObjects(currentTime, availbleTime);
802}
803
804void Texture::releaseTextureObject(unsigned int contextID, Texture::TextureObject* to)
805{
806    getTextureObjectManager(contextID)->releaseTextureObject(to);
807}
808
809#else
810
811///////////////////////////////////////////////////////////////////////////////////////////////////////////
812//
813//  Original texture object manager
814//
815class OriginalTextureObjectManager : public osg::Referenced
816{
817public:
818
819    OriginalTextureObjectManager():
820        _expiryDelay(0.0)
821    {
822        // printf("Constructing OriginalTextureObjectManager\n");
823    }
824
825    ~OriginalTextureObjectManager()
826    {
827        // printf("Destructing OriginalTextureObjectManager\n");
828    }
829
830    virtual Texture::TextureObject* generateTextureObject(Texture* texture, unsigned int contextID,GLenum target);
831
832    virtual Texture::TextureObject* generateTextureObject(Texture* texture, unsigned int contextID,
833                                                 GLenum    target,
834                                                 GLint     numMipmapLevels,
835                                                 GLenum    internalFormat,
836                                                 GLsizei   width,
837                                                 GLsizei   height,
838                                                 GLsizei   depth,
839                                                 GLint     border);
840
841    virtual Texture::TextureObject* reuseTextureObject(Texture* texture, unsigned int contextID,
842                                              GLenum    target,
843                                              GLint     numMipmapLevels,
844                                              GLenum    internalFormat,
845                                              GLsizei   width,
846                                              GLsizei   height,
847                                              GLsizei   depth,
848                                              GLint     border);
849
850    inline Texture::TextureObject* reuseOrGenerateTextureObject(Texture* texture, unsigned int contextID,
851                                              GLenum    target,
852                                              GLint     numMipmapLevels,
853                                              GLenum    internalFormat,
854                                              GLsizei   width,
855                                              GLsizei   height,
856                                              GLsizei   depth,
857                                              GLint     border)
858    {
859        Texture::TextureObject* to = reuseTextureObject(texture, contextID,target,numMipmapLevels,internalFormat,width,height,depth,border);
860        if (to) return to;
861        else return generateTextureObject(texture, contextID,target,numMipmapLevels,internalFormat,width,height,depth,border);
862    }                                                     
863
864    void flushAllTextureObjects(unsigned int contextID);
865
866    void discardAllTextureObjects(unsigned int contextID);
867
868    void flushTextureObjects(unsigned int contextID,double currentTime, double& availableTime);
869
870    void setExpiryDelay(double expiryDelay) { _expiryDelay = expiryDelay; }
871
872    double getExpiryDelay() const { return _expiryDelay; }
873
874    /** How long to keep unused texture objects before deletion. */
875    double                  _expiryDelay;
876
877    typedef osg::buffered_object<Texture::TextureObjectList> TextureObjectListMap;
878    TextureObjectListMap    _textureObjectListMap;
879
880    // mutex to keep access serialized.
881    OpenThreads::Mutex      _mutex;
882};
883
884unsigned int Texture::s_numberTextureReusedLastInLastFrame = 0;
885unsigned int Texture::s_numberNewTextureInLastFrame = 0;
886unsigned int Texture::s_numberDeletedTextureInLastFrame = 0;
887
888
889static ref_ptr<OriginalTextureObjectManager> s_textureObjectManager = new OriginalTextureObjectManager;
890
891
892Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Texture* texture, unsigned int contextID,GLenum target)
893{
894    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
895    ElapsedTime elapsedTime(&(tom->getGenerateTime()));
896    tom->getNumberGenerated()++;
897
898    GLuint id;
899    glGenTextures( 1L, &id );
900
901    return new Texture::TextureObject(texture, id,target);
902}
903
904static int s_number = 0;
905
906Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Texture* texture, unsigned int contextID,
907                                                                             GLenum    target,
908                                                                             GLint     numMipmapLevels,
909                                                                             GLenum    internalFormat,
910                                                                             GLsizei   width,
911                                                                             GLsizei   height,
912                                                                             GLsizei   depth,
913                                                                             GLint     border)
914{
915    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
916    ElapsedTime elapsedTime(&(tom->getGenerateTime()));
917    tom->getNumberGenerated()++;
918
919    ++s_number;
920    ++Texture::s_numberNewTextureInLastFrame;
921    // notify(NOTICE)<<"creating new texture object "<<s_number<<std::endl;
922
923    // no useable texture object found so return 0
924    GLuint id;
925    glGenTextures( 1L, &id );
926
927    return new Texture::TextureObject(texture, id,target,numMipmapLevels,internalFormat,width,height,depth,border);
928}
929
930Texture::TextureObject* OriginalTextureObjectManager::reuseTextureObject(Texture* texture, unsigned int contextID,
931                                                                             GLenum    target,
932                                                                             GLint     numMipmapLevels,
933                                                                             GLenum    internalFormat,
934                                                                             GLsizei   width,
935                                                                             GLsizei   height,
936                                                                             GLsizei   depth,
937                                                                             GLint     border)
938{
939    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
940    ElapsedTime elapsedTime(&(tom->getGenerateTime()));
941    tom->getNumberGenerated()++;
942
943    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
944
945    Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
946    for(Texture::TextureObjectList::iterator itr = tol.begin();
947        itr != tol.end();
948        ++itr)
949    {
950        if ((*itr)->match(target,numMipmapLevels,internalFormat,width,height,depth,border))
951        {
952            // found usable texture object.
953            Texture::TextureObject* textureObject = (*itr).release();
954            tol.erase(itr);
955           
956            // notify(NOTICE)<<"reusing texture object "<<std::endl;
957           
958            ++Texture::s_numberTextureReusedLastInLastFrame;
959
960            textureObject->setTexture(texture);
961
962            return textureObject;
963        }
964    }
965   
966    return 0;
967}
968
969void OriginalTextureObjectManager::flushAllTextureObjects(unsigned int contextID)
970{
971    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
972    ElapsedTime elapsedTime(&(tom->getDeleteTime()));
973
974    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
975
976    Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
977
978    // osg::notify(osg::INFO)<<"Flushing texture objects num="<<tol.size()<<" contextID="<<contextID<<std::endl;
979
980    for(Texture::TextureObjectList::iterator itr=tol.begin();
981        itr!=tol.end();
982        ++itr)
983    {
984        // osg::notify(osg::NOTICE)<<"  deleting texture object "<<(*itr)->_id<<std::endl;
985        GLuint id = (*itr)->id();
986        glDeleteTextures( 1L, &id);
987
988        tom->getNumberDeleted()++;
989    }
990    tol.clear();
991}
992
993void OriginalTextureObjectManager::discardAllTextureObjects(unsigned int contextID)
994{
995    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
996
997    Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
998    tol.clear();
999}
1000
1001void OriginalTextureObjectManager::flushTextureObjects(unsigned int contextID,double currentTime, double& availableTime)
1002{
1003
1004    // if no time available don't try to flush objects.
1005    if (availableTime<=0.0) return;
1006
1007    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
1008    ElapsedTime timer(&(tom->getDeleteTime()));
1009
1010    unsigned int numObjectsDeleted = 0;
1011    unsigned int maxNumObjectsToDelete = 4;
1012
1013    {
1014        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
1015
1016        Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
1017
1018        // reset the time of any uninitialized objects.
1019        Texture::TextureObjectList::iterator itr;
1020        for(itr=tol.begin();
1021            itr!=tol.end();
1022            ++itr)
1023        {
1024            if ((*itr)->getTimeStamp()==0.0) (*itr)->setTimeStamp(currentTime);
1025        }
1026
1027        double expiryTime = currentTime-_expiryDelay;
1028
1029        for(itr=tol.begin();
1030            itr!=tol.end() && timer.elapsedTime()<availableTime && tol.size()>s_minimumNumberOfTextureObjectsToRetainInCache && numObjectsDeleted<maxNumObjectsToDelete;
1031            )
1032        {
1033            if ((*itr)->getTimeStamp()<=expiryTime)
1034            {
1035                --s_number;
1036                ++Texture::s_numberDeletedTextureInLastFrame;
1037
1038                GLuint id = (*itr)->id();
1039                glDeleteTextures( 1L, &id);
1040                itr = tol.erase(itr);
1041                ++numObjectsDeleted;
1042            }
1043            else
1044            {
1045                ++itr;
1046            }
1047        }
1048    }
1049
1050    tom->getNumberDeleted()+=numObjectsDeleted;
1051       
1052    availableTime -= timer.elapsedTime();
1053}
1054
1055
1056static OriginalTextureObjectManager* getOriginalTextureObjectManager()
1057{
1058    return s_textureObjectManager.get();
1059}
1060
1061
1062Texture::TextureObject* Texture::generateTextureObject(const Texture* texture, unsigned int contextID,GLenum target)
1063{
1064    if (getOriginalTextureObjectManager()) return getOriginalTextureObjectManager()->generateTextureObject(const_cast<osg::Texture*>(texture),contextID,target);
1065    else return 0;
1066}
1067
1068Texture::TextureObject* Texture::generateTextureObject(const Texture* texture, unsigned int contextID,
1069                                             GLenum    target,
1070                                             GLint     numMipmapLevels,
1071                                             GLenum    internalFormat,
1072                                             GLsizei   width,
1073                                             GLsizei   height,
1074                                             GLsizei   depth,
1075                                             GLint     border)
1076{
1077    if (getOriginalTextureObjectManager())
1078        return getOriginalTextureObjectManager()->reuseOrGenerateTextureObject(const_cast<osg::Texture*>(texture),
1079                                             contextID,
1080                                             target,
1081                                             numMipmapLevels,
1082                                             internalFormat,
1083                                             width,
1084                                             height,
1085                                             depth,
1086                                             border);
1087    else
1088        return 0;
1089}                                             
1090
1091void Texture::flushAllDeletedTextureObjects(unsigned int contextID)
1092{
1093    if (getOriginalTextureObjectManager()) getOriginalTextureObjectManager()->flushAllTextureObjects(contextID);
1094}
1095
1096void Texture::discardAllDeletedTextureObjects(unsigned int contextID)
1097{
1098    if (getOriginalTextureObjectManager()) getOriginalTextureObjectManager()->discardAllTextureObjects(contextID);
1099}
1100
1101void Texture::flushDeletedTextureObjects(unsigned int contextID,double currentTime, double& availbleTime)
1102{
1103    if (getOriginalTextureObjectManager()) getOriginalTextureObjectManager()->flushTextureObjects(contextID, currentTime, availbleTime);
1104}
1105
1106void Texture::releaseTextureObject(unsigned int contextID, Texture::TextureObject* to)
1107{
1108    if (getOriginalTextureObjectManager())
1109    {
1110        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getOriginalTextureObjectManager()->_mutex);
1111        getOriginalTextureObjectManager()->_textureObjectListMap[contextID].push_back(to);
1112    }
1113}
1114
1115#endif
1116
1117
1118
1119Texture::Texture():
1120            _wrap_s(CLAMP),
1121            _wrap_t(CLAMP),
1122            _wrap_r(CLAMP),
1123            _min_filter(LINEAR_MIPMAP_LINEAR), // trilinear
1124            _mag_filter(LINEAR),
1125            _maxAnisotropy(1.0f),
1126            _useHardwareMipMapGeneration(true),
1127            _unrefImageDataAfterApply(false),
1128            _clientStorageHint(false),
1129            _resizeNonPowerOfTwoHint(true),
1130            _borderColor(0.0, 0.0, 0.0, 0.0),
1131            _borderWidth(0),
1132            _internalFormatMode(USE_IMAGE_DATA_FORMAT),
1133            _internalFormatType(NORMALIZED),
1134            _internalFormat(0),
1135            _sourceFormat(0),
1136            _sourceType(0),
1137            _use_shadow_comparison(false),
1138            _shadow_compare_func(LEQUAL),
1139            _shadow_texture_mode(LUMINANCE),
1140            _shadow_ambient(0)
1141{
1142}
1143
1144Texture::Texture(const Texture& text,const CopyOp& copyop):
1145            StateAttribute(text,copyop),
1146            _wrap_s(text._wrap_s),
1147            _wrap_t(text._wrap_t),
1148            _wrap_r(text._wrap_r),
1149            _min_filter(text._min_filter),
1150            _mag_filter(text._mag_filter),
1151            _maxAnisotropy(text._maxAnisotropy),
1152            _useHardwareMipMapGeneration(text._useHardwareMipMapGeneration),
1153            _unrefImageDataAfterApply(text._unrefImageDataAfterApply),
1154            _clientStorageHint(text._clientStorageHint),
1155            _resizeNonPowerOfTwoHint(text._resizeNonPowerOfTwoHint),
1156            _borderColor(text._borderColor),
1157            _borderWidth(text._borderWidth),
1158            _internalFormatMode(text._internalFormatMode),
1159            _internalFormatType(text._internalFormatType),
1160            _internalFormat(text._internalFormat),
1161            _sourceFormat(text._sourceFormat),
1162            _sourceType(text._sourceType),
1163            _use_shadow_comparison(text._use_shadow_comparison),
1164            _shadow_compare_func(text._shadow_compare_func),
1165            _shadow_texture_mode(text._shadow_texture_mode),
1166            _shadow_ambient(text._shadow_ambient)
1167{
1168}
1169
1170Texture::~Texture()
1171{
1172    // delete old texture objects.
1173    dirtyTextureObject();
1174}
1175
1176int Texture::compareTexture(const Texture& rhs) const
1177{
1178    COMPARE_StateAttribute_Parameter(_wrap_s)
1179    COMPARE_StateAttribute_Parameter(_wrap_t)
1180    COMPARE_StateAttribute_Parameter(_wrap_r)
1181    COMPARE_StateAttribute_Parameter(_min_filter)
1182    COMPARE_StateAttribute_Parameter(_mag_filter)
1183    COMPARE_StateAttribute_Parameter(_maxAnisotropy)
1184    COMPARE_StateAttribute_Parameter(_useHardwareMipMapGeneration)
1185    COMPARE_StateAttribute_Parameter(_internalFormatMode)
1186
1187    // only compare _internalFomat is it has alrady been set in both lhs, and rhs
1188    if (_internalFormat!=0 && rhs._internalFormat!=0)
1189    {
1190        COMPARE_StateAttribute_Parameter(_internalFormat)
1191    }
1192
1193    COMPARE_StateAttribute_Parameter(_sourceFormat)
1194    COMPARE_StateAttribute_Parameter(_sourceType)
1195
1196    COMPARE_StateAttribute_Parameter(_use_shadow_comparison)
1197    COMPARE_StateAttribute_Parameter(_shadow_compare_func)
1198    COMPARE_StateAttribute_Parameter(_shadow_texture_mode)
1199    COMPARE_StateAttribute_Parameter(_shadow_ambient)
1200
1201    COMPARE_StateAttribute_Parameter(_unrefImageDataAfterApply)
1202    COMPARE_StateAttribute_Parameter(_clientStorageHint)
1203    COMPARE_StateAttribute_Parameter(_resizeNonPowerOfTwoHint)
1204
1205    COMPARE_StateAttribute_Parameter(_internalFormatType);
1206   
1207    return 0;
1208}
1209
1210int Texture::compareTextureObjects(const Texture& rhs) const
1211{
1212    if (_textureObjectBuffer.size()<rhs._textureObjectBuffer.size()) return -1;
1213    if (rhs._textureObjectBuffer.size()<_textureObjectBuffer.size()) return 1;
1214    for(unsigned int i=0; i<_textureObjectBuffer.size(); ++i)
1215    {
1216        if (_textureObjectBuffer[i] < rhs._textureObjectBuffer[i]) return -1;
1217        else if (rhs._textureObjectBuffer[i] < _textureObjectBuffer[i]) return 1;
1218    }
1219    return 0;
1220}
1221
1222void Texture::setWrap(WrapParameter which, WrapMode wrap)
1223{
1224    switch( which )
1225    {
1226        case WRAP_S : _wrap_s = wrap; dirtyTextureParameters(); break;
1227        case WRAP_T : _wrap_t = wrap; dirtyTextureParameters(); break;
1228        case WRAP_R : _wrap_r = wrap; dirtyTextureParameters(); break;
1229        default : notify(WARN)<<"Error: invalid 'which' passed Texture::setWrap("<<(unsigned int)which<<","<<(unsigned int)wrap<<")"<<std::endl; break;
1230    }
1231   
1232}
1233
1234
1235Texture::WrapMode Texture::getWrap(WrapParameter which) const
1236{
1237    switch( which )
1238    {
1239        case WRAP_S : return _wrap_s;
1240        case WRAP_T : return _wrap_t;
1241        case WRAP_R : return _wrap_r;
1242        default : notify(WARN)<<"Error: invalid 'which' passed Texture::getWrap(which)"<<std::endl; return _wrap_s;
1243    }
1244}
1245
1246
1247void Texture::setFilter(FilterParameter which, FilterMode filter)
1248{
1249    switch( which )
1250    {
1251        case MIN_FILTER : _min_filter = filter; dirtyTextureParameters(); break;
1252        case MAG_FILTER : _mag_filter = filter; dirtyTextureParameters(); break;
1253        default : notify(WARN)<<"Error: invalid 'which' passed Texture::setFilter("<<(unsigned int)which<<","<<(unsigned int)filter<<")"<<std::endl; break;
1254    }
1255}
1256
1257
1258Texture::FilterMode Texture::getFilter(FilterParameter which) const
1259{
1260    switch( which )
1261    {
1262        case MIN_FILTER : return _min_filter;
1263        case MAG_FILTER : return _mag_filter;
1264        default : notify(WARN)<<"Error: invalid 'which' passed Texture::getFilter(which)"<< std::endl; return _min_filter;
1265    }
1266}
1267
1268void Texture::setMaxAnisotropy(float anis)
1269{
1270    if (_maxAnisotropy!=anis)
1271    {
1272        _maxAnisotropy = anis;
1273        dirtyTextureParameters();
1274    }
1275}
1276
1277
1278/** Force a recompile on next apply() of associated OpenGL texture objects.*/
1279void Texture::dirtyTextureObject()
1280{
1281    for(unsigned int i=0; i<_textureObjectBuffer.size();++i)
1282    {
1283        if (_textureObjectBuffer[i].valid())
1284        {
1285            Texture::releaseTextureObject(i, _textureObjectBuffer[i].get());
1286            _textureObjectBuffer[i] = 0;
1287        }
1288    }
1289}
1290
1291void Texture::dirtyTextureParameters()
1292{
1293    _texParametersDirtyList.setAllElementsTo(1);
1294}
1295
1296void Texture::allocateMipmapLevels()
1297{
1298    _texMipmapGenerationDirtyList.setAllElementsTo(1);
1299}
1300
1301void Texture::computeInternalFormatWithImage(const osg::Image& image) const
1302{
1303    GLint internalFormat = image.getInternalTextureFormat();
1304
1305    if (_internalFormatMode==USE_IMAGE_DATA_FORMAT)
1306    {
1307        internalFormat = image.getInternalTextureFormat();
1308    }
1309    else if (_internalFormatMode==USE_USER_DEFINED_FORMAT)
1310    {
1311        internalFormat = _internalFormat;
1312    }
1313    else
1314    {
1315
1316        const unsigned int contextID = 0; // state.getContextID();  // set to 0 right now, assume same parameters for each graphics context...
1317        const Extensions* extensions = getExtensions(contextID,true);
1318
1319        switch(_internalFormatMode)
1320        {
1321        case(USE_ARB_COMPRESSION):
1322            if (extensions->isTextureCompressionARBSupported())
1323            {
1324                switch(image.getPixelFormat())
1325                {
1326                    case(1): internalFormat = GL_COMPRESSED_ALPHA_ARB; break;
1327                    case(2): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
1328                    case(3): internalFormat = GL_COMPRESSED_RGB_ARB; break;
1329                    case(4): internalFormat = GL_COMPRESSED_RGBA_ARB; break;
1330                    case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_ARB; break;
1331                    case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_ARB; break;
1332                    case(GL_ALPHA): internalFormat = GL_COMPRESSED_ALPHA_ARB; break;
1333                    case(GL_LUMINANCE): internalFormat = GL_COMPRESSED_LUMINANCE_ARB; break;
1334                    case(GL_LUMINANCE_ALPHA): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
1335                    case(GL_INTENSITY): internalFormat = GL_COMPRESSED_INTENSITY_ARB; break;
1336                }
1337            }
1338            else internalFormat = image.getInternalTextureFormat();
1339            break;
1340
1341        case(USE_S3TC_DXT1_COMPRESSION):
1342            if (extensions->isTextureCompressionS3TCSupported())
1343            {
1344                switch(image.getPixelFormat())
1345                {
1346                    case(3):        internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1347                    case(4):        internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
1348                    case(GL_RGB):   internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1349                    case(GL_RGBA):  internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
1350                    default:        internalFormat = image.getInternalTextureFormat(); break;
1351                }
1352            }
1353            else internalFormat = image.getInternalTextureFormat();
1354            break;
1355
1356        case(USE_S3TC_DXT3_COMPRESSION):
1357            if (extensions->isTextureCompressionS3TCSupported())
1358            {
1359                switch(image.getPixelFormat())
1360                {
1361                    case(3):
1362                    case(GL_RGB):   internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1363                    case(4):
1364                    case(GL_RGBA):  internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
1365                    default:        internalFormat = image.getInternalTextureFormat(); break;
1366                }
1367            }
1368            else internalFormat = image.getInternalTextureFormat();
1369            break;
1370
1371        case(USE_S3TC_DXT5_COMPRESSION):
1372            if (extensions->isTextureCompressionS3TCSupported())
1373            {
1374                switch(image.getPixelFormat())
1375                {
1376                    case(3):
1377                    case(GL_RGB):   internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1378                    case(4):
1379                    case(GL_RGBA):  internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
1380                    default:        internalFormat = image.getInternalTextureFormat(); break;
1381                }
1382            }
1383            else internalFormat = image.getInternalTextureFormat();
1384            break;
1385        default:
1386            break;
1387        }
1388    }
1389   
1390    _internalFormat = internalFormat;
1391    computeInternalFormatType();
1392   
1393    //osg::notify(osg::NOTICE)<<"Internal format="<<std::hex<<internalFormat<<std::dec<<std::endl;
1394}
1395
1396void Texture::computeInternalFormatType() const
1397{
1398    // Here we could also precompute the _sourceFormat if it is not set,
1399    // since it is different for different internal formats
1400    // (i.e. rgba integer texture --> _sourceFormat = GL_RGBA_INTEGER_EXT)
1401    // Should we do this?  ( Art, 09. Sept. 2007)
1402   
1403    // compute internal format type based on the internal format
1404    switch(_internalFormat)
1405    {
1406        case GL_RGBA32UI_EXT:
1407        case GL_RGBA16UI_EXT:
1408        case GL_RGBA8UI_EXT:
1409
1410        case GL_RGB32UI_EXT:
1411        case GL_RGB16UI_EXT:
1412        case GL_RGB8UI_EXT:
1413
1414        case GL_LUMINANCE32UI_EXT
1415        case GL_LUMINANCE16UI_EXT:   
1416        case GL_LUMINANCE8UI_EXT:   
1417
1418        case GL_INTENSITY32UI_EXT:   
1419        case GL_INTENSITY16UI_EXT:   
1420        case GL_INTENSITY8UI_EXT:   
1421
1422        case GL_LUMINANCE_ALPHA32UI_EXT:   
1423        case GL_LUMINANCE_ALPHA16UI_EXT:   
1424        case GL_LUMINANCE_ALPHA8UI_EXT :   
1425            _internalFormatType = UNSIGNED_INTEGER;
1426            break;
1427
1428        case GL_RGBA32I_EXT:
1429        case GL_RGBA16I_EXT:
1430        case GL_RGBA8I_EXT:
1431
1432        case GL_RGB32I_EXT:
1433        case GL_RGB16I_EXT:
1434        case GL_RGB8I_EXT:
1435
1436        case GL_LUMINANCE32I_EXT:   
1437        case GL_LUMINANCE16I_EXT:   
1438        case GL_LUMINANCE8I_EXT:   
1439
1440        case GL_INTENSITY32I_EXT:   
1441        case GL_INTENSITY16I_EXT:   
1442        case GL_INTENSITY8I_EXT:   
1443
1444        case GL_LUMINANCE_ALPHA32I_EXT:   
1445        case GL_LUMINANCE_ALPHA16I_EXT:   
1446        case GL_LUMINANCE_ALPHA8I_EXT:   
1447            _internalFormatType = SIGNED_INTEGER;
1448            break;
1449       
1450        case GL_RGBA32F_ARB:
1451        case GL_RGBA16F_ARB:
1452
1453        case GL_RGB32F_ARB:
1454        case GL_RGB16F_ARB:
1455
1456        case GL_LUMINANCE32F_ARB:
1457        case GL_LUMINANCE16F_ARB:   
1458
1459        case GL_INTENSITY32F_ARB:
1460        case GL_INTENSITY16F_ARB:   
1461
1462        case GL_LUMINANCE_ALPHA32F_ARB:
1463        case GL_LUMINANCE_ALPHA16F_ARB:   
1464            _internalFormatType = FLOAT;
1465            break;
1466           
1467        default:
1468            _internalFormatType = NORMALIZED;
1469            break;
1470    };
1471}
1472
1473bool Texture::isCompressedInternalFormat() const
1474{
1475    return isCompressedInternalFormat(getInternalFormat());
1476}
1477
1478bool Texture::isCompressedInternalFormat(GLint internalFormat)
1479{
1480    switch(internalFormat)
1481    {
1482        case(GL_COMPRESSED_ALPHA_ARB):
1483        case(GL_COMPRESSED_INTENSITY_ARB):
1484        case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB):
1485        case(GL_COMPRESSED_LUMINANCE_ARB):
1486        case(GL_COMPRESSED_RGBA_ARB):
1487        case(GL_COMPRESSED_RGB_ARB):
1488        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
1489        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
1490        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
1491        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
1492            return true;
1493        default:
1494            return false;
1495    }
1496}
1497
1498void Texture::getCompressedSize(GLenum internalFormat, GLint width, GLint height, GLint depth, GLint& blockSize, GLint& size)
1499{
1500    if (internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
1501        blockSize = 8;
1502    else if (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT || internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
1503        blockSize = 16;
1504    else
1505    {
1506        notify(WARN)<<"Texture::getCompressedSize(...) : cannot compute correct size of compressed format ("<<internalFormat<<") returning 0."<<std::endl;
1507        blockSize = 0;
1508    }
1509         
1510    size = ((width+3)/4)*((height+3)/4)*depth*blockSize;       
1511}
1512
1513void Texture::applyTexParameters(GLenum target, State& state) const
1514{
1515    // get the contextID (user defined ID of 0 upwards) for the
1516    // current OpenGL context.
1517    const unsigned int contextID = state.getContextID();
1518    const Extensions* extensions = getExtensions(contextID,true);
1519
1520    WrapMode ws = _wrap_s, wt = _wrap_t, wr = _wrap_r;
1521
1522    // GL_IBM_texture_mirrored_repeat, fall-back REPEAT
1523    if (!extensions->isTextureMirroredRepeatSupported())
1524    {
1525        if (ws == MIRROR)
1526            ws = REPEAT;
1527        if (wt == MIRROR)
1528            wt = REPEAT;
1529        if (wr == MIRROR)
1530            wr = REPEAT;
1531    }
1532
1533    // GL_EXT_texture_edge_clamp, fall-back CLAMP
1534    if (!extensions->isTextureEdgeClampSupported())
1535    {
1536        if (ws == CLAMP_TO_EDGE)
1537            ws = CLAMP;
1538        if (wt == CLAMP_TO_EDGE)
1539            wt = CLAMP;
1540        if (wr == CLAMP_TO_EDGE)
1541            wr = CLAMP;
1542    }
1543
1544    if(!extensions->isTextureBorderClampSupported())
1545    {
1546        if(ws == CLAMP_TO_BORDER)
1547            ws = CLAMP;
1548        if(wt == CLAMP_TO_BORDER)
1549            wt = CLAMP;
1550        if(wr == CLAMP_TO_BORDER)
1551            wr = CLAMP;
1552    }
1553   
1554    const Image * image = getImage(0);
1555    if( image &&
1556        image->isMipmap() &&
1557        extensions->isTextureMaxLevelSupported() &&
1558        int( image->getNumMipmapLevels() ) <
1559            Image::computeNumberOfMipmapLevels( image->s(), image->t(), image->r() ) )
1560            glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, image->getNumMipmapLevels() - 1 );   
1561
1562
1563    glTexParameteri( target, GL_TEXTURE_WRAP_S, ws );
1564   
1565    if (target!=GL_TEXTURE_1D) glTexParameteri( target, GL_TEXTURE_WRAP_T, wt );
1566   
1567    if (target==GL_TEXTURE_3D) glTexParameteri( target, GL_TEXTURE_WRAP_R, wr );
1568
1569   
1570    glTexParameteri( target, GL_TEXTURE_MIN_FILTER, _min_filter);
1571    glTexParameteri( target, GL_TEXTURE_MAG_FILTER, _mag_filter);
1572
1573    // Art: I think anisotropic filtering is not supported by the integer textures
1574    if (extensions->isTextureFilterAnisotropicSupported() &&
1575        _internalFormatType != SIGNED_INTEGER && _internalFormatType != UNSIGNED_INTEGER)
1576    {
1577        // note, GL_TEXTURE_MAX_ANISOTROPY_EXT will either be defined
1578        // by gl.h (or via glext.h) or by include/osg/Texture.
1579        glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, _maxAnisotropy);
1580    }
1581
1582    if (extensions->isTextureBorderClampSupported())
1583    {
1584        if (_internalFormatType == SIGNED_INTEGER)
1585        {
1586            GLint color[4] = {(GLint)_borderColor.r(), (GLint)_borderColor.g(), (GLint)_borderColor.b(), (GLint)_borderColor.a()};
1587            extensions->glTexParameterIiv(target, GL_TEXTURE_BORDER_COLOR, color);
1588        }else if (_internalFormatType == UNSIGNED_INTEGER)
1589        {
1590            GLuint color[4] = {(GLuint)_borderColor.r(), (GLuint)_borderColor.g(), (GLuint)_borderColor.b(), (GLuint)_borderColor.a()};
1591            extensions->glTexParameterIuiv(target, GL_TEXTURE_BORDER_COLOR, color);
1592        }else{
1593            GLfloat color[4] = {(GLfloat)_borderColor.r(), (GLfloat)_borderColor.g(), (GLfloat)_borderColor.b(), (GLfloat)_borderColor.a()};
1594            glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color);
1595        }
1596    }
1597
1598    // integer texture are not supported by the shadow
1599    if (extensions->isShadowSupported() && (target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE) &&
1600        _internalFormatType != SIGNED_INTEGER && _internalFormatType != UNSIGNED_INTEGER)
1601    {
1602        if (_use_shadow_comparison)
1603        {
1604            glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
1605            glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC_ARB, _shadow_compare_func);
1606            glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, _shadow_texture_mode);
1607
1608            // if ambient value is 0 - it is default behaviour of GL_ARB_shadow
1609            // no need for GL_ARB_shadow_ambient in this case
1610            if (extensions->isShadowAmbientSupported() && _shadow_ambient > 0)
1611            {
1612                glTexParameterf(target, TEXTURE_COMPARE_FAIL_VALUE_ARB, _shadow_ambient);
1613            }
1614        }
1615        else 
1616        {
1617            glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
1618        }
1619    }
1620
1621    getTextureParameterDirty(state.getContextID()) = false;
1622
1623}
1624
1625void Texture::computeRequiredTextureDimensions(State& state, const osg::Image& image,GLsizei& inwidth, GLsizei& inheight,GLsizei& numMipmapLevels) const
1626{
1627    const unsigned int contextID = state.getContextID();
1628    const Extensions* extensions = getExtensions(contextID,true);
1629
1630    int width,height;
1631
1632    if( !_resizeNonPowerOfTwoHint && extensions->isNonPowerOfTwoTextureSupported(_min_filter) )
1633    {
1634        width = image.s();
1635        height = image.t();
1636    }
1637    else
1638    {
1639        width = Image::computeNearestPowerOfTwo(image.s()-2*_borderWidth)+2*_borderWidth;
1640        height = Image::computeNearestPowerOfTwo(image.t()-2*_borderWidth)+2*_borderWidth;
1641    }
1642
1643    // cap the size to what the graphics hardware can handle.
1644    if (width>extensions->maxTextureSize()) width = extensions->maxTextureSize();
1645    if (height>extensions->maxTextureSize()) height = extensions->maxTextureSize();
1646
1647    inwidth = width;
1648    inheight = height;
1649   
1650    if( _min_filter == LINEAR || _min_filter == NEAREST)
1651    {
1652        numMipmapLevels = 1;
1653    }
1654    else if( image.isMipmap() )
1655    {
1656        numMipmapLevels = image.getNumMipmapLevels();
1657    }
1658    else
1659    {
1660        numMipmapLevels = 1;
1661        for(int s=1; s<width || s<height; s <<= 1, ++numMipmapLevels) {}
1662    }
1663
1664    // osg::notify(osg::NOTICE)<<"Texture::computeRequiredTextureDimensions() image.s() "<<image.s()<<" image.t()="<<image.t()<<" width="<<width<<" height="<<height<<" numMipmapLevels="<<numMipmapLevels<<std::endl;
1665    // osg::notify(osg::NOTICE)<<"  _resizeNonPowerOfTwoHint="<<_resizeNonPowerOfTwoHint<<" extensions->isNonPowerOfTwoTextureSupported(_min_filter)="<<extensions->isNonPowerOfTwoTextureSupported(_min_filter) <<std::endl;
1666}
1667
1668bool Texture::areAllTextureObjectsLoaded() const
1669{
1670    for(unsigned int i=0;i<DisplaySettings::instance()->getMaxNumberOfGraphicsContexts();++i)
1671    {
1672        if (_textureObjectBuffer[i]==0) return false;
1673    }
1674    return true;
1675}
1676
1677
1678void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight,GLsizei numMipmapLevels) const
1679{
1680    // if we don't have a valid image we can't create a texture!
1681    if (!image || !image->data())
1682        return;
1683
1684#ifdef DO_TIMING
1685    osg::Timer_t start_tick = osg::Timer::instance()->tick();
1686    osg::notify(osg::NOTICE)<<"glTexImage2D pixelFormat = "<<std::hex<<image->getPixelFormat()<<std::dec<<std::endl;
1687#endif
1688
1689    // get the contextID (user defined ID of 0 upwards) for the
1690    // current OpenGL context.
1691    const unsigned int contextID = state.getContextID();
1692    const Extensions* extensions = getExtensions(contextID,true);
1693
1694    // select the internalFormat required for the texture.
1695    bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
1696
1697    // If the texture's internal format is a compressed type, then the
1698    // user is requesting that the graphics card compress the image if it's
1699    // not already compressed. However, if the image is not a multiple of
1700    // four in each dimension the subsequent calls to glTexSubImage* will
1701    // fail. Revert to uncompressed format in this case.
1702    if (isCompressedInternalFormat(_internalFormat) &&
1703        (((inwidth >> 2) << 2) != inwidth ||
1704         ((inheight >> 2) << 2) != inheight))
1705    {
1706        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";
1707        switch(_internalFormat)
1708        {
1709            case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1710            case GL_COMPRESSED_RGB: _internalFormat = GL_RGB; break;
1711            case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1712            case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1713            case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1714            case GL_COMPRESSED_RGBA: _internalFormat = GL_RGBA; break;
1715            case GL_COMPRESSED_ALPHA: _internalFormat = GL_ALPHA; break;
1716            case GL_COMPRESSED_LUMINANCE: _internalFormat = GL_LUMINANCE; break;
1717            case GL_COMPRESSED_LUMINANCE_ALPHA: _internalFormat = GL_LUMINANCE_ALPHA; break;
1718            case GL_COMPRESSED_INTENSITY: _internalFormat = GL_INTENSITY; break;
1719        }
1720    }
1721   
1722    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
1723   
1724    bool useClientStorage = extensions->isClientStorageSupported() && getClientStorageHint();
1725    if (useClientStorage)
1726    {
1727        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_TRUE);
1728        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_PRIORITY,0.0f);
1729       
1730        #ifdef GL_TEXTURE_STORAGE_HINT_APPLE   
1731            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
1732        #endif
1733    }
1734   
1735    unsigned char* data = (unsigned char*)image->data();
1736 
1737    // osg::notify(osg::NOTICE)<<"inwidth="<<inwidth<<" inheight="<<inheight<<" image->getFileName()"<<image->getFileName()<<std::endl;
1738
1739    bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
1740    if (needImageRescale)
1741    {
1742
1743        // resize the image to power of two.
1744       
1745        if (image->isMipmap())
1746        {
1747            notify(WARN)<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
1748            return;
1749        }
1750        else if (compressed_image)
1751        {
1752            notify(WARN)<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
1753            return;
1754        }
1755       
1756        unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
1757        data = new unsigned char [newTotalSize];
1758       
1759        if (!data)
1760        {
1761            notify(WARN)<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
1762            return;
1763        }
1764
1765        if (!image->getFileName().empty()) notify(NOTICE) << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
1766        else notify(NOTICE) << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
1767
1768        // rescale the image to the correct size.
1769        glPixelStorei(GL_PACK_ALIGNMENT,image->getPacking());
1770        gluScaleImage(image->getPixelFormat(),
1771                      image->s(),image->t(),image->getDataType(),image->data(),
1772                      inwidth,inheight,image->getDataType(),data);
1773       
1774    }   
1775
1776    bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
1777    bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
1778    bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
1779
1780    unsigned char* dataMinusOffset = 0;
1781    unsigned char* dataPlusOffset = 0;
1782
1783    const PixelBufferObject* pbo = image->getPixelBufferObject();
1784    if (pbo && pbo->isPBOSupported(contextID) && !needImageRescale && !useGluBuildMipMaps)
1785    {
1786        state.bindPixelBufferObject(pbo);
1787        dataMinusOffset = data;
1788        dataPlusOffset = reinterpret_cast<unsigned char*>(pbo->offset());
1789#ifdef DO_TIMING
1790        osg::notify(osg::NOTICE)<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
1791#endif
1792    }
1793    else
1794    {
1795        pbo = 0;
1796    }
1797
1798    if( !mipmappingRequired || useHardwareMipMapGeneration)
1799    {
1800
1801        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
1802
1803        if ( !compressed_image)
1804        {
1805            numMipmapLevels = 1;
1806
1807            glTexImage2D( target, 0, _internalFormat,
1808                inwidth, inheight, _borderWidth,
1809                (GLenum)image->getPixelFormat(),
1810                (GLenum)image->getDataType(),
1811                data -dataMinusOffset+dataPlusOffset);
1812
1813        }
1814        else if (extensions->isCompressedTexImage2DSupported())
1815        {
1816            numMipmapLevels = 1;
1817
1818            GLint blockSize, size;
1819            getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size);
1820
1821            extensions->glCompressedTexImage2D(target, 0, _internalFormat,
1822                inwidth, inheight,0,
1823                size,
1824                data-dataMinusOffset+dataPlusOffset);               
1825        }
1826
1827        mipmapAfterTexImage(state, mipmapResult);
1828    }
1829    else
1830    {
1831        // we require mip mapping.
1832        if(image->isMipmap())
1833        {
1834
1835            // image is mip mapped so we take the mip map levels from the image.
1836       
1837            numMipmapLevels = image->getNumMipmapLevels();
1838
1839            int width  = inwidth;
1840            int height = inheight;
1841
1842            if( !compressed_image )
1843            {
1844                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
1845                {
1846
1847                    if (width == 0)
1848                        width = 1;
1849                    if (height == 0)
1850                        height = 1;
1851
1852                    glTexImage2D( target, k, _internalFormat,
1853                         width, height, _borderWidth,
1854                        (GLenum)image->getPixelFormat(),
1855                        (GLenum)image->getDataType(),
1856                        image->getMipmapData(k)-dataMinusOffset+dataPlusOffset);
1857
1858                    width >>= 1;
1859                    height >>= 1;
1860                }
1861            }
1862            else if (extensions->isCompressedTexImage2DSupported())
1863            {
1864                GLint blockSize, size;
1865
1866                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
1867                {
1868                    if (width == 0)
1869                        width = 1;
1870                    if (height == 0)
1871                        height = 1;
1872
1873                    getCompressedSize(_internalFormat, width, height, 1, blockSize,size);
1874                   
1875                    extensions->glCompressedTexImage2D(target, k, _internalFormat,
1876                                                       width, height, _borderWidth,
1877                                                       size, image->getMipmapData(k)-dataMinusOffset+dataPlusOffset);               
1878
1879                    width >>= 1;
1880                    height >>= 1;
1881                }
1882            }
1883        }
1884        else
1885        {
1886       
1887            if ( !compressed_image)
1888            {
1889                numMipmapLevels = 0;
1890
1891                gluBuild2DMipmaps( target, _internalFormat,
1892                    inwidth,inheight,
1893                    (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
1894                    data);
1895
1896                int width  = image->s();
1897                int height = image->t();
1898                for( numMipmapLevels = 0 ; (width || height) ; ++numMipmapLevels)
1899                {
1900                    width >>= 1;
1901                    height >>= 1;
1902                }
1903            }
1904            else 
1905            {
1906                notify(WARN)<<"Warning:: Compressed image cannot be mip mapped"<<std::endl;
1907            }
1908
1909        }
1910
1911    }
1912
1913    if (pbo)
1914    {
1915        state.unbindPixelBufferObject();
1916    }
1917   
1918#ifdef DO_TIMING
1919    static double s_total_time = 0.0;
1920    double delta_time = osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick());
1921    s_total_time += delta_time;
1922    osg::notify(osg::NOTICE)<<"glTexImage2D "<<delta_time<<"ms  total "<<s_total_time<<"ms"<<std::endl;
1923#endif
1924
1925    if (needImageRescale)
1926    {
1927        // clean up the resized image.
1928        delete [] data;
1929    }
1930   
1931    if (useClientStorage)
1932    {
1933        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_FALSE);
1934    }
1935}
1936
1937
1938
1939void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight, GLint inInternalFormat, GLint numMipmapLevels) const
1940{
1941    // if we don't have a valid image we can't create a texture!
1942    if (!image || !image->data())
1943        return;
1944
1945    // image size has changed so we have to re-load the image from scratch.
1946    if (image->s()!=inwidth || image->t()!=inheight || image->getInternalTextureFormat()!=inInternalFormat )
1947    {
1948        applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
1949        return;
1950    }
1951    // else image size the same as when loaded so we can go ahead and subload
1952   
1953    // If the texture's internal format is a compressed type, then the
1954    // user is requesting that the graphics card compress the image if it's
1955    // not already compressed. However, if the image is not a multiple of
1956    // four in each dimension the subsequent calls to glTexSubImage* will
1957    // fail. Revert to uncompressed format in this case.
1958    if (isCompressedInternalFormat(_internalFormat) &&
1959        (((inwidth >> 2) << 2) != inwidth ||
1960         ((inheight >> 2) << 2) != inheight))
1961    {
1962        applyTexImage2D_load(state, target, image, inwidth, inheight, numMipmapLevels);
1963        return;
1964    }
1965
1966#ifdef DO_TIMING
1967    osg::Timer_t start_tick = osg::Timer::instance()->tick();
1968    osg::notify(osg::NOTICE)<<"glTexSubImage2D pixelFormat = "<<std::hex<<image->getPixelFormat()<<std::dec<<std::endl;
1969#endif
1970   
1971
1972    // get the contextID (user defined ID of 0 upwards) for the
1973    // current OpenGL context.
1974    const unsigned int contextID = state.getContextID();
1975    const Extensions* extensions = getExtensions(contextID,true);
1976
1977    // select the internalFormat required for the texture.
1978    bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
1979   
1980    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
1981   
1982    unsigned char* data = (unsigned char*)image->data();
1983 
1984
1985    bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
1986    if (needImageRescale)
1987    {
1988
1989        // resize the image to power of two.
1990       
1991        if (image->isMipmap())
1992        {
1993            notify(WARN)<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
1994            return;
1995        }
1996        else if (compressed_image)
1997        {
1998            notify(WARN)<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
1999            return;
2000        }
2001       
2002        unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
2003        data = new unsigned char [newTotalSize];
2004       
2005        if (!data)
2006        {
2007            notify(WARN)<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
2008            return;
2009        }
2010
2011        if (!image->getFileName().empty()) notify(NOTICE) << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
2012        else notify(NOTICE) << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
2013
2014        // rescale the image to the correct size.
2015        glPixelStorei(GL_PACK_ALIGNMENT,image->getPacking());
2016        gluScaleImage(image->getPixelFormat(),
2017                      image->s(),image->t(),image->getDataType(),image->data(),
2018                      inwidth,inheight,image->getDataType(),data);
2019       
2020    }   
2021
2022
2023    bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
2024    bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
2025    bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
2026
2027    unsigned char* dataMinusOffset = 0;
2028    unsigned char* dataPlusOffset = 0;
2029   
2030    const PixelBufferObject* pbo = image->getPixelBufferObject();
2031    if (pbo && pbo->isPBOSupported(contextID) && !needImageRescale && !useGluBuildMipMaps)
2032    {
2033        state.bindPixelBufferObject(pbo);
2034        dataMinusOffset = data;
2035        dataPlusOffset = reinterpret_cast<unsigned char*>(pbo->offset());
2036#ifdef DO_TIMING
2037        osg::notify(osg::NOTICE)<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
2038#endif
2039    }
2040    else
2041    {
2042        pbo = 0;
2043    }
2044
2045    if( !mipmappingRequired || useHardwareMipMapGeneration)
2046    {
2047
2048        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
2049
2050        if (!compressed_image)
2051        {
2052#if 0
2053            glTexImage2D( target, 0, _internalFormat,
2054                inwidth, inheight, _borderWidth,
2055                (GLenum)image->getPixelFormat(),
2056                (GLenum)image->getDataType(),
2057                data -dataMinusOffset+dataPlusOffset);
2058#else
2059            glTexSubImage2D( target, 0,
2060                0, 0,
2061                inwidth, inheight,
2062                (GLenum)image->getPixelFormat(),
2063                (GLenum)image->getDataType(),
2064                data - dataMinusOffset + dataPlusOffset);
2065#endif
2066        }
2067        else if (extensions->isCompressedTexImage2DSupported())
2068        {       
2069            GLint blockSize,size;
2070            getCompressedSize(image->getInternalTextureFormat(), inwidth, inheight, 1, blockSize,size);
2071
2072            extensions->glCompressedTexSubImage2D(target, 0,
2073                0,0,
2074                inwidth, inheight,
2075                (GLenum)image->getPixelFormat(),
2076                size,
2077                data - dataMinusOffset + dataPlusOffset );               
2078        }
2079
2080        mipmapAfterTexImage(state, mipmapResult);
2081    }
2082    else
2083    {
2084        if (image->isMipmap())
2085        {
2086            numMipmapLevels = image->getNumMipmapLevels();
2087
2088            int width  = inwidth;
2089            int height = inheight;
2090
2091            if( !compressed_image )
2092            {
2093                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
2094                {
2095
2096                    if (width == 0)
2097                        width = 1;
2098                    if (height == 0)
2099                        height = 1;
2100
2101                    glTexSubImage2D( target, k,
2102                        0, 0,
2103                        width, height,
2104                        (GLenum)image->getPixelFormat(),
2105                        (GLenum)image->getDataType(),
2106                        image->getMipmapData(k) - dataMinusOffset + dataPlusOffset);
2107
2108                    width >>= 1;
2109                    height >>= 1;
2110                }
2111            }
2112            else if (extensions->isCompressedTexImage2DSupported())
2113            {
2114                GLint blockSize,size;
2115                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
2116                {
2117                    if (width == 0)
2118                        width = 1;
2119                    if (height == 0)
2120                        height = 1;
2121
2122                    getCompressedSize(image->getInternalTextureFormat(), width, height, 1, blockSize,size);
2123
2124                    //state.checkGLErrors("before extensions->glCompressedTexSubImage2D(");
2125
2126                    extensions->glCompressedTexSubImage2D(target, k, 
2127                                                       0, 0,
2128                                                       width, height,
2129                                                       (GLenum)image->getPixelFormat(),
2130                                                       size,
2131                                                        image->getMipmapData(k) - dataMinusOffset + dataPlusOffset);               
2132
2133                    //state.checkGLErrors("after extensions->glCompressedTexSubImage2D(");
2134
2135                    width >>= 1;
2136                    height >>= 1;
2137                }
2138
2139            }
2140        }
2141        else
2142        {
2143            //notify(WARN)<<"Warning:: cannot subload mip mapped texture from non mipmapped image."<<std::endl;
2144            applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
2145            return;
2146        }
2147    }
2148   
2149    if (pbo)
2150    {
2151        state.unbindPixelBufferObject();
2152    }
2153#ifdef DO_TIMING
2154    osg::notify(osg::NOTICE)<<"glTexSubImage2D "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
2155#endif
2156
2157    if (needImageRescale)
2158    {
2159        // clean up the resized image.
2160        delete [] data;
2161    }
2162}
2163
2164bool Texture::isHardwareMipmapGenerationEnabled(const State& state) const
2165{
2166    if (_useHardwareMipMapGeneration)
2167    {
2168        unsigned int contextID = state.getContextID();
2169        const Extensions* extensions = getExtensions(contextID,true);
2170
2171        if (extensions->isGenerateMipMapSupported())
2172        {
2173            return true;
2174        }
2175
2176        const FBOExtensions* fbo_ext = FBOExtensions::instance(contextID,true);
2177
2178        if (fbo_ext->glGenerateMipmapEXT)
2179        {
2180            return true;
2181        }
2182    }
2183
2184    return false;
2185}
2186
2187Texture::GenerateMipmapMode Texture::mipmapBeforeTexImage(const State& state, bool hardwareMipmapOn) const
2188{
2189    if (hardwareMipmapOn)
2190    {
2191        int width = getTextureWidth();
2192        int height = getTextureHeight();
2193
2194        //quick bithack to determine whether width or height are non-power-of-two
2195        if ((width & (width - 1)) || (height & (height - 1)))
2196        {
2197            //GL_GENERATE_MIPMAP_SGIS with non-power-of-two textures on NVIDIA hardware
2198            //is extremely slow. Use glGenerateMipmapEXT() instead if supported.
2199            if (_internalFormatType != SIGNED_INTEGER &&
2200                _internalFormatType != UNSIGNED_INTEGER)
2201            {
2202                if (FBOExtensions::instance(state.getContextID(), true)->glGenerateMipmapEXT)
2203                {
2204                    return GENERATE_MIPMAP;
2205                }
2206            }
2207        }
2208
2209        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
2210        return GENERATE_MIPMAP_TEX_PARAMETER;
2211    }
2212    return GENERATE_MIPMAP_NONE;
2213}
2214
2215void Texture::mipmapAfterTexImage(State& state, GenerateMipmapMode beforeResult) const
2216{
2217    switch (beforeResult)
2218    {
2219    case GENERATE_MIPMAP:
2220        {
2221            unsigned int contextID = state.getContextID();
2222            TextureObject* textureObject = getTextureObject(contextID);
2223            if (textureObject)
2224            {
2225                osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(contextID, true);
2226                fbo_ext->glGenerateMipmapEXT(textureObject->target());
2227            }
2228        }
2229        break;
2230    case GENERATE_MIPMAP_TEX_PARAMETER:
2231        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
2232        break;
2233    case GENERATE_MIPMAP_NONE:
2234        break;
2235    }
2236}
2237
2238void Texture::generateMipmap(State& state) const
2239{
2240    const unsigned int contextID = state.getContextID();
2241
2242    // get the texture object for the current contextID.
2243    TextureObject* textureObject = getTextureObject(contextID);
2244
2245    // if not initialized before, then do nothing
2246    if (textureObject == NULL) return;
2247
2248    _texMipmapGenerationDirtyList[contextID] = 0;
2249   
2250    // if internal format does not provide automatic mipmap generation, then do manual allocation
2251    if (_internalFormatType == SIGNED_INTEGER || _internalFormatType == UNSIGNED_INTEGER)
2252    {
2253        allocateMipmap(state);
2254        return;
2255    }
2256   
2257    // get fbo extension which provides us with the glGenerateMipmapEXT function
2258    osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(state.getContextID(), true);
2259
2260    // check if the function is supported
2261    if (fbo_ext->glGenerateMipmapEXT)
2262    {
2263        textureObject->bind();
2264        fbo_ext->glGenerateMipmapEXT(textureObject->target());
2265       
2266        // inform state that this texture is the current one bound.
2267        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
2268   
2269    // if the function is not supported, then do manual allocation
2270    }else
2271    {
2272        allocateMipmap(state);
2273    }
2274   
2275}
2276
2277void Texture::compileGLObjects(State& state) const
2278{
2279    apply(state);
2280}
2281
2282void Texture::resizeGLObjectBuffers(unsigned int maxSize)
2283{
2284    _textureObjectBuffer.resize(maxSize);
2285}
2286
2287void Texture::releaseGLObjects(State* state) const
2288{
2289//    if (state) osg::notify(osg::NOTICE)<<"Texture::releaseGLObjects contextID="<<state->getContextID()<<std::endl;
2290//    else osg::notify(osg::NOTICE)<<"Texture::releaseGLObjects no State "<<std::endl;
2291
2292    if (!state) const_cast<Texture*>(this)->dirtyTextureObject();
2293    else
2294    {
2295        unsigned int contextID = state->getContextID();
2296        if (_textureObjectBuffer[contextID].valid())
2297        {
2298            Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get());
2299
2300            _textureObjectBuffer[contextID] = 0;
2301        }
2302    }
2303}
2304
2305Texture::Extensions* Texture::getExtensions(unsigned int contextID,bool createIfNotInitalized)
2306{
2307    if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID);
2308    return s_extensions[contextID].get();
2309}
2310
2311void Texture::setExtensions(unsigned int contextID,Extensions* extensions)
2312{
2313    s_extensions[contextID] = extensions;
2314}
2315
2316Texture::Extensions::Extensions(unsigned int contextID)
2317{
2318    setupGLExtensions(contextID);
2319}
2320
2321Texture::Extensions::Extensions(const Extensions& rhs):
2322    Referenced()
2323{
2324    _isMultiTexturingSupported = rhs._isMultiTexturingSupported;
2325    _isTextureFilterAnisotropicSupported = rhs._isTextureFilterAnisotropicSupported;
2326    _isTextureCompressionARBSupported = rhs._isTextureCompressionARBSupported;
2327    _isTextureCompressionS3TCSupported = rhs._isTextureCompressionS3TCSupported;
2328    _isTextureMirroredRepeatSupported = rhs._isTextureMirroredRepeatSupported;
2329    _isTextureEdgeClampSupported = rhs._isTextureEdgeClampSupported;
2330    _isTextureBorderClampSupported = rhs._isTextureBorderClampSupported;
2331    _isGenerateMipMapSupported = rhs._isGenerateMipMapSupported;
2332
2333    _maxTextureSize = rhs._maxTextureSize;
2334
2335    _glCompressedTexImage2D = rhs._glCompressedTexImage2D;
2336
2337    _isShadowSupported = rhs._isShadowSupported;
2338    _isShadowAmbientSupported = rhs._isShadowAmbientSupported;
2339
2340    _isClientStorageSupported = rhs._isClientStorageSupported;
2341
2342    _isNonPowerOfTwoTextureMipMappedSupported = rhs._isNonPowerOfTwoTextureMipMappedSupported;
2343    _isNonPowerOfTwoTextureNonMipMappedSupported = rhs._isNonPowerOfTwoTextureNonMipMappedSupported;
2344
2345    _isTextureIntegerEXTSupported = rhs._isTextureIntegerEXTSupported;
2346    _isTextureMaxLevelSupported = rhs._isTextureMaxLevelSupported;
2347}
2348
2349void Texture::Extensions::lowestCommonDenominator(const Extensions& rhs)
2350{
2351    if (!rhs._isMultiTexturingSupported) _isMultiTexturingSupported = false;
2352   
2353    if (!rhs._isTextureFilterAnisotropicSupported) _isTextureFilterAnisotropicSupported = false;
2354    if (!rhs._isTextureMirroredRepeatSupported) _isTextureMirroredRepeatSupported = false;
2355    if (!rhs._isTextureEdgeClampSupported) _isTextureEdgeClampSupported = false;
2356    if (!rhs._isTextureBorderClampSupported) _isTextureBorderClampSupported = false;
2357   
2358    if (!rhs._isTextureCompressionARBSupported) _isTextureCompressionARBSupported = false;
2359    if (!rhs._isTextureCompressionS3TCSupported) _isTextureCompressionS3TCSupported = false;
2360   
2361    if (!rhs._isGenerateMipMapSupported) _isGenerateMipMapSupported = false;
2362
2363    if (rhs._maxTextureSize<_maxTextureSize) _maxTextureSize = rhs._maxTextureSize;
2364    if (rhs._numTextureUnits<_numTextureUnits) _numTextureUnits = rhs._numTextureUnits;
2365
2366    if (!rhs._glCompressedTexImage2D) _glCompressedTexImage2D = 0;
2367    if (!rhs._glCompressedTexSubImage2D) _glCompressedTexSubImage2D = 0;
2368    if (!rhs._glGetCompressedTexImage) _glGetCompressedTexImage = 0;
2369
2370    if (!rhs._isShadowSupported) _isShadowSupported = false;
2371    if (!rhs._isShadowAmbientSupported) _isShadowAmbientSupported = false;
2372   
2373    if (!rhs._isClientStorageSupported) _isClientStorageSupported = false;
2374
2375    if (!rhs._isNonPowerOfTwoTextureMipMappedSupported) _isNonPowerOfTwoTextureMipMappedSupported = false;
2376    if (!rhs._isNonPowerOfTwoTextureNonMipMappedSupported) _isNonPowerOfTwoTextureNonMipMappedSupported = false;
2377
2378    if (!rhs._isTextureIntegerEXTSupported) _isTextureIntegerEXTSupported = false;
2379    if (!rhs._isTextureMaxLevelSupported) _isTextureMaxLevelSupported = false;
2380}
2381
2382void Texture::Extensions::setupGLExtensions(unsigned int contextID)
2383{
2384    const char* version = (const char*) glGetString( GL_VERSION );
2385    if (!version)
2386    {
2387        osg::notify(osg::FATAL)<<"Error: In Texture::Extensions::setupGLExtensions(..) OpenGL version test failed, requires valid graphics context."<<std::endl;
2388        return;
2389    }
2390   
2391    const char* renderer = (const char*) glGetString(GL_RENDERER);
2392    std::string rendererString(renderer ? renderer : "");
2393   
2394    _isMultiTexturingSupported = isGLExtensionOrVersionSupported( contextID,"GL_ARB_multitexture", 1.3f) ||
2395                                 isGLExtensionOrVersionSupported(contextID,"GL_EXT_multitexture", 1.3f);
2396                                 
2397    _isTextureFilterAnisotropicSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_filter_anisotropic");
2398   
2399    _isTextureCompressionARBSupported = isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_compression", 1.3f);
2400   
2401    _isTextureCompressionS3TCSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_compression_s3tc");
2402   
2403    _isTextureMirroredRepeatSupported = isGLExtensionOrVersionSupported(contextID,"GL_IBM_texture_mirrored_repeat", 1.4f) ||
2404                                        isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_mirrored_repeat", 1.4f);
2405                                       
2406    _isTextureEdgeClampSupported = isGLExtensionOrVersionSupported(contextID,"GL_EXT_texture_edge_clamp", 1.2f) ||
2407                                   isGLExtensionOrVersionSupported(contextID,"GL_SGIS_texture_edge_clamp", 1.2f);
2408                                   
2409    _isTextureBorderClampSupported = isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_border_clamp", 1.3f);
2410   
2411    _isGenerateMipMapSupported = isGLExtensionOrVersionSupported(contextID,"GL_SGIS_generate_mipmap", 1.4f);
2412                                 
2413    _isShadowSupported = isGLExtensionSupported(contextID,"GL_ARB_shadow");
2414   
2415    _isShadowAmbientSupported = isGLExtensionSupported(contextID,"GL_ARB_shadow_ambient");
2416
2417    _isClientStorageSupported = isGLExtensionSupported(contextID,"GL_APPLE_client_storage");
2418
2419    _isNonPowerOfTwoTextureNonMipMappedSupported = isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_non_power_of_two", 2.0);
2420
2421    _isNonPowerOfTwoTextureMipMappedSupported = _isNonPowerOfTwoTextureNonMipMappedSupported;
2422   
2423    _isTextureIntegerEXTSupported = isGLExtensionSupported(contextID, "GL_EXT_texture_integer");
2424
2425    if (rendererString.find("Radeon")!=std::string::npos || rendererString.find("RADEON")!=std::string::npos)
2426    {
2427        _isNonPowerOfTwoTextureMipMappedSupported = false;
2428        osg::notify(osg::INFO)<<"Disabling _isNonPowerOfTwoTextureMipMappedSupported for ATI hardware."<<std::endl;
2429    }
2430
2431    if (rendererString.find("GeForce FX")!=std::string::npos)
2432    {
2433        _isNonPowerOfTwoTextureMipMappedSupported = false;
2434        osg::notify(osg::INFO)<<"Disabling _isNonPowerOfTwoTextureMipMappedSupported for GeForce FX hardware."<<std::endl;
2435    }
2436
2437    glGetIntegerv(GL_MAX_TEXTURE_SIZE,&_maxTextureSize);
2438
2439    char *ptr;
2440    if( (ptr = getenv("OSG_MAX_TEXTURE_SIZE")) != 0)
2441    {
2442        GLint osg_max_size = atoi(ptr);
2443
2444        if (osg_max_size<_maxTextureSize)
2445        {
2446
2447            _maxTextureSize = osg_max_size;
2448        }
2449    }
2450
2451    if( _isMultiTexturingSupported )
2452    {
2453       glGetIntegerv(GL_MAX_TEXTURE_UNITS,&_numTextureUnits);
2454    }
2455    else
2456    {
2457       _numTextureUnits = 1;
2458    }
2459
2460    setGLExtensionFuncPtr(_glCompressedTexImage2D,"glCompressedTexImage2D","glCompressedTexImage2DARB");
2461    setGLExtensionFuncPtr(_glCompressedTexSubImage2D,"glCompressedTexSubImage2D","glCompressedTexSubImage2DARB");
2462    setGLExtensionFuncPtr(_glGetCompressedTexImage,"glGetCompressedTexImage","glGetCompressedTexImageARB");;
2463
2464    setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIiv", "glTexParameterIivARB");
2465    setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuiv", "glTexParameterIuivARB");
2466   
2467    if (_glTexParameterIiv == NULL) setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIivEXT");
2468    if (_glTexParameterIuiv == NULL) setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuivEXT");
2469
2470    _isTextureMaxLevelSupported = ( getGLVersionNumber() >= 1.2f );
2471}
2472
2473
2474void Texture::Extensions::glTexParameterIiv(GLenum target, GLenum pname, const GLint* data) const
2475{
2476    if (_glTexParameterIiv)
2477    {
2478        _glTexParameterIiv(target, pname, data);
2479    }
2480    else
2481    {
2482        notify(WARN)<<"Error: glTexParameterIiv not supported by OpenGL driver"<<std::endl;
2483    }
2484}
2485
2486void Texture::Extensions::glTexParameterIuiv(GLenum target, GLenum pname, const GLuint* data) const
2487{
2488    if (_glTexParameterIuiv)
2489    {
2490        _glTexParameterIuiv(target, pname, data);
2491    }
2492    else
2493    {
2494        notify(WARN)<<"Error: glTexParameterIuiv not supported by OpenGL driver"<<std::endl;
2495    }
2496}
2497
2498void Texture::Extensions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const
2499{
2500    if (_glCompressedTexImage2D)
2501    {
2502        _glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
2503    }
2504    else
2505    {
2506        notify(WARN)<<"Error: glCompressedTexImage2D not supported by OpenGL driver"<<std::endl;
2507    }
2508   
2509}
2510
2511void Texture::Extensions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) const
2512{
2513    if (_glCompressedTexSubImage2D)
2514    {
2515        _glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
2516    }
2517    else
2518    {
2519        notify(WARN)<<"Error: glCompressedTexImage2D not supported by OpenGL driver"<<std::endl;
2520    }
2521   
2522}
2523void Texture::Extensions::glGetCompressedTexImage(GLenum target, GLint level, GLvoid *data) const
2524{
2525    if (_glGetCompressedTexImage)
2526    {
2527        _glGetCompressedTexImage(target, level, data);
2528    }
2529    else
2530    {
2531        notify(WARN)<<"Error: glGetCompressedTexImage not supported by OpenGL driver"<<std::endl;
2532    }
2533}
2534
2535}
Note: See TracBrowser for help on using the browser.