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

Revision 13041, 54.7 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

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