root/OpenSceneGraph/trunk/src/osg/TextureCubeMap.cpp @ 10924

Revision 10924, 16.2 kB (checked in by robert, 4 years ago)

Refactored the way that osg::Image/ImageSequence manages the update callback that needs to be attached to Textures to make it possible to use the Image::update() mechansim in other subclasses from osg::Image.
To enable the automatic attachment of the required update callback to call osg::Image::update(..) subclasses from osg::Image will
need to implement the osg::Image::requestUpdateCall() and return true, and implement the osg::Image::update(NodeVisitor?*) method to recieve the update call during the update traversal.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
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/ref_ptr>
15#include <osg/Image>
16#include <osg/State>
17#include <osg/TextureCubeMap>
18#include <osg/Notify>
19
20#include <osg/GLU>
21
22
23using namespace osg;
24
25static GLenum faceTarget[6] =
26{
27    GL_TEXTURE_CUBE_MAP_POSITIVE_X,
28    GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
29    GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
30    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
31    GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
32    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
33};
34
35
36TextureCubeMap::TextureCubeMap():
37            _textureWidth(0),
38            _textureHeight(0),
39            _numMipmapLevels(0)
40{
41    setUseHardwareMipMapGeneration(false);
42}
43
44TextureCubeMap::TextureCubeMap(const TextureCubeMap& text,const CopyOp& copyop):
45            Texture(text,copyop),
46            _textureWidth(text._textureWidth),
47            _textureHeight(text._textureHeight),
48            _numMipmapLevels(text._numMipmapLevels),
49            _subloadCallback(text._subloadCallback)
50{
51    _images[0] = copyop(text._images[0].get());
52    _images[1] = copyop(text._images[1].get());
53    _images[2] = copyop(text._images[2].get());
54    _images[3] = copyop(text._images[3].get());
55    _images[4] = copyop(text._images[4].get());
56    _images[5] = copyop(text._images[5].get());
57
58    _modifiedCount[0].setAllElementsTo(0);
59    _modifiedCount[1].setAllElementsTo(0);
60    _modifiedCount[2].setAllElementsTo(0);
61    _modifiedCount[3].setAllElementsTo(0);
62    _modifiedCount[4].setAllElementsTo(0);
63    _modifiedCount[5].setAllElementsTo(0);
64
65}   
66
67
68TextureCubeMap::~TextureCubeMap()
69{
70}
71
72
73int TextureCubeMap::compare(const StateAttribute& sa) const
74{
75    // check the types are equal and then create the rhs variable
76    // used by the COMPARE_StateAttribute_Paramter macro's below.
77    COMPARE_StateAttribute_Types(TextureCubeMap,sa)
78
79    bool noImages = true;
80    for (int n=0; n<6; n++)
81    {
82        if (noImages && _images[n].valid()) noImages = false;
83        if (noImages && rhs._images[n].valid()) noImages = false;
84   
85        if (_images[n]!=rhs._images[n]) // smart pointer comparison.
86        {
87            if (_images[n].valid())
88            {
89                if (rhs._images[n].valid())
90                {
91                    int result = _images[n]->compare(*rhs._images[n]);
92                    if (result!=0) return result;
93                }
94                else
95                {
96                    return 1; // valid lhs._image is greater than null.
97                }
98            }
99            else if (rhs._images[n].valid())
100            {
101                return -1; // valid rhs._image is greater than null.
102            }
103        }
104    }
105
106    if (noImages)
107    {
108        // no image attached to either Texture2D
109        // but could these textures already be downloaded?
110        // check the _textureObjectBuffer to see if they have been
111        // downloaded
112
113        int result = compareTextureObjects(rhs);
114        if (result!=0) return result;
115    }
116
117    int result = compareTexture(rhs);
118    if (result!=0) return result;
119
120    // compare each paramter in turn against the rhs.
121    COMPARE_StateAttribute_Parameter(_textureWidth)
122    COMPARE_StateAttribute_Parameter(_textureHeight)
123    COMPARE_StateAttribute_Parameter(_subloadCallback)
124
125    return 0; // passed all the above comparison macro's, must be equal.
126}
127
128
129void TextureCubeMap::setImage( unsigned int face, Image* image)
130{
131    if (_images[face] == image) return;
132
133    unsigned numImageRequireUpdateBefore = 0;
134    for (unsigned int i=0; i<getNumImages(); ++i)
135    {
136        if (_images[i].valid() && _images[i]->requiresUpdateCall()) ++numImageRequireUpdateBefore;
137    }
138
139    _images[face] = image;
140    _modifiedCount[face].setAllElementsTo(0);
141
142
143    // find out if we need to reset the update callback to handle the animation of image
144    unsigned numImageRequireUpdateAfter = 0;
145    for (unsigned int i=0; i<getNumImages(); ++i)
146    {
147        if (_images[i].valid() && _images[i]->requiresUpdateCall()) ++numImageRequireUpdateAfter;
148    }
149
150    if (numImageRequireUpdateBefore>0)
151    {
152        if (numImageRequireUpdateAfter==0)
153        {
154            setUpdateCallback(0);
155            setDataVariance(osg::Object::STATIC);
156        }
157    }
158    else if (numImageRequireUpdateAfter>0)
159    {
160        setUpdateCallback(new Image::UpdateCallback());
161        setDataVariance(osg::Object::DYNAMIC);
162    }
163}
164
165Image* TextureCubeMap::getImage(unsigned int face)
166{
167    return _images[face].get();
168}
169
170const Image* TextureCubeMap::getImage(unsigned int face) const
171{
172    return _images[face].get();
173}
174
175bool TextureCubeMap::imagesValid() const
176{
177    for (int n=0; n<6; n++)
178    {
179        if (!_images[n].valid() || !_images[n]->data())
180            return false;
181    }
182    return true;
183}
184
185void TextureCubeMap::computeInternalFormat() const
186{
187    if (imagesValid()) computeInternalFormatWithImage(*_images[0]);
188    else computeInternalFormatType();
189}
190
191void TextureCubeMap::apply(State& state) const
192{
193    // get the contextID (user defined ID of 0 upwards) for the
194    // current OpenGL context.
195    const unsigned int contextID = state.getContextID();
196
197    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID).get();
198    ElapsedTime elapsedTime(&(tom->getApplyTime()));
199    tom->getNumberApplied()++;
200
201    const Extensions* extensions = getExtensions(contextID,true);
202
203    if (!extensions->isCubeMapSupported())
204        return;
205
206    // get the texture object for the current contextID.
207    TextureObject* textureObject = getTextureObject(contextID);
208
209    if (textureObject)
210    {
211        const osg::Image* image = _images[0].get();
212        if (image && getModifiedCount(0, contextID) != image->getModifiedCount())
213        {
214            // compute the internal texture format, this set the _internalFormat to an appropriate value.
215            computeInternalFormat();
216
217            GLsizei new_width, new_height, new_numMipmapLevels;
218
219            // compute the dimensions of the texture.
220            computeRequiredTextureDimensions(state, *image, new_width, new_height, new_numMipmapLevels);
221
222            if (!textureObject->match(GL_TEXTURE_CUBE_MAP, new_numMipmapLevels, _internalFormat, new_width, new_height, 1, _borderWidth))
223            {
224                Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get());
225                _textureObjectBuffer[contextID] = 0;
226                textureObject = 0;
227            }
228        }
229    }
230
231    if (textureObject)
232    {
233        textureObject->bind();
234
235        if (getTextureParameterDirty(state.getContextID())) applyTexParameters(GL_TEXTURE_CUBE_MAP,state);
236
237        if (_subloadCallback.valid())
238        {
239            _subloadCallback->subload(*this,state);
240        }
241        else
242        {
243            for (int n=0; n<6; n++)
244            {
245                const osg::Image* image = _images[n].get();
246                if (image && getModifiedCount((Face)n,contextID) != image->getModifiedCount())
247                {
248                    applyTexImage2D_subload( state, faceTarget[n], _images[n].get(), _textureWidth, _textureHeight, _internalFormat, _numMipmapLevels);
249                    getModifiedCount((Face)n,contextID) = image->getModifiedCount();
250                }
251            }
252        }
253
254    }
255    else if (_subloadCallback.valid())
256    {
257        _textureObjectBuffer[contextID] = textureObject = generateTextureObject(this, contextID,GL_TEXTURE_CUBE_MAP);
258
259        textureObject->bind();
260
261        applyTexParameters(GL_TEXTURE_CUBE_MAP,state);
262
263        _subloadCallback->load(*this,state);
264
265        // in theory the following line is redundent, but in practice
266        // have found that the first frame drawn doesn't apply the textures
267        // unless a second bind is called?!!
268        // perhaps it is the first glBind which is not required...
269        //glBindTexture( GL_TEXTURE_CUBE_MAP, handle );
270
271    }
272    else if (imagesValid())
273    {
274
275        // compute the internal texture format, this set the _internalFormat to an appropriate value.
276        computeInternalFormat();
277
278        // compute the dimensions of the texture.
279        computeRequiredTextureDimensions(state,*_images[0],_textureWidth, _textureHeight, _numMipmapLevels);
280
281        // cubemap textures must have square dimensions
282        if( _textureWidth != _textureHeight )
283        {
284            _textureWidth = _textureHeight = minimum( _textureWidth , _textureHeight );
285        }
286
287        textureObject = generateTextureObject(
288                this, contextID,GL_TEXTURE_CUBE_MAP,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,1,0);
289       
290        textureObject->bind();
291
292        applyTexParameters(GL_TEXTURE_CUBE_MAP,state);
293
294        for (int n=0; n<6; n++)
295        {
296            const osg::Image* image = _images[n].get();
297            if (image)
298            {
299                if (textureObject->isAllocated())
300                {
301                    applyTexImage2D_subload( state, faceTarget[n], image, _textureWidth, _textureHeight, _internalFormat, _numMipmapLevels);
302                }
303                else
304                {
305                    applyTexImage2D_load( state, faceTarget[n], image, _textureWidth, _textureHeight, _numMipmapLevels);
306                }
307                getModifiedCount((Face)n,contextID) = image->getModifiedCount();
308            }
309
310
311        }
312
313        _textureObjectBuffer[contextID] = textureObject;
314
315        if (state.getMaxTexturePoolSize()==0 && _unrefImageDataAfterApply && areAllTextureObjectsLoaded())
316        {
317            TextureCubeMap* non_const_this = const_cast<TextureCubeMap*>(this);
318            for (int n=0; n<6; n++)
319            {               
320                if (_images[n].valid() && _images[n]->getDataVariance()==STATIC)
321                {
322                    non_const_this->_images[n] = 0;
323                }
324            }
325        }
326       
327    }
328    else if ( (_textureWidth!=0) && (_textureHeight!=0) && (_internalFormat!=0) )
329    {
330        _textureObjectBuffer[contextID] = textureObject = generateTextureObject(
331                this, contextID,GL_TEXTURE_CUBE_MAP,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,1,0);
332       
333        textureObject->bind();
334
335        applyTexParameters(GL_TEXTURE_CUBE_MAP,state);
336
337        for (int n=0; n<6; n++)
338        {               
339            // no image present, but dimensions at set so less create the texture
340            glTexImage2D( faceTarget[n], 0, _internalFormat,
341                         _textureWidth, _textureHeight, _borderWidth,
342                         _sourceFormat ? _sourceFormat : _internalFormat,
343                         _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
344                         0);               
345        }
346       
347    }
348    else
349    {
350        glBindTexture( GL_TEXTURE_CUBE_MAP, 0 );
351    }
352
353    // if texture object is now valid and we have to allocate mipmap levels, then
354    if (textureObject != 0 && _texMipmapGenerationDirtyList[contextID])
355    {
356        generateMipmap(state);
357    }
358}
359
360void TextureCubeMap::copyTexSubImageCubeMap(State& state, int face, int xoffset, int yoffset, int x, int y, int width, int height )
361{
362    const unsigned int contextID = state.getContextID();
363    const Extensions* extensions = getExtensions(contextID,true);
364
365    if (!extensions->isCubeMapSupported())
366        return;
367
368    if (_internalFormat==0) _internalFormat=GL_RGBA;
369
370    // get the texture object for the current contextID.
371    TextureObject* textureObject = getTextureObject(contextID);
372
373    if (!textureObject)
374    {
375
376        if (_textureWidth==0) _textureWidth = width;
377        if (_textureHeight==0) _textureHeight = height;
378
379        // create texture object.
380        apply(state);
381       
382        textureObject = getTextureObject(contextID);
383       
384        if (!textureObject)
385        {
386            // failed to create texture object
387            osg::notify(osg::NOTICE)<<"Warning : failed to create TextureCubeMap texture obeject, copyTexSubImageCubeMap abondoned."<<std::endl;
388            return;
389        }
390       
391    }
392
393    GLenum target = faceTarget[face];
394   
395    if (textureObject)
396    {
397        // we have a valid image
398        textureObject->bind();
399       
400        applyTexParameters(GL_TEXTURE_CUBE_MAP, state);
401
402        bool needHardwareMipMap = (_min_filter != LINEAR && _min_filter != NEAREST);
403        bool hardwareMipMapOn = false;
404        if (needHardwareMipMap)
405        {
406            hardwareMipMapOn = isHardwareMipmapGenerationEnabled(state);
407
408            if (!hardwareMipMapOn)
409            {
410                // have to switch off mip mapping
411                notify(NOTICE)<<"Warning: TextureCubeMap::copyTexImage2D(,,,,) switch off mip mapping as hardware support not available."<<std::endl;
412                _min_filter = LINEAR;
413            }
414        }
415
416        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, hardwareMipMapOn);
417
418        glCopyTexSubImage2D( target , 0, xoffset, yoffset, x, y, width, height);
419
420        mipmapAfterTexImage(state, mipmapResult);
421
422        // inform state that this texture is the current one bound.
423        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
424
425    }
426}
427
428void TextureCubeMap::allocateMipmap(State& state) const
429{
430    const unsigned int contextID = state.getContextID();
431
432    // get the texture object for the current contextID.
433    TextureObject* textureObject = getTextureObject(contextID);
434   
435    if (textureObject && _textureWidth != 0 && _textureHeight != 0)
436    {
437        // bind texture
438        textureObject->bind();
439
440        // compute number of mipmap levels
441        int width = _textureWidth;
442        int height = _textureHeight;
443        int numMipmapLevels = Image::computeNumberOfMipmapLevels(width, height);
444
445        // we do not reallocate the level 0, since it was already allocated
446        width >>= 1;
447        height >>= 1;
448       
449        for( GLsizei k = 1; k < numMipmapLevels  && (width || height); k++)
450        {
451            if (width == 0)
452                width = 1;
453            if (height == 0)
454                height = 1;
455
456            for (int n=0; n<6; n++)
457            {
458                glTexImage2D( faceTarget[n], k, _internalFormat,
459                            width, height, _borderWidth,
460                            _sourceFormat ? _sourceFormat : _internalFormat,
461                            _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
462                            0);
463            }
464       
465            width >>= 1;
466            height >>= 1;
467        }
468               
469        // inform state that this texture is the current one bound.
470        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);       
471    }
472}
473
474typedef buffered_value< ref_ptr<TextureCubeMap::Extensions> > BufferedExtensions;
475static BufferedExtensions s_extensions;
476
477TextureCubeMap::Extensions* TextureCubeMap::getExtensions(unsigned int contextID,bool createIfNotInitalized)
478{
479    if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID);
480    return s_extensions[contextID].get();
481}
482
483void TextureCubeMap::setExtensions(unsigned int contextID,Extensions* extensions)
484{
485    s_extensions[contextID] = extensions;
486}
487
488TextureCubeMap::Extensions::Extensions(unsigned int contextID)
489{
490    setupGLExtensions(contextID);
491}
492
493TextureCubeMap::Extensions::Extensions(const Extensions& rhs):
494    Referenced()
495{
496    _isCubeMapSupported = rhs._isCubeMapSupported;
497}
498
499void TextureCubeMap::Extensions::lowestCommonDenominator(const Extensions& rhs)
500{
501    if (!rhs._isCubeMapSupported) _isCubeMapSupported = false;
502}
503
504void TextureCubeMap::Extensions::setupGLExtensions(unsigned int contextID)
505{
506    _isCubeMapSupported = OSG_GLES2_FEATURES || OSG_GL3_FEATURES ||
507                          isGLExtensionSupported(contextID,"GL_ARB_texture_cube_map") ||
508                          isGLExtensionSupported(contextID,"GL_EXT_texture_cube_map") ||
509                          strncmp((const char*)glGetString(GL_VERSION),"1.3",3)>=0;;
510}
Note: See TracBrowser for help on using the browser.