osgEarth 2.1.1
|
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 )