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

Revision 9124, 87.0 kB (checked in by robert, 5 years ago)

From Michael Platings, Converted std::fstream/ifstream/ofstream to osgDB::fstream/ifstream/ofstream and
fopen to osgDB::fopen to facilitate support for wide character filenames using UT8 encoding.

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