root/OpenSceneGraph/trunk/examples/osgvolume/osgvolume.cpp @ 5763

Revision 5763, 64.9 kB (checked in by robert, 8 years ago)

Added support for float or double osg::Plane, and the default osg::Plane to double.
Performance tests on big models did not indicate any performance penalty in using doubles over floats,
so the move to doubles should mainly impact precision improvements for whole earth databases.

Also made improvements to osgUtil::PlaneIntersector? and osgSim::ElevationSlice? classes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/Node>
2#include <osg/Geometry>
3#include <osg/Notify>
4#include <osg/Texture3D>
5#include <osg/TexGen>
6#include <osg/Geode>
7#include <osg/Billboard>
8#include <osg/PositionAttitudeTransform>
9#include <osg/ClipNode>
10#include <osg/AlphaFunc>
11#include <osg/TexGenNode>
12#include <osg/TexEnv>
13#include <osg/TexEnvCombine>
14#include <osg/Material>
15#include <osg/PrimitiveSet>
16#include <osg/Endian>
17
18#include <osgDB/Registry>
19#include <osgDB/ReadFile>
20#include <osgDB/WriteFile>
21#include <osgDB/FileUtils>
22#include <osgDB/FileNameUtils>
23
24#include <osgGA/EventVisitor>
25
26#include <osgUtil/CullVisitor>
27
28#include <osgProducer/Viewer>
29
30
31typedef std::vector< osg::ref_ptr<osg::Image> > ImageList;
32
33//  example ReadOperator
34// struct ReadOperator
35// {
36//     inline void luminance(float l) const { rgba(l,l,l,1.0f); }
37//     inline void alpha(float a) const { rgba(1.0f,1.0f,1.0f,a); }
38//     inline void luminance_alpha(float l,float a) const { rgba(l,l,l,a); }
39//     inline void rgb(float r,float g,float b) const { rgba(r,g,b,1.0f); }
40//     inline void rgba(float r,float g,float b,float a) const { std::cout<<"pixel("<<r<<", "<<g<<", "<<b<<", "<<a<<")"<<std::endl; }
41// };
42
43
44template <typename T, class O>   
45void _readRow(unsigned int num, GLenum pixelFormat, T* data,float scale, const O& operation)
46{
47    switch(pixelFormat)
48    {
49        case(GL_LUMINANCE):         { for(unsigned int i=0;i<num;++i) { float l = float(*data++)*scale; operation.luminance(l); } }  break;
50        case(GL_ALPHA):             { for(unsigned int i=0;i<num;++i) { float a = float(*data++)*scale; operation.alpha(a); } }  break;
51        case(GL_LUMINANCE_ALPHA):   { for(unsigned int i=0;i<num;++i) { float l = float(*data++)*scale; float a = float(*data++)*scale; operation.luminance_alpha(l,a); } }  break;
52        case(GL_RGB):               { for(unsigned int i=0;i<num;++i) { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; operation.rgb(r,g,b); } }  break;
53        case(GL_RGBA):              { for(unsigned int i=0;i<num;++i) { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; float a = float(*data++)*scale; operation.rgba(r,g,b,a); } }  break;
54        case(GL_BGR):               { for(unsigned int i=0;i<num;++i) { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; operation.rgb(r,g,b); } }  break;
55        case(GL_BGRA):              { for(unsigned int i=0;i<num;++i) { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; float a = float(*data++)*scale; operation.rgba(r,g,b,a); } }  break;
56    }
57}
58
59template <class O>   
60void readRow(unsigned int num, GLenum pixelFormat, GLenum dataType, unsigned char* data, const O& operation)
61{
62    switch(dataType)
63    {
64        case(GL_BYTE):              _readRow(num,pixelFormat, (char*)data,            1.0f/128.0f,        operation); break;
65        case(GL_UNSIGNED_BYTE):     _readRow(num,pixelFormat, (unsigned char*)data,   1.0f/255.0f,        operation); break;
66        case(GL_SHORT):             _readRow(num,pixelFormat, (short*) data,          1.0f/32768.0f,      operation); break;
67        case(GL_UNSIGNED_SHORT):    _readRow(num,pixelFormat, (unsigned short*)data,  1.0f/65535.0f,      operation); break;
68        case(GL_INT):               _readRow(num,pixelFormat, (int*) data,            1.0f/2147483648.0f, operation); break;
69        case(GL_UNSIGNED_INT):      _readRow(num,pixelFormat, (unsigned int*) data,   1.0f/4294967295.0f, operation); break;
70        case(GL_FLOAT):             _readRow(num,pixelFormat, (float*) data,          1.0f,               operation); break;
71    }
72}
73
74template <class O>   
75void readImage(osg::Image* image, const O& operation)
76{
77    if (!image) return;
78   
79    for(int r=0;r<image->r();++r)
80    {
81        for(int t=0;t<image->t();++t)
82        {
83            readRow(image->s(), image->getPixelFormat(), image->getDataType(), image->data(0,t,r), operation);
84        }
85    }
86}
87
88//  example ModifyOperator
89// struct ModifyOperator
90// {
91//     inline void luminance(float& l) const {}
92//     inline void alpha(float& a) const {}
93//     inline void luminance_alpha(float& l,float& a) const {}
94//     inline void rgb(float& r,float& g,float& b) const {}
95//     inline void rgba(float& r,float& g,float& b,float& a) const {}
96// };
97
98
99template <typename T, class M>   
100void _modifyRow(unsigned int num, GLenum pixelFormat, T* data,float scale, const M& operation)
101{
102    float inv_scale = 1.0f/scale;
103    switch(pixelFormat)
104    {
105        case(GL_LUMINANCE):         { for(unsigned int i=0;i<num;++i) { float l = float(*data)*scale; operation.luminance(l); *data++ = T(l*inv_scale); } }  break;
106        case(GL_ALPHA):             { for(unsigned int i=0;i<num;++i) { float a = float(*data)*scale; operation.alpha(a); *data++ = T(a*inv_scale); } }  break;
107        case(GL_LUMINANCE_ALPHA):   { for(unsigned int i=0;i<num;++i) { float l = float(*data)*scale; float a = float(*(data+1))*scale; operation.luminance_alpha(l,a); *data++ = T(l*inv_scale); *data++ = T(a*inv_scale); } }  break;
108        case(GL_RGB):               { for(unsigned int i=0;i<num;++i) { float r = float(*data)*scale; float g = float(*(data+1))*scale; float b = float(*(data+2))*scale; operation.rgb(r,g,b); *data++ = T(r*inv_scale); *data++ = T(g*inv_scale); *data++ = T(b*inv_scale); } }  break;
109        case(GL_RGBA):              { for(unsigned int i=0;i<num;++i) { float r = float(*data)*scale; float g = float(*(data+1))*scale; float b = float(*(data+2))*scale; float a = float(*(data+3))*scale; operation.rgba(r,g,b,a); *data++ = T(r*inv_scale); *data++ = T(g*inv_scale); *data++ = T(g*inv_scale); *data++ = T(a*inv_scale); } }  break;
110        case(GL_BGR):               { for(unsigned int i=0;i<num;++i) { float b = float(*data)*scale; float g = float(*(data+1))*scale; float r = float(*(data+2))*scale; operation.rgb(r,g,b); *data++ = T(b*inv_scale); *data++ = T(g*inv_scale); *data++ = T(r*inv_scale); } }  break;
111        case(GL_BGRA):              { for(unsigned int i=0;i<num;++i) { float b = float(*data)*scale; float g = float(*(data+1))*scale; float r = float(*(data+2))*scale; float a = float(*(data+3))*scale; operation.rgba(r,g,b,a); *data++ = T(g*inv_scale); *data++ = T(b*inv_scale); *data++ = T(r*inv_scale); *data++ = T(a*inv_scale); } }  break;
112    }
113}
114
115template <class M>   
116void modifyRow(unsigned int num, GLenum pixelFormat, GLenum dataType, unsigned char* data, const M& operation)
117{
118    switch(dataType)
119    {
120        case(GL_BYTE):              _modifyRow(num,pixelFormat, (char*)data,            1.0f/128.0f,        operation); break;
121        case(GL_UNSIGNED_BYTE):     _modifyRow(num,pixelFormat, (unsigned char*)data,   1.0f/255.0f,        operation); break;
122        case(GL_SHORT):             _modifyRow(num,pixelFormat, (short*) data,          1.0f/32768.0f,      operation); break;
123        case(GL_UNSIGNED_SHORT):    _modifyRow(num,pixelFormat, (unsigned short*)data,  1.0f/65535.0f,      operation); break;
124        case(GL_INT):               _modifyRow(num,pixelFormat, (int*) data,            1.0f/2147483648.0f, operation); break;
125        case(GL_UNSIGNED_INT):      _modifyRow(num,pixelFormat, (unsigned int*) data,   1.0f/4294967295.0f, operation); break;
126        case(GL_FLOAT):             _modifyRow(num,pixelFormat, (float*) data,          1.0f,               operation); break;
127    }
128}
129
130template <class M>   
131void modifyImage(osg::Image* image, const M& operation)
132{
133    if (!image) return;
134   
135    for(int r=0;r<image->r();++r)
136    {
137        for(int t=0;t<image->t();++t)
138        {
139            modifyRow(image->s(), image->getPixelFormat(), image->getDataType(), image->data(0,t,r), operation);
140        }
141    }
142}
143
144struct PassThroughTransformFunction
145{
146    unsigned char operator() (unsigned char c) const { return c; }
147};
148
149
150struct ProcessRow
151{
152    virtual ~ProcessRow() {}
153
154    virtual void operator() (unsigned int num,
155                    GLenum source_pixelFormat, unsigned char* source,
156                    GLenum dest_pixelFormat, unsigned char* dest) const 
157    {
158        switch(source_pixelFormat)
159        {
160        case(GL_LUMINANCE):
161        case(GL_ALPHA):
162            switch(dest_pixelFormat)
163            {
164            case(GL_LUMINANCE):
165            case(GL_ALPHA): A_to_A(num, source, dest); break;
166            case(GL_LUMINANCE_ALPHA): A_to_LA(num, source, dest); break;
167            case(GL_RGB): A_to_RGB(num, source, dest); break;
168            case(GL_RGBA): A_to_RGBA(num, source, dest); break;
169            }
170            break;
171        case(GL_LUMINANCE_ALPHA):
172            switch(dest_pixelFormat)
173            {
174            case(GL_LUMINANCE):
175            case(GL_ALPHA): LA_to_A(num, source, dest); break;
176            case(GL_LUMINANCE_ALPHA): LA_to_LA(num, source, dest); break;
177            case(GL_RGB): LA_to_RGB(num, source, dest); break;
178            case(GL_RGBA): LA_to_RGBA(num, source, dest); break;
179            }
180            break;
181        case(GL_RGB):
182            switch(dest_pixelFormat)
183            {
184            case(GL_LUMINANCE):
185            case(GL_ALPHA): RGB_to_A(num, source, dest); break;
186            case(GL_LUMINANCE_ALPHA): RGB_to_LA(num, source, dest); break;
187            case(GL_RGB): RGB_to_RGB(num, source, dest); break;
188            case(GL_RGBA): RGB_to_RGBA(num, source, dest); break;
189            }
190            break;
191        case(GL_RGBA):
192            switch(dest_pixelFormat)
193            {
194            case(GL_LUMINANCE):
195            case(GL_ALPHA): RGBA_to_A(num, source, dest); break;
196            case(GL_LUMINANCE_ALPHA): RGBA_to_LA(num, source, dest); break;
197            case(GL_RGB): RGBA_to_RGB(num, source, dest); break;
198            case(GL_RGBA): RGBA_to_RGBA(num, source, dest); break;
199            }
200            break;
201        }
202    }
203
204    ///////////////////////////////////////////////////////////////////////////////
205    // alpha sources..   
206    virtual void A_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
207    {
208        for(unsigned int i=0;i<num;++i)
209        {
210            *dest++ = *source++;
211        }
212    }
213
214    virtual void A_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
215    {
216        for(unsigned int i=0;i<num;++i)
217        {
218            *dest++ = *source;
219            *dest++ = *source++;
220        }
221    }
222                   
223    virtual void A_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
224    {
225        for(unsigned int i=0;i<num;++i)
226        {
227            *dest++ = *source;
228            *dest++ = *source;
229            *dest++ = *source++;
230        }
231    }
232
233    virtual void A_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
234    {
235        for(unsigned int i=0;i<num;++i)
236        {
237            *dest++ = *source;
238            *dest++ = *source;
239            *dest++ = *source;
240            *dest++ = *source++;
241        }
242    }
243
244    ///////////////////////////////////////////////////////////////////////////////
245    // alpha luminiance sources..   
246    virtual void LA_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
247    {
248        for(unsigned int i=0;i<num;++i)
249        {
250            ++source;
251            *dest++ = *source++;
252        }
253    }
254
255    virtual void LA_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
256    {
257        for(unsigned int i=0;i<num;++i)
258        {
259            *dest++ = *source++;
260            *dest++ = *source++;
261        }
262    }
263                   
264    virtual void LA_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
265    {
266        for(unsigned int i=0;i<num;++i)
267        {
268            *dest++ = *source;
269            *dest++ = *source;
270            *dest++ = *source;
271            source+=2;
272        }
273    }
274
275    virtual void LA_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
276    {
277        for(unsigned int i=0;i<num;++i)
278        {
279            *dest++ = *source;
280            *dest++ = *source;
281            *dest++ = *source++;
282            *dest++ = *source++;
283        }
284    }
285
286    ///////////////////////////////////////////////////////////////////////////////
287    // RGB sources..   
288    virtual void RGB_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
289    {
290        for(unsigned int i=0;i<num;++i)
291        {
292            unsigned char val = *source;
293            *dest++ = val;
294            source += 3;
295        }
296    }
297
298    virtual void RGB_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
299    {
300        for(unsigned int i=0;i<num;++i)
301        {
302            unsigned char val = *source;
303            *dest++ = val;
304            *dest++ = val;
305            source += 3;
306        }
307    }
308                   
309    virtual void RGB_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
310    {
311        for(unsigned int i=0;i<num;++i)
312        {
313            *dest++ = *source++;
314            *dest++ = *source++;
315            *dest++ = *source++;
316        }
317    }
318
319    virtual void RGB_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
320    {
321        for(unsigned int i=0;i<num;++i)
322        {
323            unsigned char val = *source;
324            *dest++ = *source++;
325            *dest++ = *source++;
326            *dest++ = *source++;
327            *dest++ = val;
328        }
329    }
330
331    ///////////////////////////////////////////////////////////////////////////////
332    // RGBA sources..   
333    virtual void RGBA_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
334    {
335        for(unsigned int i=0;i<num;++i)
336        {
337            source += 3;
338            *dest++ = *source++;
339        }
340    }
341
342    virtual void RGBA_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
343    {
344        for(unsigned int i=0;i<num;++i)
345        {
346            unsigned char val = *source;
347            source += 3;
348            *dest++ = val;
349            *dest++ = *source++;
350        }
351    }
352                   
353    virtual void RGBA_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
354    {
355        for(unsigned int i=0;i<num;++i)
356        {
357            *dest++ = *source++;
358            *dest++ = *source++;
359            *dest++ = *source++;
360            ++source;
361        }
362    }
363
364    virtual void RGBA_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
365    {
366        for(unsigned int i=0;i<num;++i)
367        {
368            *dest++ = *source++;
369            *dest++ = *source++;
370            *dest++ = *source++;
371            *dest++ = *source++;
372        }
373    }
374};
375
376
377void clampToNearestValidPowerOfTwo(int& sizeX, int& sizeY, int& sizeZ, int s_maximumTextureSize, int t_maximumTextureSize, int r_maximumTextureSize)
378{
379    // compute nearest powers of two for each axis.
380    int s_nearestPowerOfTwo = 1;
381    while(s_nearestPowerOfTwo<sizeX && s_nearestPowerOfTwo<s_maximumTextureSize) s_nearestPowerOfTwo*=2;
382
383    int t_nearestPowerOfTwo = 1;
384    while(t_nearestPowerOfTwo<sizeY && t_nearestPowerOfTwo<t_maximumTextureSize) t_nearestPowerOfTwo*=2;
385
386    int r_nearestPowerOfTwo = 1;
387    while(r_nearestPowerOfTwo<sizeZ && r_nearestPowerOfTwo<r_maximumTextureSize) r_nearestPowerOfTwo*=2;
388
389    sizeX = s_nearestPowerOfTwo;
390    sizeY = t_nearestPowerOfTwo;
391    sizeZ = r_nearestPowerOfTwo;
392}
393
394osg::Image* createTexture3D(ImageList& imageList, ProcessRow& processRow,
395            unsigned int numComponentsDesired,
396            int s_maximumTextureSize,
397            int t_maximumTextureSize,
398            int r_maximumTextureSize )
399{
400    int max_s = 0;
401    int max_t = 0;
402    unsigned int max_components = 0;
403    int total_r = 0;
404    ImageList::iterator itr;
405    for(itr=imageList.begin();
406        itr!=imageList.end();
407        ++itr)
408    {
409        osg::Image* image = itr->get();
410        GLenum pixelFormat = image->getPixelFormat();
411        if (pixelFormat==GL_ALPHA ||
412            pixelFormat==GL_LUMINANCE ||
413            pixelFormat==GL_LUMINANCE_ALPHA ||
414            pixelFormat==GL_RGB ||
415            pixelFormat==GL_RGBA)
416        {
417            max_s = osg::maximum(image->s(), max_s);
418            max_t = osg::maximum(image->t(), max_t);
419            max_components = osg::maximum(osg::Image::computeNumComponents(pixelFormat), max_components);
420            total_r += image->r();
421        }
422        else
423        {
424            osg::notify(osg::NOTICE)<<"Image "<<image->getFileName()<<" has unsuitable pixel format"<< std::hex<< pixelFormat << std::dec << std::endl;
425        }
426    }
427   
428    if (numComponentsDesired!=0) max_components = numComponentsDesired;
429   
430    GLenum desiredPixelFormat = 0;
431    switch(max_components)
432    {
433    case(1):
434        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_LUMINANCE" << std::endl;
435        desiredPixelFormat = GL_LUMINANCE;
436        break;
437    case(2):
438        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_LUMINANCE_ALPHA" << std::endl;
439        desiredPixelFormat = GL_LUMINANCE_ALPHA;
440        break;
441    case(3):
442        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_RGB" << std::endl;
443        desiredPixelFormat = GL_RGB;
444        break;
445    case(4):
446        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_RGBA" << std::endl;
447        desiredPixelFormat = GL_RGBA;
448        break;
449    }   
450    if (desiredPixelFormat==0) return 0;
451   
452    // compute nearest powers of two for each axis.
453    int s_nearestPowerOfTwo = 1;
454    while(s_nearestPowerOfTwo<max_s && s_nearestPowerOfTwo<s_maximumTextureSize) s_nearestPowerOfTwo*=2;
455
456    int t_nearestPowerOfTwo = 1;
457    while(t_nearestPowerOfTwo<max_t && t_nearestPowerOfTwo<t_maximumTextureSize) t_nearestPowerOfTwo*=2;
458
459    int r_nearestPowerOfTwo = 1;
460    while(r_nearestPowerOfTwo<total_r && r_nearestPowerOfTwo<r_maximumTextureSize) r_nearestPowerOfTwo*=2;
461
462
463    osg::notify(osg::NOTICE)<<"max image width = "<<max_s<<"  nearest power of two = "<<s_nearestPowerOfTwo<<std::endl;
464    osg::notify(osg::NOTICE)<<"max image height = "<<max_t<<"  nearest power of two = "<<t_nearestPowerOfTwo<<std::endl;
465    osg::notify(osg::NOTICE)<<"max image depth = "<<total_r<<"  nearest power of two = "<<r_nearestPowerOfTwo<<std::endl;
466   
467    // now allocate the 3d texture;
468    osg::ref_ptr<osg::Image> image_3d = new osg::Image;
469    image_3d->allocateImage(s_nearestPowerOfTwo,t_nearestPowerOfTwo,r_nearestPowerOfTwo,
470                            desiredPixelFormat,GL_UNSIGNED_BYTE);
471       
472
473    unsigned int r_offset = (total_r<r_nearestPowerOfTwo) ? r_nearestPowerOfTwo/2 - total_r/2 : 0;
474
475    int curr_dest_r = r_offset;
476
477    // copy across the values from the source images into the image_3d.
478    for(itr=imageList.begin();
479        itr!=imageList.end();
480        ++itr)
481    {
482        osg::Image* image = itr->get();
483        GLenum pixelFormat = image->getPixelFormat();
484        if (pixelFormat==GL_ALPHA ||
485            pixelFormat==GL_LUMINANCE ||
486            pixelFormat==GL_LUMINANCE_ALPHA ||
487            pixelFormat==GL_RGB ||
488            pixelFormat==GL_RGBA)
489        {
490       
491            int num_r = osg::minimum(image->r(), (image_3d->r() - curr_dest_r));
492            int num_t = osg::minimum(image->t(), image_3d->t());
493            int num_s = osg::minimum(image->s(), image_3d->s());
494       
495            unsigned int s_offset_dest = (image->s()<s_nearestPowerOfTwo) ? s_nearestPowerOfTwo/2 - image->s()/2 : 0;
496            unsigned int t_offset_dest = (image->t()<t_nearestPowerOfTwo) ? t_nearestPowerOfTwo/2 - image->t()/2 : 0;
497
498            for(int r=0;r<num_r;++r, ++curr_dest_r)
499            {
500                for(int t=0;t<num_t;++t)
501                {
502                    unsigned char* dest = image_3d->data(s_offset_dest,t+t_offset_dest,curr_dest_r);
503                    unsigned char* source = image->data(0,t,r);
504
505                    processRow(num_s, image->getPixelFormat(), source, image_3d->getPixelFormat(), dest);
506                }
507            }
508        }
509    }
510    return image_3d.release();
511}
512
513
514osg::Image* createNormalMapTexture(osg::Image* image_3d)
515{
516    unsigned int sourcePixelIncrement = 1;
517    unsigned int alphaOffset = 0;
518    switch(image_3d->getPixelFormat())
519    {
520    case(GL_ALPHA):
521    case(GL_LUMINANCE):
522        sourcePixelIncrement = 1;
523        alphaOffset = 0;
524        break;
525    case(GL_LUMINANCE_ALPHA):
526        sourcePixelIncrement = 2;
527        alphaOffset = 1;
528        break;
529    case(GL_RGB):
530        sourcePixelIncrement = 3;
531        alphaOffset = 0;
532        break;
533    case(GL_RGBA):
534        sourcePixelIncrement = 4;
535        alphaOffset = 3;
536        break;
537    default:
538        osg::notify(osg::NOTICE)<<"Source pixel format not support for normal map generation."<<std::endl;
539        return 0;
540    }
541   
542    osg::ref_ptr<osg::Image> normalmap_3d = new osg::Image;
543    normalmap_3d->allocateImage(image_3d->s(),image_3d->t(),image_3d->r(),
544                            GL_RGBA,GL_UNSIGNED_BYTE);
545
546    if (osg::getCpuByteOrder()==osg::LittleEndian) alphaOffset = sourcePixelIncrement-alphaOffset-1;
547
548    for(int r=1;r<image_3d->r()-1;++r)
549    {
550        for(int t=1;t<image_3d->t()-1;++t)
551        {
552            unsigned char* ptr = image_3d->data(1,t,r)+alphaOffset;
553            unsigned char* left = image_3d->data(0,t,r)+alphaOffset;
554            unsigned char* right = image_3d->data(2,t,r)+alphaOffset;
555            unsigned char* above = image_3d->data(1,t+1,r)+alphaOffset;
556            unsigned char* below = image_3d->data(1,t-1,r)+alphaOffset;
557            unsigned char* in = image_3d->data(1,t,r+1)+alphaOffset;
558            unsigned char* out = image_3d->data(1,t,r-1)+alphaOffset;
559
560            unsigned char* destination = (unsigned char*) normalmap_3d->data(1,t,r);
561
562            for(int s=1;s<image_3d->s()-1;++s)
563            {
564
565                osg::Vec3 grad((float)(*left)-(float)(*right),
566                               (float)(*below)-(float)(*above),
567                               (float)(*out) -(float)(*in));
568
569                grad.normalize();
570
571                if (grad.x()==0.0f && grad.y()==0.0f && grad.z()==0.0f)
572                {
573                    grad.set(128.0f,128.0f,128.0f);
574                }
575                else
576                {
577                    grad.x() = osg::clampBetween((grad.x()+1.0f)*128.0f,0.0f,255.0f);
578                    grad.y() = osg::clampBetween((grad.y()+1.0f)*128.0f,0.0f,255.0f);
579                    grad.z() = osg::clampBetween((grad.z()+1.0f)*128.0f,0.0f,255.0f);
580                }
581
582                *(destination++) = (unsigned char)(grad.x()); // scale and bias X.
583                *(destination++) = (unsigned char)(grad.y()); // scale and bias Y.
584                *(destination++) = (unsigned char)(grad.z()); // scale and bias Z.
585
586                *destination++ = *ptr;
587
588                ptr += sourcePixelIncrement;
589                left += sourcePixelIncrement;
590                right += sourcePixelIncrement;
591                above += sourcePixelIncrement;
592                below += sourcePixelIncrement;
593                in += sourcePixelIncrement;
594                out += sourcePixelIncrement;
595            }
596        }
597    }
598   
599    return normalmap_3d.release();
600}
601
602
603
604osg::Node* createCube(float size,float alpha, unsigned int numSlices, float sliceEnd=1.0f)
605{
606
607    // set up the Geometry.
608    osg::Geometry* geom = new osg::Geometry;
609
610    float halfSize = size*0.5f;
611    float y = halfSize;
612    float dy =-size*1.4/(float)(numSlices-1)*sliceEnd;
613
614    //y = -halfSize;
615    //dy *= 0.5;
616
617    osg::Vec3Array* coords = new osg::Vec3Array(4*numSlices);
618    geom->setVertexArray(coords);
619    for(unsigned int i=0;i<numSlices;++i, y+=dy)
620    {
621        (*coords)[i*4+0].set(-halfSize,y,halfSize);
622        (*coords)[i*4+1].set(-halfSize,y,-halfSize);
623        (*coords)[i*4+2].set(halfSize,y,-halfSize);
624        (*coords)[i*4+3].set(halfSize,y,halfSize);
625    }
626   
627    osg::Vec3Array* normals = new osg::Vec3Array(1);
628    (*normals)[0].set(0.0f,-1.0f,0.0f);
629    geom->setNormalArray(normals);
630    geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
631
632    osg::Vec4Array* colors = new osg::Vec4Array(1);
633    (*colors)[0].set(1.0f,1.0f,1.0f,alpha);
634    geom->setColorArray(colors);
635    geom->setColorBinding(osg::Geometry::BIND_OVERALL);
636
637    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,coords->size()));
638
639    osg::Billboard* billboard = new osg::Billboard;
640    billboard->setMode(osg::Billboard::POINT_ROT_WORLD);
641    billboard->addDrawable(geom);
642    billboard->setPosition(0,osg::Vec3(0.0f,0.0f,0.0f));
643   
644    return billboard;
645}
646
647class FollowMouseCallback : public osgGA::GUIEventHandler, public osg::StateSet::Callback
648{
649    public:
650   
651        FollowMouseCallback()
652        {
653            _updateTransparency = false;
654            _updateAlphaCutOff = false;
655            _updateSampleDensity = false;
656        }
657
658        FollowMouseCallback(const FollowMouseCallback&,const osg::CopyOp&) {}
659
660        META_Object(osg,FollowMouseCallback);
661
662        virtual void operator() (osg::StateSet* stateset, osg::NodeVisitor* nv)
663        {
664            if (nv->getVisitorType()==osg::NodeVisitor::EVENT_VISITOR)
665            {
666                osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(nv);
667                if (ev)
668                {
669                    osgGA::GUIActionAdapter* aa = ev->getActionAdapter();
670                    osgGA::EventQueue::Events& events = ev->getEvents();
671                    for(osgGA::EventQueue::Events::iterator itr=events.begin();
672                        itr!=events.end();
673                        ++itr)
674                    {
675                        handle(*(*itr), *aa, stateset, ev);
676                    }
677                }
678            }
679        }
680       
681        virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&, osg::Object* object, osg::NodeVisitor*)
682        {
683            osg::StateSet* stateset = dynamic_cast<osg::StateSet*>(object);
684            if (!stateset) return false;
685           
686            switch(ea.getEventType())
687            {
688                case(osgGA::GUIEventAdapter::MOVE):
689                case(osgGA::GUIEventAdapter::DRAG):
690                {
691                    float v = ea.getY()*0.5f+0.5f;
692                    osg::Uniform* uniform = 0;
693                    if (_updateTransparency && (uniform = stateset->getUniform("transparency"))) uniform->set(v);
694                    if (_updateAlphaCutOff && (uniform = stateset->getUniform("alphaCutOff"))) uniform->set(v);
695                    if (_updateSampleDensity && (uniform = stateset->getUniform("sampleDensity"))) uniform->set(powf(v,5));
696                    break;
697                }
698                case(osgGA::GUIEventAdapter::KEYDOWN):
699                {
700                    if (ea.getKey()=='t') _updateTransparency = true;
701                    if (ea.getKey()=='a') _updateAlphaCutOff = true;
702                    if (ea.getKey()=='d') _updateSampleDensity = true;
703                    break;
704                }
705                case(osgGA::GUIEventAdapter::KEYUP):
706                {
707                    if (ea.getKey()=='t') _updateTransparency = false;
708                    if (ea.getKey()=='a') _updateAlphaCutOff = false;
709                    if (ea.getKey()=='d') _updateSampleDensity = false;
710                    break;
711                }
712                default:
713                    break;
714            }
715            return false;
716        }
717       
718        bool _updateTransparency;
719        bool _updateAlphaCutOff;
720        bool _updateSampleDensity;
721
722};
723
724osg::Node* createShaderModel(osg::ref_ptr<osg::Image>& image_3d, osg::ref_ptr<osg::Image>& /*normalmap_3d*/,
725                       osg::Texture::InternalFormatMode internalFormatMode,
726                       float /*xSize*/, float /*ySize*/, float /*zSize*/,
727                       float /*xMultiplier*/, float /*yMultiplier*/, float /*zMultiplier*/,
728                       unsigned int /*numSlices*/=500, float /*sliceEnd*/=1.0f, float alphaFuncValue=0.02f)
729{
730    osg::Geode* geode = new osg::Geode;
731    osg::StateSet* stateset = geode->getOrCreateStateSet();
732   
733    stateset->setEventCallback(new FollowMouseCallback);
734   
735    stateset->setMode(GL_ALPHA_TEST,osg::StateAttribute::ON);
736
737    // set up the 3d texture itself,
738    // note, well set the filtering up so that mip mapping is disabled,
739    // gluBuild3DMipsmaps doesn't do a very good job of handled the
740    // inbalanced dimensions of the 256x256x4 texture.
741    osg::Texture3D* texture3D = new osg::Texture3D;
742    texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
743    texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
744    texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
745    texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
746    texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
747    if (image_3d->getPixelFormat()==GL_ALPHA ||
748        image_3d->getPixelFormat()==GL_LUMINANCE)
749    {
750        texture3D->setInternalFormatMode(osg::Texture3D::USE_USER_DEFINED_FORMAT);
751        texture3D->setInternalFormat(GL_INTENSITY);
752    }
753    else
754    {
755        texture3D->setInternalFormatMode(internalFormatMode);
756    }
757
758    texture3D->setImage(image_3d.get());
759
760    stateset->setTextureAttributeAndModes(0,texture3D,osg::StateAttribute::ON);
761
762    osg::Program* program = new osg::Program;
763    stateset->setAttribute(program);
764
765    // get shaders from source
766    std::string vertexShaderFile = osgDB::findDataFile("volume.vert");
767    if (!vertexShaderFile.empty())
768    {
769        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, vertexShaderFile));
770    }
771    else
772    {
773        char vertexShaderSource[] =
774            "varying vec3 texcoord;\n"
775            "varying vec3 deltaTexCoord;\n"
776            "\n"
777            "void main(void)\n"
778            "{\n"
779            "    texcoord = gl_MultiTexCoord0.xyz;\n"
780            "    gl_Position     = ftransform();  \n"
781            "    deltaTexCoord = normalize(gl_ModelViewMatrixInverse * vec4(0,0,0,1) - gl_Vertex);\n"
782            "}\n";
783
784        osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
785        program->addShader(vertex_shader);
786
787    }
788   
789    std::string fragmentShaderFile = osgDB::findDataFile("volume.frag");
790    if (!fragmentShaderFile.empty())
791    {
792        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, fragmentShaderFile));
793    }
794    else
795    {
796        //////////////////////////////////////////////////////////////////
797        // fragment shader
798        //
799        char fragmentShaderSource[] =
800            "uniform sampler3D baseTexture;\n"
801            "uniform float sampleDensity;\n"
802            "uniform float transparency;\n"
803            "uniform float alphaCutOff;\n"
804            "\n"
805            "varying vec3 deltaTexCoord;\n"
806            "varying vec3 texcoord;\n"
807            "void main(void) \n"
808            "{ \n"
809            "    vec3 deltaTexCoord2 = normalize(deltaTexCoord)*sampleDensity; \n"
810            "\n"
811            "    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); \n"
812            "    \n"
813            "    while (texcoord.x>=0.0 && texcoord.x<=1.0 &&\n"
814            "           texcoord.y>=0.0 && texcoord.y<=1.0 &&\n"
815            "           texcoord.z>=0.0 && texcoord.z<=1.0)\n"
816            "    {\n"
817            "       vec4 color = texture3D( baseTexture, texcoord);\n"
818            "       float r = color[3]*transparency;\n"
819            "       if (r>alphaCutOff)\n"
820            "       {\n"
821            "         gl_FragColor.xyz = gl_FragColor.xyz*(1.0-r)+color.xyz*r;\n"
822            "         gl_FragColor.w += r;\n"
823            "       }\n"
824            "       texcoord += deltaTexCoord2; \n"
825            "    }\n"
826            "    if (gl_FragColor.w>1.0) gl_FragColor.w = 1.0; \n"
827            "}\n";
828
829        osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
830        program->addShader(fragment_shader);
831    }
832
833    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
834    stateset->addUniform(baseTextureSampler);
835
836    osg::Uniform* sampleDensity = new osg::Uniform("sampleDensity", 0.01f);
837    stateset->addUniform(sampleDensity);
838
839    osg::Uniform* transpancy = new osg::Uniform("transparency",0.5f);
840    stateset->addUniform(transpancy);
841
842    osg::Uniform* alphaCutOff = new osg::Uniform("alphaCutOff",alphaFuncValue);
843    stateset->addUniform(alphaCutOff);
844
845    stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
846
847    {
848        osg::Geometry* geom = new osg::Geometry;
849
850        osg::Vec3Array* coords = new osg::Vec3Array(8);
851        (*coords)[0].set(0,0,0);
852        (*coords)[1].set(1,0,0);
853        (*coords)[2].set(1,1,0);
854        (*coords)[3].set(0,1,0);
855        (*coords)[4].set(0,0,1);
856        (*coords)[5].set(1,0,1);
857        (*coords)[6].set(1,1,1);
858        (*coords)[7].set(0,1,1);
859        geom->setVertexArray(coords);
860
861        osg::Vec3Array* tcoords = new osg::Vec3Array(8);
862        (*tcoords)[0].set(0,0,0);
863        (*tcoords)[1].set(1,0,0);
864        (*tcoords)[2].set(1,1,0);
865        (*tcoords)[3].set(0,1,0);
866        (*tcoords)[4].set(0,0,1);
867        (*tcoords)[5].set(1,0,1);
868        (*tcoords)[6].set(1,1,1);
869        (*tcoords)[7].set(0,1,1);
870        geom->setTexCoordArray(0,tcoords);
871
872        osg::Vec4Array* colours = new osg::Vec4Array(1);
873        (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
874        geom->setColorArray(colours);
875        geom->setColorBinding(osg::Geometry::BIND_OVERALL);
876
877        osg::DrawElementsUShort* drawElements = new osg::DrawElementsUShort(GL_QUADS);
878        // bottom
879        drawElements->push_back(0);
880        drawElements->push_back(1);
881        drawElements->push_back(2);
882        drawElements->push_back(3);
883       
884        // bottom
885        drawElements->push_back(3);
886        drawElements->push_back(2);
887        drawElements->push_back(6);
888        drawElements->push_back(7);
889
890        // left
891        drawElements->push_back(0);
892        drawElements->push_back(3);
893        drawElements->push_back(7);
894        drawElements->push_back(4);
895
896        // right
897        drawElements->push_back(5);
898        drawElements->push_back(6);
899        drawElements->push_back(2);
900        drawElements->push_back(1);
901
902        // front
903        drawElements->push_back(1);
904        drawElements->push_back(0);
905        drawElements->push_back(4);
906        drawElements->push_back(5);
907
908        // top
909        drawElements->push_back(7);
910        drawElements->push_back(6);
911        drawElements->push_back(5);
912        drawElements->push_back(4);
913
914        geom->addPrimitiveSet(drawElements);
915
916        geode->addDrawable(geom);
917
918    }
919
920    return geode;
921}
922
923osg::Node* createModel(osg::ref_ptr<osg::Image>& image_3d, osg::ref_ptr<osg::Image>& normalmap_3d,
924                       osg::Texture::InternalFormatMode internalFormatMode,
925                       float xSize, float ySize, float zSize,
926                       float xMultiplier, float yMultiplier, float zMultiplier,
927                       unsigned int numSlices=500, float sliceEnd=1.0f, float alphaFuncValue=0.02f)
928{
929    bool two_pass = normalmap_3d.valid() && (image_3d->getPixelFormat()==GL_RGB || image_3d->getPixelFormat()==GL_RGBA);
930
931    osg::Group* group = new osg::Group;
932   
933    osg::TexGenNode* texgenNode_0 = new osg::TexGenNode;
934    texgenNode_0->setTextureUnit(0);
935    texgenNode_0->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
936    texgenNode_0->getTexGen()->setPlane(osg::TexGen::S, osg::Plane(xMultiplier,0.0f,0.0f,0.5f));
937    texgenNode_0->getTexGen()->setPlane(osg::TexGen::T, osg::Plane(0.0f,yMultiplier,0.0f,0.5f));
938    texgenNode_0->getTexGen()->setPlane(osg::TexGen::R, osg::Plane(0.0f,0.0f,zMultiplier,0.5f));
939   
940    if (two_pass)
941    {
942        osg::TexGenNode* texgenNode_1 = new osg::TexGenNode;
943        texgenNode_1->setTextureUnit(1);
944        texgenNode_1->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
945        texgenNode_1->getTexGen()->setPlane(osg::TexGen::S, texgenNode_0->getTexGen()->getPlane(osg::TexGen::S));
946        texgenNode_1->getTexGen()->setPlane(osg::TexGen::T, texgenNode_0->getTexGen()->getPlane(osg::TexGen::T));
947        texgenNode_1->getTexGen()->setPlane(osg::TexGen::R, texgenNode_0->getTexGen()->getPlane(osg::TexGen::R));
948
949        texgenNode_1->addChild(texgenNode_0);
950
951        group->addChild(texgenNode_1);
952    }
953    else
954    { 
955        group->addChild(texgenNode_0);
956    }
957
958    osg::BoundingBox bb(-xSize*0.5f,-ySize*0.5f,-zSize*0.5f,xSize*0.5f,ySize*0.5f,zSize*0.5f);
959
960    osg::ClipNode* clipnode = new osg::ClipNode;
961    clipnode->addChild(createCube(1.0f,1.0f, numSlices,sliceEnd));
962    clipnode->createClipBox(bb);
963
964    {
965        // set up the Geometry to enclose the clip volume to prevent near/far clipping from affecting billboard
966        osg::Geometry* geom = new osg::Geometry;
967
968        osg::Vec3Array* coords = new osg::Vec3Array();
969        coords->push_back(bb.corner(0));
970        coords->push_back(bb.corner(1));
971        coords->push_back(bb.corner(2));
972        coords->push_back(bb.corner(3));
973        coords->push_back(bb.corner(4));
974        coords->push_back(bb.corner(5));
975        coords->push_back(bb.corner(6));
976        coords->push_back(bb.corner(7));
977
978        geom->setVertexArray(coords);
979
980        osg::Vec4Array* colors = new osg::Vec4Array(1);
981        (*colors)[0].set(1.0f,1.0f,1.0f,1.0f);
982        geom->setColorArray(colors);
983        geom->setColorBinding(osg::Geometry::BIND_OVERALL);
984
985        geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS,0,coords->size()));
986
987        osg::Geode* geode = new osg::Geode;
988        geode->addDrawable(geom);
989       
990        clipnode->addChild(geode);
991       
992    }
993
994    texgenNode_0->addChild(clipnode);
995
996    osg::StateSet* stateset = texgenNode_0->getOrCreateStateSet();
997
998    stateset->setMode(GL_LIGHTING,osg::StateAttribute::ON);
999    stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
1000    stateset->setAttribute(new osg::AlphaFunc(osg::AlphaFunc::GREATER,alphaFuncValue));
1001   
1002    osg::Material* material = new osg::Material;
1003    material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1004    stateset->setAttributeAndModes(material);
1005   
1006    osg::Vec3 lightDirection(1.0f,-1.0f,1.0f);
1007    lightDirection.normalize();
1008
1009    if (normalmap_3d.valid())
1010    {
1011        if (two_pass)
1012        {
1013
1014            // set up normal texture
1015            osg::Texture3D* bump_texture3D = new osg::Texture3D;
1016            bump_texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
1017            bump_texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
1018            bump_texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
1019            bump_texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
1020            bump_texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
1021            bump_texture3D->setImage(normalmap_3d.get());
1022
1023            bump_texture3D->setInternalFormatMode(internalFormatMode);
1024
1025            stateset->setTextureAttributeAndModes(0,bump_texture3D,osg::StateAttribute::ON);
1026
1027            osg::TexEnvCombine* tec = new osg::TexEnvCombine;
1028            tec->setConstantColorAsLightDirection(lightDirection);
1029
1030            tec->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB);
1031            tec->setSource0_RGB(osg::TexEnvCombine::CONSTANT);
1032            tec->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
1033            tec->setSource1_RGB(osg::TexEnvCombine::TEXTURE);
1034            tec->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
1035
1036            tec->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
1037            tec->setSource0_Alpha(osg::TexEnvCombine::PRIMARY_COLOR);
1038            tec->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);
1039            tec->setSource1_Alpha(osg::TexEnvCombine::TEXTURE);
1040            tec->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA);
1041
1042            stateset->setTextureAttributeAndModes(0, tec, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
1043
1044            stateset->setTextureMode(0,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
1045            stateset->setTextureMode(0,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
1046            stateset->setTextureMode(0,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
1047
1048
1049            // set up color texture
1050            osg::Texture3D* texture3D = new osg::Texture3D;
1051            texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
1052            texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
1053            texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
1054            texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
1055            texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
1056            if (image_3d->getPixelFormat()==GL_ALPHA ||
1057                image_3d->getPixelFormat()==GL_LUMINANCE)
1058            {
1059                texture3D->setInternalFormatMode(osg::Texture3D::USE_USER_DEFINED_FORMAT);
1060                texture3D->setInternalFormat(GL_INTENSITY);
1061            }
1062            else
1063            {
1064                texture3D->setInternalFormatMode(internalFormatMode);
1065            }
1066            texture3D->setImage(image_3d.get());
1067
1068            stateset->setTextureAttributeAndModes(1,texture3D,osg::StateAttribute::ON);
1069
1070            stateset->setTextureMode(1,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
1071            stateset->setTextureMode(1,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
1072            stateset->setTextureMode(1,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
1073
1074            stateset->setTextureAttributeAndModes(1,new osg::TexEnv(),osg::StateAttribute::ON);
1075
1076        }
1077        else
1078        {
1079            osg::ref_ptr<osg::Image> normalmap_3d = createNormalMapTexture(image_3d.get());
1080            osg::Texture3D* bump_texture3D = new osg::Texture3D;
1081            bump_texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
1082            bump_texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
1083            bump_texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
1084            bump_texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
1085            bump_texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
1086            bump_texture3D->setImage(normalmap_3d.get());
1087
1088            bump_texture3D->setInternalFormatMode(internalFormatMode);
1089
1090            stateset->setTextureAttributeAndModes(0,bump_texture3D,osg::StateAttribute::ON);
1091
1092            osg::TexEnvCombine* tec = new osg::TexEnvCombine;
1093            tec->setConstantColorAsLightDirection(lightDirection);
1094
1095            tec->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB);
1096            tec->setSource0_RGB(osg::TexEnvCombine::CONSTANT);
1097            tec->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
1098            tec->setSource1_RGB(osg::TexEnvCombine::TEXTURE);
1099            tec->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
1100
1101            tec->setCombine_Alpha(osg::TexEnvCombine::MODULATE);
1102            tec->setSource0_Alpha(osg::TexEnvCombine::PRIMARY_COLOR);
1103            tec->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);
1104            tec->setSource1_Alpha(osg::TexEnvCombine::TEXTURE);
1105            tec->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA);
1106
1107            stateset->setTextureAttributeAndModes(0, tec, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
1108
1109            stateset->setTextureMode(0,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
1110            stateset->setTextureMode(0,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
1111            stateset->setTextureMode(0,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
1112
1113            image_3d = normalmap_3d;
1114        }
1115    }
1116    else
1117    {     
1118        // set up the 3d texture itself,
1119        // note, well set the filtering up so that mip mapping is disabled,
1120        // gluBuild3DMipsmaps doesn't do a very good job of handled the
1121        // inbalanced dimensions of the 256x256x4 texture.
1122        osg::Texture3D* texture3D = new osg::Texture3D;
1123        texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
1124        texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
1125        texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
1126        texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
1127        texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
1128        if (image_3d->getPixelFormat()==GL_ALPHA ||
1129            image_3d->getPixelFormat()==GL_LUMINANCE)
1130        {
1131            texture3D->setInternalFormatMode(osg::Texture3D::USE_USER_DEFINED_FORMAT);
1132            texture3D->setInternalFormat(GL_INTENSITY);
1133        }
1134        else
1135        {
1136            texture3D->setInternalFormatMode(internalFormatMode);
1137        }
1138
1139        texture3D->setImage(image_3d.get());
1140
1141        stateset->setTextureAttributeAndModes(0,texture3D,osg::StateAttribute::ON);
1142
1143        stateset->setTextureMode(0,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
1144        stateset->setTextureMode(0,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
1145        stateset->setTextureMode(0,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
1146
1147        stateset->setTextureAttributeAndModes(0,new osg::TexEnv(),osg::StateAttribute::ON);
1148    }
1149 
1150    return group;
1151}
1152
1153struct FindRangeOperator
1154{
1155    FindRangeOperator():
1156        _rmin(FLT_MAX),
1157        _rmax(-FLT_MAX),
1158        _gmin(FLT_MAX),
1159        _gmax(-FLT_MAX),
1160        _bmin(FLT_MAX),
1161        _bmax(-FLT_MAX),
1162        _amin(FLT_MAX),
1163        _amax(-FLT_MAX) {}
1164       
1165    mutable float _rmin, _rmax, _gmin, _gmax, _bmin, _bmax, _amin, _amax;
1166
1167    inline void luminance(float l) const { rgb(l,l,l); }
1168    inline void alpha(float a) const { _amin = osg::minimum(a,_amin); _amax = osg::maximum(a,_amax); }
1169    inline void luminance_alpha(float l,float a) const { rgb(l,l,l); alpha(a); }
1170    inline void rgb(float r,float g,float b) const { _rmin = osg::minimum(r,_rmin); _rmax = osg::maximum(r,_rmax); _gmin = osg::minimum(g,_gmin); _gmax = osg::maximum(g,_gmax); _bmin = osg::minimum(b,_bmin); _bmax = osg::maximum(b,_bmax);  }
1171    inline void rgba(float r,float g,float b,float a) const { rgb(r,g,b); alpha(a); }
1172};
1173 
1174struct ScaleOperator
1175{
1176    ScaleOperator():_scale(1.0f) {}
1177    ScaleOperator(float scale):_scale(scale) {}
1178    ScaleOperator(const ScaleOperator& so):_scale(so._scale) {}
1179   
1180    ScaleOperator& operator = (const ScaleOperator& so) { _scale = so._scale; return *this; }
1181
1182    float _scale;
1183
1184    inline void luminance(float& l) const { l*= _scale; }
1185    inline void alpha(float& a) const { a*= _scale; }
1186    inline void luminance_alpha(float& l,float& a) const { l*= _scale; a*= _scale;  }
1187    inline void rgb(float& r,float& g,float& b) const { r*= _scale; g*=_scale; b*=_scale; }
1188    inline void rgba(float& r,float& g,float& b,float& a) const { r*= _scale; g*=_scale; b*=_scale; a*=_scale; }
1189};
1190
1191struct RecordRowOperator
1192{
1193    RecordRowOperator(unsigned int num):_colours(num),_pos(0) {}
1194
1195    mutable std::vector<osg::Vec4>  _colours;
1196    mutable unsigned int            _pos;
1197   
1198    inline void luminance(float l) const { rgba(l,l,l,1.0f); }
1199    inline void alpha(float a) const { rgba(1.0f,1.0f,1.0f,a); }
1200    inline void luminance_alpha(float l,float a) const { rgba(l,l,l,a);  }
1201    inline void rgb(float r,float g,float b) const { rgba(r,g,b,1.0f); }
1202    inline void rgba(float r,float g,float b,float a) const { _colours[_pos++].set(r,g,b,a); }
1203};
1204
1205struct WriteRowOperator
1206{
1207    WriteRowOperator():_pos(0) {}
1208    WriteRowOperator(unsigned int num):_colours(num),_pos(0) {}
1209
1210    std::vector<osg::Vec4>  _colours;
1211    mutable unsigned int    _pos;
1212   
1213    inline void luminance(float& l) const { l = _colours[_pos++].r(); }
1214    inline void alpha(float& a) const { a = _colours[_pos++].a(); }
1215    inline void luminance_alpha(float& l,float& a) const { l = _colours[_pos].r(); a = _colours[_pos++].a(); }
1216    inline void rgb(float& r,float& g,float& b) const { r = _colours[_pos].r(); g = _colours[_pos].g(); b = _colours[_pos].b(); }
1217    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(); }
1218};
1219
1220osg::Image* readRaw(int sizeX, int sizeY, int sizeZ, int numberBytesPerComponent, int numberOfComponents, const std::string& endian, const std::string& raw_filename)
1221{
1222    std::ifstream fin(raw_filename.c_str(), std::ifstream::binary);
1223    if (!fin) return 0;
1224
1225    GLenum pixelFormat;
1226    switch(numberOfComponents)
1227    {
1228        case 1 : pixelFormat = GL_LUMINANCE; break;
1229        case 2 : pixelFormat = GL_LUMINANCE_ALPHA; break;
1230        case 3 : pixelFormat = GL_RGB; break;
1231        case 4 : pixelFormat = GL_RGBA; break;
1232        default :
1233            osg::notify(osg::NOTICE)<<"Error: numberOfComponents="<<numberOfComponents<<" not supported, only 1,2,3 or 4 are supported."<<std::endl;
1234            return 0;
1235    }
1236
1237   
1238    GLenum dataType;
1239    switch(numberBytesPerComponent)
1240    {
1241        case 1 : dataType = GL_UNSIGNED_BYTE; break;
1242        case 2 : dataType = GL_UNSIGNED_SHORT; break;
1243        case 4 : dataType = GL_UNSIGNED_INT; break;
1244        default :
1245            osg::notify(osg::NOTICE)<<"Error: numberBytesPerComponent="<<numberBytesPerComponent<<" not supported, only 1,2 or 4 are supported."<<std::endl;
1246            return 0;
1247    }
1248   
1249    int s_maximumTextureSize=256, t_maximumTextureSize=256, r_maximumTextureSize=256;
1250   
1251    int sizeS = sizeX;
1252    int sizeT = sizeY;
1253    int sizeR = sizeZ;
1254    clampToNearestValidPowerOfTwo(sizeS, sizeT, sizeR, s_maximumTextureSize, t_maximumTextureSize, r_maximumTextureSize);
1255
1256    osg::ref_ptr<osg::Image> image = new osg::Image;
1257    image->allocateImage(sizeS, sizeT, sizeR, pixelFormat, dataType);
1258   
1259   
1260    bool endianSwap = (osg::getCpuByteOrder()==osg::BigEndian) ? (endian!="big") : (endian=="big");
1261   
1262    unsigned int r_offset = (sizeZ<sizeR) ? sizeR/2 - sizeZ/2 : 0;
1263   
1264    int offset = endianSwap ? numberBytesPerComponent : 0;
1265    int delta = endianSwap ? -1 : 1;
1266    for(int r=0;r<sizeZ;++r)
1267    {
1268        for(int t=0;t<sizeY;++t)
1269        {
1270            char* data = (char*) image->data(0,t,r+r_offset);
1271            for(int s=0;s<sizeX;++s)
1272            {
1273                if (!fin) return 0;
1274               
1275                for(int c=0;c<numberOfComponents;++c)
1276                {
1277                    char* ptr = data+offset;
1278                    for(int b=0;b<numberBytesPerComponent;++b)
1279                    {
1280                        fin.read((char*)ptr, 1);
1281                        ptr += delta;
1282                    }
1283                    data += numberBytesPerComponent;
1284                }
1285            }
1286        }
1287    }
1288
1289
1290    // normalise texture
1291    {
1292        // compute range of values
1293        FindRangeOperator rangeOp;   
1294        readImage(image.get(), rangeOp);
1295        modifyImage(image.get(),ScaleOperator(1.0f/rangeOp._rmax));
1296    }
1297   
1298   
1299    fin.close();
1300
1301    if (dataType!=GL_UNSIGNED_BYTE)
1302    {
1303        // need to convert to ubyte
1304       
1305        osg::ref_ptr<osg::Image> new_image = new osg::Image;
1306        new_image->allocateImage(sizeS, sizeT, sizeR, pixelFormat, GL_UNSIGNED_BYTE);
1307       
1308        RecordRowOperator readOp(sizeS);
1309        WriteRowOperator writeOp;
1310
1311        for(int r=0;r<sizeR;++r)
1312        {
1313            for(int t=0;t<sizeT;++t)
1314            {
1315                // reset the indices to begining
1316                readOp._pos = 0;
1317                writeOp._pos = 0;
1318           
1319                // read the pixels into readOp's _colour array
1320                readRow(sizeS, pixelFormat, dataType, image->data(0,t,r), readOp);
1321                               
1322                // pass readOp's _colour array contents over to writeOp (note this is just a pointer swap).
1323                writeOp._colours.swap(readOp._colours);
1324               
1325                modifyRow(sizeS, pixelFormat, GL_UNSIGNED_BYTE, new_image->data(0,t,r), writeOp);
1326
1327                // return readOp's _colour array contents back to its rightful owner.
1328                writeOp._colours.swap(readOp._colours);
1329            }
1330        }
1331       
1332        image = new_image;
1333    }
1334   
1335    return image.release();
1336   
1337   
1338}
1339
1340enum ColourSpaceOperation
1341{
1342    NO_COLOUR_SPACE_OPERATION,
1343    MODULATE_ALPHA_BY_LUMINANCE,
1344    MODULATE_ALPHA_BY_COLOUR,
1345    REPLACE_ALPHA_WITH_LUMINACE
1346};
1347
1348struct ModulateAlphaByLuminanceOperator
1349{
1350    ModulateAlphaByLuminanceOperator() {}
1351
1352    inline void luminance(float&) const {}
1353    inline void alpha(float&) const {}
1354    inline void luminance_alpha(float& l,float& a) const { a*= l; }
1355    inline void rgb(float&,float&,float&) const {}
1356    inline void rgba(float& r,float& g,float& b,float& a) const { float l = (r+g+b)*0.3333333; a *= l;}
1357};
1358
1359struct ModulateAlphaByColourOperator
1360{
1361    ModulateAlphaByColourOperator(const osg::Vec4& colour):_colour(colour) { _lum = _colour.length(); }
1362   
1363    osg::Vec4 _colour;
1364    float _lum;
1365
1366    inline void luminance(float&) const {}
1367    inline void alpha(float&) const {}
1368    inline void luminance_alpha(float& l,float& a) const { a*= l*_lum; }
1369    inline void rgb(float&,float&,float&) const {}
1370    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()); }
1371};
1372
1373struct ReplaceAlphaWithLuminanceOperator
1374{
1375    ReplaceAlphaWithLuminanceOperator() {}
1376
1377    inline void luminance(float&) const {}
1378    inline void alpha(float&) const {}
1379    inline void luminance_alpha(float& l,float& a) const { a= l; }
1380    inline void rgb(float&,float&,float&) const { }
1381    inline void rgba(float& r,float& g,float& b,float& a) const { float l = (r+g+b)*0.3333333; a = l; }
1382};
1383
1384void doColourSpaceConversion(ColourSpaceOperation op, osg::Image* image, osg::Vec4& colour)
1385{
1386    switch(op)
1387    {
1388        case (MODULATE_ALPHA_BY_LUMINANCE):
1389            std::cout<<"doing conversion MODULATE_ALPHA_BY_LUMINANCE"<<std::endl;
1390            modifyImage(image,ModulateAlphaByLuminanceOperator());
1391            break;
1392        case (MODULATE_ALPHA_BY_COLOUR):
1393            std::cout<<"doing conversion MODULATE_ALPHA_BY_COLOUR"<<std::endl;
1394            modifyImage(image,ModulateAlphaByColourOperator(colour));
1395            break;
1396        case (REPLACE_ALPHA_WITH_LUMINACE):
1397            std::cout<<"doing conversion REPLACE_ALPHA_WITH_LUMINACE"<<std::endl;
1398            modifyImage(image,ReplaceAlphaWithLuminanceOperator());
1399            break;
1400        default:
1401            break;
1402    }
1403}
1404
1405int main( int argc, char **argv )
1406{
1407    // use an ArgumentParser object to manage the program arguments.
1408    osg::ArgumentParser arguments(&argc,argv);
1409   
1410    // set up the usage document, in case we need to print out how to use this program.
1411    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of 3D textures.");
1412    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
1413    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
1414    arguments.getApplicationUsage()->addCommandLineOption("-n","Create normal map for per voxel lighting.");
1415    arguments.getApplicationUsage()->addCommandLineOption("-s <numSlices>","Number of slices to create.");
1416    arguments.getApplicationUsage()->addCommandLineOption("--images [filenames]","Specify a stack of 2d images to build the 3d volume from.");
1417    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use OpenGL Shading Language.");
1418    arguments.getApplicationUsage()->addCommandLineOption("--xSize <size>","Relative width of rendered brick.");
1419    arguments.getApplicationUsage()->addCommandLineOption("--ySize <size>","Relative length of rendered brick.");
1420    arguments.getApplicationUsage()->addCommandLineOption("--zSize <size>","Relative height of rendered brick.");
1421    arguments.getApplicationUsage()->addCommandLineOption("--xMultiplier <multiplier>","Tex coord x mulitplier.");
1422    arguments.getApplicationUsage()->addCommandLineOption("--yMultiplier <multiplier>","Tex coord y mulitplier.");
1423    arguments.getApplicationUsage()->addCommandLineOption("--zMultiplier <multiplier>","Tex coord z mulitplier.");
1424    arguments.getApplicationUsage()->addCommandLineOption("--clip <ratio>","clip volume as a ratio, 0.0 clip all, 1.0 clip none.");
1425    arguments.getApplicationUsage()->addCommandLineOption("--maxTextureSize <size>","Set the texture maximum resolution in the s,t,r (x,y,z) dimensions.");
1426    arguments.getApplicationUsage()->addCommandLineOption("--s_maxTextureSize <size>","Set the texture maximum resolution in the s (x) dimension.");
1427    arguments.getApplicationUsage()->addCommandLineOption("--t_maxTextureSize <size>","Set the texture maximum resolution in the t (y) dimension.");
1428    arguments.getApplicationUsage()->addCommandLineOption("--r_maxTextureSize <size>","Set the texture maximum resolution in the r (z) dimension.");
1429    arguments.getApplicationUsage()->addCommandLineOption("--compressed","Enable the usage of compressed textures.");
1430    arguments.getApplicationUsage()->addCommandLineOption("--compressed-arb","Enable the usage of OpenGL ARB compressed textures.");
1431    arguments.getApplicationUsage()->addCommandLineOption("--compressed-dxt1","Enable the usage of S3TC DXT1 compressed textures.");
1432    arguments.getApplicationUsage()->addCommandLineOption("--compressed-dxt3","Enable the usage of S3TC DXT3 compressed textures.");
1433    arguments.getApplicationUsage()->addCommandLineOption("--compressed-dxt5","Enable the usage of S3TC DXT5 compressed textures.");
1434    arguments.getApplicationUsage()->addCommandLineOption("--modulate-alpha-by-luminance","For each pixel multiple the alpha value by the luminance.");
1435    arguments.getApplicationUsage()->addCommandLineOption("--replace-alpha-with-luminance","For each pixel mSet the alpha value to the luminance.");
1436    arguments.getApplicationUsage()->addCommandLineOption("--num-components <num>","Set the number of components to in he target image.");
1437//    arguments.getApplicationUsage()->addCommandLineOption("--raw <sizeX> <sizeY> <sizeZ> <numberBytesPerComponent> <numberOfComponents> <endian> <filename>","read a raw image data");
1438
1439    // construct the viewer.
1440    osgProducer::Viewer viewer(arguments);
1441
1442    // set up the value with sensible default event handlers.
1443    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
1444
1445    // get details on keyboard and mouse bindings used by the viewer.
1446    viewer.getUsage(*arguments.getApplicationUsage());
1447
1448    // if user request help write it out to cout.
1449    if (arguments.read("-h") || arguments.read("--help"))
1450    {
1451        arguments.getApplicationUsage()->write(std::cout);
1452        return 1;
1453    }
1454
1455    std::string outputFile;
1456    while (arguments.read("-o",outputFile)) {}
1457
1458
1459    unsigned int numSlices=500;
1460    while (arguments.read("-s",numSlices)) {}
1461   
1462   
1463    float sliceEnd=1.0f;
1464    while (arguments.read("--clip",sliceEnd)) {}
1465
1466    float alphaFunc=0.02f;
1467    while (arguments.read("--alphaFunc",alphaFunc)) {}
1468
1469
1470    bool createNormalMap = false;
1471    while (arguments.read("-n")) createNormalMap=true;
1472
1473    float xSize=1.0f, ySize=1.0f, zSize=1.0f;
1474    while (arguments.read("--xSize",xSize)) {}
1475    while (arguments.read("--ySize",ySize)) {}
1476    while (arguments.read("--zSize",zSize)) {}
1477
1478    float xMultiplier=1.0f, yMultiplier=1.0f, zMultiplier=1.0f;
1479    while (arguments.read("--xMultiplier",xMultiplier)) {}
1480    while (arguments.read("--yMultiplier",yMultiplier)) {}
1481    while (arguments.read("--zMultiplier",zMultiplier)) {}
1482
1483    int s_maximumTextureSize = 256;
1484    int t_maximumTextureSize = 256;
1485    int r_maximumTextureSize = 256;
1486    int maximumTextureSize = 256;
1487    while(arguments.read("--maxTextureSize",maximumTextureSize))
1488    {
1489        s_maximumTextureSize = maximumTextureSize;
1490        t_maximumTextureSize = maximumTextureSize;
1491        r_maximumTextureSize = maximumTextureSize;
1492    }
1493    while(arguments.read("--s_maxTextureSize",s_maximumTextureSize)) {}
1494    while(arguments.read("--t_maxTextureSize",t_maximumTextureSize)) {}
1495    while(arguments.read("--r_maxTextureSize",r_maximumTextureSize)) {}
1496
1497    osg::Texture::InternalFormatMode internalFormatMode = osg::Texture::USE_IMAGE_DATA_FORMAT;
1498    while(arguments.read("--compressed") || arguments.read("--compressed-arb")) { internalFormatMode = osg::Texture::USE_ARB_COMPRESSION; }
1499
1500    while(arguments.read("--compressed-dxt1")) { internalFormatMode = osg::Texture::USE_S3TC_DXT1_COMPRESSION; }
1501    while(arguments.read("--compressed-dxt3")) { internalFormatMode = osg::Texture::USE_S3TC_DXT3_COMPRESSION; }
1502    while(arguments.read("--compressed-dxt5")) { internalFormatMode = osg::Texture::USE_S3TC_DXT5_COMPRESSION; }
1503   
1504   
1505    // set up colour space operation.
1506    ColourSpaceOperation colourSpaceOperation = NO_COLOUR_SPACE_OPERATION;
1507    osg::Vec4 colourModulate(0.25f,0.25f,0.25f,0.25f);
1508    while(arguments.read("--modulate-alpha-by-luminance")) { colourSpaceOperation = MODULATE_ALPHA_BY_LUMINANCE; }
1509    while(arguments.read("--modulate-alpha-by-colour", colourModulate.x(),colourModulate.y(),colourModulate.z(),colourModulate.w() )) { colourSpaceOperation = MODULATE_ALPHA_BY_COLOUR; }
1510    while(arguments.read("--replace-alpha-with-luminance")) { colourSpaceOperation = REPLACE_ALPHA_WITH_LUMINACE; }
1511       
1512   
1513    unsigned int numComponentsDesired = 0;
1514    while(arguments.read("--num-components", numComponentsDesired)) {}
1515
1516    bool useShader = false;
1517    while(arguments.read("--shader")) { useShader = true; }
1518
1519    osg::ref_ptr<osg::Image> image_3d;
1520
1521    int sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents;
1522    std::string endian, raw_filename;
1523    while (arguments.read("--raw", sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents, endian, raw_filename))
1524    {
1525        image_3d = readRaw(sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents, endian, raw_filename);
1526    }
1527
1528    while (arguments.read("--images"))
1529    {
1530        ImageList imageList;
1531        for(int pos=1;pos<arguments.argc() && !arguments.isOption(pos);++pos)
1532        {
1533            // not an option so assume string is a filename.
1534            osg::Image *image = osgDB::readImageFile( arguments[pos]);
1535
1536            if(image)
1537            {
1538                imageList.push_back(image);
1539            }
1540        }
1541       
1542        // pack the textures into a single texture.
1543        ProcessRow processRow;
1544        image_3d = createTexture3D(imageList, processRow, numComponentsDesired, s_maximumTextureSize, t_maximumTextureSize, r_maximumTextureSize);
1545    }
1546
1547
1548    // any option left unread are converted into errors to write out later.
1549    arguments.reportRemainingOptionsAsUnrecognized();
1550
1551    // report any errors if they have occured when parsing the program aguments.
1552    if (arguments.errors())
1553    {
1554        arguments.writeErrorMessages(std::cout);
1555        return 1;
1556    }
1557
1558    // assume remaining argments are file names of textures.
1559    for(int pos=1;pos<arguments.argc() && !image_3d;++pos)
1560    {
1561        if (!arguments.isOption(pos))
1562        {
1563            // not an option so assume string is a filename.
1564            image_3d = osgDB::readImageFile( arguments[pos]);
1565        }
1566    }
1567   
1568    if (!image_3d) return 0;
1569   
1570    if (colourSpaceOperation!=NO_COLOUR_SPACE_OPERATION)
1571    {
1572        doColourSpaceConversion(colourSpaceOperation, image_3d.get(), colourModulate);
1573    }
1574   
1575    osg::ref_ptr<osg::Image> normalmap_3d = createNormalMap ? createNormalMapTexture(image_3d.get()) : 0;
1576
1577
1578
1579    // create a model from the images.
1580    osg::Node* rootNode = 0;
1581   
1582    if (useShader)
1583    {
1584        rootNode = createShaderModel(image_3d, normalmap_3d,
1585                               internalFormatMode,
1586                               xSize, ySize, zSize,
1587                               xMultiplier, yMultiplier, zMultiplier,
1588                               numSlices, sliceEnd, alphaFunc);
1589    }
1590    else
1591    {
1592        rootNode = createModel(image_3d, normalmap_3d,
1593                               internalFormatMode,
1594                               xSize, ySize, zSize,
1595                               xMultiplier, yMultiplier, zMultiplier,
1596                               numSlices, sliceEnd, alphaFunc);
1597    }
1598   
1599    if (!outputFile.empty())
1600    {   
1601        std::string ext = osgDB::getFileExtension(outputFile);
1602        std::string name_no_ext = osgDB::getNameLessExtension(outputFile);
1603        if (ext=="osg")
1604        {
1605            if (image_3d.valid())
1606            {
1607                image_3d->setFileName(name_no_ext + ".dds");           
1608                osgDB::writeImageFile(*image_3d, image_3d->getFileName());
1609            }
1610            if (normalmap_3d.valid())
1611            {
1612                normalmap_3d->setFileName(name_no_ext + "_normalmap.dds");           
1613                osgDB::writeImageFile(*normalmap_3d, normalmap_3d->getFileName());
1614            }
1615           
1616            osgDB::writeNodeFile(*rootNode, outputFile);
1617        }
1618        else if (ext=="ive")
1619        {
1620            osgDB::writeNodeFile(*rootNode, outputFile);       
1621        }
1622        else if (ext=="dds")
1623        {
1624            osgDB::writeImageFile(*image_3d, outputFile);       
1625        }
1626        else
1627        {
1628            std::cout<<"Extension not support for file output, not file written."<<std::endl;
1629        }
1630       
1631        return 0;
1632    }
1633
1634
1635    if (rootNode)
1636    {
1637
1638        // set the scene to render
1639        viewer.setSceneData(rootNode);
1640       
1641        // create the windows and run the threads.
1642        viewer.realize();
1643
1644        while( !viewer.done() )
1645        {
1646            // wait for all cull and draw threads to complete.
1647            viewer.sync();
1648
1649            // update the scene by traversing it with the the update visitor which will
1650            // call all node update callbacks and animations.
1651            viewer.update();
1652
1653            // fire off the cull and draw traversals of the scene.
1654            viewer.frame();
1655
1656        }
1657       
1658        // wait for all cull and draw threads to complete.
1659        viewer.sync();
1660
1661        // run a clean up frame to delete all OpenGL objects.
1662        viewer.cleanup_frame();
1663
1664        // wait for all the clean up frame to complete.
1665        viewer.sync();
1666    }   
1667   
1668    return 0;
1669
1670}
Note: See TracBrowser for help on using the browser.