void SparseTexture2DArray::apply( osg::State& state ) const { // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. const unsigned int contextID = state.getContextID(); Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID).get(); //ElapsedTime elapsedTime(&(tom->getApplyTime())); tom->getNumberApplied()++; const Extensions* extensions = getExtensions(contextID,true); // if not supported, then return if (!extensions->isTexture2DArraySupported() || !extensions->isTexture3DSupported()) { OSG_WARN<<"Warning: Texture2DArray::apply(..) failed, 2D texture arrays are not support by OpenGL driver."<<std::endl; return; } // get the texture object for the current contextID. TextureObject* textureObject = getTextureObject(contextID); if (textureObject && _textureDepth>0) { const osg::Image* image = firstValidImage(); if (image && getModifiedCount(0, contextID) != image->getModifiedCount()) { // compute the internal texture format, this set the _internalFormat to an appropriate value. computeInternalFormat(); GLsizei new_width, new_height, new_numMipmapLevels; // compute the dimensions of the texture. computeRequiredTextureDimensions(state, *image, new_width, new_height, new_numMipmapLevels); if (!textureObject->match(GL_TEXTURE_2D_ARRAY_EXT, new_numMipmapLevels, _internalFormat, new_width, new_height, 1, _borderWidth)) { Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get()); _textureObjectBuffer[contextID] = 0; textureObject = 0; } } } // if we already have an texture object, then if (textureObject) { // bind texture object textureObject->bind(); // if texture parameters changed, then reset them if (getTextureParameterDirty(state.getContextID())) applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT,state); // if subload is specified, then use it to subload the images to GPU memory //if (_subloadCallback.valid()) //{ // _subloadCallback->subload(*this,state); //} //else { // for each image of the texture array do for (GLsizei n=0; n < _textureDepth; n++) { osg::Image* image = _images[n].get(); // if image content is modified, then upload it to the GPU memory // GW: this means we have to "dirty" an image before setting it! if (image && getModifiedCount(n,contextID) != image->getModifiedCount()) { applyTexImage2DArray_subload(state, image, _textureWidth, _textureHeight, n, _internalFormat, _numMipmapLevels); getModifiedCount(n,contextID) = image->getModifiedCount(); } } } } // nothing before, but we have valid images, so do manual upload and create texture object manually else if ( firstValidImage() != 0L ) // if (imagesValid()) { // compute the internal texture format, this set the _internalFormat to an appropriate value. computeInternalFormat(); // compute the dimensions of the texture. osg::Image* firstImage = firstValidImage(); computeRequiredTextureDimensions(state, *firstImage, _textureWidth, _textureHeight, _numMipmapLevels); // create texture object textureObject = generateTextureObject( this, contextID,GL_TEXTURE_2D_ARRAY_EXT,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0); // bind texture textureObject->bind(); applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT, state); _textureObjectBuffer[contextID] = textureObject; // First we need to allocate the texture memory int sourceFormat = _sourceFormat ? _sourceFormat : _internalFormat; if( isCompressedInternalFormat( sourceFormat ) && sourceFormat == _internalFormat && extensions->isCompressedTexImage3DSupported() ) { extensions->glCompressedTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat, _textureWidth, _textureHeight, _textureDepth, _borderWidth, firstImage->getImageSizeInBytes() * _textureDepth, 0); } else { // Override compressed source format with safe GL_RGBA value which not generate error // We can safely do this as source format is not important when source data is NULL if( isCompressedInternalFormat( sourceFormat ) ) sourceFormat = GL_RGBA; extensions->glTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat, _textureWidth, _textureHeight, _textureDepth, _borderWidth, sourceFormat, _sourceType ? _sourceType : GL_UNSIGNED_BYTE, 0); } // For certain we have to manually allocate memory for mipmaps if images are compressed // if not allocated OpenGL will produce errors on mipmap upload. // I have not tested if this is neccessary for plain texture formats but // common sense suggests its required as well. if( _min_filter != LINEAR && _min_filter != NEAREST && firstImage->isMipmap() ) allocateMipmap( state ); // now for each layer we upload it into the memory for (GLsizei n=0; n<_textureDepth; n++) { // if image is valid then upload it to the texture memory osg::Image* image = _images[n].get(); if (image) { // now load the image data into the memory, this will also check if image do have valid properties applyTexImage2DArray_subload(state, image, _textureWidth, _textureHeight, n, _internalFormat, _numMipmapLevels); getModifiedCount(n,contextID) = image->getModifiedCount(); } } const Texture::Extensions* texExtensions = Texture::getExtensions(contextID,true); // source images have no mipmamps but we could generate them... if( _min_filter != LINEAR && _min_filter != NEAREST && !firstImage->isMipmap() && _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported() ) { _numMipmapLevels = osg::Image::computeNumberOfMipmapLevels( _textureWidth, _textureHeight ); generateMipmap( state ); } textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0); // unref image data? if (isSafeToUnrefImageData(state)) { SparseTexture2DArray* non_const_this = const_cast<SparseTexture2DArray*>(this); for (int n=0; n<_textureDepth; n++) { if (_images[n].valid() && _images[n]->getDataVariance()==STATIC) { non_const_this->_images[n] = NULL; } } } } // No images present, but dimensions are set. So create empty texture else if ( (_textureWidth > 0) && (_textureHeight > 0) && (_textureDepth > 0) && (_internalFormat!=0) ) { // generate texture _textureObjectBuffer[contextID] = textureObject = generateTextureObject( this, contextID, GL_TEXTURE_2D_ARRAY_EXT,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0); textureObject->bind(); applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT,state); extensions->glTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat, _textureWidth, _textureHeight, _textureDepth, _borderWidth, _sourceFormat ? _sourceFormat : _internalFormat, _sourceType ? _sourceType : GL_UNSIGNED_BYTE, 0); } // nothing before, so just unbind the texture target else { glBindTexture( GL_TEXTURE_2D_ARRAY_EXT, 0 ); } // if texture object is now valid and we have to allocate mipmap levels, then if (textureObject != 0 && _texMipmapGenerationDirtyList[contextID]) { generateMipmap(state); } }