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

Revision 12727, 89.4 kB (checked in by robert, 3 years ago)

Reverted the change to the default setting of _resizeNonPowerOfTwoHint back to true for all platforms to ensure the
same behaivour across platforms, something that can be achieved now thanks to the integrated GLU library.

Corrected the default of the ResizeNonPowerOfTwoHint? to true to reflect the actual default setting set by the
Texture default constructor.

  • 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 = 16;
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
1846    bool useClientStorage = extensions->isClientStorageSupported() && getClientStorageHint();
1847    if (useClientStorage)
1848    {
1849        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_TRUE);
1850
1851        #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
1852            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_PRIORITY,0.0f);
1853        #endif
1854
1855        #ifdef GL_TEXTURE_STORAGE_HINT_APPLE   
1856            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
1857        #endif
1858    }
1859
1860    unsigned char* dataPtr = (unsigned char*)image->data();
1861
1862    // OSG_NOTICE<<"inwidth="<<inwidth<<" inheight="<<inheight<<" image->getFileName()"<<image->getFileName()<<std::endl;
1863
1864    bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
1865    if (needImageRescale)
1866    {
1867        // resize the image to power of two.
1868       
1869        if (image->isMipmap())
1870        {
1871            OSG_WARN<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
1872            return;
1873        }
1874        else if (compressed_image)
1875        {
1876            OSG_WARN<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
1877            return;
1878        }
1879       
1880        unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
1881        dataPtr = new unsigned char [newTotalSize];
1882       
1883        if (!dataPtr)
1884        {
1885            OSG_WARN<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
1886            return;
1887        }
1888
1889        if (!image->getFileName().empty()) { OSG_NOTICE << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl; }
1890        else { OSG_NOTICE << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl; }
1891
1892        PixelStorageModes psm;
1893        psm.pack_alignment = image->getPacking();
1894        psm.unpack_alignment = image->getPacking();
1895
1896        // rescale the image to the correct size.
1897        gluScaleImage(&psm, image->getPixelFormat(),
1898                        image->s(),image->t(),image->getDataType(),image->data(),
1899                        inwidth,inheight,image->getDataType(),
1900                        dataPtr);
1901
1902    }
1903
1904    bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
1905    bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
1906    bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
1907
1908    GLBufferObject* pbo = image->getOrCreateGLBufferObject(contextID);
1909    if (pbo && !needImageRescale && !useGluBuildMipMaps)
1910    {
1911        state.bindPixelBufferObject(pbo);
1912        dataPtr = reinterpret_cast<unsigned char*>(pbo->getOffset(image->getBufferIndex()));
1913#ifdef DO_TIMING
1914        OSG_NOTICE<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
1915#endif
1916    }
1917    else
1918    {
1919        pbo = 0;
1920    }
1921
1922    if( !mipmappingRequired || useHardwareMipMapGeneration)
1923    {
1924
1925        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
1926
1927        if ( !compressed_image)
1928        {
1929            numMipmapLevels = 1;
1930
1931            glTexImage2D( target, 0, _internalFormat,
1932                inwidth, inheight, _borderWidth,
1933                (GLenum)image->getPixelFormat(),
1934                (GLenum)image->getDataType(),
1935                dataPtr);
1936
1937        }
1938        else if (extensions->isCompressedTexImage2DSupported())
1939        {
1940            numMipmapLevels = 1;
1941
1942            GLint blockSize, size;
1943            getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size);
1944
1945            extensions->glCompressedTexImage2D(target, 0, _internalFormat,
1946                inwidth, inheight,0,
1947                size,
1948                dataPtr);
1949        }
1950
1951        mipmapAfterTexImage(state, mipmapResult);
1952    }
1953    else
1954    {
1955        // we require mip mapping.
1956        if(image->isMipmap())
1957        {
1958
1959            // image is mip mapped so we take the mip map levels from the image.
1960       
1961            numMipmapLevels = image->getNumMipmapLevels();
1962
1963            int width  = inwidth;
1964            int height = inheight;
1965
1966            if( !compressed_image )
1967            {
1968                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
1969                {
1970
1971                    if (width == 0)
1972                        width = 1;
1973                    if (height == 0)
1974                        height = 1;
1975
1976                    glTexImage2D( target, k, _internalFormat,
1977                         width, height, _borderWidth,
1978                        (GLenum)image->getPixelFormat(),
1979                        (GLenum)image->getDataType(),
1980                        dataPtr + image->getMipmapOffset(k));
1981
1982                    width >>= 1;
1983                    height >>= 1;
1984                }
1985            }
1986            else if (extensions->isCompressedTexImage2DSupported())
1987            {
1988                GLint blockSize, size;
1989
1990                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
1991                {
1992                    if (width == 0)
1993                        width = 1;
1994                    if (height == 0)
1995                        height = 1;
1996
1997                    getCompressedSize(_internalFormat, width, height, 1, blockSize,size);
1998                   
1999                    extensions->glCompressedTexImage2D(target, k, _internalFormat,
2000                                                       width, height, _borderWidth,
2001                                                       size, dataPtr + image->getMipmapOffset(k));
2002
2003                    width >>= 1;
2004                    height >>= 1;
2005                }
2006            }
2007        }
2008        else
2009        {
2010            if ( !compressed_image)
2011            {
2012                numMipmapLevels = 0;
2013
2014                gluBuild2DMipmaps( target, _internalFormat,
2015                    inwidth,inheight,
2016                    (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
2017                    dataPtr);
2018
2019                int width  = image->s();
2020                int height = image->t();
2021                for( numMipmapLevels = 0 ; (width || height) ; ++numMipmapLevels)
2022                {
2023                    width >>= 1;
2024                    height >>= 1;
2025                }
2026            }
2027            else 
2028            {
2029                OSG_WARN<<"Warning:: Compressed image cannot be mip mapped"<<std::endl;
2030            }
2031
2032        }
2033
2034    }
2035
2036    if (pbo)
2037    {
2038        state.unbindPixelBufferObject();
2039
2040        const BufferObject* bo = image->getBufferObject();
2041        if (bo->getCopyDataAndReleaseGLBufferObject())
2042        {
2043            //OSG_NOTICE<<"Release PBO"<<std::endl;
2044            bo->releaseGLObjects(&state);
2045        }
2046    }
2047   
2048#ifdef DO_TIMING
2049    static double s_total_time = 0.0;
2050    double delta_time = osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick());
2051    s_total_time += delta_time;
2052    OSG_NOTICE<<"glTexImage2D "<<delta_time<<"ms  total "<<s_total_time<<"ms"<<std::endl;
2053#endif
2054
2055    if (needImageRescale)
2056    {
2057        // clean up the resized image.
2058        delete [] dataPtr;
2059    }
2060   
2061    if (useClientStorage)
2062    {
2063        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_FALSE);
2064    }
2065}
2066
2067
2068
2069void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight, GLint inInternalFormat, GLint numMipmapLevels) const
2070{
2071    // if we don't have a valid image we can't create a texture!
2072    if (!image || !image->data())
2073        return;
2074
2075    // image size has changed so we have to re-load the image from scratch.
2076    if (image->s()!=inwidth || image->t()!=inheight || image->getInternalTextureFormat()!=inInternalFormat )
2077    {
2078        applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
2079        return;
2080    }
2081    // else image size the same as when loaded so we can go ahead and subload
2082   
2083    // If the texture's internal format is a compressed type, then the
2084    // user is requesting that the graphics card compress the image if it's
2085    // not already compressed. However, if the image is not a multiple of
2086    // four in each dimension the subsequent calls to glTexSubImage* will
2087    // fail. Revert to uncompressed format in this case.
2088    if (isCompressedInternalFormat(_internalFormat) &&
2089        (((inwidth >> 2) << 2) != inwidth ||
2090         ((inheight >> 2) << 2) != inheight))
2091    {
2092        applyTexImage2D_load(state, target, image, inwidth, inheight, numMipmapLevels);
2093        return;
2094    }
2095
2096#ifdef DO_TIMING
2097    osg::Timer_t start_tick = osg::Timer::instance()->tick();
2098    OSG_NOTICE<<"glTexSubImage2D pixelFormat = "<<std::hex<<image->getPixelFormat()<<std::dec<<std::endl;
2099#endif
2100   
2101
2102    // get the contextID (user defined ID of 0 upwards) for the
2103    // current OpenGL context.
2104    const unsigned int contextID = state.getContextID();
2105    const Extensions* extensions = getExtensions(contextID,true);
2106
2107    // select the internalFormat required for the texture.
2108    bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
2109   
2110    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
2111   
2112    unsigned char* dataPtr = (unsigned char*)image->data();
2113
2114    bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
2115    if (needImageRescale)
2116    {
2117        // resize the image to power of two.
2118        if (image->isMipmap())
2119        {
2120            OSG_WARN<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
2121            return;
2122        }
2123        else if (compressed_image)
2124        {
2125            OSG_WARN<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
2126            return;
2127        }
2128
2129        unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
2130        dataPtr = new unsigned char [newTotalSize];
2131
2132        if (!dataPtr)
2133        {
2134            OSG_WARN<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
2135            return;
2136        }
2137
2138        if (!image->getFileName().empty()) { OSG_NOTICE << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl; }
2139        else { OSG_NOTICE << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl; }
2140
2141        // rescale the image to the correct size.
2142        PixelStorageModes psm;
2143        psm.pack_alignment = image->getPacking();
2144        psm.unpack_alignment = image->getPacking();
2145
2146        gluScaleImage(&psm, image->getPixelFormat(),
2147                      image->s(),image->t(),image->getDataType(),image->data(),
2148                      inwidth,inheight,image->getDataType(),
2149                      dataPtr);
2150    }
2151
2152
2153    bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
2154    bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
2155    bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
2156
2157    GLBufferObject* pbo = image->getOrCreateGLBufferObject(contextID);
2158    if (pbo && !needImageRescale && !useGluBuildMipMaps)
2159    {
2160        state.bindPixelBufferObject(pbo);
2161        dataPtr = reinterpret_cast<unsigned char*>(pbo->getOffset(image->getBufferIndex()));
2162#ifdef DO_TIMING
2163        OSG_NOTICE<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
2164#endif
2165    }
2166    else
2167    {
2168        pbo = 0;
2169    }
2170
2171    if( !mipmappingRequired || useHardwareMipMapGeneration)
2172    {
2173
2174        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
2175
2176        if (!compressed_image)
2177        {
2178            glTexSubImage2D( target, 0,
2179                0, 0,
2180                inwidth, inheight,
2181                (GLenum)image->getPixelFormat(),
2182                (GLenum)image->getDataType(),
2183                dataPtr);
2184        }
2185        else if (extensions->isCompressedTexImage2DSupported())
2186        {       
2187            GLint blockSize,size;
2188            getCompressedSize(image->getInternalTextureFormat(), inwidth, inheight, 1, blockSize,size);
2189
2190            extensions->glCompressedTexSubImage2D(target, 0,
2191                0,0,
2192                inwidth, inheight,
2193                (GLenum)image->getPixelFormat(),
2194                size,
2195                dataPtr);
2196        }
2197
2198        mipmapAfterTexImage(state, mipmapResult);
2199    }
2200    else
2201    {
2202        if (image->isMipmap())
2203        {
2204            numMipmapLevels = image->getNumMipmapLevels();
2205
2206            int width  = inwidth;
2207            int height = inheight;
2208
2209            if( !compressed_image )
2210            {
2211                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
2212                {
2213
2214                    if (width == 0)
2215                        width = 1;
2216                    if (height == 0)
2217                        height = 1;
2218
2219                    glTexSubImage2D( target, k,
2220                        0, 0,
2221                        width, height,
2222                        (GLenum)image->getPixelFormat(),
2223                        (GLenum)image->getDataType(),
2224                        dataPtr + image->getMipmapOffset(k));
2225
2226                    width >>= 1;
2227                    height >>= 1;
2228                }
2229            }
2230            else if (extensions->isCompressedTexImage2DSupported())
2231            {
2232                GLint blockSize,size;
2233                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
2234                {
2235                    if (width == 0)
2236                        width = 1;
2237                    if (height == 0)
2238                        height = 1;
2239
2240                    getCompressedSize(image->getInternalTextureFormat(), width, height, 1, blockSize,size);
2241
2242                    //state.checkGLErrors("before extensions->glCompressedTexSubImage2D(");
2243
2244                    extensions->glCompressedTexSubImage2D(target, k, 
2245                                                       0, 0,
2246                                                       width, height,
2247                                                       (GLenum)image->getPixelFormat(),
2248                                                       size,
2249                                                       dataPtr + image->getMipmapOffset(k));
2250
2251                    //state.checkGLErrors("after extensions->glCompressedTexSubImage2D(");
2252
2253                    width >>= 1;
2254                    height >>= 1;
2255                }
2256
2257            }
2258        }
2259        else
2260        {
2261            //OSG_WARN<<"Warning:: cannot subload mip mapped texture from non mipmapped image."<<std::endl;
2262            applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
2263        }
2264    }
2265   
2266    if (pbo)
2267    {
2268        state.unbindPixelBufferObject();
2269    }
2270#ifdef DO_TIMING
2271    OSG_NOTICE<<"glTexSubImage2D "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
2272#endif
2273
2274    if (needImageRescale)
2275    {
2276        // clean up the resized image.
2277        delete [] dataPtr;
2278    }
2279}
2280
2281bool Texture::isHardwareMipmapGenerationEnabled(const State& state) const
2282{
2283    if (_useHardwareMipMapGeneration)
2284    {
2285        unsigned int contextID = state.getContextID();
2286        const Extensions* extensions = getExtensions(contextID,true);
2287
2288        if (extensions->isGenerateMipMapSupported())
2289        {
2290            return true;
2291        }
2292
2293        const FBOExtensions* fbo_ext = FBOExtensions::instance(contextID,true);
2294
2295        if (fbo_ext->glGenerateMipmap)
2296        {
2297            return true;
2298        }
2299    }
2300
2301    return false;
2302}
2303
2304Texture::GenerateMipmapMode Texture::mipmapBeforeTexImage(const State& state, bool hardwareMipmapOn) const
2305{
2306    if (hardwareMipmapOn)
2307    {
2308#if defined( OSG_GLES2_AVAILABLE ) || defined( OSG_GL3_AVAILABLE )
2309        return GENERATE_MIPMAP;
2310#else
2311        int width = getTextureWidth();
2312        int height = getTextureHeight();
2313
2314        //quick bithack to determine whether width or height are non-power-of-two
2315        if ((width & (width - 1)) || (height & (height - 1)))
2316        {
2317            //GL_GENERATE_MIPMAP_SGIS with non-power-of-two textures on NVIDIA hardware
2318            //is extremely slow. Use glGenerateMipmapEXT() instead if supported.
2319            if (_internalFormatType != SIGNED_INTEGER &&
2320                _internalFormatType != UNSIGNED_INTEGER)
2321            {
2322                if (FBOExtensions::instance(state.getContextID(), true)->glGenerateMipmap)
2323                {
2324                    return GENERATE_MIPMAP;
2325                }
2326            }
2327        }
2328
2329        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
2330        return GENERATE_MIPMAP_TEX_PARAMETER;
2331#endif
2332    }
2333    return GENERATE_MIPMAP_NONE;
2334}
2335
2336void Texture::mipmapAfterTexImage(State& state, GenerateMipmapMode beforeResult) const
2337{
2338    switch (beforeResult)
2339    {
2340        case GENERATE_MIPMAP:
2341        {
2342            unsigned int contextID = state.getContextID();
2343            TextureObject* textureObject = getTextureObject(contextID);
2344            if (textureObject)
2345            {
2346                osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(contextID, true);
2347                fbo_ext->glGenerateMipmap(textureObject->target());
2348            }
2349            break;
2350        }
2351        case GENERATE_MIPMAP_TEX_PARAMETER:
2352            glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
2353            break;
2354        case GENERATE_MIPMAP_NONE:
2355            break;
2356    }
2357}
2358
2359void Texture::generateMipmap(State& state) const
2360{
2361    const unsigned int contextID = state.getContextID();
2362
2363    // get the texture object for the current contextID.
2364    TextureObject* textureObject = getTextureObject(contextID);
2365
2366    // if not initialized before, then do nothing
2367    if (textureObject == NULL) return;
2368
2369    _texMipmapGenerationDirtyList[contextID] = 0;
2370   
2371    // if internal format does not provide automatic mipmap generation, then do manual allocation
2372    if (_internalFormatType == SIGNED_INTEGER || _internalFormatType == UNSIGNED_INTEGER)
2373    {
2374        allocateMipmap(state);
2375        return;
2376    }
2377   
2378    // get fbo extension which provides us with the glGenerateMipmapEXT function
2379    osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(state.getContextID(), true);
2380
2381    // check if the function is supported
2382    if (fbo_ext->glGenerateMipmap)
2383    {
2384        textureObject->bind();
2385        fbo_ext->glGenerateMipmap(textureObject->target());
2386       
2387        // inform state that this texture is the current one bound.
2388        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
2389   
2390    // if the function is not supported, then do manual allocation
2391    }else
2392    {
2393        allocateMipmap(state);
2394    }
2395   
2396}
2397
2398void Texture::compileGLObjects(State& state) const
2399{
2400    apply(state);
2401}
2402
2403void Texture::resizeGLObjectBuffers(unsigned int maxSize)
2404{
2405    _textureObjectBuffer.resize(maxSize);
2406    _texParametersDirtyList.resize(maxSize);
2407    _texMipmapGenerationDirtyList.resize(maxSize);
2408}
2409
2410void Texture::releaseGLObjects(State* state) const
2411{
2412//    if (state) OSG_NOTICE<<"Texture::releaseGLObjects contextID="<<state->getContextID()<<std::endl;
2413//    else OSG_NOTICE<<"Texture::releaseGLObjects no State "<<std::endl;
2414
2415    if (!state) const_cast<Texture*>(this)->dirtyTextureObject();
2416    else
2417    {
2418        unsigned int contextID = state->getContextID();
2419        if (_textureObjectBuffer[contextID].valid())
2420        {
2421            Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get());
2422
2423            _textureObjectBuffer[contextID] = 0;
2424        }
2425    }
2426}
2427
2428Texture::Extensions* Texture::getExtensions(unsigned int contextID,bool createIfNotInitalized)
2429{
2430    if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID);
2431    return s_extensions[contextID].get();
2432}
2433
2434void Texture::setExtensions(unsigned int contextID,Extensions* extensions)
2435{
2436    s_extensions[contextID] = extensions;
2437}
2438
2439Texture::Extensions::Extensions(unsigned int contextID)
2440{
2441    const char* version = (const char*) glGetString( GL_VERSION );
2442    if (!version)
2443    {
2444        OSG_FATAL<<"Error: In Texture::Extensions::setupGLExtensions(..) OpenGL version test failed, requires valid graphics context."<<std::endl;
2445        return;
2446    }
2447   
2448    const char* renderer = (const char*) glGetString(GL_RENDERER);
2449    std::string rendererString(renderer ? renderer : "");
2450
2451    bool builtInSupport = OSG_GLES2_FEATURES || OSG_GL3_FEATURES;
2452   
2453    _isMultiTexturingSupported = builtInSupport || OSG_GLES1_FEATURES ||
2454                                 isGLExtensionOrVersionSupported( contextID,"GL_ARB_multitexture", 1.3f) ||
2455                                 isGLExtensionOrVersionSupported(contextID,"GL_EXT_multitexture", 1.3f);
2456                                 
2457    _isTextureFilterAnisotropicSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_filter_anisotropic");
2458   
2459    _isTextureCompressionARBSupported = builtInSupport || isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_compression", 1.3f);
2460   
2461    _isTextureCompressionS3TCSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_compression_s3tc");
2462
2463    _isTextureCompressionPVRTC2BPPSupported = isGLExtensionSupported(contextID,"GL_IMG_texture_compression_pvrtc");
2464
2465    _isTextureCompressionPVRTC4BPPSupported = _isTextureCompressionPVRTC2BPPSupported;//covered by same extension
2466
2467    _isTextureCompressionETCSupported = isGLExtensionSupported(contextID,"GL_OES_compressed_ETC1_RGB8_texture");
2468   
2469
2470    _isTextureCompressionRGTCSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_compression_rgtc");
2471
2472    _isTextureCompressionPVRTCSupported = isGLExtensionSupported(contextID,"GL_IMG_texture_compression_pvrtc");
2473
2474    _isTextureMirroredRepeatSupported = builtInSupport ||
2475                                        isGLExtensionOrVersionSupported(contextID,"GL_IBM_texture_mirrored_repeat", 1.4f) ||
2476                                        isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_mirrored_repeat", 1.4f);
2477                                       
2478    _isTextureEdgeClampSupported = builtInSupport ||
2479                                   isGLExtensionOrVersionSupported(contextID,"GL_EXT_texture_edge_clamp", 1.2f) ||
2480                                   isGLExtensionOrVersionSupported(contextID,"GL_SGIS_texture_edge_clamp", 1.2f);
2481                                   
2482
2483    _isTextureBorderClampSupported = OSG_GL3_FEATURES ||
2484                                     ((OSG_GL1_FEATURES || OSG_GL2_FEATURES) && isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_border_clamp", 1.3f));
2485   
2486    _isGenerateMipMapSupported = builtInSupport || isGLExtensionOrVersionSupported(contextID,"GL_SGIS_generate_mipmap", 1.4f);
2487
2488    _isTextureMultisampledSupported = isGLExtensionSupported(contextID,"GL_ARB_texture_multisample");
2489                                 
2490    _isShadowSupported = OSG_GL3_FEATURES || isGLExtensionSupported(contextID,"GL_ARB_shadow");
2491   
2492    _isShadowAmbientSupported = isGLExtensionSupported(contextID,"GL_ARB_shadow_ambient");
2493
2494    _isClientStorageSupported = isGLExtensionSupported(contextID,"GL_APPLE_client_storage");
2495
2496    _isNonPowerOfTwoTextureNonMipMappedSupported = builtInSupport || isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_non_power_of_two", 2.0) || isGLExtensionSupported(contextID,"GL_APPLE_texture_2D_limited_npot");
2497
2498    _isNonPowerOfTwoTextureMipMappedSupported = builtInSupport || _isNonPowerOfTwoTextureNonMipMappedSupported;
2499   
2500    _isTextureIntegerEXTSupported = OSG_GL3_FEATURES || isGLExtensionSupported(contextID, "GL_EXT_texture_integer");
2501
2502    #if 0
2503    if (rendererString.find("Radeon")!=std::string::npos || rendererString.find("RADEON")!=std::string::npos)
2504    {
2505        _isNonPowerOfTwoTextureMipMappedSupported = false;
2506        OSG_INFO<<"Disabling _isNonPowerOfTwoTextureMipMappedSupported for ATI hardware."<<std::endl;
2507    }
2508    #endif
2509   
2510    if (rendererString.find("GeForce FX")!=std::string::npos)
2511    {
2512        _isNonPowerOfTwoTextureMipMappedSupported = false;
2513        OSG_INFO<<"Disabling _isNonPowerOfTwoTextureMipMappedSupported for GeForce FX hardware."<<std::endl;
2514    }
2515
2516    _maxTextureSize=0;
2517    glGetIntegerv(GL_MAX_TEXTURE_SIZE,&_maxTextureSize);
2518
2519    char *ptr;
2520    if( (ptr = getenv("OSG_MAX_TEXTURE_SIZE")) != 0)
2521    {
2522        GLint osg_max_size = atoi(ptr);
2523
2524        if (osg_max_size<_maxTextureSize)
2525        {
2526
2527            _maxTextureSize = osg_max_size;
2528        }
2529    }
2530
2531    if( _isMultiTexturingSupported )
2532    {
2533       _numTextureUnits = 0;
2534       #if defined(OSG_GLES2_AVAILABLE) || defined(OSG_GL3_AVAILABLE)
2535           glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,&_numTextureUnits);
2536       #else
2537           if (osg::asciiToFloat(version)>=2.0)
2538           {
2539               glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,&_numTextureUnits);
2540           }
2541           else
2542           {
2543               glGetIntegerv(GL_MAX_TEXTURE_UNITS,&_numTextureUnits);
2544           }
2545       #endif
2546    }
2547    else
2548    {
2549       _numTextureUnits = 1;
2550    }
2551
2552    setGLExtensionFuncPtr(_glCompressedTexImage2D,"glCompressedTexImage2D","glCompressedTexImage2DARB");
2553    setGLExtensionFuncPtr(_glCompressedTexSubImage2D,"glCompressedTexSubImage2D","glCompressedTexSubImage2DARB");
2554    setGLExtensionFuncPtr(_glGetCompressedTexImage,"glGetCompressedTexImage","glGetCompressedTexImageARB");;
2555    setGLExtensionFuncPtr(_glTexImage2DMultisample, "glTexImage2DMultisample", "glTexImage2DMultisampleARB");
2556
2557    setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIiv", "glTexParameterIivARB");
2558    setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuiv", "glTexParameterIuivARB");
2559
2560
2561    if (_glTexParameterIiv == NULL) setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIivEXT");
2562    if (_glTexParameterIuiv == NULL) setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuivEXT");
2563
2564    _isTextureMaxLevelSupported = ( getGLVersionNumber() >= 1.2f );
2565}
2566
2567
2568}
Note: See TracBrowser for help on using the browser.