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

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