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

Revision 13041, 21.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/Texture3D>
15#include <osg/State>
16#include <osg/GLU>
17#include <osg/Notify>
18
19#include <string.h>
20
21
22
23using namespace osg;
24
25Texture3D::Texture3D():
26            _textureWidth(0),
27            _textureHeight(0),
28            _textureDepth(0),
29            _numMipmapLevels(0)
30{
31}
32
33
34Texture3D::Texture3D(Image* image):
35            _textureWidth(0),
36            _textureHeight(0),
37            _textureDepth(0),
38            _numMipmapLevels(0)
39{
40    setImage(image);
41}
42
43Texture3D::Texture3D(const Texture3D& text,const CopyOp& copyop):
44            Texture(text,copyop),
45            _image(copyop(text._image.get())),
46            _textureWidth(text._textureWidth),
47            _textureHeight(text._textureHeight),
48            _textureDepth(text._textureDepth),
49            _numMipmapLevels(text._numMipmapLevels),
50            _subloadCallback(text._subloadCallback)
51{
52}
53
54Texture3D::~Texture3D()
55{
56}
57
58int Texture3D::compare(const StateAttribute& sa) const
59{
60    // check the types are equal and then create the rhs variable
61    // used by the COMPARE_StateAttribute_Parameter macros below.
62    COMPARE_StateAttribute_Types(Texture3D,sa)
63
64    if (_image!=rhs._image) // smart pointer comparison.
65    {
66        if (_image.valid())
67        {
68            if (rhs._image.valid())
69            {
70                int result = _image->compare(*rhs._image);
71                if (result!=0) return result;
72            }
73            else
74            {
75                return 1; // valid lhs._image is greater than null.
76            }
77        }
78        else if (rhs._image.valid())
79        {
80            return -1; // valid rhs._image is greater than null.
81        }
82    }
83
84    if (!_image && !rhs._image)
85    {
86        // no image attached to either Texture2D
87        // but could these textures already be downloaded?
88        // check the _textureObjectBuffer to see if they have been
89        // downloaded
90
91        int result = compareTextureObjects(rhs);
92        if (result!=0) return result;
93    }
94
95    int result = compareTexture(rhs);
96    if (result!=0) return result;
97
98    // compare each parameter in turn against the rhs.
99    COMPARE_StateAttribute_Parameter(_textureWidth)
100    COMPARE_StateAttribute_Parameter(_textureHeight)
101    COMPARE_StateAttribute_Parameter(_textureDepth)
102    COMPARE_StateAttribute_Parameter(_subloadCallback)
103
104    return 0; // passed all the above comparison macros, must be equal.
105}
106
107void Texture3D::setImage(Image* image)
108{
109    if (_image == image) return;
110
111    if (_image.valid() && _image->requiresUpdateCall())
112    {
113        setUpdateCallback(0);
114        setDataVariance(osg::Object::STATIC);
115    }
116
117    // delete old texture objects.
118    dirtyTextureObject();
119
120    _modifiedCount.setAllElementsTo(0);
121
122    _image = image;
123
124    if (_image.valid() && _image->requiresUpdateCall())
125    {
126        setUpdateCallback(new Image::UpdateCallback());
127        setDataVariance(osg::Object::DYNAMIC);
128    }
129}
130
131void Texture3D::computeRequiredTextureDimensions(State& state, const osg::Image& image,GLsizei& inwidth, GLsizei& inheight,GLsizei& indepth, GLsizei& numMipmapLevels) const
132{
133    const unsigned int contextID = state.getContextID();
134    const Extensions* extensions = getExtensions(contextID,true);
135    const Texture::Extensions* texExtensions = Texture::getExtensions(contextID,true);
136
137    int width,height,depth;
138
139    if( !_resizeNonPowerOfTwoHint && texExtensions->isNonPowerOfTwoTextureSupported(_min_filter) )
140    {
141        width = image.s();
142        height = image.t();
143        depth = image.r();
144    }
145    else
146    {
147        width = Image::computeNearestPowerOfTwo(image.s()-2*_borderWidth)+2*_borderWidth;
148        height = Image::computeNearestPowerOfTwo(image.t()-2*_borderWidth)+2*_borderWidth;
149        depth = Image::computeNearestPowerOfTwo(image.r()-2*_borderWidth)+2*_borderWidth;
150    }
151
152    // cap the size to what the graphics hardware can handle.
153    if (width>extensions->maxTexture3DSize()) width = extensions->maxTexture3DSize();
154    if (height>extensions->maxTexture3DSize()) height = extensions->maxTexture3DSize();
155    if (depth>extensions->maxTexture3DSize()) depth = extensions->maxTexture3DSize();
156
157    inwidth = width;
158    inheight = height;
159    indepth = depth;
160
161    bool useHardwareMipMapGeneration = !image.isMipmap() && _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported();
162
163    if( _min_filter == LINEAR || _min_filter == NEAREST || useHardwareMipMapGeneration )
164    {
165        numMipmapLevels = 1;
166    }
167    else if( image.isMipmap() )
168    {
169        numMipmapLevels = image.getNumMipmapLevels();
170    }
171    else
172    {
173        numMipmapLevels = 0;
174        for( ; (width || height || depth) ;++numMipmapLevels)
175        {
176
177            if (width == 0)
178                width = 1;
179            if (height == 0)
180                height = 1;
181            if (depth == 0)
182                depth = 1;
183
184            width >>= 1;
185            height >>= 1;
186            depth >>= 1;
187        }
188    }
189}
190
191void Texture3D::apply(State& state) const
192{
193
194    // get the contextID (user defined ID of 0 upwards) for the
195    // current OpenGL context.
196    const unsigned int contextID = state.getContextID();
197
198    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID).get();
199    ElapsedTime elapsedTime(&(tom->getApplyTime()));
200    tom->getNumberApplied()++;
201
202    const Extensions* extensions = getExtensions(contextID,true);
203
204    if (!extensions->isTexture3DSupported())
205    {
206        OSG_WARN<<"Warning: Texture3D::apply(..) failed, 3D texturing is not support by OpenGL driver."<<std::endl;
207        return;
208    }
209
210    // get the texture object for the current contextID.
211    TextureObject* textureObject = getTextureObject(contextID);
212
213    if (textureObject)
214    {
215        if (_image.valid() && getModifiedCount(contextID) != _image->getModifiedCount())
216        {
217            // compute the internal texture format, this set the _internalFormat to an appropriate value.
218            computeInternalFormat();
219
220            GLsizei new_width, new_height, new_depth, new_numMipmapLevels;
221
222            // compute the dimensions of the texture.
223            computeRequiredTextureDimensions(state, *_image, new_width, new_height, new_depth, new_numMipmapLevels);
224
225            if (!textureObject->match(GL_TEXTURE_3D, new_numMipmapLevels, _internalFormat, new_width, new_height, new_depth, _borderWidth))
226            {
227                Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get());
228                _textureObjectBuffer[contextID] = 0;
229                textureObject = 0;
230            }
231        }
232    }
233
234    if (textureObject)
235    {
236        // we have a valid image
237        textureObject->bind();
238
239        if (getTextureParameterDirty(state.getContextID())) applyTexParameters(GL_TEXTURE_3D,state);
240
241        if (_subloadCallback.valid())
242        {
243            _subloadCallback->subload(*this,state);
244        }
245        else if (_image.get() && getModifiedCount(contextID) != _image->getModifiedCount())
246        {
247           computeRequiredTextureDimensions(state,*_image,_textureWidth, _textureHeight, _textureDepth,_numMipmapLevels);
248
249            applyTexImage3D(GL_TEXTURE_3D,_image.get(),state, _textureWidth, _textureHeight, _textureDepth,_numMipmapLevels);
250
251            // update the modified count to show that it is upto date.
252            getModifiedCount(contextID) = _image->getModifiedCount();
253        }
254
255    }
256    else if (_subloadCallback.valid())
257    {
258
259        _textureObjectBuffer[contextID] = textureObject = generateTextureObject(this, contextID,GL_TEXTURE_3D);
260
261        textureObject->bind();
262
263        applyTexParameters(GL_TEXTURE_3D,state);
264
265        _subloadCallback->load(*this,state);
266
267        textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0);
268
269        // in theory the following line is redundent, but in practice
270        // have found that the first frame drawn doesn't apply the textures
271        // unless a second bind is called?!!
272        // perhaps it is the first glBind which is not required...
273        //glBindTexture( GL_TEXTURE_3D, handle );
274
275    }
276    else if (_image.valid() && _image->data())
277    {
278
279        // compute the internal texture format, this set the _internalFormat to an appropriate value.
280        computeInternalFormat();
281
282        // compute the dimensions of the texture.
283        computeRequiredTextureDimensions(state,*_image,_textureWidth, _textureHeight, _textureDepth,_numMipmapLevels);
284
285        textureObject = generateTextureObject(this, contextID,GL_TEXTURE_3D);
286
287        textureObject->bind();
288
289
290        applyTexParameters(GL_TEXTURE_3D,state);
291
292        applyTexImage3D(GL_TEXTURE_3D,_image.get(),state, _textureWidth, _textureHeight, _textureDepth,_numMipmapLevels);
293
294        textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0);
295
296        // update the modified count to show that it is upto date.
297        getModifiedCount(contextID) = _image->getModifiedCount();
298
299        _textureObjectBuffer[contextID] = textureObject;
300
301        // unref image data?
302        if (isSafeToUnrefImageData(state) && _image->getDataVariance()==STATIC)
303        {
304            Texture3D* non_const_this = const_cast<Texture3D*>(this);
305            non_const_this->_image = NULL;
306        }
307
308    }
309    else if ( (_textureWidth!=0) && (_textureHeight!=0) && (_textureDepth!=0) && (_internalFormat!=0) )
310    {
311        _textureObjectBuffer[contextID] = textureObject = generateTextureObject(
312                this, contextID,GL_TEXTURE_3D,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0);
313
314        textureObject->bind();
315
316        applyTexParameters(GL_TEXTURE_3D,state);
317
318        // no image present, but dimensions at set so lets create the texture
319        extensions->glTexImage3D( GL_TEXTURE_3D, 0, _internalFormat,
320                     _textureWidth, _textureHeight, _textureDepth,
321                     _borderWidth,
322                     _sourceFormat ? _sourceFormat : _internalFormat,
323                     _sourceType ? _sourceType : GL_UNSIGNED_BYTE,
324                     0);
325
326        if (_readPBuffer.valid())
327        {
328            _readPBuffer->bindPBufferToTexture(GL_FRONT);
329        }
330
331    }
332    else
333    {
334        glBindTexture( GL_TEXTURE_3D, 0 );
335    }
336
337    // if texture object is now valid and we have to allocate mipmap levels, then
338    if (textureObject != 0 && _texMipmapGenerationDirtyList[contextID])
339    {
340        generateMipmap(state);
341    }
342}
343
344void Texture3D::computeInternalFormat() const
345{
346    if (_image.valid()) computeInternalFormatWithImage(*_image);
347    else computeInternalFormatType();
348}
349
350void Texture3D::applyTexImage3D(GLenum target, Image* image, State& state, GLsizei& inwidth, GLsizei& inheight, GLsizei& indepth, GLsizei& numMipmapLevels) const
351{
352    // if we don't have a valid image we can't create a texture!
353    if (!image || !image->data())
354        return;
355
356    // get the contextID (user defined ID of 0 upwards) for the
357    // current OpenGL context.
358    const unsigned int contextID = state.getContextID();
359    const Extensions* extensions = getExtensions(contextID,true);
360    const Texture::Extensions* texExtensions = Texture::getExtensions(contextID,true);
361
362    // compute the internal texture format, this set the _internalFormat to an appropriate value.
363    computeInternalFormat();
364
365    // select the internalFormat required for the texture.
366    bool compressed = isCompressedInternalFormat(_internalFormat);
367    bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
368
369    if (compressed)
370    {
371        //OSG_WARN<<"Warning::cannot currently use compressed format with 3D textures."<<std::endl;
372        //return;
373    }
374
375    //Rescale if resize hint is set or NPOT not supported or dimensions exceed max size
376    if( _resizeNonPowerOfTwoHint || !texExtensions->isNonPowerOfTwoTextureSupported(_min_filter)
377        || inwidth > extensions->maxTexture3DSize()
378        || inheight > extensions->maxTexture3DSize()
379        || indepth > extensions->maxTexture3DSize() )
380        image->ensureValidSizeForTexturing(extensions->maxTexture3DSize());
381
382    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
383#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
384    glPixelStorei(GL_UNPACK_ROW_LENGTH,image->getRowLength());
385#endif
386
387    bool useHardwareMipMapGeneration = !image->isMipmap() && _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported();
388
389    if( _min_filter == LINEAR || _min_filter == NEAREST || useHardwareMipMapGeneration )
390    {
391        bool hardwareMipMapOn = false;
392        if (_min_filter != LINEAR && _min_filter != NEAREST)
393        {
394            if (useHardwareMipMapGeneration) glTexParameteri(GL_TEXTURE_3D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
395            hardwareMipMapOn = true;
396        }
397
398        numMipmapLevels = 1;
399
400        if (!compressed_image)
401        {
402            extensions->glTexImage3D( target, 0, _internalFormat,
403                                      inwidth, inheight, indepth,
404                                      _borderWidth,
405                                      (GLenum)image->getPixelFormat(),
406                                      (GLenum)image->getDataType(),
407                                      image->data() );
408        }
409        else if (extensions->isCompressedTexImage3DSupported())
410        {
411            // OSG_WARN<<"glCompressedTexImage3D "<<inwidth<<", "<<inheight<<", "<<indepth<<std::endl;
412            numMipmapLevels = 1;
413
414            GLint blockSize, size;
415            getCompressedSize(_internalFormat, inwidth, inheight, indepth, blockSize,size);
416
417            extensions->glCompressedTexImage3D(target, 0, _internalFormat,
418                inwidth, inheight, indepth,
419                _borderWidth,
420                size,
421                image->data());
422        }
423
424        if (hardwareMipMapOn) glTexParameteri(GL_TEXTURE_3D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
425    }
426    else
427    {
428        if(!image->isMipmap())
429        {
430
431            numMipmapLevels = 1;
432
433            gluBuild3DMipmaps( extensions->glTexImage3D,
434                               target, _internalFormat,
435                               image->s(),image->t(),image->r(),
436                               (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
437                               image->data() );
438
439        }
440        else
441        {
442            numMipmapLevels = image->getNumMipmapLevels();
443
444            int width  = image->s();
445            int height = image->t();
446            int depth = image->r();
447
448            for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height || depth) ;k++)
449            {
450
451                if (width == 0)
452                    width = 1;
453                if (height == 0)
454                    height = 1;
455                if (depth == 0)
456                    depth = 1;
457
458                extensions->glTexImage3D( target, k, _internalFormat,
459                                          width, height, depth, _borderWidth,
460                                          (GLenum)image->getPixelFormat(),
461                                          (GLenum)image->getDataType(),
462                                          image->getMipmapData(k));
463
464                width >>= 1;
465                height >>= 1;
466                depth >>= 1;
467            }
468        }
469
470    }
471
472    inwidth  = image->s();
473    inheight = image->t();
474    indepth  = image->r();
475
476}
477
478void Texture3D::copyTexSubImage3D(State& state, int xoffset, int yoffset, int zoffset, int x, int y, int width, int height )
479{
480    const unsigned int contextID = state.getContextID();
481    const Extensions* extensions = getExtensions(contextID,true);
482
483    // get the texture object for the current contextID.
484    TextureObject* textureObject = getTextureObject(contextID);
485
486    if (textureObject != 0)
487    {
488        textureObject->bind();
489
490        applyTexParameters(GL_TEXTURE_3D,state);
491        extensions->glCopyTexSubImage3D( GL_TEXTURE_3D, 0, xoffset,yoffset,zoffset, x, y, width, height);
492
493        /* Redundant, delete later */
494        //glBindTexture( GL_TEXTURE_3D, handle );
495
496        // inform state that this texture is the current one bound.
497        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
498
499    }
500    else
501    {
502        OSG_WARN<<"Warning: Texture3D::copyTexSubImage3D(..) failed, cannot not copy to a non existant texture."<<std::endl;
503    }
504}
505
506void Texture3D::allocateMipmap(State& state) const
507{
508    const unsigned int contextID = state.getContextID();
509
510    // get the texture object for the current contextID.
511    TextureObject* textureObject = getTextureObject(contextID);
512
513    if (textureObject && _textureWidth != 0 && _textureHeight != 0 && _textureDepth != 0)
514    {
515        const Extensions* extensions = getExtensions(contextID,true);
516
517        // bind texture
518        textureObject->bind();
519
520        // compute number of mipmap levels
521        int width = _textureWidth;
522        int height = _textureHeight;
523        int depth = _textureDepth;
524        int numMipmapLevels = Image::computeNumberOfMipmapLevels(width, height, depth);
525
526        // we do not reallocate the level 0, since it was already allocated
527        width >>= 1;
528        height >>= 1;
529        depth >>= 1;
530
531        for( GLsizei k = 1; k < numMipmapLevels  && (width || height || depth); k++)
532        {
533            if (width == 0)
534                width = 1;
535            if (height == 0)
536                height = 1;
537            if (depth == 0)
538                depth = 1;
539
540            extensions->glTexImage3D( GL_TEXTURE_3D, k, _internalFormat,
541                     width, height, depth, _borderWidth,
542                     _sourceFormat ? _sourceFormat : _internalFormat,
543                     _sourceType ? _sourceType : GL_UNSIGNED_BYTE, NULL);
544
545            width >>= 1;
546            height >>= 1;
547            depth >>= 1;
548        }
549
550        // inform state that this texture is the current one bound.
551        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
552    }
553}
554
555typedef buffered_value< ref_ptr<Texture3D::Extensions> > BufferedExtensions;
556static BufferedExtensions s_extensions;
557
558Texture3D::Extensions* Texture3D::getExtensions(unsigned int contextID,bool createIfNotInitalized)
559{
560    if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID);
561    return s_extensions[contextID].get();
562}
563
564void Texture3D::setExtensions(unsigned int contextID,Extensions* extensions)
565{
566    s_extensions[contextID] = extensions;
567}
568
569#ifndef GL_MAX_3D_TEXTURE_SIZE
570#define GL_MAX_3D_TEXTURE_SIZE 0x8073
571#endif
572
573Texture3D::Extensions::Extensions(unsigned int contextID)
574{
575    setupGLExtensions(contextID);
576}
577
578Texture3D::Extensions::Extensions(const Extensions& rhs):
579    Referenced()
580{
581    _isTexture3DSupported = rhs._isTexture3DSupported;
582    _isTexture3DFast = rhs._isTexture3DFast;
583    _maxTexture3DSize = rhs._maxTexture3DSize;
584
585    glTexImage3D = rhs.glTexImage3D;
586    glTexSubImage3D = rhs.glTexSubImage3D;
587    glCompressedTexImage3D = rhs.glCompressedTexImage3D;
588    glCompressedTexSubImage3D = rhs.glCompressedTexSubImage3D;
589    glCopyTexSubImage3D = rhs.glCopyTexSubImage3D;
590}
591
592void Texture3D::Extensions::lowestCommonDenominator(const Extensions& rhs)
593{
594    if (!rhs._isTexture3DSupported)                 _isTexture3DSupported = false;
595    if (!rhs._isTexture3DFast)                      _isTexture3DFast = false;
596    if (rhs._maxTexture3DSize<_maxTexture3DSize)    _maxTexture3DSize = rhs._maxTexture3DSize;
597
598    if (!rhs.glTexImage3D)                         glTexImage3D = 0;
599    if (!rhs.glTexSubImage3D)                      glTexSubImage3D = 0;
600    if (!rhs.glCompressedTexImage3D)               glCompressedTexImage3D = 0;
601    if (!rhs.glCompressedTexSubImage3D)            glCompressedTexSubImage3D = 0;
602    if (!rhs.glCopyTexSubImage3D)                  glCopyTexSubImage3D = 0;
603}
604
605void Texture3D::Extensions::setupGLExtensions(unsigned int contextID)
606{
607    _isTexture3DFast = OSG_GL3_FEATURES || isGLExtensionSupported(contextID,"GL_EXT_texture3D");
608
609    if (_isTexture3DFast) _isTexture3DSupported = true;
610    else _isTexture3DSupported = strncmp((const char*)glGetString(GL_VERSION),"1.2",3)>=0;
611
612    _maxTexture3DSize = 0;
613    glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &_maxTexture3DSize);
614
615    setGLExtensionFuncPtr(glTexImage3D,"glTexImage3D","glTexImage3DEXT");
616    setGLExtensionFuncPtr(glTexSubImage3D,"glTexSubImage3D","glTexSubImage3DEXT");
617    setGLExtensionFuncPtr(glCompressedTexImage3D,"glCompressedTexImage3D","glCompressedTexImage3DARB");
618    setGLExtensionFuncPtr(glCompressedTexSubImage3D,"glCompressedTexSubImage3D","glCompressedTexSubImage3DARB");
619    setGLExtensionFuncPtr(glCopyTexSubImage3D,"glCopyTexSubImage3D","glCopyTexSubImage3DEXT");
620
621}
Note: See TracBrowser for help on using the browser.