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