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

Revision 10600, 44.8 kB (checked in by robert, 5 years ago)

Introduced new BufferObject? design + implementation in preperation of implementing a pool system for buffer objects

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