osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarth/SparseTexture2DArray.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 #include <osgEarth/SparseTexture2DArray>
00020 
00021 // this class is only supported in newer OSG versions.
00022 #if OSG_VERSION_GREATER_OR_EQUAL( 2, 9, 8 )
00023 
00024 using namespace osgEarth;
00025 
00026 int
00027 SparseTexture2DArray::firstValidImageIndex() const 
00028 {
00029     for( int i=0; i<_images.size(); ++i )
00030         if ( _images[i].valid() )
00031             return i;
00032     return -1;
00033 }
00034 
00035 osg::Image* 
00036 SparseTexture2DArray::firstValidImage() const
00037 {
00038     int i = firstValidImageIndex();
00039     return i >= 0 ? _images[i].get() : 0L;
00040 }
00041 
00042 void 
00043 SparseTexture2DArray::computeInternalFormat() const
00044 {
00045     osg::Image* image = firstValidImage();
00046     if ( image )
00047         computeInternalFormatWithImage( *image );
00048     else
00049         computeInternalFormatType();
00050 }
00051 
00052 void 
00053 SparseTexture2DArray::apply( osg::State& state ) const
00054 {
00055     // get the contextID (user defined ID of 0 upwards) for the 
00056     // current OpenGL context.
00057     const unsigned int contextID = state.getContextID();
00058 
00059     Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID).get();
00060     //ElapsedTime elapsedTime(&(tom->getApplyTime()));
00061     tom->getNumberApplied()++;
00062 
00063     const Extensions* extensions = getExtensions(contextID,true);
00064 
00065     // if not supported, then return
00066     if (!extensions->isTexture2DArraySupported() || !extensions->isTexture3DSupported())
00067     {
00068         OSG_WARN<<"Warning: Texture2DArray::apply(..) failed, 2D texture arrays are not support by OpenGL driver."<<std::endl;
00069         return;
00070     }
00071 
00072     // get the texture object for the current contextID.
00073     TextureObject* textureObject = getTextureObject(contextID);
00074 
00075     if (textureObject && _textureDepth>0)
00076     {
00077         const osg::Image* image = firstValidImage();
00078         if (image && getModifiedCount(0, contextID) != image->getModifiedCount())
00079         {
00080             // compute the internal texture format, this set the _internalFormat to an appropriate value.
00081             computeInternalFormat();
00082 
00083             GLsizei new_width, new_height, new_numMipmapLevels;
00084 
00085             // compute the dimensions of the texture.
00086             computeRequiredTextureDimensions(state, *image, new_width, new_height, new_numMipmapLevels);
00087 
00088             if (!textureObject->match(GL_TEXTURE_2D_ARRAY_EXT, new_numMipmapLevels, _internalFormat, new_width, new_height, 1, _borderWidth))
00089             {
00090                 Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get());
00091                 _textureObjectBuffer[contextID] = 0;
00092                 textureObject = 0;
00093             }
00094         }
00095     }
00096 
00097     // if we already have an texture object, then 
00098     if (textureObject)
00099     {
00100         // bind texture object
00101         textureObject->bind();
00102 
00103         // if texture parameters changed, then reset them
00104         if (getTextureParameterDirty(state.getContextID())) applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT,state);
00105 
00106         // if subload is specified, then use it to subload the images to GPU memory
00107         //if (_subloadCallback.valid())
00108         //{
00109         //    _subloadCallback->subload(*this,state);
00110         //}
00111         //else
00112         {
00113             // for each image of the texture array do
00114             for (GLsizei n=0; n < _textureDepth; n++)
00115             {
00116                 osg::Image* image = _images[n].get();
00117 
00118                 // if image content is modified, then upload it to the GPU memory
00119                 // GW: this means we have to "dirty" an image before setting it!
00120                 if (image && getModifiedCount(n,contextID) != image->getModifiedCount())
00121                 {
00122                     applyTexImage2DArray_subload(state, image, _textureWidth, _textureHeight, n, _internalFormat, _numMipmapLevels);
00123                     getModifiedCount(n,contextID) = image->getModifiedCount();
00124                 }
00125             }
00126         }
00127     }
00128 
00129     // nothing before, but we have valid images, so do manual upload and create texture object manually
00130     else if ( firstValidImage() != 0L ) // if (imagesValid())
00131     {
00132         // compute the internal texture format, this set the _internalFormat to an appropriate value.
00133         computeInternalFormat();
00134 
00135         // compute the dimensions of the texture.
00136         osg::Image* firstImage = firstValidImage();
00137         computeRequiredTextureDimensions(state, *firstImage, _textureWidth, _textureHeight, _numMipmapLevels);
00138 
00139         // create texture object
00140         textureObject = generateTextureObject(
00141             this, contextID,GL_TEXTURE_2D_ARRAY_EXT,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0);
00142 
00143         // bind texture
00144         textureObject->bind();
00145         applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT, state);
00146 
00147         _textureObjectBuffer[contextID] = textureObject;
00148 
00149         // First we need to allocate the texture memory
00150         int sourceFormat = _sourceFormat ? _sourceFormat : _internalFormat;
00151 
00152         if( isCompressedInternalFormat( sourceFormat ) && 
00153             sourceFormat == _internalFormat &&
00154             extensions->isCompressedTexImage3DSupported() )
00155         {
00156             extensions->glCompressedTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat,
00157                 _textureWidth, _textureHeight, _textureDepth, _borderWidth,
00158                 firstImage->getImageSizeInBytes() * _textureDepth,
00159                 0);
00160         }
00161         else
00162         {   
00163             // Override compressed source format with safe GL_RGBA value which not generate error
00164             // We can safely do this as source format is not important when source data is NULL
00165             if( isCompressedInternalFormat( sourceFormat ) )
00166                 sourceFormat = GL_RGBA;
00167 
00168             extensions->glTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat,
00169                 _textureWidth, _textureHeight, _textureDepth, _borderWidth,
00170                 sourceFormat, _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
00171                 0); 
00172         }
00173 
00174         // For certain we have to manually allocate memory for mipmaps if images are compressed
00175         // if not allocated OpenGL will produce errors on mipmap upload.
00176         // I have not tested if this is neccessary for plain texture formats but 
00177         // common sense suggests its required as well.
00178         if( _min_filter != LINEAR && _min_filter != NEAREST && firstImage->isMipmap() )
00179             allocateMipmap( state );
00180 
00181         // now for each layer we upload it into the memory
00182         for (GLsizei n=0; n<_textureDepth; n++)
00183         {
00184             // if image is valid then upload it to the texture memory
00185             osg::Image* image = _images[n].get();
00186             if (image)
00187             {
00188                 // now load the image data into the memory, this will also check if image do have valid properties
00189                 applyTexImage2DArray_subload(state, image, _textureWidth, _textureHeight, n, _internalFormat, _numMipmapLevels);
00190                 getModifiedCount(n,contextID) = image->getModifiedCount();
00191             }
00192         }
00193 
00194         const Texture::Extensions* texExtensions = Texture::getExtensions(contextID,true);
00195         // source images have no mipmamps but we could generate them...  
00196         if( _min_filter != LINEAR && _min_filter != NEAREST && !firstImage->isMipmap() &&  
00197             _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported() )
00198         {
00199             _numMipmapLevels = osg::Image::computeNumberOfMipmapLevels( _textureWidth, _textureHeight );
00200             generateMipmap( state );
00201         }
00202 
00203         textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0);
00204 
00205         // unref image data?
00206         if (isSafeToUnrefImageData(state))
00207         {
00208             SparseTexture2DArray* non_const_this = const_cast<SparseTexture2DArray*>(this);
00209             for (int n=0; n<_textureDepth; n++)
00210             {                
00211                 if (_images[n].valid() && _images[n]->getDataVariance()==STATIC)
00212                 {
00213                     non_const_this->_images[n] = NULL;
00214                 }
00215             }
00216         }
00217 
00218     }
00219 
00220     // No images present, but dimensions are set. So create empty texture
00221     else if ( (_textureWidth > 0) && (_textureHeight > 0) && (_textureDepth > 0) && (_internalFormat!=0) )
00222     {
00223         // generate texture 
00224         _textureObjectBuffer[contextID] = textureObject = generateTextureObject(
00225             this, contextID, GL_TEXTURE_2D_ARRAY_EXT,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0);
00226 
00227         textureObject->bind();
00228         applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT,state);
00229 
00230         extensions->glTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat,
00231             _textureWidth, _textureHeight, _textureDepth,
00232             _borderWidth,
00233             _sourceFormat ? _sourceFormat : _internalFormat,
00234             _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
00235             0); 
00236 
00237     }
00238 
00239     // nothing before, so just unbind the texture target
00240     else
00241     {
00242         glBindTexture( GL_TEXTURE_2D_ARRAY_EXT, 0 );
00243     }
00244 
00245     // if texture object is now valid and we have to allocate mipmap levels, then
00246     if (textureObject != 0 && _texMipmapGenerationDirtyList[contextID])
00247     {
00248         generateMipmap(state);
00249     }
00250 }
00251 
00252 // replaces the same func in the superclass
00253 void
00254 SparseTexture2DArray::applyTexImage2DArray_subload(osg::State& state, osg::Image* image,
00255                                                    GLsizei inwidth, GLsizei inheight, GLsizei indepth, 
00256                                                    GLint inInternalFormat, GLsizei& numMipmapLevels) const
00257 {
00259     //if (!imagesValid())
00260     //    return;
00261 
00262     // get the contextID (user defined ID of 0 upwards) for the 
00263     // current OpenGL context.
00264     const unsigned int contextID = state.getContextID();
00265     const Extensions* extensions = getExtensions(contextID,true);    
00266     const Texture::Extensions* texExtensions = Texture::getExtensions(contextID,true);
00267     GLenum target = GL_TEXTURE_2D_ARRAY_EXT;
00268 
00269     // compute the internal texture format, this set the _internalFormat to an appropriate value.
00270     computeInternalFormat();
00271 
00272     // select the internalFormat required for the texture.
00273     // bool compressed = isCompressedInternalFormat(_internalFormat);
00274     bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
00275 
00276     // if the required layer is exceeds the maximum allowed layer sizes
00277     if (indepth > extensions->maxLayerCount())
00278     {
00279         // we give a warning and do nothing
00280         OSG_WARN<<"Warning: Texture2DArray::applyTexImage2DArray_subload(..) the given layer number exceeds the maximum number of supported layers."<<std::endl;
00281         return;        
00282     }
00283 
00284     //Rescale if resize hint is set or NPOT not supported or dimensions exceed max size
00285     if( _resizeNonPowerOfTwoHint || !texExtensions->isNonPowerOfTwoTextureSupported(_min_filter)
00286         || inwidth > extensions->max2DSize()
00287         || inheight > extensions->max2DSize())
00288         image->ensureValidSizeForTexturing(extensions->max2DSize());
00289 
00290     // image size or format has changed, this is not allowed, hence return
00291     if (image->s()!=inwidth || 
00292         image->t()!=inheight || 
00293         image->getInternalTextureFormat()!=inInternalFormat ) 
00294     {
00295         OSG_WARN<<"Warning: Texture2DArray::applyTexImage2DArray_subload(..) given image do have wrong dimension or internal format."<<std::endl;
00296         return;        
00297     }    
00298 
00299     glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
00300 
00301     bool useHardwareMipmapGeneration = 
00302         !image->isMipmap() && _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported();
00303 
00304     // if no special mipmapping is required, then
00305     if( _min_filter == LINEAR || _min_filter == NEAREST || useHardwareMipmapGeneration )
00306     {
00307         if( _min_filter == LINEAR || _min_filter == NEAREST )
00308             numMipmapLevels = 1;
00309         else //Hardware Mipmap Generation
00310             numMipmapLevels = image->getNumMipmapLevels();
00311 
00312         // upload non-compressed image
00313         if ( !compressed_image )
00314         {
00315             extensions->glTexSubImage3D( target, 0,
00316                 0, 0, indepth,
00317                 inwidth, inheight, 1,
00318                 (GLenum)image->getPixelFormat(),
00319                 (GLenum)image->getDataType(),
00320                 image->data() );
00321         }
00322 
00323         // if we support compression and image is compressed, then
00324         else if (extensions->isCompressedTexImage3DSupported())
00325         {
00326             // OSG_WARN<<"glCompressedTexImage3D "<<inwidth<<", "<<inheight<<", "<<indepth<<std::endl;
00327 
00328             GLint blockSize, size;
00329             getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size);
00330 
00331             extensions->glCompressedTexSubImage3D(target, 0,
00332                 0, 0, indepth,  
00333                 inwidth, inheight, 1, 
00334                 (GLenum)image->getPixelFormat(),
00335                 size, 
00336                 image->data());
00337         }
00338 
00339         // we want to use mipmapping, so enable it
00340     }else
00341     {
00342         // image does not provide mipmaps, so we have to create them
00343         if( !image->isMipmap() )
00344         {
00345             numMipmapLevels = 1;
00346             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;
00347 
00348             // the image object does provide mipmaps, so upload the in the certain levels of a layer
00349         }else
00350         {
00351             numMipmapLevels = image->getNumMipmapLevels();
00352 
00353             int width  = image->s();
00354             int height = image->t();
00355 
00356             if( !compressed_image )
00357             {
00358 
00359                 for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height ) ;k++)
00360                 {
00361                     if (width == 0)
00362                         width = 1;
00363                     if (height == 0)
00364                         height = 1;
00365 
00366                     extensions->glTexSubImage3D( target, k, 0, 0, indepth,
00367                         width, height, 1, 
00368                         (GLenum)image->getPixelFormat(),
00369                         (GLenum)image->getDataType(),
00370                         image->getMipmapData(k));
00371 
00372                     width >>= 1;
00373                     height >>= 1;
00374                 }
00375             }
00376             else if (extensions->isCompressedTexImage3DSupported())
00377             {
00378                 GLint blockSize,size;
00379                 for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
00380                 {
00381                     if (width == 0)
00382                         width = 1;
00383                     if (height == 0)
00384                         height = 1;
00385 
00386                     getCompressedSize(image->getInternalTextureFormat(), width, height, 1, blockSize,size);
00387 
00388                     //                    state.checkGLErrors("before extensions->glCompressedTexSubImage3D(");
00389 
00390                     extensions->glCompressedTexSubImage3D(target, k, 0, 0, indepth,
00391                         width, height, 1,
00392                         (GLenum)image->getPixelFormat(),
00393                         size,
00394                         image->getMipmapData(k));
00395 
00396                     //                    state.checkGLErrors("after extensions->glCompressedTexSubImage3D(");
00397 
00398                     width >>= 1;
00399                     height >>= 1;
00400                 }
00401             }
00402         }
00403     }
00404 }
00405 
00406 #endif // OSG_VERSION_GREATER_OR_EQUAL( 2, 9, 8 )
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines