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

Revision 13041, 16.0 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • 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_Parameter macros 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 parameter 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 macros, 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        // unref image data?
316        if (isSafeToUnrefImageData(state))
317        {
318            TextureCubeMap* non_const_this = const_cast<TextureCubeMap*>(this);
319            for (int n=0; n<6; n++)
320            {
321                if (_images[n].valid() && _images[n]->getDataVariance()==STATIC)
322                {
323                    non_const_this->_images[n] = NULL;
324                }
325            }
326        }
327
328    }
329    else if ( (_textureWidth!=0) && (_textureHeight!=0) && (_internalFormat!=0) )
330    {
331        _textureObjectBuffer[contextID] = textureObject = generateTextureObject(
332                this, contextID,GL_TEXTURE_CUBE_MAP,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,1,0);
333
334        textureObject->bind();
335
336        applyTexParameters(GL_TEXTURE_CUBE_MAP,state);
337
338        for (int n=0; n<6; n++)
339        {
340            // no image present, but dimensions at set so less create the texture
341            glTexImage2D( faceTarget[n], 0, _internalFormat,
342                         _textureWidth, _textureHeight, _borderWidth,
343                         _sourceFormat ? _sourceFormat : _internalFormat,
344                         _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
345                         0);
346        }
347
348    }
349    else
350    {
351        glBindTexture( GL_TEXTURE_CUBE_MAP, 0 );
352    }
353
354    // if texture object is now valid and we have to allocate mipmap levels, then
355    if (textureObject != 0 && _texMipmapGenerationDirtyList[contextID])
356    {
357        generateMipmap(state);
358    }
359}
360
361void TextureCubeMap::copyTexSubImageCubeMap(State& state, int face, int xoffset, int yoffset, int x, int y, int width, int height )
362{
363    const unsigned int contextID = state.getContextID();
364    const Extensions* extensions = getExtensions(contextID,true);
365
366    if (!extensions->isCubeMapSupported())
367        return;
368
369    if (_internalFormat==0) _internalFormat=GL_RGBA;
370
371    // get the texture object for the current contextID.
372    TextureObject* textureObject = getTextureObject(contextID);
373
374    if (!textureObject)
375    {
376
377        if (_textureWidth==0) _textureWidth = width;
378        if (_textureHeight==0) _textureHeight = height;
379
380        // create texture object.
381        apply(state);
382
383        textureObject = getTextureObject(contextID);
384
385        if (!textureObject)
386        {
387            // failed to create texture object
388            OSG_NOTICE<<"Warning : failed to create TextureCubeMap texture obeject, copyTexSubImageCubeMap abondoned."<<std::endl;
389            return;
390        }
391
392    }
393
394    GLenum target = faceTarget[face];
395
396    if (textureObject)
397    {
398        // we have a valid image
399        textureObject->bind();
400
401        applyTexParameters(GL_TEXTURE_CUBE_MAP, state);
402
403        bool needHardwareMipMap = (_min_filter != LINEAR && _min_filter != NEAREST);
404        bool hardwareMipMapOn = false;
405        if (needHardwareMipMap)
406        {
407            hardwareMipMapOn = isHardwareMipmapGenerationEnabled(state);
408
409            if (!hardwareMipMapOn)
410            {
411                // have to switch off mip mapping
412                OSG_NOTICE<<"Warning: TextureCubeMap::copyTexImage2D(,,,,) switch off mip mapping as hardware support not available."<<std::endl;
413                _min_filter = LINEAR;
414            }
415        }
416
417        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, hardwareMipMapOn);
418
419        glCopyTexSubImage2D( target , 0, xoffset, yoffset, x, y, width, height);
420
421        mipmapAfterTexImage(state, mipmapResult);
422
423        // inform state that this texture is the current one bound.
424        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
425
426    }
427}
428
429void TextureCubeMap::allocateMipmap(State& state) const
430{
431    const unsigned int contextID = state.getContextID();
432
433    // get the texture object for the current contextID.
434    TextureObject* textureObject = getTextureObject(contextID);
435
436    if (textureObject && _textureWidth != 0 && _textureHeight != 0)
437    {
438        // bind texture
439        textureObject->bind();
440
441        // compute number of mipmap levels
442        int width = _textureWidth;
443        int height = _textureHeight;
444        int numMipmapLevels = Image::computeNumberOfMipmapLevels(width, height);
445
446        // we do not reallocate the level 0, since it was already allocated
447        width >>= 1;
448        height >>= 1;
449
450        for( GLsizei k = 1; k < numMipmapLevels  && (width || height); k++)
451        {
452            if (width == 0)
453                width = 1;
454            if (height == 0)
455                height = 1;
456
457            for (int n=0; n<6; n++)
458            {
459                glTexImage2D( faceTarget[n], k, _internalFormat,
460                            width, height, _borderWidth,
461                            _sourceFormat ? _sourceFormat : _internalFormat,
462                            _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
463                            0);
464            }
465
466            width >>= 1;
467            height >>= 1;
468        }
469
470        // inform state that this texture is the current one bound.
471        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
472    }
473}
474
475typedef buffered_value< ref_ptr<TextureCubeMap::Extensions> > BufferedExtensions;
476static BufferedExtensions s_extensions;
477
478TextureCubeMap::Extensions* TextureCubeMap::getExtensions(unsigned int contextID,bool createIfNotInitalized)
479{
480    if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID);
481    return s_extensions[contextID].get();
482}
483
484void TextureCubeMap::setExtensions(unsigned int contextID,Extensions* extensions)
485{
486    s_extensions[contextID] = extensions;
487}
488
489TextureCubeMap::Extensions::Extensions(unsigned int contextID)
490{
491    setupGLExtensions(contextID);
492}
493
494TextureCubeMap::Extensions::Extensions(const Extensions& rhs):
495    Referenced()
496{
497    _isCubeMapSupported = rhs._isCubeMapSupported;
498}
499
500void TextureCubeMap::Extensions::lowestCommonDenominator(const Extensions& rhs)
501{
502    if (!rhs._isCubeMapSupported) _isCubeMapSupported = false;
503}
504
505void TextureCubeMap::Extensions::setupGLExtensions(unsigned int contextID)
506{
507    _isCubeMapSupported = OSG_GLES2_FEATURES || OSG_GL3_FEATURES ||
508                          isGLExtensionSupported(contextID,"GL_ARB_texture_cube_map") ||
509                          isGLExtensionSupported(contextID,"GL_EXT_texture_cube_map") ||
510                          strncmp((const char*)glGetString(GL_VERSION),"1.3",3)>=0;;
511}
Note: See TracBrowser for help on using the browser.