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

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