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 
14 #include <float.h>
15 #include <string.h>
16 
17 #include <osg/Math>
18 #include <osg/ImageUtils>
19 #include <osg/Texture>
20 
21 #include <osg/Notify>
22 #include <osg/io_utils>
23 #include "dxtctool.h"
24 
25 namespace osg
26 {
27 
28 struct FindRangeOperator : public CastAndScaleToFloatOperation
29 {
FindRangeOperatorosg::FindRangeOperator30     FindRangeOperator():
31         _rmin(FLT_MAX),
32         _rmax(-FLT_MAX),
33         _gmin(FLT_MAX),
34         _gmax(-FLT_MAX),
35         _bmin(FLT_MAX),
36         _bmax(-FLT_MAX),
37         _amin(FLT_MAX),
38         _amax(-FLT_MAX) {}
39 
40     float _rmin, _rmax, _gmin, _gmax, _bmin, _bmax, _amin, _amax;
41 
luminanceosg::FindRangeOperator42     inline void luminance(float l) { rgba(l,l,l,l); }
alphaosg::FindRangeOperator43     inline void alpha(float a) { rgba(1.0f,1.0f,1.0f,a); }
luminance_alphaosg::FindRangeOperator44     inline void luminance_alpha(float l,float a) { rgba(l,l,l,a); }
rgbosg::FindRangeOperator45     inline void rgb(float r,float g,float b) { rgba(r,g,b,1.0f);  }
rgbaosg::FindRangeOperator46     inline void rgba(float r,float g,float b,float a)
47     {
48         _rmin = osg::minimum(r,_rmin);
49         _rmax = osg::maximum(r,_rmax);
50         _gmin = osg::minimum(g,_gmin);
51         _gmax = osg::maximum(g,_gmax);
52         _bmin = osg::minimum(b,_bmin);
53         _bmax = osg::maximum(b,_bmax);
54         _amin = osg::minimum(a,_amin);
55         _amax = osg::maximum(a,_amax);
56     }
57 
58 
59 
60 };
61 
62 struct OffsetAndScaleOperator
63 {
OffsetAndScaleOperatorosg::OffsetAndScaleOperator64     OffsetAndScaleOperator(const osg::Vec4& offset, const osg::Vec4& scale):
65         _offset(offset),
66         _scale(scale) {}
67 
68     osg::Vec4 _offset;
69     osg::Vec4 _scale;
70 
luminanceosg::OffsetAndScaleOperator71     inline void luminance(float& l) const { l= _offset.r() + l*_scale.r(); }
alphaosg::OffsetAndScaleOperator72     inline void alpha(float& a) const { a = _offset.a() + a*_scale.a(); }
luminance_alphaosg::OffsetAndScaleOperator73     inline void luminance_alpha(float& l,float& a) const
74     {
75         l= _offset.r() + l*_scale.r();
76         a = _offset.a() + a*_scale.a();
77     }
rgbosg::OffsetAndScaleOperator78     inline void rgb(float& r,float& g,float& b) const
79     {
80         r = _offset.r() + r*_scale.r();
81         g = _offset.g() + g*_scale.g();
82         b = _offset.b() + b*_scale.b();
83     }
rgbaosg::OffsetAndScaleOperator84     inline void rgba(float& r,float& g,float& b,float& a) const
85     {
86         r = _offset.r() + r*_scale.r();
87         g = _offset.g() + g*_scale.g();
88         b = _offset.b() + b*_scale.b();
89         a = _offset.a() + a*_scale.a();
90     }
91 };
92 
computeMinMax(const osg::Image * image,osg::Vec4 & minValue,osg::Vec4 & maxValue)93 bool computeMinMax(const osg::Image* image, osg::Vec4& minValue, osg::Vec4& maxValue)
94 {
95     if (!image) return false;
96 
97     osg::FindRangeOperator rangeOp;
98     readImage(image, rangeOp);
99     minValue.r() = rangeOp._rmin;
100     minValue.g() = rangeOp._gmin;
101     minValue.b() = rangeOp._bmin;
102     minValue.a() = rangeOp._amin;
103 
104     maxValue.r() = rangeOp._rmax;
105     maxValue.g() = rangeOp._gmax;
106     maxValue.b() = rangeOp._bmax;
107     maxValue.a() = rangeOp._amax;
108 
109     return minValue.r()<=maxValue.r() &&
110            minValue.g()<=maxValue.g() &&
111            minValue.b()<=maxValue.b() &&
112            minValue.a()<=maxValue.a();
113 }
114 
offsetAndScaleImage(osg::Image * image,const osg::Vec4 & offset,const osg::Vec4 & scale)115 bool offsetAndScaleImage(osg::Image* image, const osg::Vec4& offset, const osg::Vec4& scale)
116 {
117     if (!image) return false;
118 
119     modifyImage(image,OffsetAndScaleOperator(offset, scale));
120 
121     return true;
122 }
123 
124 template<typename SRC, typename DEST>
_copyRowAndScale(const SRC * src,DEST * dest,int num,float scale)125 void _copyRowAndScale(const SRC* src, DEST* dest, int num, float scale)
126 {
127     if (scale==1.0)
128     {
129         for(int i=0; i<num; ++i)
130         {
131             *dest = DEST(*src);
132             ++dest; ++src;
133         }
134     }
135     else
136     {
137         for(int i=0; i<num; ++i)
138         {
139             *dest = DEST(float(*src)*scale);
140             ++dest; ++src;
141         }
142     }
143 }
144 
145 template<typename DEST>
_copyRowAndScale(const unsigned char * src,GLenum srcDataType,DEST * dest,int num,float scale)146 void _copyRowAndScale(const unsigned char* src, GLenum srcDataType, DEST* dest, int num, float scale)
147 {
148     switch(srcDataType)
149     {
150         case(GL_BYTE):              _copyRowAndScale((char*)src, dest, num, scale); break;
151         case(GL_UNSIGNED_BYTE):     _copyRowAndScale((unsigned char*)src, dest, num, scale); break;
152         case(GL_SHORT):             _copyRowAndScale((short*)src, dest, num, scale); break;
153         case(GL_UNSIGNED_SHORT):    _copyRowAndScale((unsigned short*)src, dest, num, scale); break;
154         case(GL_INT):               _copyRowAndScale((int*)src, dest, num, scale); break;
155         case(GL_UNSIGNED_INT):      _copyRowAndScale((unsigned int*)src, dest, num, scale); break;
156         case(GL_FLOAT):             _copyRowAndScale((float*)src, dest, num, scale); break;
157     }
158 }
159 
_copyRowAndScale(const unsigned char * src,GLenum srcDataType,unsigned char * dest,GLenum dstDataType,int num,float scale)160 void _copyRowAndScale(const unsigned char* src, GLenum srcDataType, unsigned char* dest, GLenum dstDataType, int num, float scale)
161 {
162     switch(dstDataType)
163     {
164         case(GL_BYTE):              _copyRowAndScale(src, srcDataType, (char*)dest, num, scale); break;
165         case(GL_UNSIGNED_BYTE):     _copyRowAndScale(src, srcDataType, (unsigned char*)dest, num, scale); break;
166         case(GL_SHORT):             _copyRowAndScale(src, srcDataType, (short*)dest, num, scale); break;
167         case(GL_UNSIGNED_SHORT):    _copyRowAndScale(src, srcDataType, (unsigned short*)dest, num, scale); break;
168         case(GL_INT):               _copyRowAndScale(src, srcDataType, (int*)dest, num, scale); break;
169         case(GL_UNSIGNED_INT):      _copyRowAndScale(src, srcDataType, (unsigned int*)dest, num, scale); break;
170         case(GL_FLOAT):             _copyRowAndScale(src, srcDataType, (float*)dest, num, scale); break;
171     }
172 }
173 
174 struct RecordRowOperator : public CastAndScaleToFloatOperation
175 {
RecordRowOperatorosg::RecordRowOperator176     RecordRowOperator(unsigned int num):_colours(num),_pos(0) {}
177 
178     mutable std::vector<osg::Vec4>  _colours;
179     mutable unsigned int            _pos;
180 
luminanceosg::RecordRowOperator181     inline void luminance(float l) const { rgba(l,l,l,1.0f); }
alphaosg::RecordRowOperator182     inline void alpha(float a) const { rgba(1.0f,1.0f,1.0f,a); }
luminance_alphaosg::RecordRowOperator183     inline void luminance_alpha(float l,float a) const { rgba(l,l,l,a);  }
rgbosg::RecordRowOperator184     inline void rgb(float r,float g,float b) const { rgba(r,g,b,1.0f); }
rgbaosg::RecordRowOperator185     inline void rgba(float r,float g,float b,float a) const { _colours[_pos++].set(r,g,b,a); }
186 };
187 
188 struct WriteRowOperator
189 {
WriteRowOperatorosg::WriteRowOperator190     WriteRowOperator():_pos(0) {}
WriteRowOperatorosg::WriteRowOperator191     WriteRowOperator(unsigned int num):_colours(num),_pos(0) {}
192 
193     std::vector<osg::Vec4>  _colours;
194     mutable unsigned int    _pos;
195 
luminanceosg::WriteRowOperator196     inline void luminance(float& l) const { l = _colours[_pos++].r(); }
alphaosg::WriteRowOperator197     inline void alpha(float& a) const { a = _colours[_pos++].a(); }
luminance_alphaosg::WriteRowOperator198     inline void luminance_alpha(float& l,float& a) const { l = _colours[_pos].r(); a = _colours[_pos++].a(); }
rgbosg::WriteRowOperator199     inline void rgb(float& r,float& g,float& b) const { r = _colours[_pos].r(); g = _colours[_pos].g(); b = _colours[_pos].b(); }
rgbaosg::WriteRowOperator200     inline void rgba(float& r,float& g,float& b,float& a) const {  r = _colours[_pos].r(); g = _colours[_pos].g(); b = _colours[_pos].b(); a = _colours[_pos++].a(); }
201 };
202 
copyImage(const osg::Image * srcImage,int src_s,int src_t,int src_r,int width,int height,int depth,osg::Image * destImage,int dest_s,int dest_t,int dest_r,bool doRescale)203 bool copyImage(const osg::Image* srcImage, int src_s, int src_t, int src_r, int width, int height, int depth,
204                osg::Image* destImage, int dest_s, int dest_t, int dest_r, bool doRescale)
205 {
206     if ((dest_s+width) > (destImage->s()))
207     {
208         OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl;
209         OSG_NOTICE<<"          "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl;
210         OSG_NOTICE<<"   input width too large."<<std::endl;
211         return false;
212     }
213 
214     if ((dest_t+height) > (destImage->t()))
215     {
216         OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl;
217         OSG_NOTICE<<"          "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl;
218         OSG_NOTICE<<"   input height too large."<<std::endl;
219         return false;
220     }
221 
222     if ((dest_r+depth) > (destImage->r()))
223     {
224         OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl;
225         OSG_NOTICE<<"          "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl;
226         OSG_NOTICE<<"   input depth too large."<<std::endl;
227         return false;
228     }
229 
230     float scale = 1.0f;
231     if (doRescale && srcImage->getDataType() != destImage->getDataType())
232     {
233         switch(srcImage->getDataType())
234         {
235             case(GL_BYTE):              scale = 1.0f/128.0f ; break;
236             case(GL_UNSIGNED_BYTE):     scale = 1.0f/255.0f; break;
237             case(GL_SHORT):             scale = 1.0f/32768.0f; break;
238             case(GL_UNSIGNED_SHORT):    scale = 1.0f/65535.0f; break;
239             case(GL_INT):               scale = 1.0f/2147483648.0f; break;
240             case(GL_UNSIGNED_INT):      scale = 1.0f/4294967295.0f; break;
241             case(GL_FLOAT):             scale = 1.0f; break;
242         }
243         switch(destImage->getDataType())
244         {
245             case(GL_BYTE):              scale *= 128.0f ; break;
246             case(GL_UNSIGNED_BYTE):     scale *= 255.0f; break;
247             case(GL_SHORT):             scale *= 32768.0f; break;
248             case(GL_UNSIGNED_SHORT):    scale *= 65535.0f; break;
249             case(GL_INT):               scale *= 2147483648.0f; break;
250             case(GL_UNSIGNED_INT):      scale *= 4294967295.0f; break;
251             case(GL_FLOAT):             scale *= 1.0f; break;
252         }
253     }
254 
255     if (srcImage->getPixelFormat() == destImage->getPixelFormat())
256     {
257         //OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl;
258         //OSG_NOTICE<<"          "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl;
259 
260         if (srcImage->getDataType() == destImage->getDataType() && !doRescale)
261         {
262             //OSG_NOTICE<<"   Compatible pixelFormat and dataType."<<std::endl;
263             for(int slice = 0; slice<depth; ++slice)
264             {
265                 for(int row = 0; row<height; ++row)
266                 {
267                     const unsigned char* srcData = srcImage->data(src_s, src_t+row, src_r+slice);
268                     unsigned char* destData = destImage->data(dest_s, dest_t+row, dest_r+slice);
269                     memcpy(destData, srcData, (width*destImage->getPixelSizeInBits())/8);
270                 }
271             }
272             return true;
273         }
274         else
275         {
276             //OSG_NOTICE<<"   Compatible pixelFormat and incompatible dataType."<<std::endl;
277             for(int slice = 0; slice<depth; ++slice)
278             {
279                 for(int row = 0; row<height; ++row)
280                 {
281                     const unsigned char* srcData = srcImage->data(src_s, src_t+row, src_r+slice);
282                     unsigned char* destData = destImage->data(dest_s, dest_t+row, dest_r+slice);
283                     unsigned int numComponents = osg::Image::computeNumComponents(destImage->getPixelFormat());
284 
285                     _copyRowAndScale(srcData, srcImage->getDataType(), destData, destImage->getDataType(), (width*numComponents), scale);
286                 }
287             }
288 
289             return true;
290         }
291     }
292     else
293     {
294         //OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl;
295         //OSG_NOTICE<<"          "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl;
296 
297         RecordRowOperator readOp(width);
298         WriteRowOperator writeOp;
299 
300         for(int slice = 0; slice<depth; ++slice)
301         {
302             for(int row = 0; row<height; ++row)
303             {
304 
305                 // reset the indices to beginning
306                 readOp._pos = 0;
307                 writeOp._pos = 0;
308 
309                 // read the pixels into readOp's _colour array
310                 readRow(width, srcImage->getPixelFormat(), srcImage->getDataType(), srcImage->data(src_s,src_t+row,src_r+slice), readOp);
311 
312                 // pass readOp's _colour array contents over to writeOp (note this is just a pointer swap).
313                 writeOp._colours.swap(readOp._colours);
314 
315                 modifyRow(width, destImage->getPixelFormat(), destImage->getDataType(), destImage->data(dest_s, dest_t+row,dest_r+slice), writeOp);
316 
317                 // return readOp's _colour array contents back to its rightful owner.
318                 writeOp._colours.swap(readOp._colours);
319             }
320         }
321 
322         return true;
323     }
324 
325 }
326 
327 
328 struct SetToColourOperator
329 {
SetToColourOperatorosg::SetToColourOperator330     SetToColourOperator(const osg::Vec4& colour):
331         _colour(colour) {}
332 
luminanceosg::SetToColourOperator333     inline void luminance(float& l) const { l = (_colour.r()+_colour.g()+_colour.b())*0.333333; }
alphaosg::SetToColourOperator334     inline void alpha(float& a) const { a = _colour.a(); }
luminance_alphaosg::SetToColourOperator335     inline void luminance_alpha(float& l,float& a) const { l = (_colour.r()+_colour.g()+_colour.b())*0.333333; a = _colour.a(); }
rgbosg::SetToColourOperator336     inline void rgb(float& r,float& g,float& b) const { r = _colour.r(); g = _colour.g(); b = _colour.b(); }
rgbaosg::SetToColourOperator337     inline void rgba(float& r,float& g,float& b,float& a) const { r = _colour.r(); g = _colour.g(); b = _colour.b(); a = _colour.a(); }
338 
339     osg::Vec4 _colour;
340 };
341 
clearImageToColor(osg::Image * image,const osg::Vec4 & colour)342 bool clearImageToColor(osg::Image* image, const osg::Vec4& colour)
343 {
344     if (!image) return false;
345 
346     modifyImage(image, SetToColourOperator(colour));
347 
348     return true;
349 }
350 
351 /** Search through the list of Images and find the maximum number of components used among the images.*/
maximimNumOfComponents(const ImageList & imageList)352 unsigned int maximimNumOfComponents(const ImageList& imageList)
353 {
354     unsigned int max_components = 0;
355     for(osg::ImageList::const_iterator itr=imageList.begin();
356         itr!=imageList.end();
357         ++itr)
358     {
359         osg::Image* image = itr->get();
360         GLenum pixelFormat = image->getPixelFormat();
361         if (pixelFormat==GL_ALPHA ||
362             pixelFormat==GL_INTENSITY ||
363             pixelFormat==GL_LUMINANCE ||
364             pixelFormat==GL_LUMINANCE_ALPHA ||
365             pixelFormat==GL_RGB ||
366             pixelFormat==GL_RGBA ||
367             pixelFormat==GL_BGR ||
368             pixelFormat==GL_BGRA)
369         {
370             max_components = maximum(Image::computeNumComponents(pixelFormat), max_components);
371         }
372     }
373     return max_components;
374 }
375 
createImage3D(const ImageList & imageList,GLenum desiredPixelFormat,int s_maximumImageSize,int t_maximumImageSize,int r_maximumImageSize,bool resizeToPowerOfTwo)376 osg::Image* createImage3D(const ImageList& imageList,
377                           GLenum desiredPixelFormat,
378                           int s_maximumImageSize,
379                           int t_maximumImageSize,
380                           int r_maximumImageSize,
381                           bool resizeToPowerOfTwo)
382 {
383     OSG_INFO<<"createImage3D(..)"<<std::endl;
384     int max_s = 0;
385     int max_t = 0;
386     int total_r = 0;
387     for(osg::ImageList::const_iterator itr=imageList.begin();
388         itr!=imageList.end();
389         ++itr)
390     {
391         osg::Image* image = itr->get();
392         GLenum pixelFormat = image->getPixelFormat();
393         if (pixelFormat==GL_ALPHA ||
394             pixelFormat==GL_INTENSITY ||
395             pixelFormat==GL_LUMINANCE ||
396             pixelFormat==GL_LUMINANCE_ALPHA ||
397             pixelFormat==GL_RGB ||
398             pixelFormat==GL_RGBA ||
399             pixelFormat==GL_BGR ||
400             pixelFormat==GL_BGRA)
401         {
402             max_s = maximum(image->s(), max_s);
403             max_t = maximum(image->t(), max_t);
404             total_r += image->r();
405         }
406         else
407         {
408             OSG_INFO<<"Image "<<image->getFileName()<<" has unsuitable pixel format 0x"<< std::hex<< pixelFormat << std::dec << std::endl;
409         }
410     }
411 
412     //bool remapRGBtoLuminance;
413     //bool remapRGBtoRGBA;
414 
415     if (desiredPixelFormat==0)
416     {
417         unsigned int max_components = maximimNumOfComponents(imageList);
418         switch(max_components)
419         {
420         case(1):
421             OSG_INFO<<"desiredPixelFormat = GL_LUMINANCE" << std::endl;
422             desiredPixelFormat = GL_LUMINANCE;
423             break;
424         case(2):
425             OSG_INFO<<"desiredPixelFormat = GL_LUMINANCE_ALPHA" << std::endl;
426             desiredPixelFormat = GL_LUMINANCE_ALPHA;
427             break;
428         case(3):
429             OSG_INFO<<"desiredPixelFormat = GL_RGB" << std::endl;
430             desiredPixelFormat = GL_RGB;
431             break;
432         case(4):
433             OSG_INFO<<"desiredPixelFormat = GL_RGBA" << std::endl;
434             desiredPixelFormat = GL_RGBA;
435             break;
436         }
437     }
438     if (desiredPixelFormat==0) return 0;
439 
440     // compute nearest powers of two for each axis.
441 
442     int size_s = 1;
443     int size_t = 1;
444     int size_r = 1;
445 
446     if (resizeToPowerOfTwo)
447     {
448         while(size_s<max_s && size_s<s_maximumImageSize) size_s*=2;
449         while(size_t<max_t && size_t<t_maximumImageSize) size_t*=2;
450         while(size_r<total_r && size_r<r_maximumImageSize) size_r*=2;
451     }
452     else
453     {
454         size_s = max_s;
455         size_t = max_t;
456         size_r = total_r;
457     }
458 
459     // now allocate the 3d texture;
460     osg::ref_ptr<osg::Image> image_3d = new osg::Image;
461     image_3d->allocateImage(size_s,size_t,size_r,
462                             desiredPixelFormat,GL_UNSIGNED_BYTE);
463 
464     unsigned int r_offset = (total_r<size_r) ? (size_r-total_r)/2 : 0;
465 
466     int curr_dest_r = r_offset;
467 
468     // copy across the values from the source images into the image_3d.
469     for(osg::ImageList::const_iterator itr=imageList.begin();
470         itr!=imageList.end();
471         ++itr)
472     {
473         osg::Image* image = itr->get();
474         GLenum pixelFormat = image->getPixelFormat();
475         if (pixelFormat==GL_ALPHA ||
476             pixelFormat==GL_LUMINANCE ||
477             pixelFormat==GL_INTENSITY ||
478             pixelFormat==GL_LUMINANCE_ALPHA ||
479             pixelFormat==GL_RGB ||
480             pixelFormat==GL_RGBA ||
481             pixelFormat==GL_BGR ||
482             pixelFormat==GL_BGRA)
483         {
484 
485             int num_s = minimum(image->s(), image_3d->s());
486             int num_t = minimum(image->t(), image_3d->t());
487             int num_r = minimum(image->r(), (image_3d->r() - curr_dest_r));
488 
489             unsigned int s_offset_dest = (image->s()<size_s) ? (size_s - image->s())/2 : 0;
490             unsigned int t_offset_dest = (image->t()<size_t) ? (size_t - image->t())/2 : 0;
491 
492             copyImage(image, 0, 0, 0, num_s, num_t, num_r,
493                       image_3d.get(), s_offset_dest, t_offset_dest, curr_dest_r, false);
494 
495             curr_dest_r += num_r;
496         }
497     }
498 
499     return image_3d.release();
500 }
501 
502 struct ModulateAlphaByLuminanceOperator
503 {
ModulateAlphaByLuminanceOperatorosg::ModulateAlphaByLuminanceOperator504     ModulateAlphaByLuminanceOperator() {}
505 
luminanceosg::ModulateAlphaByLuminanceOperator506     inline void luminance(float&) const {}
alphaosg::ModulateAlphaByLuminanceOperator507     inline void alpha(float&) const {}
luminance_alphaosg::ModulateAlphaByLuminanceOperator508     inline void luminance_alpha(float& l,float& a) const { a*= l; }
rgbosg::ModulateAlphaByLuminanceOperator509     inline void rgb(float&,float&,float&) const {}
rgbaosg::ModulateAlphaByLuminanceOperator510     inline void rgba(float& r,float& g,float& b,float& a) const { float l = (r+g+b)*0.3333333; a *= l;}
511 };
512 
createImage3DWithAlpha(const ImageList & imageList,int s_maximumImageSize,int t_maximumImageSize,int r_maximumImageSize,bool resizeToPowerOfTwo)513 osg::Image* createImage3DWithAlpha(const ImageList& imageList,
514             int s_maximumImageSize,
515             int t_maximumImageSize,
516             int r_maximumImageSize,
517             bool resizeToPowerOfTwo)
518 {
519     GLenum desiredPixelFormat = 0;
520     bool modulateAlphaByLuminance = false;
521 
522     unsigned int maxNumComponents = maximimNumOfComponents(imageList);
523     if (maxNumComponents==3)
524     {
525         desiredPixelFormat = GL_RGBA;
526         modulateAlphaByLuminance = true;
527     }
528 
529     osg::ref_ptr<osg::Image> image = createImage3D(imageList,
530                                         desiredPixelFormat,
531                                         s_maximumImageSize,
532                                         t_maximumImageSize,
533                                         r_maximumImageSize,
534                                         resizeToPowerOfTwo);
535     if (image.valid())
536     {
537         if (modulateAlphaByLuminance)
538         {
539             modifyImage(image.get(), ModulateAlphaByLuminanceOperator());
540         }
541         return image.release();
542     }
543     else
544     {
545         return 0;
546     }
547 }
548 
549 
fillSpotLightImage(unsigned char * ptr,const osg::Vec4 & centerColour,const osg::Vec4 & backgroudColour,unsigned int size,float power)550 static void fillSpotLightImage(unsigned char* ptr, const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
551 {
552     if (size==1)
553     {
554         float r = 0.5f;
555         osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-r);
556         *ptr++ = (unsigned char)((color[0])*255.0f);
557         *ptr++ = (unsigned char)((color[1])*255.0f);
558         *ptr++ = (unsigned char)((color[2])*255.0f);
559         *ptr++ = (unsigned char)((color[3])*255.0f);
560         return;
561     }
562 
563     float mid = (float(size)-1.0f)*0.5f;
564     float div = 2.0f/float(size);
565     for(unsigned int row=0;row<size;++row)
566     {
567         //unsigned char* ptr = image->data(0,r,0);
568         for(unsigned int col=0;col<size;++col)
569         {
570             float dx = (float(col) - mid)*div;
571             float dy = (float(row) - mid)*div;
572             float r = powf(1.0f-sqrtf(dx*dx+dy*dy),power);
573             if (r<0.0f) r=0.0f;
574             osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-r);
575             *ptr++ = (unsigned char)((color[0])*255.0f);
576             *ptr++ = (unsigned char)((color[1])*255.0f);
577             *ptr++ = (unsigned char)((color[2])*255.0f);
578             *ptr++ = (unsigned char)((color[3])*255.0f);
579         }
580     }
581 }
582 
createSpotLightImage(const osg::Vec4 & centerColour,const osg::Vec4 & backgroudColour,unsigned int size,float power)583 osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
584 {
585 
586 #if 0
587     osg::Image* image = new osg::Image;
588     unsigned char* ptr = image->data(0,0,0);
589     fillSpotLightImage(ptr, centerColour, backgroudColour, size, power);
590 
591     return image;
592 #else
593     osg::Image* image = new osg::Image;
594     osg::Image::MipmapDataType mipmapData;
595     unsigned int s = size;
596     unsigned int totalSize = 0;
597     unsigned i;
598     for(i=0; s>0; s>>=1, ++i)
599     {
600         if (i>0) mipmapData.push_back(totalSize);
601         totalSize += s*s*4;
602     }
603 
604     unsigned char* ptr = new unsigned char[totalSize];
605     image->setImage(size, size, size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE,1);
606 
607     image->setMipmapLevels(mipmapData);
608 
609     s = size;
610     for(i=0; s>0; s>>=1, ++i)
611     {
612         fillSpotLightImage(ptr, centerColour, backgroudColour, s, power);
613         ptr += s*s*4;
614     }
615 
616     return image;
617 #endif
618 }
619 
620 
621 
622 struct ModulateAlphaByColorOperator
623 {
ModulateAlphaByColorOperatorosg::ModulateAlphaByColorOperator624     ModulateAlphaByColorOperator(const osg::Vec4& colour):_colour(colour) { _lum = _colour.length(); }
625 
626     osg::Vec4 _colour;
627     float _lum;
628 
luminanceosg::ModulateAlphaByColorOperator629     inline void luminance(float&) const {}
alphaosg::ModulateAlphaByColorOperator630     inline void alpha(float&) const {}
luminance_alphaosg::ModulateAlphaByColorOperator631     inline void luminance_alpha(float& l,float& a) const { a*= l*_lum; }
rgbosg::ModulateAlphaByColorOperator632     inline void rgb(float&,float&,float&) const {}
rgbaosg::ModulateAlphaByColorOperator633     inline void rgba(float& r,float& g,float& b,float& a) const { a = (r*_colour.r()+g*_colour.g()+b*_colour.b()+a*_colour.a()); }
634 };
635 
636 struct ReplaceAlphaWithLuminanceOperator
637 {
ReplaceAlphaWithLuminanceOperatorosg::ReplaceAlphaWithLuminanceOperator638     ReplaceAlphaWithLuminanceOperator() {}
639 
luminanceosg::ReplaceAlphaWithLuminanceOperator640     inline void luminance(float&) const {}
alphaosg::ReplaceAlphaWithLuminanceOperator641     inline void alpha(float&) const {}
luminance_alphaosg::ReplaceAlphaWithLuminanceOperator642     inline void luminance_alpha(float& l,float& a) const { a = l; }
rgbosg::ReplaceAlphaWithLuminanceOperator643     inline void rgb(float&,float&,float&) const { }
rgbaosg::ReplaceAlphaWithLuminanceOperator644     inline void rgba(float& r,float& g,float& b,float& a) const { float l = (r+g+b)*0.3333333; a = l; }
645 };
646 
colorSpaceConversion(ColorSpaceOperation op,osg::Image * image,const osg::Vec4 & colour)647 osg::Image* colorSpaceConversion(ColorSpaceOperation op, osg::Image* image, const osg::Vec4& colour)
648 {
649     GLenum requiredPixelFormat = image->getPixelFormat();
650     switch(op)
651     {
652         case (MODULATE_ALPHA_BY_LUMINANCE):
653         case (MODULATE_ALPHA_BY_COLOR):
654         case (REPLACE_ALPHA_WITH_LUMINANCE):
655             if (image->getPixelFormat()==GL_RGB || image->getPixelFormat()==GL_BGR) requiredPixelFormat = GL_RGBA;
656             break;
657         case (REPLACE_RGB_WITH_LUMINANCE):
658             if (image->getPixelFormat()==GL_RGB || image->getPixelFormat()==GL_BGR) requiredPixelFormat = GL_LUMINANCE;
659             break;
660         default:
661             break;
662     }
663 
664     if (requiredPixelFormat!=image->getPixelFormat())
665     {
666         osg::Image* newImage = new osg::Image;
667         newImage->allocateImage(image->s(), image->t(), image->r(), requiredPixelFormat, image->getDataType());
668         osg::copyImage(image, 0, 0, 0, image->s(), image->t(), image->r(),
669                     newImage, 0, 0, 0, false);
670 
671         image = newImage;
672     }
673 
674     switch(op)
675     {
676         case (MODULATE_ALPHA_BY_LUMINANCE):
677         {
678             OSG_NOTICE<<"doing conversion MODULATE_ALPHA_BY_LUMINANCE"<<std::endl;
679             osg::modifyImage(image, ModulateAlphaByLuminanceOperator());
680             return image;
681         }
682         case (MODULATE_ALPHA_BY_COLOR):
683         {
684             OSG_NOTICE<<"doing conversion MODULATE_ALPHA_BY_COLOUR"<<std::endl;
685             osg::modifyImage(image, ModulateAlphaByColorOperator(colour));
686             return image;
687         }
688         case (REPLACE_ALPHA_WITH_LUMINANCE):
689         {
690             OSG_NOTICE<<"doing conversion REPLACE_ALPHA_WITH_LUMINANCE"<<std::endl;
691             osg::modifyImage(image, ReplaceAlphaWithLuminanceOperator());
692             return image;
693         }
694         case (REPLACE_RGB_WITH_LUMINANCE):
695         {
696             OSG_NOTICE<<"doing conversion REPLACE_RGB_WITH_LUMINANCE"<<std::endl;
697             // no work here required to be done as it'll already be done by copyImage above.
698             return image;
699         }
700         default:
701             return image;
702     }
703 }
704 
705 
createImageWithOrientationConversion(const osg::Image * srcImage,const osg::Vec3i & srcOrigin,const osg::Vec3i & srcRow,const osg::Vec3i & srcColumn,const osg::Vec3i & srcLayer)706 OSG_EXPORT osg::Image* createImageWithOrientationConversion(const osg::Image* srcImage, const osg::Vec3i& srcOrigin, const osg::Vec3i& srcRow, const osg::Vec3i& srcColumn, const osg::Vec3i& srcLayer)
707 {
708     osg::ref_ptr<osg::Image> dstImage = new osg::Image;
709     int width  = osg::maximum(osg::maximum(osg::absolute(srcRow.x()), osg::absolute(srcRow.y())), osg::absolute(srcRow.z()));
710     int height = osg::maximum(osg::maximum(osg::absolute(srcColumn.x()), osg::absolute(srcColumn.y())), osg::absolute(srcColumn.z()));
711     int depth  = osg::maximum(osg::maximum(osg::absolute(srcLayer.x()), osg::absolute(srcLayer.y())), osg::absolute(srcLayer.z()));
712 
713     osg::Vec3i rowDelta(osg::signOrZero(srcRow.x()), osg::signOrZero(srcRow.y()), osg::signOrZero(srcRow.z()));
714     osg::Vec3i columnDelta(osg::signOrZero(srcColumn.x()), osg::signOrZero(srcColumn.y()), osg::signOrZero(srcColumn.z()));
715     osg::Vec3i layerDelta(osg::signOrZero(srcLayer.x()), osg::signOrZero(srcLayer.y()), osg::signOrZero(srcLayer.z()));
716 
717     unsigned int pixelSizeInBits =  srcImage->getPixelSizeInBits();
718     unsigned int pixelSizeInBytes = pixelSizeInBits/8;
719     unsigned int pixelSizeRemainder = pixelSizeInBits%8;
720     if (dxtc_tool::isDXTC(srcImage->getPixelFormat()))
721     {
722         unsigned int DXTblockSize = 8;
723         if ((srcImage->getPixelFormat() == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) || (srcImage->getPixelFormat() == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)) DXTblockSize = 16;
724         unsigned int DXTblocksWidht = (srcImage->s() + 3) / 4;//width in 4x4 blocks
725         unsigned int DXTblocksHeight = (srcImage->t() + 3) / 4;//height in 4x4 blocks
726         unsigned int dst_DXTblocksWidht = (width + 3) / 4;//width in 4x4 blocks
727         unsigned int dst_DXTblocksHeight = (height + 3) / 4;//height in 4x4 blocks
728 
729         dstImage->allocateImage(width, height, depth, srcImage->getPixelFormat(), srcImage->getDataType());
730         // copy across the pixels from the source image to the destination image.
731         if (depth != 1)
732         {
733             OSG_NOTICE << "Warning: createImageWithOrientationConversion(..) cannot handle dxt-compressed images with depth." << std::endl;
734             return const_cast<osg::Image*>(srcImage);
735         }
736         for (int l = 0; l<depth; l+=4)
737         {
738             for (int r = 0; r<height; r+=4)
739             {
740                 osg::Vec3i cp(srcOrigin.x() + columnDelta.x()*r + layerDelta.x()*l,
741                     srcOrigin.y() + columnDelta.y()*r + layerDelta.y()*l,
742                     srcOrigin.z() + columnDelta.z()*r + layerDelta.z()*l);
743                 for (int c = 0; c<width; c+=4)
744                 {
745                     unsigned int src_blockIndex = (cp.x() >> 2) + DXTblocksWidht * ((cp.y() >> 2) + (cp.z() >> 2) * DXTblocksHeight);
746                     const unsigned char *src_block = srcImage->data() + src_blockIndex * DXTblockSize;
747 
748                     unsigned int dst_blockIndex = (c >> 2) + dst_DXTblocksWidht * ((r >> 2) + (l >> 2) * dst_DXTblocksHeight);
749                     unsigned char *dst_block = dstImage->data() + dst_blockIndex * DXTblockSize;
750 
751                     memcpy((void *)dst_block, (void *)src_block, DXTblockSize);
752                     osg::Vec3i srcSubOrigin(cp.x() & 0x7, cp.y() & 0x7, cp.z() & 0x7);
753                     dxtc_tool::compressedBlockOrientationConversion(srcImage->getPixelFormat(),src_block, dst_block, srcSubOrigin, rowDelta, columnDelta);
754 
755                     cp.x() += 4 * rowDelta.x();
756                     cp.y() += 4 * rowDelta.y();
757                     cp.z() += 4 * rowDelta.z();
758                 }
759             }
760         }
761         return dstImage.release();
762     }
763     if (pixelSizeRemainder!=0)
764     {
765         OSG_NOTICE<<"Warning: createImageWithOrientationConversion(..) cannot handle non byte aligned pixel formats."<<std::endl;
766         return const_cast<osg::Image*>(srcImage);
767     }
768 
769     dstImage->allocateImage(width, height, depth, srcImage->getPixelFormat(), srcImage->getDataType());
770 
771     // copy across the pixels from the source image to the destination image.
772     for(int l=0; l<depth; l++)
773     {
774         for(int r=0; r<height; r++)
775         {
776             osg::Vec3i cp( srcOrigin.x() + columnDelta.x()*r + layerDelta.x()*l,
777                            srcOrigin.y() + columnDelta.y()*r + layerDelta.y()*l,
778                            srcOrigin.z() + columnDelta.z()*r + layerDelta.z()*l);
779 
780 
781             for(int c=0; c<width; c++)
782             {
783                 // OSG_NOTICE<<"source cp = ("<<cp<<")  destination ("<<c<<","<<r<<","<<l<<")"<<std::endl;
784                 const unsigned char* src_pixel = srcImage->data(cp.x(), cp.y(), cp.z());
785                 unsigned char* dst_pixel = dstImage->data(c, r, l);
786                 for(unsigned int i=0; i<pixelSizeInBytes; ++i)
787                 {
788                     *(dst_pixel++) = *(src_pixel++);
789                 }
790                 cp.x() += rowDelta.x();
791                 cp.y() += rowDelta.y();
792                 cp.z() += rowDelta.z();
793             }
794         }
795     }
796 
797     return dstImage.release();
798 }
799 
800 }
801 
802