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

Revision 12842, 49.0 kB (checked in by robert, 3 years ago)

Added flipDepth() method

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