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

Revision 8931, 78.3 kB (checked in by robert, 6 years ago)

Added shader based transfer function, enabled via --gpu-tf

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