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

Revision 12912, 53.7 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/GL>
14#include <osg/GLU>
15
16#include <osg/Image>
17#include <osg/Notify>
18#include <osg/io_utils>
19
20#include <osg/Geode>
21#include <osg/Geometry>
22#include <osg/StateSet>
23#include <osg/Texture1D>
24#include <osg/Texture2D>
25#include <osg/Texture3D>
26#include <osg/Texture2DArray>
27#include <osg/Light>
28
29#include <string.h>
30#include <stdlib.h>
31
32#include "dxtctool.h"
33
34using namespace osg;
35using namespace std;
36
37void Image::UpdateCallback::operator () (osg::StateAttribute* attr, osg::NodeVisitor* nv)
38{
39    osg::Texture* texture = attr ? attr->asTexture() : 0;
40
41    // OSG_NOTICE<<"ImageSequence::UpdateCallback::"<<texture<<std::endl;
42    if (texture)
43    {
44        for(unsigned int i=0; i<texture->getNumImages(); ++i)
45        {
46            texture->getImage(i)->update(nv);
47        }
48    }
49}
50
51Image::DataIterator::DataIterator(const Image* image):
52    _image(image),
53    _rowNum(0),
54    _imageNum(0),
55    _mipmapNum(0),
56    _currentPtr(0),
57    _currentSize(0)
58{
59    assign();
60}
61
62Image::DataIterator::DataIterator(const DataIterator& ri):
63    _image(ri._image),
64    _rowNum(ri._rowNum),
65    _imageNum(ri._imageNum),
66    _mipmapNum(ri._mipmapNum),
67    _currentPtr(0),
68    _currentSize(0)
69{
70    assign();
71}
72
73void Image::DataIterator::operator ++ ()
74{
75    if (!_image || _image->isDataContiguous())
76    {
77        // for contiguous image data we never need more than one block of data
78        _currentPtr = 0;
79        _currentSize = 0;
80        return;
81    }
82
83    if (_image->isMipmap())
84    {
85        // advance to next row
86        ++_rowNum;
87
88        if (_rowNum>=_image->t())
89        {
90            // moved over end of current image so move to next
91            _rowNum = 0;
92            ++_imageNum;
93
94            if (_imageNum>=_image->r())
95            {
96                // move to next mipmap
97                _imageNum = 0;
98                ++_mipmapNum;
99
100                if (_mipmapNum>=_image->getNumMipmapLevels())
101                {
102                    _currentPtr = 0;
103                    _currentSize = 0;
104                    return;
105                }
106            }
107        }
108    }
109    else
110    {
111        // advance to next row
112        ++_rowNum;
113       
114        if (_rowNum>=_image->t())
115        {
116            // moved over end of current image so move to next
117            _rowNum = 0;
118            ++_imageNum;
119
120            if (_imageNum>=_image->r())
121            {
122                // we've moved off the end of the osg::Image so reset to null
123                _currentPtr = 0;
124                _currentSize = 0;
125                return;
126            }
127        }
128    }
129   
130    assign();
131}
132
133void Image::DataIterator::assign()
134{
135    //OSG_NOTICE<<"DataIterator::assign A"<<std::endl;
136    if (!_image)
137    {
138        _currentPtr = 0;
139        _currentSize = 0;
140        return;
141    }
142   
143    //OSG_NOTICE<<"DataIterator::assign B"<<std::endl;
144
145    if (_image->isDataContiguous())
146    {
147        _currentPtr = _image->data();
148        _currentSize = _image->getTotalSizeInBytesIncludingMipmaps();
149
150        //OSG_NOTICE<<"   _currentPtr="<<(void*)_currentPtr<<std::endl;
151        //OSG_NOTICE<<"   _currentSize="<<_currentSize<<std::endl;
152
153        return;
154    }
155   
156    //OSG_NOTICE<<"DataIterator::assign C"<<std::endl;
157
158    if (_image->isMipmap())
159    {
160        //OSG_NOTICE<<"DataIterator::assign D"<<std::endl;
161
162        if (_mipmapNum>=_image->getNumMipmapLevels())
163        {
164            _currentPtr = 0;
165            _currentSize = 0;
166            return;
167        }
168        const unsigned char* ptr = _image->getMipmapData(_mipmapNum);
169       
170        int rowLength = _image->getRowLength()>>_mipmapNum;
171        if (rowLength==0) rowLength = 1;
172       
173        int imageHeight = _image->t()>>_mipmapNum;
174        if (imageHeight==0) imageHeight = 1;
175       
176        unsigned int rowWidthInBytes = Image::computeRowWidthInBytes(rowLength,_image->getPixelFormat(),_image->getDataType(),_image->getPacking());
177        unsigned int imageSizeInBytes = rowWidthInBytes*imageHeight;
178       
179        _currentPtr = ptr + rowWidthInBytes*_rowNum + imageSizeInBytes*_imageNum;
180        _currentSize = rowWidthInBytes;
181    }
182    else
183    {
184        //OSG_NOTICE<<"DataIterator::assign E"<<std::endl;
185
186        if (_imageNum>=_image->r() || _rowNum>=_image->t())
187        {
188            _currentPtr = 0;
189            _currentSize = 0;
190            return;
191        }
192
193        //OSG_NOTICE<<"DataIterator::assign F"<<std::endl;
194
195        _currentPtr = _image->data(0, _rowNum, _imageNum);
196        _currentSize = _image->getRowSizeInBytes();
197        return;
198    }
199}
200
201
202Image::Image()
203    :BufferData(),
204    _fileName(""),
205    _writeHint(NO_PREFERENCE),
206    _origin(BOTTOM_LEFT),
207    _s(0), _t(0), _r(0),
208    _rowLength(0),
209    _internalTextureFormat(0),
210    _pixelFormat(0),
211    _dataType(0),
212    _packing(4),
213    _pixelAspectRatio(1.0),
214    _allocationMode(USE_NEW_DELETE),
215    _data(0L)
216{
217    setDataVariance(STATIC);
218}
219
220Image::Image(const Image& image,const CopyOp& copyop):
221    BufferData(image,copyop),
222    _fileName(image._fileName),
223    _writeHint(image._writeHint),
224    _origin(image._origin),
225    _s(image._s), _t(image._t), _r(image._r),
226    _rowLength(0),
227    _internalTextureFormat(image._internalTextureFormat),
228    _pixelFormat(image._pixelFormat),
229    _dataType(image._dataType),
230    _packing(image._packing),
231    _pixelAspectRatio(image._pixelAspectRatio),
232    _allocationMode(USE_NEW_DELETE),
233    _data(0L),
234    _mipmapData(image._mipmapData)
235{
236    if (image._data)
237    {
238        int size = image.getTotalSizeInBytesIncludingMipmaps();
239        setData(new unsigned char [size],USE_NEW_DELETE);
240        unsigned char* dest_ptr = _data;
241        for(DataIterator itr(&image); itr.valid(); ++itr)
242        {
243            memcpy(dest_ptr, itr.data(), itr.size());
244            dest_ptr += itr.size();
245        }
246    }
247}
248
249Image::~Image()
250{
251    deallocateData();
252}
253
254void Image::deallocateData()
255{
256    if (_data) {
257        if (_allocationMode==USE_NEW_DELETE) delete [] _data;
258        else if (_allocationMode==USE_MALLOC_FREE) ::free(_data);
259        _data = 0;
260    }
261}
262
263int Image::compare(const Image& rhs) const
264{
265    // if at least one filename is empty, then need to test buffer
266    // pointers because images could have been created on the fly
267    // and therefore we can't rely on file names to get an accurate
268    // comparison
269    if (getFileName().empty() || rhs.getFileName().empty())
270    {
271        if (_data<rhs._data) return -1;
272        if (_data>rhs._data) return 1;
273    }
274
275    // need to test against image contents here...
276    COMPARE_StateAttribute_Parameter(_s)
277    COMPARE_StateAttribute_Parameter(_t)
278    COMPARE_StateAttribute_Parameter(_internalTextureFormat)
279    COMPARE_StateAttribute_Parameter(_pixelFormat)
280    COMPARE_StateAttribute_Parameter(_dataType)
281    COMPARE_StateAttribute_Parameter(_packing)
282    COMPARE_StateAttribute_Parameter(_mipmapData)
283    COMPARE_StateAttribute_Parameter(_modifiedCount)
284
285    // same buffer + same parameters = same image
286    if ((_data || rhs._data) && (_data == rhs._data)) return 0;
287
288    // slowest comparison at the bottom!
289    COMPARE_StateAttribute_Parameter(getFileName())   
290
291    return 0;
292}
293
294void Image::setFileName(const std::string& fileName)
295{
296    _fileName = fileName;
297}
298
299void Image::setData(unsigned char* data, AllocationMode mode)
300{
301    deallocateData();
302    _data = data;
303    _allocationMode = mode;
304}
305
306
307bool Image::isPackedType(GLenum type)
308{
309    switch(type)
310    {
311        case(GL_UNSIGNED_BYTE_3_3_2):
312        case(GL_UNSIGNED_BYTE_2_3_3_REV):
313        case(GL_UNSIGNED_SHORT_5_6_5):
314        case(GL_UNSIGNED_SHORT_5_6_5_REV):
315        case(GL_UNSIGNED_SHORT_4_4_4_4):
316        case(GL_UNSIGNED_SHORT_4_4_4_4_REV):
317        case(GL_UNSIGNED_SHORT_5_5_5_1):
318        case(GL_UNSIGNED_SHORT_1_5_5_5_REV):
319        case(GL_UNSIGNED_INT_8_8_8_8):
320        case(GL_UNSIGNED_INT_8_8_8_8_REV):
321        case(GL_UNSIGNED_INT_10_10_10_2):
322        case(GL_UNSIGNED_INT_2_10_10_10_REV): return true;
323        default: return false;
324    }   
325}
326
327
328GLenum Image::computePixelFormat(GLenum format)
329{
330    switch(format)
331    {
332        case(GL_ALPHA16F_ARB):
333        case(GL_ALPHA32F_ARB):
334            return GL_ALPHA;
335        case(GL_LUMINANCE16F_ARB):
336        case(GL_LUMINANCE32F_ARB):
337            return GL_LUMINANCE;
338        case(GL_INTENSITY16F_ARB):
339        case(GL_INTENSITY32F_ARB):
340            return GL_INTENSITY;
341        case(GL_LUMINANCE_ALPHA16F_ARB):
342        case(GL_LUMINANCE_ALPHA32F_ARB):
343            return GL_LUMINANCE_ALPHA;
344        case(GL_RGB32F_ARB):
345        case(GL_RGB16F_ARB):
346            return GL_RGB;
347        case(GL_RGBA32F_ARB):
348        case(GL_RGBA16F_ARB):
349            return GL_RGBA;
350
351        case(GL_ALPHA8I_EXT):
352        case(GL_ALPHA16I_EXT):
353        case(GL_ALPHA32I_EXT):
354        case(GL_ALPHA8UI_EXT):
355        case(GL_ALPHA16UI_EXT):
356        case(GL_ALPHA32UI_EXT):
357            return GL_ALPHA_INTEGER_EXT;
358        case(GL_LUMINANCE8I_EXT):
359        case(GL_LUMINANCE16I_EXT):
360        case(GL_LUMINANCE32I_EXT):
361        case(GL_LUMINANCE8UI_EXT):
362        case(GL_LUMINANCE16UI_EXT):
363        case(GL_LUMINANCE32UI_EXT):
364            return GL_LUMINANCE_INTEGER_EXT;
365        case(GL_INTENSITY8I_EXT):
366        case(GL_INTENSITY16I_EXT):
367        case(GL_INTENSITY32I_EXT):
368        case(GL_INTENSITY8UI_EXT):
369        case(GL_INTENSITY16UI_EXT):
370        case(GL_INTENSITY32UI_EXT):
371            OSG_WARN<<"Image::computePixelFormat("<<std::hex<<format<<std::dec<<") intensity pixel format is not correctly specified, so assume GL_LUMINANCE_INTEGER."<<std::endl;           
372            return GL_LUMINANCE_INTEGER_EXT;
373        case(GL_LUMINANCE_ALPHA8I_EXT):
374        case(GL_LUMINANCE_ALPHA16I_EXT):
375        case(GL_LUMINANCE_ALPHA32I_EXT):
376        case(GL_LUMINANCE_ALPHA8UI_EXT):
377        case(GL_LUMINANCE_ALPHA16UI_EXT):
378        case(GL_LUMINANCE_ALPHA32UI_EXT):
379            return GL_LUMINANCE_ALPHA_INTEGER_EXT;
380        case(GL_RGB32I_EXT):
381        case(GL_RGB16I_EXT):
382        case(GL_RGB8I_EXT):
383        case(GL_RGB32UI_EXT):
384        case(GL_RGB16UI_EXT):
385        case(GL_RGB8UI_EXT):
386            return GL_RGB_INTEGER_EXT;
387        case(GL_RGBA32I_EXT):
388        case(GL_RGBA16I_EXT):
389        case(GL_RGBA8I_EXT):
390        case(GL_RGBA32UI_EXT):
391        case(GL_RGBA16UI_EXT):
392        case(GL_RGBA8UI_EXT):
393            return GL_RGBA_INTEGER_EXT;;
394
395        default:
396            return format;
397    }
398}
399
400GLenum Image::computeFormatDataType(GLenum pixelFormat)
401{
402    switch (pixelFormat)
403    {
404        case GL_LUMINANCE32F_ARB:
405        case GL_LUMINANCE16F_ARB:
406        case GL_LUMINANCE_ALPHA32F_ARB:
407        case GL_LUMINANCE_ALPHA16F_ARB:
408        case GL_RGB32F_ARB:
409        case GL_RGB16F_ARB:
410        case GL_RGBA32F_ARB:
411        case GL_RGBA16F_ARB: return GL_FLOAT;
412
413        case GL_RGBA32UI_EXT:
414        case GL_RGB32UI_EXT:
415        case GL_LUMINANCE32UI_EXT:
416        case GL_LUMINANCE_ALPHA32UI_EXT: return GL_UNSIGNED_INT;
417
418        case GL_RGB16UI_EXT:
419        case GL_RGBA16UI_EXT:
420        case GL_LUMINANCE16UI_EXT:
421        case GL_LUMINANCE_ALPHA16UI_EXT: return GL_UNSIGNED_SHORT;
422
423        case GL_RGBA8UI_EXT:
424        case GL_RGB8UI_EXT:
425        case GL_LUMINANCE8UI_EXT:
426        case GL_LUMINANCE_ALPHA8UI_EXTreturn GL_UNSIGNED_BYTE;
427
428        case GL_RGBA32I_EXT
429        case GL_RGB32I_EXT:
430        case GL_LUMINANCE32I_EXT:
431        case GL_LUMINANCE_ALPHA32I_EXT: return GL_INT;
432
433        case GL_RGBA16I_EXT:
434        case GL_RGB16I_EXT:
435        case GL_LUMINANCE16I_EXT:
436        case GL_LUMINANCE_ALPHA16I_EXT: return GL_SHORT;
437
438        case GL_RGB8I_EXT:
439        case GL_RGBA8I_EXT:
440        case GL_LUMINANCE8I_EXT:
441        case GL_LUMINANCE_ALPHA8I_EXT: return GL_BYTE;
442
443        case GL_RGBA:
444        case GL_RGB:
445        case GL_LUMINANCE:
446        case GL_LUMINANCE_ALPHA: return GL_UNSIGNED_BYTE;
447
448        default:
449        {
450            OSG_WARN<<"error computeFormatType = "<<std::hex<<pixelFormat<<std::dec<<std::endl;
451            return 0;
452        }
453    }
454}
455
456unsigned int Image::computeNumComponents(GLenum pixelFormat)
457{
458    switch(pixelFormat)
459    {
460        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): return 3;
461        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): return 4;
462        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): return 4;
463        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): return 4;
464        case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT): return 1;
465        case(GL_COMPRESSED_RED_RGTC1_EXT):   return 1;
466        case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): return 2;
467        case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): return 2;   
468        case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): return 3;
469        case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): return 3;
470        case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): return 4;
471        case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): return 4;
472        case(GL_ETC1_RGB8_OES): return 3;
473        case(GL_COLOR_INDEX): return 1;
474        case(GL_STENCIL_INDEX): return 1;
475        case(GL_DEPTH_COMPONENT): return 1;
476        case(GL_RED): return 1;
477        case(GL_GREEN): return 1;
478        case(GL_BLUE): return 1;
479        case(GL_ALPHA): return 1;
480        case(GL_ALPHA8I_EXT): return 1;
481        case(GL_ALPHA8UI_EXT): return 1;
482        case(GL_ALPHA16I_EXT): return 1;
483        case(GL_ALPHA16UI_EXT): return 1;
484        case(GL_ALPHA32I_EXT): return 1;
485        case(GL_ALPHA32UI_EXT): return 1;
486        case(GL_ALPHA16F_ARB): return 1;
487        case(GL_ALPHA32F_ARB): return 1;
488        case(GL_RGB): return 3;
489        case(GL_BGR): return 3;
490        case(GL_RGB8I_EXT): return 3;
491        case(GL_RGB8UI_EXT): return 3;
492        case(GL_RGB16I_EXT): return 3;
493        case(GL_RGB16UI_EXT): return 3;
494        case(GL_RGB32I_EXT): return 3;
495        case(GL_RGB32UI_EXT): return 3;
496        case(GL_RGB16F_ARB): return 3;
497        case(GL_RGB32F_ARB): return 3;
498        case(GL_RGBA16F_ARB): return 4;
499        case(GL_RGBA32F_ARB): return 4;
500        case(GL_RGBA): return 4;
501        case(GL_BGRA): return 4;
502        case(GL_RGBA8): return 4;
503        case(GL_LUMINANCE): return 1;
504        case(GL_LUMINANCE4): return 1;
505        case(GL_LUMINANCE8): return 1;
506        case(GL_LUMINANCE12): return 1;
507        case(GL_LUMINANCE16): return 1;
508        case(GL_LUMINANCE8I_EXT): return 1;
509        case(GL_LUMINANCE8UI_EXT): return 1;
510        case(GL_LUMINANCE16I_EXT): return 1;
511        case(GL_LUMINANCE16UI_EXT): return 1;
512        case(GL_LUMINANCE32I_EXT): return 1;
513        case(GL_LUMINANCE32UI_EXT): return 1;
514        case(GL_LUMINANCE16F_ARB): return 1;
515        case(GL_LUMINANCE32F_ARB): return 1;
516        case(GL_LUMINANCE4_ALPHA4): return 2;
517        case(GL_LUMINANCE6_ALPHA2): return 2;
518        case(GL_LUMINANCE8_ALPHA8): return 2;
519        case(GL_LUMINANCE12_ALPHA4): return 2;
520        case(GL_LUMINANCE12_ALPHA12): return 2;
521        case(GL_LUMINANCE16_ALPHA16): return 2;
522        case(GL_INTENSITY): return 1;
523        case(GL_INTENSITY4): return 1;
524        case(GL_INTENSITY8): return 1;
525        case(GL_INTENSITY12): return 1;
526        case(GL_INTENSITY16): return 1;
527        case(GL_INTENSITY8UI_EXT): return 1;
528        case(GL_INTENSITY8I_EXT): return 1;
529        case(GL_INTENSITY16I_EXT): return 1;
530        case(GL_INTENSITY16UI_EXT): return 1;
531        case(GL_INTENSITY32I_EXT): return 1;
532        case(GL_INTENSITY32UI_EXT): return 1;
533        case(GL_INTENSITY16F_ARB): return 1;
534        case(GL_INTENSITY32F_ARB): return 1;
535        case(GL_LUMINANCE_ALPHA): return 2;
536        case(GL_LUMINANCE_ALPHA8I_EXT): return 2;
537        case(GL_LUMINANCE_ALPHA8UI_EXT): return 2;
538        case(GL_LUMINANCE_ALPHA16I_EXT): return 2;
539        case(GL_LUMINANCE_ALPHA16UI_EXT): return 2;
540        case(GL_LUMINANCE_ALPHA32I_EXT): return 2;
541        case(GL_LUMINANCE_ALPHA32UI_EXT): return 2;
542        case(GL_LUMINANCE_ALPHA16F_ARB): return 2;
543        case(GL_LUMINANCE_ALPHA32F_ARB): return 2;
544        case(GL_HILO_NV): return 2;
545        case(GL_DSDT_NV): return 2;
546        case(GL_DSDT_MAG_NV): return 3;
547        case(GL_DSDT_MAG_VIB_NV): return 4;
548        case(GL_RED_INTEGER_EXT): return 1;
549        case(GL_GREEN_INTEGER_EXT): return 1;
550        case(GL_BLUE_INTEGER_EXT): return 1;
551        case(GL_ALPHA_INTEGER_EXT): return 1;
552        case(GL_RGB_INTEGER_EXT): return 3;
553        case(GL_RGBA_INTEGER_EXT): return 4;
554        case(GL_BGR_INTEGER_EXT): return 3;
555        case(GL_BGRA_INTEGER_EXT): return 4;
556        case(GL_LUMINANCE_INTEGER_EXT): return 1;
557        case(GL_LUMINANCE_ALPHA_INTEGER_EXT): return 2;
558
559        default:
560        {
561            OSG_WARN<<"error pixelFormat = "<<std::hex<<pixelFormat<<std::dec<<std::endl;
562            return 0;
563        }
564    }       
565}
566
567
568unsigned int Image::computePixelSizeInBits(GLenum format,GLenum type)
569{
570
571    switch(format)
572    {
573        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): return 4;
574        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): return 4;
575        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): return 8;
576        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): return 8;
577        case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT): return 4;
578        case(GL_COMPRESSED_RED_RGTC1_EXT):   return 4;
579        case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): return 8;
580        case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): return 8;
581        case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): return 4;
582        case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): return 2;
583        case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): return 4;
584        case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): return 2;
585        case(GL_ETC1_RGB8_OES): return 4;
586        default: break;
587    }
588
589    // note, haven't yet added proper handling of the ARB GL_COMPRESSRED_* pathways
590    // yet, no clear size for these since its probably implementation dependent
591    // which raises the question of how to actually querry for these sizes...
592    // will need to revisit this issue, for now just report an error.
593    // this is possible a bit of mute point though as since the ARB compressed formats
594    // arn't yet used for storing images to disk, so its likely that users wont have
595    // osg::Image's for pixel formats set the ARB compressed formats, just using these
596    // compressed formats as internal texture modes.  This is very much speculation though
597    // if get the below error then its time to revist this issue :-)
598    // Robert Osfield, Jan 2005.
599    switch(format)
600    {
601        case(GL_COMPRESSED_ALPHA):
602        case(GL_COMPRESSED_LUMINANCE):
603        case(GL_COMPRESSED_LUMINANCE_ALPHA):
604        case(GL_COMPRESSED_INTENSITY):
605        case(GL_COMPRESSED_RGB):
606        case(GL_COMPRESSED_RGBA):
607            OSG_WARN<<"Image::computePixelSizeInBits(format,type) : cannot compute correct size of compressed format ("<<format<<") returning 0."<<std::endl;
608            return 0;
609        default: break;
610    }
611
612    switch(format)
613    {
614        case(GL_LUMINANCE4): return 4;
615        case(GL_LUMINANCE8): return 8;
616        case(GL_LUMINANCE12): return 12;
617        case(GL_LUMINANCE16): return 16;
618        case(GL_LUMINANCE4_ALPHA4): return 8;
619        case(GL_LUMINANCE6_ALPHA2): return 8;
620        case(GL_LUMINANCE8_ALPHA8): return 16;
621        case(GL_LUMINANCE12_ALPHA4): return 16;
622        case(GL_LUMINANCE12_ALPHA12): return 24;
623        case(GL_LUMINANCE16_ALPHA16): return 32;
624        case(GL_INTENSITY4): return 4;
625        case(GL_INTENSITY8): return 8;
626        case(GL_INTENSITY12): return 12;
627        case(GL_INTENSITY16): return 16;
628        default: break;
629    }
630
631    switch(type)
632    {
633   
634        case(GL_BITMAP): return computeNumComponents(format);
635       
636        case(GL_BYTE):
637        case(GL_UNSIGNED_BYTE): return 8*computeNumComponents(format);
638       
639        case(GL_HALF_FLOAT_NV):
640        case(GL_SHORT):
641        case(GL_UNSIGNED_SHORT): return 16*computeNumComponents(format);
642       
643        case(GL_INT):
644        case(GL_UNSIGNED_INT):
645        case(GL_FLOAT): return 32*computeNumComponents(format);
646   
647   
648        case(GL_UNSIGNED_BYTE_3_3_2):
649        case(GL_UNSIGNED_BYTE_2_3_3_REV): return 8;
650       
651        case(GL_UNSIGNED_SHORT_5_6_5):
652        case(GL_UNSIGNED_SHORT_5_6_5_REV):
653        case(GL_UNSIGNED_SHORT_4_4_4_4):
654        case(GL_UNSIGNED_SHORT_4_4_4_4_REV):
655        case(GL_UNSIGNED_SHORT_5_5_5_1):
656        case(GL_UNSIGNED_SHORT_1_5_5_5_REV): return 16;
657       
658        case(GL_UNSIGNED_INT_8_8_8_8):
659        case(GL_UNSIGNED_INT_8_8_8_8_REV):
660        case(GL_UNSIGNED_INT_10_10_10_2):
661        case(GL_UNSIGNED_INT_2_10_10_10_REV): return 32;
662        default:
663        {
664            OSG_WARN<<"error type = "<<type<<std::endl;
665            return 0;
666        }
667    }   
668
669}
670
671unsigned int Image::computeBlockSize(GLenum pixelFormat, GLenum packing)
672{
673    switch(pixelFormat)
674    {
675        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
676        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
677            return osg::maximum(8u,packing); // block size of 8
678        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
679        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
680        case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG):
681        case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG):
682        case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG):
683        case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG):
684        case(GL_ETC1_RGB8_OES):
685            return osg::maximum(16u,packing); // block size of 16
686        case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT):
687        case(GL_COMPRESSED_RED_RGTC1_EXT):
688            return osg::maximum(8u,packing); // block size of 8
689            break;
690        case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
691        case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
692            return osg::maximum(16u,packing); // block size of 16
693        default:
694            break;
695    }
696    return packing;
697}
698
699unsigned int Image::computeRowWidthInBytes(int width,GLenum pixelFormat,GLenum type,int packing)
700{
701    unsigned int pixelSize = computePixelSizeInBits(pixelFormat,type);
702    int widthInBits = width*pixelSize;
703    int packingInBits = packing!=0 ? packing*8 : 8;
704    //OSG_INFO << "width="<<width<<" pixelSize="<<pixelSize<<"  width in bit="<<widthInBits<<" packingInBits="<<packingInBits<<" widthInBits%packingInBits="<<widthInBits%packingInBits<<std::endl;
705    return (widthInBits/packingInBits + ((widthInBits%packingInBits)?1:0))*packing;
706}
707
708unsigned int Image::computeImageSizeInBytes(int width,int height, int depth, GLenum pixelFormat,GLenum type,int packing)
709{
710    if (width==0 || height==0 || depth==0) return 0;
711   
712    return osg::maximum(
713            Image::computeRowWidthInBytes(width,pixelFormat,type,packing)*height*depth,
714            computeBlockSize(pixelFormat, packing)
715        );
716}
717
718int Image::computeNearestPowerOfTwo(int s,float bias)
719{
720    if ((s & (s-1))!=0)
721    {
722        // it isn't so lets find the closest power of two.
723        // yes, logf and powf are slow, but this code should
724        // only be called during scene graph initilization,
725        // if at all, so not critical in the greater scheme.
726        float p2 = logf((float)s)/logf(2.0f);
727        float rounded_p2 = floorf(p2+bias);
728        s = (int)(powf(2.0f,rounded_p2));
729    }
730    return s;
731}
732
733int Image::computeNumberOfMipmapLevels(int s,int t, int r)
734{
735    int w = maximum(s, t);
736    w = maximum(w, r);
737    return 1 + static_cast<int>(floor(logf(w)/logf(2.0f)));
738}
739
740bool Image::isCompressed() const
741{
742    switch(_pixelFormat)
743    {
744        case(GL_COMPRESSED_ALPHA_ARB):
745        case(GL_COMPRESSED_INTENSITY_ARB):
746        case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB):
747        case(GL_COMPRESSED_LUMINANCE_ARB):
748        case(GL_COMPRESSED_RGBA_ARB):
749        case(GL_COMPRESSED_RGB_ARB):
750        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
751        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
752        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
753        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
754        case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT):
755        case(GL_COMPRESSED_RED_RGTC1_EXT):
756        case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
757        case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
758        case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG):
759        case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG):
760        case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG):
761        case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG):
762        case(GL_ETC1_RGB8_OES):
763            return true;
764        default:
765            return false;
766    }
767}
768
769unsigned int Image::getTotalSizeInBytesIncludingMipmaps() const
770{
771    if (_mipmapData.empty())
772    {
773        // no mips so just return size of main image
774        return getTotalSizeInBytes();
775    }
776   
777    int s = _s;
778    int t = _t;
779    int r = _r;
780    unsigned int totalSize = 0;
781    for(unsigned int i=0;i<_mipmapData.size()+1;++i)
782    {
783        totalSize += computeImageSizeInBytes(s, t, r, _pixelFormat, _dataType, _packing);
784       
785        s >>= 1;
786        t >>= 1;
787        r >>= 1;
788
789        if (s<1) s=1;
790        if (t<1) t=1;
791        if (r<1) r=1;
792   }
793
794   return totalSize;
795}
796
797
798void Image::setInternalTextureFormat(GLint internalFormat)
799{
800    // won't do any sanity checking right now, leave it to
801    // OpenGL to make the call.
802    _internalTextureFormat = internalFormat;
803}
804
805void Image::setPixelFormat(GLenum pixelFormat)
806{
807    _pixelFormat = pixelFormat;
808}
809
810void Image::setDataType(GLenum dataType)
811{
812    if (_dataType==dataType) return; // do nothing if the same.
813
814    if (_dataType==0)
815    {
816        // setting the datatype for the first time
817        _dataType = dataType;
818    }
819    else
820    {
821        OSG_WARN<<"Image::setDataType(..) - warning, attempt to reset the data type not permitted."<<std::endl;
822    }
823}
824
825
826void Image::allocateImage(int s,int t,int r,
827                        GLenum format,GLenum type,
828                        int packing)
829{
830    _mipmapData.clear();
831
832    unsigned int previousTotalSize = 0;
833   
834    if (_data) previousTotalSize = computeRowWidthInBytes(_s,_pixelFormat,_dataType,_packing)*_t*_r;
835   
836    unsigned int newTotalSize = computeRowWidthInBytes(s,format,type,packing)*t*r;
837
838    if (newTotalSize!=previousTotalSize)
839    {
840        if (newTotalSize)
841            setData(new unsigned char [newTotalSize],USE_NEW_DELETE);
842        else
843            deallocateData(); // and sets it to NULL.
844    }
845
846    if (_data)
847    {
848        _s = s;
849        _t = t;
850        _r = r;
851        _pixelFormat = format;
852        _dataType = type;
853        _packing = packing;
854        _rowLength = 0;
855       
856        // preserve internalTextureFormat if already set, otherwise
857        // use the pixelFormat as the source for the format.
858        if (_internalTextureFormat==0) _internalTextureFormat = format;
859    }
860    else
861    {
862   
863        // failed to allocate memory, for now, will simply set values to 0.
864        _s = 0;
865        _t = 0;
866        _r = 0;
867        _pixelFormat = 0;
868        _dataType = 0;
869        _packing = 0;
870        _rowLength = 0;
871       
872        // commenting out reset of _internalTextureFormat as we are changing
873        // policy so that allocateImage honours previous settings of _internalTextureFormat.
874        //_internalTextureFormat = 0;
875    }
876   
877    dirty();
878}
879
880void Image::setImage(int s,int t,int r,
881                     GLint internalTextureFormat,
882                     GLenum format,GLenum type,
883                     unsigned char *data,
884                     AllocationMode mode,
885                     int packing,
886                     int rowLength)
887{
888    _mipmapData.clear();
889
890    _s = s;
891    _t = t;
892    _r = r;
893
894    _internalTextureFormat = internalTextureFormat;
895    _pixelFormat    = format;
896    _dataType       = type;
897
898    setData(data,mode);
899
900    _packing = packing;
901    _rowLength = rowLength;
902       
903    dirty();
904
905}
906
907void Image::readPixels(int x,int y,int width,int height,
908                       GLenum format,GLenum type)
909{
910    allocateImage(width,height,1,format,type);
911
912    glPixelStorei(GL_PACK_ALIGNMENT,_packing);
913    glPixelStorei(GL_PACK_ROW_LENGTH,_rowLength);
914
915    glReadPixels(x,y,width,height,format,type,_data);
916}
917
918
919void Image::readImageFromCurrentTexture(unsigned int contextID, bool copyMipMapsIfAvailable, GLenum type)
920{
921#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
922    // OSG_NOTICE<<"Image::readImageFromCurrentTexture()"<<std::endl;
923
924    const osg::Texture::Extensions* extensions = osg::Texture::getExtensions(contextID,true);
925    const osg::Texture3D::Extensions* extensions3D = osg::Texture3D::getExtensions(contextID,true);
926    const osg::Texture2DArray::Extensions* extensions2DArray = osg::Texture2DArray::getExtensions(contextID,true);
927
928   
929    GLboolean binding1D = GL_FALSE, binding2D = GL_FALSE, binding3D = GL_FALSE, binding2DArray = GL_FALSE;
930
931    glGetBooleanv(GL_TEXTURE_BINDING_1D, &binding1D);
932    glGetBooleanv(GL_TEXTURE_BINDING_2D, &binding2D);
933    glGetBooleanv(GL_TEXTURE_BINDING_3D, &binding3D);
934
935    if (extensions2DArray->isTexture2DArraySupported())
936    {
937        glGetBooleanv(GL_TEXTURE_BINDING_2D_ARRAY_EXT, &binding2DArray);
938    }
939
940    GLenum textureMode = binding1D ? GL_TEXTURE_1D : binding2D ? GL_TEXTURE_2D : binding3D ? GL_TEXTURE_3D : binding2DArray ? GL_TEXTURE_2D_ARRAY_EXT : 0;
941   
942    if (textureMode==0) return;
943
944    GLint internalformat;
945    GLint width;
946    GLint height;
947    GLint depth;
948    GLint packing;
949    GLint rowLength;
950
951    GLint numMipMaps = 0;
952    if (copyMipMapsIfAvailable)
953    {
954        for(;numMipMaps<20;++numMipMaps)
955        {
956            glGetTexLevelParameteriv(textureMode, numMipMaps, GL_TEXTURE_WIDTH, &width);
957            glGetTexLevelParameteriv(textureMode, numMipMaps, GL_TEXTURE_HEIGHT, &height);
958            glGetTexLevelParameteriv(textureMode, numMipMaps, GL_TEXTURE_DEPTH, &depth);
959            // OSG_NOTICE<<"   numMipMaps="<<numMipMaps<<" width="<<width<<" height="<<height<<" depth="<<depth<<std::endl;
960            if (width==0 || height==0 || depth==0) break;
961        }
962    }
963    else
964    {
965        numMipMaps = 1;
966    }
967   
968    // OSG_NOTICE<<"Image::readImageFromCurrentTexture() : numMipMaps = "<<numMipMaps<<std::endl;
969
970       
971    GLint compressed = 0;
972
973    if (textureMode==GL_TEXTURE_2D)
974    {
975        if (extensions->isCompressedTexImage2DSupported())
976        {
977            glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_COMPRESSED_ARB,&compressed);
978        }
979    }
980    else if (textureMode==GL_TEXTURE_3D)
981    {
982        if (extensions3D->isCompressedTexImage3DSupported())
983        {
984            glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_COMPRESSED_ARB,&compressed);
985        }
986    }
987    else if (textureMode==GL_TEXTURE_2D_ARRAY_EXT)
988    {
989        if (extensions2DArray->isCompressedTexImage3DSupported())
990        {
991            glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_COMPRESSED_ARB,&compressed);
992        }
993    }
994   
995   
996       
997    /* if the compression has been successful */
998    if (compressed == GL_TRUE)
999    {
1000
1001        MipmapDataType mipMapData;
1002       
1003        unsigned int total_size = 0;
1004        GLint i;
1005        for(i=0;i<numMipMaps;++i)
1006        {
1007            if (i>0) mipMapData.push_back(total_size);
1008           
1009            GLint compressed_size;
1010            glGetTexLevelParameteriv(textureMode, i, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, &compressed_size);
1011           
1012            total_size += compressed_size;
1013        }
1014       
1015       
1016        unsigned char* data = new unsigned char[total_size];
1017        if (!data)
1018        {
1019            OSG_WARN<<"Warning: Image::readImageFromCurrentTexture(..) out of memory, now image read."<<std::endl;
1020            return;
1021        }
1022
1023        deallocateData(); // and sets it to NULL.
1024
1025        glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1026        glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_WIDTH, &width);
1027        glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_HEIGHT, &height);
1028        glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_DEPTH, &depth);
1029        glGetIntegerv(GL_UNPACK_ALIGNMENT, &packing);
1030        glPixelStorei(GL_PACK_ALIGNMENT, packing);
1031        glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowLength);
1032        glPixelStorei(GL_PACK_ROW_LENGTH, rowLength);
1033
1034        _data = data;
1035        _s = width;
1036        _t = height;
1037        _r = depth;
1038       
1039        _pixelFormat = internalformat;
1040        _dataType = type;
1041        _internalTextureFormat = internalformat;
1042        _mipmapData = mipMapData;
1043        _allocationMode=USE_NEW_DELETE;
1044        _packing = packing;
1045        _rowLength = rowLength;
1046
1047        for(i=0;i<numMipMaps;++i)
1048        {
1049            extensions->glGetCompressedTexImage(textureMode, i, getMipmapData(i));
1050        }
1051
1052        dirty();
1053   
1054    }
1055    else
1056    {
1057        MipmapDataType mipMapData;
1058
1059        // Get the internal texture format and packing value from OpenGL,
1060        // instead of using possibly outdated values from the class.
1061        glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1062        glGetIntegerv(GL_UNPACK_ALIGNMENT, &packing);
1063        glPixelStorei(GL_PACK_ALIGNMENT, packing);
1064        glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowLength);
1065        glPixelStorei(GL_PACK_ROW_LENGTH, rowLength);
1066
1067        unsigned int total_size = 0;
1068        GLint i;
1069        for(i=0;i<numMipMaps;++i)
1070        {
1071            if (i>0) mipMapData.push_back(total_size);
1072           
1073            glGetTexLevelParameteriv(textureMode, i, GL_TEXTURE_WIDTH, &width);
1074            glGetTexLevelParameteriv(textureMode, i, GL_TEXTURE_HEIGHT, &height);
1075            glGetTexLevelParameteriv(textureMode, i, GL_TEXTURE_DEPTH, &depth);
1076           
1077            unsigned int level_size = computeRowWidthInBytes(width,internalformat,type,packing)*height*depth;
1078
1079            total_size += level_size;
1080        }
1081       
1082       
1083        unsigned char* data = new unsigned char[total_size];
1084        if (!data)
1085        {
1086            OSG_WARN<<"Warning: Image::readImageFromCurrentTexture(..) out of memory, now image read."<<std::endl;
1087            return;
1088        }
1089
1090        deallocateData(); // and sets it to NULL.
1091
1092        glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_WIDTH, &width);
1093        glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_HEIGHT, &height);
1094        glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_DEPTH, &depth);
1095
1096        _data = data;
1097        _s = width;
1098        _t = height;
1099        _r = depth;
1100       
1101        _pixelFormat = computePixelFormat(internalformat);
1102        _dataType = type;
1103        _internalTextureFormat = internalformat;
1104        _mipmapData = mipMapData;
1105        _allocationMode=USE_NEW_DELETE;
1106        _packing = packing;
1107        _rowLength = rowLength;
1108       
1109        for(i=0;i<numMipMaps;++i)
1110        {
1111            glGetTexImage(textureMode,i,_pixelFormat,_dataType,getMipmapData(i));
1112        }
1113
1114        dirty();
1115    }   
1116#else
1117    OSG_NOTICE<<"Warning: Image::readImageFromCurrentTexture() not supported."<<std::endl;
1118#endif
1119}
1120
1121void Image::scaleImage(int s,int t,int r, GLenum newDataType)
1122{
1123    if (_s==s && _t==t && _r==r) return;
1124
1125    if (_data==NULL)
1126    {
1127        OSG_WARN << "Error Image::scaleImage() do not succeed : cannot scale NULL image."<<std::endl;
1128        return;
1129    }
1130
1131    if (_r!=1 || r!=1)
1132    {
1133        OSG_WARN << "Error Image::scaleImage() do not succeed : scaling of volumes not implemented."<<std::endl;
1134        return;
1135    }
1136
1137    unsigned int newTotalSize = computeRowWidthInBytes(s,_pixelFormat,newDataType,_packing)*t;
1138
1139    // need to sort out what size to really use...
1140    unsigned char* newData = new unsigned char [newTotalSize];
1141    if (!newData)
1142    {
1143        // should we throw an exception???  Just return for time being.
1144        OSG_FATAL << "Error Image::scaleImage() do not succeed : out of memory."<<newTotalSize<<std::endl;
1145        return;
1146    }
1147
1148    PixelStorageModes psm;
1149    psm.pack_alignment = _packing;
1150    psm.pack_row_length = _rowLength;
1151    psm.unpack_alignment = _packing;
1152
1153    GLint status = gluScaleImage(&psm, _pixelFormat,
1154        _s,
1155        _t,
1156        _dataType,
1157        _data,
1158        s,
1159        t,
1160        newDataType,
1161        newData);
1162
1163    if (status==0)
1164    {
1165
1166        // free old image.
1167        _s = s;
1168        _t = t;
1169        _rowLength = 0;
1170        _dataType = newDataType;
1171        setData(newData,USE_NEW_DELETE);
1172    }
1173    else
1174    {
1175        delete [] newData;
1176
1177        OSG_WARN << "Error Image::scaleImage() did not succeed : errorString = "<< gluErrorString((GLenum)status) << ". The rendering context may be invalid." << std::endl;
1178    }
1179
1180    dirty();
1181}
1182
1183void Image::copySubImage(int s_offset, int t_offset, int r_offset, const osg::Image* source)
1184{
1185    if (!source) return;
1186    if (s_offset<0 || t_offset<0 || r_offset<0)
1187    {
1188        OSG_WARN<<"Warning: negative offsets passed to Image::copySubImage(..) not supported, operation ignored."<<std::endl;
1189        return;
1190    }
1191
1192    if (!_data)
1193    {
1194        OSG_INFO<<"allocating image"<<endl;
1195        allocateImage(s_offset+source->s(),t_offset+source->t(),r_offset+source->r(),
1196                    source->getPixelFormat(),source->getDataType(),
1197                    source->getPacking());
1198    }
1199
1200    if (s_offset>=_s || t_offset>=_t  || r_offset>=_r)
1201    {
1202        OSG_WARN<<"Warning: offsets passed to Image::copySubImage(..) outside destination image, operation ignored."<<std::endl;
1203        return;
1204    }
1205
1206
1207    if (_pixelFormat != source->getPixelFormat())
1208    {
1209        OSG_WARN<<"Warning: image with an incompatible pixel formats passed to Image::copySubImage(..), operation ignored."<<std::endl;
1210        return;
1211    }
1212
1213    void* data_destination = data(s_offset,t_offset,r_offset);
1214
1215    PixelStorageModes psm;
1216    psm.pack_alignment = _packing;
1217    psm.pack_row_length = _rowLength!=0 ? _rowLength : _s;
1218    psm.unpack_alignment = source->getPacking();
1219    psm.unpack_row_length = source->getRowLength();
1220
1221    GLint status = gluScaleImage(&psm, _pixelFormat,
1222        source->s(),
1223        source->t(),
1224        source->getDataType(),
1225        source->data(),
1226        source->s(),
1227        source->t(),
1228        _dataType,
1229        data_destination);
1230
1231    if (status!=0)
1232    {
1233        OSG_WARN << "Error Image::scaleImage() did not succeed : errorString = "<< gluErrorString((GLenum)status) << ". The rendering context may be invalid." << std::endl;
1234    }
1235}
1236
1237void Image::flipHorizontal()
1238{
1239    if (_data==NULL)
1240    {
1241        OSG_WARN << "Error Image::flipHorizontal() did not succeed : cannot flip NULL image."<<std::endl;
1242        return;
1243    }
1244
1245    unsigned int elemSize = getPixelSizeInBits()/8;
1246
1247    if (_mipmapData.empty())
1248    {
1249        unsigned int rowStepInBytes = getRowStepInBytes();
1250        unsigned int imageStepInBytes = getImageStepInBytes();
1251       
1252        for(int r=0;r<_r;++r)
1253        {
1254            for (int t=0; t<_t; ++t)
1255            {
1256                unsigned char* rowData = _data + t*rowStepInBytes + r*imageStepInBytes;
1257                unsigned char* left  = rowData ;
1258                unsigned char* right = rowData + ((_s-1)*getPixelSizeInBits())/8;
1259
1260                while (left < right)
1261                {
1262                    char tmp[32];  // max elem size is four floats
1263                    memcpy(tmp, left, elemSize);
1264                    memcpy(left, right, elemSize);
1265                    memcpy(right, tmp, elemSize);
1266                    left  += elemSize;
1267                    right -= elemSize;
1268                }
1269            }
1270        }
1271    }
1272    else
1273    {
1274        OSG_WARN << "Error Image::flipHorizontal() did not succeed : cannot flip mipmapped image."<<std::endl;
1275        return;
1276    }
1277       
1278    dirty();
1279}
1280
1281void flipImageVertical(unsigned char* top, unsigned char* bottom, unsigned int rowSize, unsigned int rowStep)
1282{
1283    while(top<bottom)
1284    {
1285        unsigned char* t = top;
1286        unsigned char* b = bottom;
1287        for(unsigned int i=0;i<rowSize;++i, ++t,++b)
1288        {
1289            unsigned char temp=*t;
1290            *t = *b;
1291            *b = temp;
1292        }
1293        top += rowStep;
1294        bottom -= rowStep;
1295    }
1296}
1297
1298
1299void Image::flipVertical()
1300{
1301    if (_data==NULL)
1302    {
1303        OSG_WARN << "Error Image::flipVertical() do not succeed : cannot flip NULL image."<<std::endl;
1304        return;
1305    }
1306
1307    if (!_mipmapData.empty() && _r>1)
1308    {
1309        OSG_WARN << "Error Image::flipVertical() do not succeed : flipping of mipmap 3d textures not yet supported."<<std::endl;
1310        return;
1311    }
1312
1313    unsigned int rowSize = getRowSizeInBytes();
1314    unsigned int rowStep = getRowStepInBytes();
1315
1316    if (_mipmapData.empty())
1317    {
1318        // no mipmaps,
1319        // so we can safely handle 3d textures
1320        for(int r=0;r<_r;++r)
1321        {
1322            if (!dxtc_tool::VerticalFlip(_s,_t,_pixelFormat,data(0,0,r)))
1323            {
1324                // its not a compressed image, so implement flip oursleves.
1325                unsigned char* top = data(0,0,r);
1326                unsigned char* bottom = top + (_t-1)*rowStep;
1327                   
1328                flipImageVertical(top, bottom, rowSize, rowStep);
1329            }
1330        }
1331    }
1332    else if (_r==1)
1333    {
1334        if (!dxtc_tool::VerticalFlip(_s,_t,_pixelFormat,_data))
1335        {
1336            // its not a compressed image, so implement flip oursleves.
1337            unsigned char* top = data(0,0,0);
1338            unsigned char* bottom = top + (_t-1)*rowStep;
1339
1340            flipImageVertical(top, bottom, rowSize, rowStep);
1341        }
1342
1343        int s = _s;
1344        int t = _t;
1345        //int r = _r;
1346
1347        for(unsigned int i=0;i<_mipmapData.size() && _mipmapData[i];++i)
1348        {
1349            s >>= 1;
1350            t >>= 1;
1351            if (s==0) s=1;
1352            if (t==0) t=1;
1353            if (!dxtc_tool::VerticalFlip(s,t,_pixelFormat,_data+_mipmapData[i]))
1354            {
1355                // its not a compressed image, so implement flip oursleves.
1356                unsigned char* top = _data+_mipmapData[i];
1357                unsigned char* bottom = top + (t-1)*rowStep;
1358
1359                flipImageVertical(top, bottom, rowSize, rowStep);
1360            }
1361       }
1362    }   
1363
1364    dirty();
1365}
1366
1367void Image::flipDepth()
1368{
1369    if (_data==NULL)
1370    {
1371        OSG_WARN << "Error Image::flipVertical() do not succeed : cannot flip NULL image."<<std::endl;
1372        return;
1373    }
1374
1375    if (_r==1)
1376    {
1377        return;
1378    }
1379
1380    if (!_mipmapData.empty() && _r>1)
1381    {
1382        OSG_WARN << "Error Image::flipVertical() do not succeed : flipping of mipmap 3d textures not yet supported."<<std::endl;
1383        return;
1384    }
1385
1386    unsigned int sizeOfRow = getRowSizeInBytes();
1387
1388    int r_front = 0;
1389    int r_back = _r-1;
1390    for(; r_front<r_back; ++r_front,--r_back)
1391    {
1392        for(int row=0; row<_t; ++row)
1393        {       
1394            unsigned char* front = data(0, row, r_front);
1395            unsigned char* back = data(0, row, r_back);
1396            for(unsigned int i=0; i<sizeOfRow; ++i, ++front, ++back)
1397            {
1398                std::swap(*front, *back);
1399            }
1400        }
1401    }
1402}
1403
1404
1405void Image::ensureValidSizeForTexturing(GLint maxTextureSize)
1406{
1407    int new_s = computeNearestPowerOfTwo(_s);
1408    int new_t = computeNearestPowerOfTwo(_t);
1409   
1410    if (new_s>maxTextureSize) new_s = maxTextureSize;
1411    if (new_t>maxTextureSize) new_t = maxTextureSize;
1412   
1413    if (new_s!=_s || new_t!=_t)
1414    {
1415        if (!_fileName.empty()) { OSG_NOTICE << "Scaling image '"<<_fileName<<"' from ("<<_s<<","<<_t<<") to ("<<new_s<<","<<new_t<<")"<<std::endl; }
1416        else { OSG_NOTICE << "Scaling image from ("<<_s<<","<<_t<<") to ("<<new_s<<","<<new_t<<")"<<std::endl; }
1417
1418        scaleImage(new_s,new_t,_r);
1419    }
1420}
1421
1422
1423template <typename T>   
1424bool _findLowerAlphaValueInRow(unsigned int num, T* data,T value, unsigned int delta)
1425{
1426    for(unsigned int i=0;i<num;++i)
1427    {
1428        if (*data<value) return true;
1429        data += delta;
1430    }
1431    return false;
1432}
1433
1434template <typename T>   
1435bool _maskedFindLowerAlphaValueInRow(unsigned int num, T* data,T value, T mask, unsigned int delta)
1436{
1437    for(unsigned int i=0;i<num;++i)
1438    {
1439        if ((*data & mask)<value) return true;
1440        data += delta;
1441    }
1442    return false;
1443}
1444
1445bool Image::isImageTranslucent() const
1446{
1447    unsigned int offset = 0;
1448    unsigned int delta = 1;
1449    switch(_pixelFormat)
1450    {
1451        case(GL_ALPHA):
1452            offset = 0;
1453            delta = 1;
1454            break;
1455        case(GL_LUMINANCE_ALPHA):
1456            offset = 1;
1457            delta = 2;
1458            break;
1459        case(GL_RGBA):
1460            offset = 3;
1461            delta = 4;
1462            break;
1463        case(GL_BGRA):
1464            offset = 3;
1465            delta = 4;
1466            break;
1467        case(GL_RGB):
1468            return false;
1469        case(GL_BGR):
1470            return false;
1471        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
1472            return false;
1473        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
1474        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
1475        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
1476            return dxtc_tool::CompressedImageTranslucent(_s, _t, _pixelFormat, _data);
1477        default:
1478            return false;
1479    }
1480
1481    for(int ir=0;ir<r();++ir)
1482    {
1483        for(int it=0;it<t();++it)
1484        {
1485            const unsigned char* d = data(0,it,ir);
1486            switch(_dataType)
1487            {
1488                case(GL_BYTE):
1489                    if (_findLowerAlphaValueInRow(s(), (char*)d +offset, (char)127, delta))
1490                        return true;
1491                    break;
1492                case(GL_UNSIGNED_BYTE):
1493                    if (_findLowerAlphaValueInRow(s(), (unsigned char*)d + offset, (unsigned char)255, delta))
1494                        return true;
1495                    break;
1496                case(GL_SHORT):
1497                    if (_findLowerAlphaValueInRow(s(), (short*)d + offset, (short)32767, delta))
1498                        return true;
1499                    break;
1500                case(GL_UNSIGNED_SHORT):
1501                    if (_findLowerAlphaValueInRow(s(), (unsigned short*)d + offset, (unsigned short)65535, delta))
1502                        return true;
1503                    break;
1504                case(GL_INT):
1505                    if (_findLowerAlphaValueInRow(s(), (int*)d + offset, (int)2147483647, delta))
1506                        return true;
1507                    break;
1508                case(GL_UNSIGNED_INT):
1509                    if (_findLowerAlphaValueInRow(s(), (unsigned int*)d + offset, 4294967295u, delta))
1510                        return true;
1511                    break;
1512                case(GL_FLOAT):
1513                    if (_findLowerAlphaValueInRow(s(), (float*)d + offset, 1.0f, delta))
1514                        return true;
1515                    break;
1516                case(GL_UNSIGNED_SHORT_5_5_5_1):
1517                    if (_maskedFindLowerAlphaValueInRow(s(), (unsigned short*)d,
1518                                                        (unsigned short)0x0001,
1519                                                        (unsigned short)0x0001, 1))
1520                        return true;
1521                    break;
1522                case(GL_UNSIGNED_SHORT_1_5_5_5_REV):
1523                    if (_maskedFindLowerAlphaValueInRow(s(), (unsigned short*)d,
1524                                                        (unsigned short)0x8000,
1525                                                        (unsigned short)0x8000, 1))
1526                        return true;
1527                    break;
1528                case(GL_UNSIGNED_SHORT_4_4_4_4):
1529                    if (_maskedFindLowerAlphaValueInRow(s(), (unsigned short*)d,
1530                                                        (unsigned short)0x000f,
1531                                                        (unsigned short)0x000f, 1))
1532                        return true;
1533                    break;
1534                case(GL_UNSIGNED_SHORT_4_4_4_4_REV):
1535                    if (_maskedFindLowerAlphaValueInRow(s(), (unsigned short*)d,
1536                                                        (unsigned short)0xf000,
1537                                                        (unsigned short)0xf000, 1))
1538                        return true;
1539                    break;
1540                case(GL_UNSIGNED_INT_10_10_10_2):
1541                    if (_maskedFindLowerAlphaValueInRow(s(), (unsigned int*)d,
1542                                                        0x00000003u,
1543                                                        0x00000003u, 1))
1544                        return true;
1545                    break;                   
1546                case(GL_UNSIGNED_INT_2_10_10_10_REV):
1547                    if (_maskedFindLowerAlphaValueInRow(s(), (unsigned int*)d,
1548                                                        0xc0000000u,
1549                                                        0xc0000000u, 1))
1550                        return true;
1551                    break;
1552                case(GL_HALF_FLOAT_NV):
1553                    if (_findLowerAlphaValueInRow(s(), (unsigned short*)d + offset,
1554                                                  (unsigned short)0x3c00, delta))
1555                        return true;
1556                    break;
1557            }
1558        }
1559    }
1560
1561    return false;
1562}
1563
1564///////////////////////////////////////////////////////////////////////////////
1565
1566
1567Geode* osg::createGeodeForImage(osg::Image* image)
1568{
1569    return createGeodeForImage(image,image->s(),image->t());
1570}
1571
1572
1573#include <osg/TextureRectangle> 
1574
1575
1576Geode* osg::createGeodeForImage(osg::Image* image,float s,float t)
1577{
1578    if (image)
1579    {
1580        if (s>0 && t>0)
1581        {
1582
1583            float y = 1.0;
1584            float x = y*(s/t);
1585
1586            float texcoord_y_b = (image->getOrigin() == osg::Image::BOTTOM_LEFT) ? 0.0f : 1.0f;
1587            float texcoord_y_t = (image->getOrigin() == osg::Image::BOTTOM_LEFT) ? 1.0f : 0.0f;
1588
1589            // set up the texture.
1590
1591#if 0
1592            osg::TextureRectangle* texture = new osg::TextureRectangle;
1593            texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
1594            texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
1595            //texture->setResizeNonPowerOfTwoHint(false);
1596            float texcoord_x = image->s();
1597            texcoord_y_b *= image->t();
1598            texcoord_y_t *= image->t();
1599#else
1600            osg::Texture2D* texture = new osg::Texture2D;
1601            texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
1602            texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
1603            texture->setResizeNonPowerOfTwoHint(false);
1604            float texcoord_x = 1.0f;
1605#endif
1606            texture->setImage(image);
1607
1608            // set up the drawstate.
1609            osg::StateSet* dstate = new osg::StateSet;
1610            dstate->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
1611            dstate->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
1612            dstate->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON);
1613
1614            // set up the geoset.                unsigned int rowSize = computeRowWidthInBytes(s,_pixelFormat,_dataType,_packing);
1615
1616            Geometry* geom = new Geometry;
1617            geom->setStateSet(dstate);
1618
1619            Vec3Array* coords = new Vec3Array(4);
1620            (*coords)[0].set(-x,0.0f,y);
1621            (*coords)[1].set(-x,0.0f,-y);
1622            (*coords)[2].set(x,0.0f,-y);
1623            (*coords)[3].set(x,0.0f,y);
1624            geom->setVertexArray(coords);
1625
1626            Vec2Array* tcoords = new Vec2Array(4);
1627            (*tcoords)[0].set(0.0f*texcoord_x,texcoord_y_t);
1628            (*tcoords)[1].set(0.0f*texcoord_x,texcoord_y_b);
1629            (*tcoords)[2].set(1.0f*texcoord_x,texcoord_y_b);
1630            (*tcoords)[3].set(1.0f*texcoord_x,texcoord_y_t);
1631            geom->setTexCoordArray(0,tcoords);
1632
1633            osg::Vec4Array* colours = new osg::Vec4Array(1);
1634            (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
1635            geom->setColorArray(colours);
1636            geom->setColorBinding(Geometry::BIND_OVERALL);
1637
1638            geom->addPrimitiveSet(new DrawArrays(PrimitiveSet::QUADS,0,4));
1639
1640            // set up the geode.
1641            osg::Geode* geode = new osg::Geode;
1642            geode->addDrawable(geom);
1643
1644            return geode;
1645
1646        }
1647        else
1648        {
1649            return NULL;
1650        }
1651    }
1652    else
1653    {
1654        return NULL;
1655    }
1656}
1657
1658template <typename T>   
1659Vec4 _readColor(GLenum pixelFormat, T* data,float scale)
1660{
1661    switch(pixelFormat)
1662    {
1663        case(GL_DEPTH_COMPONENT):   //intentionally fall through and execute the code for GL_LUMINANCE
1664        case(GL_LUMINANCE):         { float l = float(*data++)*scale; return Vec4(l, l, l, 1.0f); }
1665        case(GL_ALPHA):             { float a = float(*data++)*scale; return Vec4(1.0f, 1.0f, 1.0f, a); }
1666        case(GL_LUMINANCE_ALPHA):   { float l = float(*data++)*scale; float a = float(*data++)*scale; return Vec4(l,l,l,a); }
1667        case(GL_RGB):               { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; return Vec4(r,g,b,1.0f); }
1668        case(GL_RGBA):              { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; float a = float(*data++)*scale; return Vec4(r,g,b,a); }
1669        case(GL_BGR):               { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; return Vec4(r,g,b,1.0f); }
1670        case(GL_BGRA):              { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; float a = float(*data++)*scale; return Vec4(r,g,b,a); }
1671    }
1672    return Vec4(1.0f,1.0f,1.0f,1.0f);
1673}
1674
1675Vec4 Image::getColor(unsigned int s,unsigned t,unsigned r) const
1676{
1677    const unsigned char* ptr = data(s,t,r);
1678
1679    switch(_dataType)
1680    {
1681        case(GL_BYTE):              return _readColor(_pixelFormat, (char*)ptr,             1.0f/128.0f);
1682        case(GL_UNSIGNED_BYTE):     return _readColor(_pixelFormat, (unsigned char*)ptr,    1.0f/255.0f);
1683        case(GL_SHORT):             return _readColor(_pixelFormat, (short*)ptr,            1.0f/32768.0f);
1684        case(GL_UNSIGNED_SHORT):    return _readColor(_pixelFormat, (unsigned short*)ptr,   1.0f/65535.0f);
1685        case(GL_INT):               return _readColor(_pixelFormat, (int*)ptr,              1.0f/2147483648.0f);
1686        case(GL_UNSIGNED_INT):      return _readColor(_pixelFormat, (unsigned int*)ptr,     1.0f/4294967295.0f);
1687        case(GL_FLOAT):             return _readColor(_pixelFormat, (float*)ptr,            1.0f);
1688    }
1689    return Vec4(1.0f,1.0f,1.0f,1.0f);
1690}
1691
1692Vec4 Image::getColor(const Vec3& texcoord) const
1693{
1694    int s = int(texcoord.x()*float(_s-1)) % _s;
1695    int t = int(texcoord.y()*float(_t-1)) % _t;
1696    int r = int(texcoord.z()*float(_r-1)) % _r;
1697    //OSG_NOTICE<<"getColor("<<texcoord<<")="<<getColor(s,t,r)<<std::endl;
1698    return getColor(s,t,r);
1699}
Note: See TracBrowser for help on using the browser.