root/OpenSceneGraph/trunk/src/osg/Texture1D.cpp @ 12912

Revision 12912, 16.4 kB (checked in by robert, 3 years ago)

Added support for using GL_UNPACK_ROW_LENGTH in conjunction with texture's + osg::Image via new RowLength?
parameter in osg::Image. To support this Image::setData(..) now has a new optional rowLength parameter which
defaults to 0, which provides the original behaviour, Image::setRowLength(int) and int Image::getRowLength() are also provided.

With the introduction of RowLength? support in osg::Image it is now possible to create a sub image where
the t size of the image are smaller than the row length, useful for when you have a large image on the CPU
and which to use a small portion of it on the GPU. However, when these sub images are created the data
within the image is no longer contiguous so data access can no longer assume that all the data is in
one block. The new method Image::isDataContiguous() enables the user to check whether the data is contiguous,
and if not one can either access the data row by row using Image::data(column,row,image) accessor, or use the
new Image::DataIterator? for stepping through each block on memory assocatied with the image.

To support the possibility of non contiguous osg::Image usage of image objects has had to be updated to
check DataContiguous? and handle the case or use access via the DataIerator? or by row by row. To achieve
this a relatively large number of files has had to be modified, in particular the texture classes and
image plugins that doing writing.

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