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

Revision 10723, 15.3 kB (checked in by robert, 5 years ago)

Fixed build with no automatic conversion of ref_ptr<> to C pointer

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