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

Revision 12912, 29.6 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
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/Texture2DArray>
15#include <osg/State>
16#include <osg/Notify>
17
18#include <string.h>
19
20
21using namespace osg;
22
23Texture2DArray::Texture2DArray():
24            _textureWidth(0),
25            _textureHeight(0),
26            _textureDepth(0),
27            _numMipmapLevels(0)
28{
29}
30
31Texture2DArray::Texture2DArray(const Texture2DArray& text,const CopyOp& copyop):
32            Texture(text,copyop),
33            _textureWidth(text._textureWidth),
34            _textureHeight(text._textureHeight),
35            _textureDepth(text._textureDepth),
36            _numMipmapLevels(text._numMipmapLevels),
37            _subloadCallback(text._subloadCallback)
38{
39    // copy all images by iterating through all of them
40    for (int i=0; i < text._textureDepth; i++)
41    {
42        _images.push_back(copyop(text._images[i].get()));
43        _modifiedCount.push_back(ImageModifiedCount());
44    }
45}
46
47Texture2DArray::~Texture2DArray()
48{
49}
50
51int Texture2DArray::compare(const StateAttribute& sa) const
52{
53    // check the types are equal and then create the rhs variable
54    // used by the COMPARE_StateAttribute_Parameter macros below.
55    COMPARE_StateAttribute_Types(Texture2DArray,sa)
56
57    bool noImages = true;
58    for (int n=0; n < _textureDepth; n++)
59    {
60        if (noImages && _images[n].valid()) noImages = false;
61        if (noImages && rhs._images[n].valid()) noImages = false;
62   
63        if (_images[n]!=rhs._images[n]) // smart pointer comparison.
64        {
65            if (_images[n].valid())
66            {
67                if (rhs._images[n].valid())
68                {
69                    int result = _images[n]->compare(*rhs._images[n]);
70                    if (result!=0) return result;
71                }
72                else
73                {
74                    return 1; // valid lhs._image is greater than null.
75                }
76            }
77            else if (rhs._images[n].valid())
78            {
79                return -1; // valid rhs._image is greater than null.
80            }
81        }
82    }
83
84   
85    if (noImages)
86    {
87        int result = compareTextureObjects(rhs);
88        if (result!=0) return result;
89    }
90
91    int result = compareTexture(rhs);
92    if (result!=0) return result;
93
94    // compare each parameter in turn against the rhs.
95    COMPARE_StateAttribute_Parameter(_textureWidth)
96    COMPARE_StateAttribute_Parameter(_textureHeight)
97    COMPARE_StateAttribute_Parameter(_textureDepth)
98    COMPARE_StateAttribute_Parameter(_subloadCallback)
99
100    return 0; // passed all the above comparison macros, must be equal.
101}
102
103void Texture2DArray::setImage(unsigned int layer, Image* image)
104{
105    // check if the layer exceeds the texture depth
106    if (static_cast<int>(layer) >= _textureDepth)
107    {
108        // print warning and do nothing
109        OSG_WARN<<"Warning: Texture2DArray::setImage(..) failed, the given layer number is bigger then the size of the texture array."<<std::endl;
110        return;
111    }
112   
113    if (_images[layer] == image) return;
114
115    unsigned numImageRequireUpdateBefore = 0;
116    for (unsigned int i=0; i<getNumImages(); ++i)
117    {
118        if (_images[i].valid() && _images[i]->requiresUpdateCall()) ++numImageRequireUpdateBefore;
119    }
120
121    // set image
122    _images[layer] = image;
123   _modifiedCount[layer].setAllElementsTo(0);
124
125    // find out if we need to reset the update callback to handle the animation of image
126    unsigned numImageRequireUpdateAfter = 0;
127    for (unsigned int i=0; i<getNumImages(); ++i)
128    {
129        if (_images[i].valid() && _images[i]->requiresUpdateCall()) ++numImageRequireUpdateAfter;
130    }
131
132    if (numImageRequireUpdateBefore>0)
133    {
134        if (numImageRequireUpdateAfter==0)
135        {
136            setUpdateCallback(0);
137            setDataVariance(osg::Object::STATIC);
138        }
139    }
140    else if (numImageRequireUpdateAfter>0)
141    {
142        setUpdateCallback(new Image::UpdateCallback());
143        setDataVariance(osg::Object::DYNAMIC);
144    }
145}
146 
147void Texture2DArray::setTextureSize(int width, int height, int depth)
148{
149    // set dimensions
150    _textureWidth = width;
151    _textureHeight = height;
152    setTextureDepth(depth);
153}
154
155void Texture2DArray::setTextureDepth(int depth)
156{   
157    // if we decrease the number of layers, then delete non-used
158    if (depth < _textureDepth)
159    {
160        _images.resize(depth);
161        _modifiedCount.resize(depth);
162    }
163   
164    // if we increase the array, then add new empty elements
165    if (depth > _textureDepth)
166    {
167        _images.resize(depth, ref_ptr<Image>(0));
168        _modifiedCount.resize(depth, ImageModifiedCount());
169    }
170       
171    // resize the texture array
172    _textureDepth = depth;
173}
174
175Image* Texture2DArray::getImage(unsigned int layer)
176{
177    return _images[layer].get();
178}
179
180const Image* Texture2DArray::getImage(unsigned int layer) const
181{
182    return _images[layer].get();
183}
184
185bool Texture2DArray::imagesValid() const
186{
187    if (_textureDepth < 1) return false;
188    for (int n=0; n < _textureDepth; n++)
189    {
190        if (!_images[n].valid() || !_images[n]->data())
191            return false;
192    }
193    return true;
194}
195
196void Texture2DArray::computeInternalFormat() const
197{
198    if (imagesValid()) computeInternalFormatWithImage(*_images[0]);
199    else computeInternalFormatType();
200}
201
202
203void Texture2DArray::apply(State& state) const
204{
205    // get the contextID (user defined ID of 0 upwards) for the
206    // current OpenGL context.
207    const unsigned int contextID = state.getContextID();
208
209    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID).get();
210    ElapsedTime elapsedTime(&(tom->getApplyTime()));
211    tom->getNumberApplied()++;
212
213    const Extensions* extensions = getExtensions(contextID,true);
214
215    // if not supported, then return
216    if (!extensions->isTexture2DArraySupported() || !extensions->isTexture3DSupported())
217    {
218        OSG_WARN<<"Warning: Texture2DArray::apply(..) failed, 2D texture arrays are not support by OpenGL driver."<<std::endl;
219        return;
220    }
221   
222    // get the texture object for the current contextID.
223    TextureObject* textureObject = getTextureObject(contextID);
224
225    if (textureObject && _textureDepth>0)
226    {
227        const osg::Image* image = _images[0].get();
228        if (image && getModifiedCount(0, contextID) != image->getModifiedCount())
229        {
230            // compute the internal texture format, this set the _internalFormat to an appropriate value.
231            computeInternalFormat();
232
233            GLsizei new_width, new_height, new_numMipmapLevels;
234
235            // compute the dimensions of the texture.
236            computeRequiredTextureDimensions(state, *image, new_width, new_height, new_numMipmapLevels);
237
238            if (!textureObject->match(GL_TEXTURE_2D_ARRAY_EXT, new_numMipmapLevels, _internalFormat, new_width, new_height, 1, _borderWidth))
239            {
240                Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get());
241                _textureObjectBuffer[contextID] = 0;
242                textureObject = 0;
243            }
244        }
245    }
246
247    // if we already have an texture object, then
248    if (textureObject)
249    {
250        // bind texture object
251        textureObject->bind();
252
253        // if texture parameters changed, then reset them
254        if (getTextureParameterDirty(state.getContextID())) applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT,state);
255
256        // if subload is specified, then use it to subload the images to GPU memory
257        if (_subloadCallback.valid())
258        {
259            _subloadCallback->subload(*this,state);
260        }
261        else
262        {
263            // for each image of the texture array do
264            for (GLsizei n=0; n < _textureDepth; n++)
265            {
266                osg::Image* image = _images[n].get();
267               
268                // if image content is modified, then upload it to the GPU memory
269                if (image && getModifiedCount(n,contextID) != image->getModifiedCount())
270                {
271                    applyTexImage2DArray_subload(state, image, _textureWidth, _textureHeight, n, _internalFormat, _numMipmapLevels);
272                    getModifiedCount(n,contextID) = image->getModifiedCount();
273                }
274            }
275        }
276
277    }
278   
279    // there is no texture object, but exists a subload callback, so use it to upload images
280    else if (_subloadCallback.valid())
281    {
282        // generate texture (i.e. glGenTexture) and apply parameters
283        _textureObjectBuffer[contextID] = textureObject = generateTextureObject(this, contextID, GL_TEXTURE_2D_ARRAY_EXT);
284        textureObject->bind();
285        applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT, state);
286        _subloadCallback->load(*this,state);
287    }
288   
289    // nothing before, but we have valid images, so do manual upload and create texture object manually
290    // TODO: we assume _images[0] is valid, however this may not be always the case
291    //       some kind of checking for the first valid image is required (Art, may 2008)
292    else if (imagesValid())
293    {
294        // compute the internal texture format, this set the _internalFormat to an appropriate value.
295        computeInternalFormat();
296
297        // compute the dimensions of the texture.
298        computeRequiredTextureDimensions(state,*_images[0],_textureWidth, _textureHeight, _numMipmapLevels);
299
300        // create texture object
301        textureObject = generateTextureObject(
302                this, contextID,GL_TEXTURE_2D_ARRAY_EXT,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0);
303       
304        // bind texture
305        textureObject->bind();
306        applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT, state);
307
308        _textureObjectBuffer[contextID] = textureObject;
309
310        // First we need to allocate the texture memory
311        int sourceFormat = _sourceFormat ? _sourceFormat : _internalFormat;
312
313        if( isCompressedInternalFormat( sourceFormat ) &&
314            sourceFormat == _internalFormat &&
315            extensions->isCompressedTexImage3DSupported() )
316        {
317            extensions->glCompressedTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat,
318                     _textureWidth, _textureHeight, _textureDepth, _borderWidth,
319                     _images[0]->getImageSizeInBytes() * _textureDepth,
320                     0);
321        }
322        else
323        {   
324            // Override compressed source format with safe GL_RGBA value which not generate error
325            // We can safely do this as source format is not important when source data is NULL
326            if( isCompressedInternalFormat( sourceFormat ) )
327                sourceFormat = GL_RGBA;
328
329            extensions->glTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat,
330                     _textureWidth, _textureHeight, _textureDepth, _borderWidth,
331                     sourceFormat, _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
332                     0);
333        }
334
335       // For certain we have to manually allocate memory for mipmaps if images are compressed
336       // if not allocated OpenGL will produce errors on mipmap upload.
337       // I have not tested if this is neccessary for plain texture formats but
338       // common sense suggests its required as well.
339       if( _min_filter != LINEAR && _min_filter != NEAREST && _images[0]->isMipmap() )
340           allocateMipmap( state );
341
342        // now for each layer we upload it into the memory
343        for (GLsizei n=0; n<_textureDepth; n++)
344        {
345            // if image is valid then upload it to the texture memory
346            osg::Image* image = _images[n].get();
347            if (image)
348            {
349                // now load the image data into the memory, this will also check if image do have valid properties
350                applyTexImage2DArray_subload(state, image, _textureWidth, _textureHeight, n, _internalFormat, _numMipmapLevels);
351                getModifiedCount(n,contextID) = image->getModifiedCount();
352            }
353        }
354
355        const Texture::Extensions* texExtensions = Texture::getExtensions(contextID,true);
356        // source images have no mipmamps but we could generate them... 
357        if( _min_filter != LINEAR && _min_filter != NEAREST && !_images[0]->isMipmap() && 
358            _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported() )
359            {
360                _numMipmapLevels = Image::computeNumberOfMipmapLevels( _textureWidth, _textureHeight );
361                generateMipmap( state );
362            }
363
364        textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0);
365       
366        // unref image data?
367        if (isSafeToUnrefImageData(state))
368        {
369            Texture2DArray* non_const_this = const_cast<Texture2DArray*>(this);
370            for (int n=0; n<_textureDepth; n++)
371            {               
372                if (_images[n].valid() && _images[n]->getDataVariance()==STATIC)
373                {
374                    non_const_this->_images[n] = NULL;
375                }
376            }
377        }
378       
379    }
380   
381    // No images present, but dimensions are set. So create empty texture
382    else if ( (_textureWidth > 0) && (_textureHeight > 0) && (_textureDepth > 0) && (_internalFormat!=0) )
383    {
384        // generate texture
385        _textureObjectBuffer[contextID] = textureObject = generateTextureObject(
386                this, contextID, GL_TEXTURE_2D_ARRAY_EXT,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0);
387       
388        textureObject->bind();
389        applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT,state);
390       
391        extensions->glTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat,
392                     _textureWidth, _textureHeight, _textureDepth,
393                     _borderWidth,
394                     _sourceFormat ? _sourceFormat : _internalFormat,
395                     _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
396                     0);
397       
398    }
399   
400    // nothing before, so just unbind the texture target
401    else
402    {
403        glBindTexture( GL_TEXTURE_2D_ARRAY_EXT, 0 );
404    }
405
406    // if texture object is now valid and we have to allocate mipmap levels, then
407    if (textureObject != 0 && _texMipmapGenerationDirtyList[contextID])
408    {
409        generateMipmap(state);
410    }
411}
412
413
414void Texture2DArray::applyTexImage2DArray_subload(State& state, Image* image, GLsizei inwidth, GLsizei inheight, GLsizei indepth, GLint inInternalFormat, GLsizei& numMipmapLevels) const
415{
416    // if we don't have a valid image we can't create a texture!
417    if (!imagesValid())
418        return;
419
420    // get the contextID (user defined ID of 0 upwards) for the
421    // current OpenGL context.
422    const unsigned int contextID = state.getContextID();
423    const Extensions* extensions = getExtensions(contextID,true);   
424    const Texture::Extensions* texExtensions = Texture::getExtensions(contextID,true);
425    GLenum target = GL_TEXTURE_2D_ARRAY_EXT;
426   
427    // compute the internal texture format, this set the _internalFormat to an appropriate value.
428    computeInternalFormat();
429
430    // select the internalFormat required for the texture.
431    // bool compressed = isCompressedInternalFormat(_internalFormat);
432    bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
433
434    // if the required layer is exceeds the maximum allowed layer sizes
435    if (indepth > extensions->maxLayerCount())
436    {
437        // we give a warning and do nothing
438        OSG_WARN<<"Warning: Texture2DArray::applyTexImage2DArray_subload(..) the given layer number exceeds the maximum number of supported layers."<<std::endl;
439        return;       
440    }
441
442    //Rescale if resize hint is set or NPOT not supported or dimensions exceed max size
443    if( _resizeNonPowerOfTwoHint || !texExtensions->isNonPowerOfTwoTextureSupported(_min_filter)
444        || inwidth > extensions->max2DSize()
445        || inheight > extensions->max2DSize())
446        image->ensureValidSizeForTexturing(extensions->max2DSize());
447
448    // image size or format has changed, this is not allowed, hence return
449    if (image->s()!=inwidth ||
450        image->t()!=inheight ||
451        image->getInternalTextureFormat()!=inInternalFormat )
452    {
453        OSG_WARN<<"Warning: Texture2DArray::applyTexImage2DArray_subload(..) given image do have wrong dimension or internal format."<<std::endl;
454        return;       
455    }   
456   
457    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
458    glPixelStorei(GL_UNPACK_ROW_LENGTH,image->getRowLength());
459
460    bool useHardwareMipmapGeneration =
461        !image->isMipmap() && _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported();
462
463    // if no special mipmapping is required, then
464    if( _min_filter == LINEAR || _min_filter == NEAREST || useHardwareMipmapGeneration )
465    {
466        if( _min_filter == LINEAR || _min_filter == NEAREST )
467            numMipmapLevels = 1;
468        else //Hardware Mipmap Generation
469            numMipmapLevels = image->getNumMipmapLevels();
470
471        // upload non-compressed image
472        if ( !compressed_image )
473        {
474            extensions->glTexSubImage3D( target, 0,
475                                      0, 0, indepth,
476                                      inwidth, inheight, 1,
477                                      (GLenum)image->getPixelFormat(),
478                                      (GLenum)image->getDataType(),
479                                      image->data() );
480        }
481       
482        // if we support compression and image is compressed, then
483        else if (extensions->isCompressedTexImage3DSupported())
484        {
485            // OSG_WARN<<"glCompressedTexImage3D "<<inwidth<<", "<<inheight<<", "<<indepth<<std::endl;
486
487            GLint blockSize, size;
488            getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size);
489
490            extensions->glCompressedTexSubImage3D(target, 0,
491                0, 0, indepth, 
492                inwidth, inheight, 1,
493                (GLenum)image->getPixelFormat(),
494                size,
495                image->data());
496        }
497
498    // we want to use mipmapping, so enable it
499    }else
500    {
501        // image does not provide mipmaps, so we have to create them
502        if( !image->isMipmap() )
503        {
504            numMipmapLevels = 1;
505            OSG_WARN<<"Warning: Texture2DArray::applyTexImage2DArray_subload(..) mipmap layer not passed, and auto mipmap generation turned off or not available. Check texture's min/mag filters & hardware mipmap generation."<<std::endl;
506
507            // the image object does provide mipmaps, so upload the in the certain levels of a layer
508        }else
509        {
510            numMipmapLevels = image->getNumMipmapLevels();
511
512            int width  = image->s();
513            int height = image->t();
514
515            if( !compressed_image )
516            {
517
518                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height ) ;k++)
519                {
520                    if (width == 0)
521                       width = 1;
522                    if (height == 0)
523                       height = 1;
524
525                    extensions->glTexSubImage3D( target, k, 0, 0, indepth,
526                                              width, height, 1,
527                                              (GLenum)image->getPixelFormat(),
528                                              (GLenum)image->getDataType(),
529                                               image->getMipmapData(k));
530
531                    width >>= 1;
532                    height >>= 1;
533                }
534            }
535            else if (extensions->isCompressedTexImage3DSupported())
536            {
537                GLint blockSize,size;
538                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
539                {
540                    if (width == 0)
541                        width = 1;
542                    if (height == 0)
543                        height = 1;
544
545                    getCompressedSize(image->getInternalTextureFormat(), width, height, 1, blockSize,size);
546
547//                    state.checkGLErrors("before extensions->glCompressedTexSubImage3D(");
548
549                    extensions->glCompressedTexSubImage3D(target, k, 0, 0, indepth,
550                                                       width, height, 1,
551                                                       (GLenum)image->getPixelFormat(),
552                                                       size,
553                                                       image->getMipmapData(k));
554
555//                    state.checkGLErrors("after extensions->glCompressedTexSubImage3D(");
556
557                    width >>= 1;
558                    height >>= 1;
559                }
560            }
561        }
562
563    }
564}
565
566
567void Texture2DArray::copyTexSubImage2DArray(State& state, int xoffset, int yoffset, int zoffset, int x, int y, int width, int height )
568{
569    const unsigned int contextID = state.getContextID();
570    const Extensions* extensions = getExtensions(contextID,true);
571
572    // get the texture object for the current contextID.
573    TextureObject* textureObject = getTextureObject(contextID);
574
575    // if texture object is valid
576    if (textureObject != 0)
577    {
578        textureObject->bind();
579
580        applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT,state);
581        extensions->glCopyTexSubImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, xoffset,yoffset,zoffset, x, y, width, height);
582
583        // inform state that this texture is the current one bound.
584        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
585
586    }
587    else
588    {
589        OSG_WARN<<"Warning: Texture2DArray::copyTexSubImage2DArray(..) failed, cannot not copy to a non existant texture."<<std::endl;
590    }
591}
592
593void Texture2DArray::allocateMipmap(State& state) const
594{
595    const unsigned int contextID = state.getContextID();
596
597    // get the texture object for the current contextID.
598    TextureObject* textureObject = getTextureObject(contextID);
599   
600    if (textureObject && _textureWidth != 0 && _textureHeight != 0 && _textureDepth != 0)
601    {       
602        const Extensions* extensions = getExtensions(contextID,true);
603
604        int safeSourceFormat = _sourceFormat ? _sourceFormat : _internalFormat;
605
606        // Make sure source format does not contain compressed formats value (like DXT3)
607        // they are invalid when passed to glTexImage3D source format parameter
608        if( isCompressedInternalFormat( safeSourceFormat ) )
609        {
610            if( safeSourceFormat != _internalFormat || !extensions->isCompressedTexImage3DSupported() )
611                safeSourceFormat = GL_RGBA;
612        }
613
614        // bind texture
615        textureObject->bind();
616
617        // compute number of mipmap levels
618        int width = _textureWidth;
619        int height = _textureHeight;
620        int numMipmapLevels = Image::computeNumberOfMipmapLevels(width, height);
621
622        // we do not reallocate the level 0, since it was already allocated
623        width >>= 1;
624        height >>= 1;
625       
626        for( GLsizei k = 1; k < numMipmapLevels  && (width || height); k++)
627        {
628            if (width == 0)
629                width = 1;
630            if (height == 0)
631                height = 1;
632
633            if( isCompressedInternalFormat(safeSourceFormat) )
634            {
635                int size = 0, blockSize = 0;
636
637                getCompressedSize( _internalFormat, width, height, _textureDepth, blockSize, size);
638
639                extensions->glCompressedTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, k, _internalFormat,
640                                                    width, height, _textureDepth, _borderWidth,
641                                                    size,
642                                                    NULL);
643            }
644            else
645            {
646                extensions->glTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, k, _internalFormat,
647                     width, height, _textureDepth, _borderWidth,
648                     safeSourceFormat, _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
649                     NULL);
650            }
651
652            width >>= 1;
653            height >>= 1;
654        }
655               
656        // inform state that this texture is the current one bound.
657        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);       
658    }
659}
660
661typedef buffered_value< ref_ptr<Texture2DArray::Extensions> > BufferedExtensions;
662static BufferedExtensions s_extensions;
663
664Texture2DArray::Extensions* Texture2DArray::getExtensions(unsigned int contextID,bool createIfNotInitalized)
665{
666    if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID);
667    return s_extensions[contextID].get();
668}
669
670void Texture2DArray::setExtensions(unsigned int contextID,Extensions* extensions)
671{
672    s_extensions[contextID] = extensions;
673}
674
675Texture2DArray::Extensions::Extensions(unsigned int contextID)
676{
677    setupGLExtensions(contextID);
678}
679
680Texture2DArray::Extensions::Extensions(const Extensions& rhs):
681    Referenced()
682{
683    _isTexture3DSupported = rhs._isTexture3DSupported;
684    _isTexture2DArraySupported = rhs._isTexture2DArraySupported;
685   
686    _max2DSize = rhs._max2DSize;
687    _maxLayerCount = rhs._maxLayerCount;
688   
689    _glTexImage3D = rhs._glTexImage3D;
690    _glTexSubImage3D = rhs._glTexSubImage3D;
691    _glCopyTexSubImage3D = rhs._glCopyTexSubImage3D;
692    _glCompressedTexImage3D = rhs._glCompressedTexImage3D;
693    _glCompressedTexSubImage3D = rhs._glCompressedTexSubImage3D;;
694}
695
696void Texture2DArray::Extensions::lowestCommonDenominator(const Extensions& rhs)
697{
698    if (!rhs._isTexture3DSupported)                 _isTexture3DSupported = false;
699    if (!rhs._isTexture2DArraySupported)            _isTexture2DArraySupported = false;
700    if (rhs._max2DSize<_max2DSize)                  _max2DSize = rhs._max2DSize;
701    if (rhs._maxLayerCount<_maxLayerCount)          _maxLayerCount = rhs._maxLayerCount;
702
703    if (!rhs._glTexImage3D)                         _glTexImage3D = 0;
704    if (!rhs._glTexSubImage3D)                      _glTexSubImage3D = 0;
705    if (!rhs._glCompressedTexImage3D)               _glTexImage3D = 0;
706    if (!rhs._glCompressedTexSubImage3D)            _glTexSubImage3D = 0;
707    if (!rhs._glCopyTexSubImage3D)                  _glCopyTexSubImage3D = 0;
708}
709
710void Texture2DArray::Extensions::setupGLExtensions(unsigned int contextID)
711{
712    _isTexture3DSupported = OSG_GL3_FEATURES ||
713                            isGLExtensionSupported(contextID,"GL_EXT_texture3D") ||
714                            strncmp((const char*)glGetString(GL_VERSION),"1.2",3)>=0;
715
716    _isTexture2DArraySupported = OSG_GL3_FEATURES || isGLExtensionSupported(contextID,"GL_EXT_texture_array");
717
718    _max2DSize = 0;
719    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &_max2DSize);
720    _maxLayerCount = 0;
721    glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, &_maxLayerCount);
722
723    setGLExtensionFuncPtr(_glTexImage3D, "glTexImage3D","glTexImage3DEXT");
724    setGLExtensionFuncPtr(_glTexSubImage3D, "glTexSubImage3D","glTexSubImage3DEXT");
725    setGLExtensionFuncPtr(_glCompressedTexImage3D, "glCompressedTexImage3D","glCompressedTexImage3DARB");
726    setGLExtensionFuncPtr(_glCompressedTexSubImage3D, "glCompressedTexSubImage3D","glCompressedTexSubImage3DARB");
727    setGLExtensionFuncPtr(_glCopyTexSubImage3D, "glCopyTexSubImage3D","glCopyTexSubImage3DEXT");
728}
729
730void Texture2DArray::Extensions::glTexImage3D( GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) const
731{
732    if (_glTexImage3D)
733    {
734        _glTexImage3D( target, level, internalFormat, width, height, depth, border, format, type, pixels);
735    }
736    else
737    {
738        OSG_WARN<<"Error: glTexImage3D not supported by OpenGL driver"<<std::endl;
739    }
740}
741
742void Texture2DArray::Extensions::glTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) const
743{
744    if (_glTexSubImage3D)
745    {
746        _glTexSubImage3D( target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
747    }
748    else
749    {
750        OSG_WARN<<"Error: glTexSubImage3D not supported by OpenGL driver"<<std::endl;
751    }
752}
753
754void Texture2DArray::Extensions::glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data) const
755{
756    if (_glCompressedTexImage3D)
757    {
758        _glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data);
759    }
760    else
761    {
762        OSG_WARN<<"Error: glCompressedTexImage3D not supported by OpenGL driver"<<std::endl;
763    }
764}
765
766void Texture2DArray::Extensions::glCompressedTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data ) const
767{
768    if (_glCompressedTexSubImage3D)
769    {
770        _glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
771    }
772    else
773    {
774        OSG_WARN<<"Error: glCompressedTexImage2D not supported by OpenGL driver"<<std::endl;
775    }
776}
777
778void Texture2DArray::Extensions::glCopyTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height ) const
779{
780    if (_glCopyTexSubImage3D)
781    {
782        _glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
783    }
784    else
785    {
786        OSG_WARN<<"Error: glCopyTexSubImage3D not supported by OpenGL driver"<<std::endl;
787    }
788}
Note: See TracBrowser for help on using the browser.