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

Revision 12912, 89.8 kB (checked in by robert, 2 years ago)

Added support for using GL_UNPACK_ROW_LENGTH in conjunction with texture's + osg::Image via new RowLength?
parameter in osg::Image. To support this Image::setData(..) now has a new optional rowLength parameter which
defaults to 0, which provides the original behaviour, Image::setRowLength(int) and int Image::getRowLength() are also provided.

With the introduction of RowLength? support in osg::Image it is now possible to create a sub image where
the t size of the image are smaller than the row length, useful for when you have a large image on the CPU
and which to use a small portion of it on the GPU. However, when these sub images are created the data
within the image is no longer contiguous so data access can no longer assume that all the data is in
one block. The new method Image::isDataContiguous() enables the user to check whether the data is contiguous,
and if not one can either access the data row by row using Image::data(column,row,image) accessor, or use the
new Image::DataIterator? for stepping through each block on memory assocatied with the image.

To support the possibility of non contiguous osg::Image usage of image objects has had to be updated to
check DataContiguous? and handle the case or use access via the DataIerator? or by row by row. To achieve
this a relatively large number of files has had to be modified, in particular the texture classes and
image plugins that doing writing.

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