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

Revision 8787, 68.4 kB (checked in by robert, 6 years ago)

Added support for event handler for non shader path, enable alpha func

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