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

Revision 13041, 89.3 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

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