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

Revision 10865, 15.5 kB (checked in by robert, 5 years ago)

Fixed typo

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