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

Revision 4502, 64.4 kB (checked in by robert, 10 years ago)

Added event handler to shader code so that alphaCuttOff, transparency and
sampleDensity are controlled via 'a', 't' and 'd' respectively.

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