示例#1
0
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);
    }
}