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

Revision 10535, 53.5 kB (checked in by robert, 5 years ago)

Fixed typo

  • 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 <osgManipulator/TabBoxDragger>
59#include <osgManipulator/TabPlaneTrackballDragger>
60#include <osgManipulator/TrackballDragger>
61
62#include <osg/io_utils>
63
64#include <algorithm>
65#include <iostream>
66
67#include <osg/ImageUtils>
68#include <osgVolume/Volume>
69#include <osgVolume/VolumeTile>
70#include <osgVolume/RayTracedTechnique>
71#include <osgVolume/FixedFunctionTechnique>
72
73typedef std::vector< osg::ref_ptr<osg::Image> > ImageList;
74
75enum ShadingModel
76{
77    Standard,
78    Light,
79    Isosurface,
80    MaximumIntensityProjection
81};
82
83struct PassThroughTransformFunction
84{
85    unsigned char operator() (unsigned char c) const { return c; }
86};
87
88
89struct ProcessRow
90{
91    virtual ~ProcessRow() {}
92
93    virtual void operator() (unsigned int num,
94                    GLenum source_pixelFormat, unsigned char* source,
95                    GLenum dest_pixelFormat, unsigned char* dest) const 
96    {
97        switch(source_pixelFormat)
98        {
99        case(GL_LUMINANCE):
100        case(GL_ALPHA):
101            switch(dest_pixelFormat)
102            {
103            case(GL_LUMINANCE):
104            case(GL_ALPHA): A_to_A(num, source, dest); break;
105            case(GL_LUMINANCE_ALPHA): A_to_LA(num, source, dest); break;
106            case(GL_RGB): A_to_RGB(num, source, dest); break;
107            case(GL_RGBA): A_to_RGBA(num, source, dest); break;
108            }
109            break;
110        case(GL_LUMINANCE_ALPHA):
111            switch(dest_pixelFormat)
112            {
113            case(GL_LUMINANCE):
114            case(GL_ALPHA): LA_to_A(num, source, dest); break;
115            case(GL_LUMINANCE_ALPHA): LA_to_LA(num, source, dest); break;
116            case(GL_RGB): LA_to_RGB(num, source, dest); break;
117            case(GL_RGBA): LA_to_RGBA(num, source, dest); break;
118            }
119            break;
120        case(GL_RGB):
121            switch(dest_pixelFormat)
122            {
123            case(GL_LUMINANCE):
124            case(GL_ALPHA): RGB_to_A(num, source, dest); break;
125            case(GL_LUMINANCE_ALPHA): RGB_to_LA(num, source, dest); break;
126            case(GL_RGB): RGB_to_RGB(num, source, dest); break;
127            case(GL_RGBA): RGB_to_RGBA(num, source, dest); break;
128            }
129            break;
130        case(GL_RGBA):
131            switch(dest_pixelFormat)
132            {
133            case(GL_LUMINANCE):
134            case(GL_ALPHA): RGBA_to_A(num, source, dest); break;
135            case(GL_LUMINANCE_ALPHA): RGBA_to_LA(num, source, dest); break;
136            case(GL_RGB): RGBA_to_RGB(num, source, dest); break;
137            case(GL_RGBA): RGBA_to_RGBA(num, source, dest); break;
138            }
139            break;
140        }
141    }
142
143    ///////////////////////////////////////////////////////////////////////////////
144    // alpha sources..   
145    virtual void A_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
146    {
147        for(unsigned int i=0;i<num;++i)
148        {
149            *dest++ = *source++;
150        }
151    }
152
153    virtual void A_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
154    {
155        for(unsigned int i=0;i<num;++i)
156        {
157            *dest++ = *source;
158            *dest++ = *source++;
159        }
160    }
161                   
162    virtual void A_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
163    {
164        for(unsigned int i=0;i<num;++i)
165        {
166            *dest++ = *source;
167            *dest++ = *source;
168            *dest++ = *source++;
169        }
170    }
171
172    virtual void A_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
173    {
174        for(unsigned int i=0;i<num;++i)
175        {
176            *dest++ = *source;
177            *dest++ = *source;
178            *dest++ = *source;
179            *dest++ = *source++;
180        }
181    }
182
183    ///////////////////////////////////////////////////////////////////////////////
184    // alpha luminance sources..   
185    virtual void LA_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
186    {
187        for(unsigned int i=0;i<num;++i)
188        {
189            ++source;
190            *dest++ = *source++;
191        }
192    }
193
194    virtual void LA_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
195    {
196        for(unsigned int i=0;i<num;++i)
197        {
198            *dest++ = *source++;
199            *dest++ = *source++;
200        }
201    }
202                   
203    virtual void LA_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
204    {
205        for(unsigned int i=0;i<num;++i)
206        {
207            *dest++ = *source;
208            *dest++ = *source;
209            *dest++ = *source;
210            source+=2;
211        }
212    }
213
214    virtual void LA_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
215    {
216        for(unsigned int i=0;i<num;++i)
217        {
218            *dest++ = *source;
219            *dest++ = *source;
220            *dest++ = *source++;
221            *dest++ = *source++;
222        }
223    }
224
225    ///////////////////////////////////////////////////////////////////////////////
226    // RGB sources..   
227    virtual void RGB_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
228    {
229        for(unsigned int i=0;i<num;++i)
230        {
231            unsigned char val = *source;
232            *dest++ = val;
233            source += 3;
234        }
235    }
236
237    virtual void RGB_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
238    {
239        for(unsigned int i=0;i<num;++i)
240        {
241            unsigned char val = *source;
242            *dest++ = val;
243            *dest++ = val;
244            source += 3;
245        }
246    }
247                   
248    virtual void RGB_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
249    {
250        for(unsigned int i=0;i<num;++i)
251        {
252            *dest++ = *source++;
253            *dest++ = *source++;
254            *dest++ = *source++;
255        }
256    }
257
258    virtual void RGB_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
259    {
260        for(unsigned int i=0;i<num;++i)
261        {
262            unsigned char val = *source;
263            *dest++ = *source++;
264            *dest++ = *source++;
265            *dest++ = *source++;
266            *dest++ = val;
267        }
268    }
269
270    ///////////////////////////////////////////////////////////////////////////////
271    // RGBA sources..   
272    virtual void RGBA_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
273    {
274        for(unsigned int i=0;i<num;++i)
275        {
276            source += 3;
277            *dest++ = *source++;
278        }
279    }
280
281    virtual void RGBA_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
282    {
283        for(unsigned int i=0;i<num;++i)
284        {
285            unsigned char val = *source;
286            source += 3;
287            *dest++ = val;
288            *dest++ = *source++;
289        }
290    }
291                   
292    virtual void RGBA_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
293    {
294        for(unsigned int i=0;i<num;++i)
295        {
296            *dest++ = *source++;
297            *dest++ = *source++;
298            *dest++ = *source++;
299            ++source;
300        }
301    }
302
303    virtual void RGBA_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
304    {
305        for(unsigned int i=0;i<num;++i)
306        {
307            *dest++ = *source++;
308            *dest++ = *source++;
309            *dest++ = *source++;
310            *dest++ = *source++;
311        }
312    }
313};
314
315
316void clampToNearestValidPowerOfTwo(int& sizeX, int& sizeY, int& sizeZ, int s_maximumTextureSize, int t_maximumTextureSize, int r_maximumTextureSize)
317{
318    // compute nearest powers of two for each axis.
319    int s_nearestPowerOfTwo = 1;
320    while(s_nearestPowerOfTwo<sizeX && s_nearestPowerOfTwo<s_maximumTextureSize) s_nearestPowerOfTwo*=2;
321
322    int t_nearestPowerOfTwo = 1;
323    while(t_nearestPowerOfTwo<sizeY && t_nearestPowerOfTwo<t_maximumTextureSize) t_nearestPowerOfTwo*=2;
324
325    int r_nearestPowerOfTwo = 1;
326    while(r_nearestPowerOfTwo<sizeZ && r_nearestPowerOfTwo<r_maximumTextureSize) r_nearestPowerOfTwo*=2;
327
328    sizeX = s_nearestPowerOfTwo;
329    sizeY = t_nearestPowerOfTwo;
330    sizeZ = r_nearestPowerOfTwo;
331}
332
333osg::Image* createTexture3D(ImageList& imageList, ProcessRow& processRow,
334            unsigned int numComponentsDesired,
335            int s_maximumTextureSize,
336            int t_maximumTextureSize,
337            int r_maximumTextureSize,
338            bool resizeToPowerOfTwo)
339{
340    int max_s = 0;
341    int max_t = 0;
342    unsigned int max_components = 0;
343    int total_r = 0;
344    ImageList::iterator itr;
345    for(itr=imageList.begin();
346        itr!=imageList.end();
347        ++itr)
348    {
349        osg::Image* image = itr->get();
350        GLenum pixelFormat = image->getPixelFormat();
351        if (pixelFormat==GL_ALPHA ||
352            pixelFormat==GL_INTENSITY ||
353            pixelFormat==GL_LUMINANCE ||
354            pixelFormat==GL_LUMINANCE_ALPHA ||
355            pixelFormat==GL_RGB ||
356            pixelFormat==GL_RGBA)
357        {
358            max_s = osg::maximum(image->s(), max_s);
359            max_t = osg::maximum(image->t(), max_t);
360            max_components = osg::maximum(osg::Image::computeNumComponents(pixelFormat), max_components);
361            total_r += image->r();
362        }
363        else
364        {
365            osg::notify(osg::NOTICE)<<"Image "<<image->getFileName()<<" has unsuitable pixel format"<< std::hex<< pixelFormat << std::dec << std::endl;
366        }
367    }
368   
369    if (numComponentsDesired!=0) max_components = numComponentsDesired;
370   
371    GLenum desiredPixelFormat = 0;
372    switch(max_components)
373    {
374    case(1):
375        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_LUMINANCE" << std::endl;
376        desiredPixelFormat = GL_LUMINANCE;
377        break;
378    case(2):
379        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_LUMINANCE_ALPHA" << std::endl;
380        desiredPixelFormat = GL_LUMINANCE_ALPHA;
381        break;
382    case(3):
383        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_RGB" << std::endl;
384        desiredPixelFormat = GL_RGB;
385        break;
386    case(4):
387        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_RGBA" << std::endl;
388        desiredPixelFormat = GL_RGBA;
389        break;
390    }   
391    if (desiredPixelFormat==0) return 0;
392   
393    // compute nearest powers of two for each axis.
394   
395    int s_nearestPowerOfTwo = 1;
396    int t_nearestPowerOfTwo = 1;
397    int r_nearestPowerOfTwo = 1;
398
399    if (resizeToPowerOfTwo)
400    {
401        while(s_nearestPowerOfTwo<max_s && s_nearestPowerOfTwo<s_maximumTextureSize) s_nearestPowerOfTwo*=2;
402        while(t_nearestPowerOfTwo<max_t && t_nearestPowerOfTwo<t_maximumTextureSize) t_nearestPowerOfTwo*=2;
403        while(r_nearestPowerOfTwo<total_r && r_nearestPowerOfTwo<r_maximumTextureSize) r_nearestPowerOfTwo*=2;
404
405        osg::notify(osg::NOTICE)<<"max image width = "<<max_s<<"  nearest power of two = "<<s_nearestPowerOfTwo<<std::endl;
406        osg::notify(osg::NOTICE)<<"max image height = "<<max_t<<"  nearest power of two = "<<t_nearestPowerOfTwo<<std::endl;
407        osg::notify(osg::NOTICE)<<"max image depth = "<<total_r<<"  nearest power of two = "<<r_nearestPowerOfTwo<<std::endl;
408    }
409    else
410    {
411        s_nearestPowerOfTwo = max_s;
412        t_nearestPowerOfTwo = max_t;
413        r_nearestPowerOfTwo = total_r;
414    }
415   
416    // now allocate the 3d texture;
417    osg::ref_ptr<osg::Image> image_3d = new osg::Image;
418    image_3d->allocateImage(s_nearestPowerOfTwo,t_nearestPowerOfTwo,r_nearestPowerOfTwo,
419                            desiredPixelFormat,GL_UNSIGNED_BYTE);
420       
421
422    unsigned int r_offset = (total_r<r_nearestPowerOfTwo) ? r_nearestPowerOfTwo/2 - total_r/2 : 0;
423
424    int curr_dest_r = r_offset;
425
426    // copy across the values from the source images into the image_3d.
427    for(itr=imageList.begin();
428        itr!=imageList.end();
429        ++itr)
430    {
431        osg::Image* image = itr->get();
432        GLenum pixelFormat = image->getPixelFormat();
433        if (pixelFormat==GL_ALPHA ||
434            pixelFormat==GL_LUMINANCE ||
435            pixelFormat==GL_INTENSITY ||
436            pixelFormat==GL_LUMINANCE_ALPHA ||
437            pixelFormat==GL_RGB ||
438            pixelFormat==GL_RGBA)
439        {
440       
441            int num_r = osg::minimum(image->r(), (image_3d->r() - curr_dest_r));
442            int num_t = osg::minimum(image->t(), image_3d->t());
443            int num_s = osg::minimum(image->s(), image_3d->s());
444       
445            unsigned int s_offset_dest = (image->s()<s_nearestPowerOfTwo) ? s_nearestPowerOfTwo/2 - image->s()/2 : 0;
446            unsigned int t_offset_dest = (image->t()<t_nearestPowerOfTwo) ? t_nearestPowerOfTwo/2 - image->t()/2 : 0;
447
448            for(int r=0;r<num_r;++r, ++curr_dest_r)
449            {
450                for(int t=0;t<num_t;++t)
451                {
452                    unsigned char* dest = image_3d->data(s_offset_dest,t+t_offset_dest,curr_dest_r);
453                    unsigned char* source = image->data(0,t,r);
454
455                    processRow(num_s, image->getPixelFormat(), source, image_3d->getPixelFormat(), dest);
456                }
457            }
458        }
459    }
460    return image_3d.release();
461}
462
463
464struct ScaleOperator
465{
466    ScaleOperator():_scale(1.0f) {}
467    ScaleOperator(float scale):_scale(scale) {}
468    ScaleOperator(const ScaleOperator& so):_scale(so._scale) {}
469   
470    ScaleOperator& operator = (const ScaleOperator& so) { _scale = so._scale; return *this; }
471
472    float _scale;
473
474    inline void luminance(float& l) const { l*= _scale; }
475    inline void alpha(float& a) const { a*= _scale; }
476    inline void luminance_alpha(float& l,float& a) const { l*= _scale; a*= _scale;  }
477    inline void rgb(float& r,float& g,float& b) const { r*= _scale; g*=_scale; b*=_scale; }
478    inline void rgba(float& r,float& g,float& b,float& a) const { r*= _scale; g*=_scale; b*=_scale; a*=_scale; }
479};
480
481struct RecordRowOperator
482{
483    RecordRowOperator(unsigned int num):_colours(num),_pos(0) {}
484
485    mutable std::vector<osg::Vec4>  _colours;
486    mutable unsigned int            _pos;
487   
488    inline void luminance(float l) const { rgba(l,l,l,1.0f); }
489    inline void alpha(float a) const { rgba(1.0f,1.0f,1.0f,a); }
490    inline void luminance_alpha(float l,float a) const { rgba(l,l,l,a);  }
491    inline void rgb(float r,float g,float b) const { rgba(r,g,b,1.0f); }
492    inline void rgba(float r,float g,float b,float a) const { _colours[_pos++].set(r,g,b,a); }
493};
494
495struct WriteRowOperator
496{
497    WriteRowOperator():_pos(0) {}
498    WriteRowOperator(unsigned int num):_colours(num),_pos(0) {}
499
500    std::vector<osg::Vec4>  _colours;
501    mutable unsigned int    _pos;
502   
503    inline void luminance(float& l) const { l = _colours[_pos++].r(); }
504    inline void alpha(float& a) const { a = _colours[_pos++].a(); }
505    inline void luminance_alpha(float& l,float& a) const { l = _colours[_pos].r(); a = _colours[_pos++].a(); }
506    inline void rgb(float& r,float& g,float& b) const { r = _colours[_pos].r(); g = _colours[_pos].g(); b = _colours[_pos].b(); }
507    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(); }
508};
509
510osg::Image* readRaw(int sizeX, int sizeY, int sizeZ, int numberBytesPerComponent, int numberOfComponents, const std::string& endian, const std::string& raw_filename)
511{
512    osgDB::ifstream fin(raw_filename.c_str(), std::ifstream::binary);
513    if (!fin) return 0;
514
515    GLenum pixelFormat;
516    switch(numberOfComponents)
517    {
518        case 1 : pixelFormat = GL_LUMINANCE; break;
519        case 2 : pixelFormat = GL_LUMINANCE_ALPHA; break;
520        case 3 : pixelFormat = GL_RGB; break;
521        case 4 : pixelFormat = GL_RGBA; break;
522        default :
523            osg::notify(osg::NOTICE)<<"Error: numberOfComponents="<<numberOfComponents<<" not supported, only 1,2,3 or 4 are supported."<<std::endl;
524            return 0;
525    }
526
527   
528    GLenum dataType;
529    switch(numberBytesPerComponent)
530    {
531        case 1 : dataType = GL_UNSIGNED_BYTE; break;
532        case 2 : dataType = GL_UNSIGNED_SHORT; break;
533        case 4 : dataType = GL_UNSIGNED_INT; break;
534        default :
535            osg::notify(osg::NOTICE)<<"Error: numberBytesPerComponent="<<numberBytesPerComponent<<" not supported, only 1,2 or 4 are supported."<<std::endl;
536            return 0;
537    }
538   
539    int s_maximumTextureSize=256, t_maximumTextureSize=256, r_maximumTextureSize=256;
540   
541    int sizeS = sizeX;
542    int sizeT = sizeY;
543    int sizeR = sizeZ;
544    clampToNearestValidPowerOfTwo(sizeS, sizeT, sizeR, s_maximumTextureSize, t_maximumTextureSize, r_maximumTextureSize);
545
546    osg::ref_ptr<osg::Image> image = new osg::Image;
547    image->allocateImage(sizeS, sizeT, sizeR, pixelFormat, dataType);
548   
549   
550    bool endianSwap = (osg::getCpuByteOrder()==osg::BigEndian) ? (endian!="big") : (endian=="big");
551   
552    unsigned int r_offset = (sizeZ<sizeR) ? sizeR/2 - sizeZ/2 : 0;
553   
554    int offset = endianSwap ? numberBytesPerComponent : 0;
555    int delta = endianSwap ? -1 : 1;
556    for(int r=0;r<sizeZ;++r)
557    {
558        for(int t=0;t<sizeY;++t)
559        {
560            char* data = (char*) image->data(0,t,r+r_offset);
561            for(int s=0;s<sizeX;++s)
562            {
563                if (!fin) return 0;
564               
565                for(int c=0;c<numberOfComponents;++c)
566                {
567                    char* ptr = data+offset;
568                    for(int b=0;b<numberBytesPerComponent;++b)
569                    {
570                        fin.read((char*)ptr, 1);
571                        ptr += delta;
572                    }
573                    data += numberBytesPerComponent;
574                }
575            }
576        }
577    }
578
579
580    // normalise texture
581    {
582        // compute range of values
583        osg::Vec4 minValue, maxValue;
584        osg::computeMinMax(image.get(), minValue, maxValue);
585        osg::modifyImage(image.get(),ScaleOperator(1.0f/maxValue.r()));
586    }
587   
588   
589    fin.close();
590
591    if (dataType!=GL_UNSIGNED_BYTE)
592    {
593        // need to convert to ubyte
594       
595        osg::ref_ptr<osg::Image> new_image = new osg::Image;
596        new_image->allocateImage(sizeS, sizeT, sizeR, pixelFormat, GL_UNSIGNED_BYTE);
597       
598        RecordRowOperator readOp(sizeS);
599        WriteRowOperator writeOp;
600
601        for(int r=0;r<sizeR;++r)
602        {
603            for(int t=0;t<sizeT;++t)
604            {
605                // reset the indices to beginning
606                readOp._pos = 0;
607                writeOp._pos = 0;
608           
609                // read the pixels into readOp's _colour array
610                osg::readRow(sizeS, pixelFormat, dataType, image->data(0,t,r), readOp);
611                               
612                // pass readOp's _colour array contents over to writeOp (note this is just a pointer swap).
613                writeOp._colours.swap(readOp._colours);
614               
615                osg::modifyRow(sizeS, pixelFormat, GL_UNSIGNED_BYTE, new_image->data(0,t,r), writeOp);
616
617                // return readOp's _colour array contents back to its rightful owner.
618                writeOp._colours.swap(readOp._colours);
619            }
620        }
621       
622        image = new_image;
623    }
624   
625    return image.release();
626   
627   
628}
629
630enum ColourSpaceOperation
631{
632    NO_COLOUR_SPACE_OPERATION,
633    MODULATE_ALPHA_BY_LUMINANCE,
634    MODULATE_ALPHA_BY_COLOUR,
635    REPLACE_ALPHA_WITH_LUMINANCE,
636    REPLACE_RGB_WITH_LUMINANCE
637};
638
639struct ModulateAlphaByLuminanceOperator
640{
641    ModulateAlphaByLuminanceOperator() {}
642
643    inline void luminance(float&) const {}
644    inline void alpha(float&) const {}
645    inline void luminance_alpha(float& l,float& a) const { a*= l; }
646    inline void rgb(float&,float&,float&) const {}
647    inline void rgba(float& r,float& g,float& b,float& a) const { float l = (r+g+b)*0.3333333; a *= l;}
648};
649
650struct ModulateAlphaByColourOperator
651{
652    ModulateAlphaByColourOperator(const osg::Vec4& colour):_colour(colour) { _lum = _colour.length(); }
653   
654    osg::Vec4 _colour;
655    float _lum;
656
657    inline void luminance(float&) const {}
658    inline void alpha(float&) const {}
659    inline void luminance_alpha(float& l,float& a) const { a*= l*_lum; }
660    inline void rgb(float&,float&,float&) const {}
661    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()); }
662};
663
664struct ReplaceAlphaWithLuminanceOperator
665{
666    ReplaceAlphaWithLuminanceOperator() {}
667
668    inline void luminance(float&) const {}
669    inline void alpha(float&) const {}
670    inline void luminance_alpha(float& l,float& a) const { a= l; }
671    inline void rgb(float&,float&,float&) const { }
672    inline void rgba(float& r,float& g,float& b,float& a) const { float l = (r+g+b)*0.3333333; a = l; }
673};
674
675osg::Image* doColourSpaceConversion(ColourSpaceOperation op, osg::Image* image, osg::Vec4& colour)
676{
677    switch(op)
678    {
679        case (MODULATE_ALPHA_BY_LUMINANCE):
680        {
681            std::cout<<"doing conversion MODULATE_ALPHA_BY_LUMINANCE"<<std::endl;
682            osg::modifyImage(image,ModulateAlphaByLuminanceOperator());
683            return image;
684        }
685        case (MODULATE_ALPHA_BY_COLOUR):
686        {
687            std::cout<<"doing conversion MODULATE_ALPHA_BY_COLOUR"<<std::endl;
688            osg::modifyImage(image,ModulateAlphaByColourOperator(colour));
689            return image;
690        }
691        case (REPLACE_ALPHA_WITH_LUMINANCE):
692        {
693            std::cout<<"doing conversion REPLACE_ALPHA_WITH_LUMINANCE"<<std::endl;
694            osg::modifyImage(image,ReplaceAlphaWithLuminanceOperator());
695            return image;
696        }
697        case (REPLACE_RGB_WITH_LUMINANCE):
698        {
699            std::cout<<"doing conversion REPLACE_ALPHA_WITH_LUMINANCE"<<std::endl;
700            osg::Image* newImage = new osg::Image;
701            newImage->allocateImage(image->s(), image->t(), image->r(), GL_LUMINANCE, image->getDataType());
702            osg::copyImage(image, 0, 0, 0, image->s(), image->t(), image->r(),
703                           newImage, 0, 0, 0, false);
704            return newImage;
705        }
706        default:
707            return image;
708    }
709}
710
711
712osg::TransferFunction1D* readTransferFunctionFile(const std::string& filename)
713{
714    std::string foundFile = osgDB::findDataFile(filename);
715    if (foundFile.empty())
716    {
717        std::cout<<"Error: could not find transfer function file : "<<filename<<std::endl;
718        return 0;
719    }
720   
721    std::cout<<"Reading transfer function "<<filename<<std::endl;
722
723    osg::TransferFunction1D::ColorMap colorMap;
724    osgDB::ifstream fin(foundFile.c_str());
725    while(fin)
726    {
727        float value, red, green, blue, alpha;
728        fin >> value >> red >> green >> blue >> alpha;
729        if (fin)
730        {
731            std::cout<<"value = "<<value<<" ("<<red<<", "<<green<<", "<<blue<<", "<<alpha<<")"<<std::endl;
732            colorMap[value] = osg::Vec4(red,green,blue,alpha);
733        }
734    }
735   
736    if (colorMap.empty())
737    {
738        std::cout<<"Error: No values read from transfer function file: "<<filename<<std::endl;
739        return 0;
740    }
741   
742    osg::TransferFunction1D* tf = new osg::TransferFunction1D;
743    tf->assign(colorMap);
744   
745    return tf;
746}
747
748
749class TestSupportOperation: public osg::GraphicsOperation
750{
751public:
752
753    TestSupportOperation():
754        osg::GraphicsOperation("TestSupportOperation",false),
755        supported(true),
756        errorMessage(),
757        maximumTextureSize(256) {}
758
759    virtual void operator () (osg::GraphicsContext* gc)
760    {
761        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mutex);
762
763        glGetIntegerv( GL_MAX_3D_TEXTURE_SIZE, &maximumTextureSize );
764       
765        osg::notify(osg::NOTICE)<<"Max texture size="<<maximumTextureSize<<std::endl;
766    }
767       
768    OpenThreads::Mutex  mutex;
769    bool                supported;
770    std::string         errorMessage;
771    GLint               maximumTextureSize;
772};
773
774class DraggerVolumeTileCallback : public osgManipulator::DraggerCallback
775{
776public:
777
778    DraggerVolumeTileCallback(osgVolume::VolumeTile* volume, osgVolume::Locator* locator):
779        _volume(volume),
780        _locator(locator) {}
781
782
783    virtual bool receive(const osgManipulator::MotionCommand& command);
784
785
786    osg::observer_ptr<osgVolume::VolumeTile>    _volume;
787    osg::ref_ptr<osgVolume::Locator>            _locator;
788
789    osg::Matrix _startMotionMatrix;
790
791    osg::Matrix _localToWorld;
792    osg::Matrix _worldToLocal;
793
794};
795
796bool DraggerVolumeTileCallback::receive(const osgManipulator::MotionCommand& command)
797{
798    if (!_locator) return false;
799
800    switch (command.getStage())
801    {
802        case osgManipulator::MotionCommand::START:
803        {
804            // Save the current matrix
805            _startMotionMatrix = _locator->getTransform();
806
807            // Get the LocalToWorld and WorldToLocal matrix for this node.
808            osg::NodePath nodePathToRoot;
809            osgManipulator::computeNodePathToRoot(*_volume,nodePathToRoot);
810            _localToWorld = _startMotionMatrix * osg::computeLocalToWorld(nodePathToRoot);
811            _worldToLocal = osg::Matrix::inverse(_localToWorld);
812
813            return true;
814        }
815        case osgManipulator::MotionCommand::MOVE:
816        {
817            // Transform the command's motion matrix into local motion matrix.
818            osg::Matrix localMotionMatrix = _localToWorld * command.getWorldToLocal()
819                                            * command.getMotionMatrix()
820                                            * command.getLocalToWorld() * _worldToLocal;
821
822            // Transform by the localMotionMatrix
823            _locator->setTransform(localMotionMatrix * _startMotionMatrix);
824
825            // osg::notify(osg::NOTICE)<<"New locator matrix "<<_locator->getTransform()<<std::endl;
826
827            return true;
828        }
829        case osgManipulator::MotionCommand::FINISH:
830        {
831            return true;
832        }
833        case osgManipulator::MotionCommand::NONE:
834        default:
835            return false;
836    }
837}
838
839int main( int argc, char **argv )
840{
841    // use an ArgumentParser object to manage the program arguments.
842    osg::ArgumentParser arguments(&argc,argv);
843   
844    // set up the usage document, in case we need to print out how to use this program.
845    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of 3D textures.");
846    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
847    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
848    arguments.getApplicationUsage()->addCommandLineOption("-s <numSlices>","Number of slices to create.");
849    arguments.getApplicationUsage()->addCommandLineOption("--images [filenames]","Specify a stack of 2d images to build the 3d volume from.");
850    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use OpenGL Shading Language. (default)");
851    arguments.getApplicationUsage()->addCommandLineOption("--no-shader","Disable use of OpenGL Shading Language.");
852    arguments.getApplicationUsage()->addCommandLineOption("--gpu-tf","Aply the transfer function on the GPU. (default)");
853    arguments.getApplicationUsage()->addCommandLineOption("--cpu-tf","Apply the transfer function on the CPU.");
854    arguments.getApplicationUsage()->addCommandLineOption("--mip","Use Maximum Intensity Projection (MIP) filtering.");
855    arguments.getApplicationUsage()->addCommandLineOption("--xSize <size>","Relative width of rendered brick.");
856    arguments.getApplicationUsage()->addCommandLineOption("--ySize <size>","Relative length of rendered brick.");
857    arguments.getApplicationUsage()->addCommandLineOption("--zSize <size>","Relative height of rendered brick.");
858    arguments.getApplicationUsage()->addCommandLineOption("--xMultiplier <multiplier>","Tex coord x mulitplier.");
859    arguments.getApplicationUsage()->addCommandLineOption("--yMultiplier <multiplier>","Tex coord y mulitplier.");
860    arguments.getApplicationUsage()->addCommandLineOption("--zMultiplier <multiplier>","Tex coord z mulitplier.");
861    arguments.getApplicationUsage()->addCommandLineOption("--clip <ratio>","clip volume as a ratio, 0.0 clip all, 1.0 clip none.");
862    arguments.getApplicationUsage()->addCommandLineOption("--maxTextureSize <size>","Set the texture maximum resolution in the s,t,r (x,y,z) dimensions.");
863    arguments.getApplicationUsage()->addCommandLineOption("--s_maxTextureSize <size>","Set the texture maximum resolution in the s (x) dimension.");
864    arguments.getApplicationUsage()->addCommandLineOption("--t_maxTextureSize <size>","Set the texture maximum resolution in the t (y) dimension.");
865    arguments.getApplicationUsage()->addCommandLineOption("--r_maxTextureSize <size>","Set the texture maximum resolution in the r (z) dimension.");
866    arguments.getApplicationUsage()->addCommandLineOption("--compressed","Enable the usage of compressed textures.");
867    arguments.getApplicationUsage()->addCommandLineOption("--compressed-arb","Enable the usage of OpenGL ARB compressed textures.");
868    arguments.getApplicationUsage()->addCommandLineOption("--compressed-dxt1","Enable the usage of S3TC DXT1 compressed textures.");
869    arguments.getApplicationUsage()->addCommandLineOption("--compressed-dxt3","Enable the usage of S3TC DXT3 compressed textures.");
870    arguments.getApplicationUsage()->addCommandLineOption("--compressed-dxt5","Enable the usage of S3TC DXT5 compressed textures.");
871    arguments.getApplicationUsage()->addCommandLineOption("--modulate-alpha-by-luminance","For each pixel multiply the alpha value by the luminance.");
872    arguments.getApplicationUsage()->addCommandLineOption("--replace-alpha-with-luminance","For each pixel set the alpha value to the luminance.");
873    arguments.getApplicationUsage()->addCommandLineOption("--replace-rgb-with-luminance","For each rgb pixel convert to the luminance.");
874    arguments.getApplicationUsage()->addCommandLineOption("--num-components <num>","Set the number of components to in he target image.");
875    arguments.getApplicationUsage()->addCommandLineOption("--no-rescale","Disable the rescaling of the pixel data to 0.0 to 1.0 range");
876    arguments.getApplicationUsage()->addCommandLineOption("--rescale","Enable the rescale of the pixel data to 0.0 to 1.0 range (default).");
877    arguments.getApplicationUsage()->addCommandLineOption("--shift-min-to-zero","Shift the pixel data so min value is 0.0.");
878    arguments.getApplicationUsage()->addCommandLineOption("--sequence-length <num>","Set the length of time that a sequence of images with run for.");
879    arguments.getApplicationUsage()->addCommandLineOption("--sd <num>","Short hand for --sequence-length");
880//    arguments.getApplicationUsage()->addCommandLineOption("--raw <sizeX> <sizeY> <sizeZ> <numberBytesPerComponent> <numberOfComponents> <endian> <filename>","read a raw image data");
881
882    // construct the viewer.
883    osgViewer::Viewer viewer(arguments);
884
885    // add the window size toggle handler
886    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
887       
888    {
889        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
890
891        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
892       
893        osgGA::FlightManipulator* flightManipulator = new osgGA::FlightManipulator();
894        flightManipulator->setYawControlMode(osgGA::FlightManipulator::NO_AUTOMATIC_YAW);
895        keyswitchManipulator->addMatrixManipulator( '2', "Flight", flightManipulator );
896
897        viewer.setCameraManipulator( keyswitchManipulator.get() );
898    }
899
900    // add the stats handler
901    viewer.addEventHandler(new osgViewer::StatsHandler);
902
903    viewer.getCamera()->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
904
905    // if user request help write it out to cout.
906    if (arguments.read("-h") || arguments.read("--help"))
907    {
908        arguments.getApplicationUsage()->write(std::cout);
909        return 1;
910    }
911
912    std::string outputFile;
913    while (arguments.read("-o",outputFile)) {}
914
915
916
917    osg::ref_ptr<osg::TransferFunction1D> transferFunction;
918    std::string tranferFunctionFile;
919    while (arguments.read("--tf",tranferFunctionFile))
920    {
921        transferFunction = readTransferFunctionFile(tranferFunctionFile);
922    }
923   
924    while(arguments.read("--test"))
925    {
926        transferFunction = new osg::TransferFunction1D;
927        transferFunction->setColor(0.0, osg::Vec4(1.0,0.0,0.0,0.0));
928        transferFunction->setColor(0.5, osg::Vec4(1.0,1.0,0.0,0.5));
929        transferFunction->setColor(1.0, osg::Vec4(0.0,0.0,1.0,1.0));
930    }
931
932    while(arguments.read("--test2"))
933    {
934        transferFunction = new osg::TransferFunction1D;
935        transferFunction->setColor(0.0, osg::Vec4(1.0,0.0,0.0,0.0));
936        transferFunction->setColor(0.5, osg::Vec4(1.0,1.0,0.0,0.5));
937        transferFunction->setColor(1.0, osg::Vec4(0.0,0.0,1.0,1.0));
938        transferFunction->assign(transferFunction->getColorMap());
939    }
940
941    unsigned int numSlices=500;
942    while (arguments.read("-s",numSlices)) {}
943   
944   
945    float sliceEnd=1.0f;
946    while (arguments.read("--clip",sliceEnd)) {}
947
948    float alphaFunc=0.02f;
949    while (arguments.read("--alphaFunc",alphaFunc)) {}
950
951
952   
953    ShadingModel shadingModel = Standard;
954    while(arguments.read("--mip")) shadingModel =  MaximumIntensityProjection;
955
956    while (arguments.read("--isosurface")) shadingModel = Isosurface;
957
958    while (arguments.read("--light")) shadingModel = Light;
959
960    float xSize=0.0f, ySize=0.0f, zSize=0.0f;
961    while (arguments.read("--xSize",xSize)) {}
962    while (arguments.read("--ySize",ySize)) {}
963    while (arguments.read("--zSize",zSize)) {}
964
965    osg::ref_ptr<TestSupportOperation> testSupportOperation = new TestSupportOperation;
966    viewer.setRealizeOperation(testSupportOperation.get());
967   
968    viewer.realize();
969
970    int maximumTextureSize = testSupportOperation->maximumTextureSize;
971    int s_maximumTextureSize = maximumTextureSize;
972    int t_maximumTextureSize = maximumTextureSize;
973    int r_maximumTextureSize = maximumTextureSize;
974    while(arguments.read("--maxTextureSize",maximumTextureSize))
975    {
976        s_maximumTextureSize = maximumTextureSize;
977        t_maximumTextureSize = maximumTextureSize;
978        r_maximumTextureSize = maximumTextureSize;
979    }
980    while(arguments.read("--s_maxTextureSize",s_maximumTextureSize)) {}
981    while(arguments.read("--t_maxTextureSize",t_maximumTextureSize)) {}
982    while(arguments.read("--r_maxTextureSize",r_maximumTextureSize)) {}
983
984    osg::Texture::InternalFormatMode internalFormatMode = osg::Texture::USE_IMAGE_DATA_FORMAT;
985    while(arguments.read("--compressed") || arguments.read("--compressed-arb")) { internalFormatMode = osg::Texture::USE_ARB_COMPRESSION; }
986
987    while(arguments.read("--compressed-dxt1")) { internalFormatMode = osg::Texture::USE_S3TC_DXT1_COMPRESSION; }
988    while(arguments.read("--compressed-dxt3")) { internalFormatMode = osg::Texture::USE_S3TC_DXT3_COMPRESSION; }
989    while(arguments.read("--compressed-dxt5")) { internalFormatMode = osg::Texture::USE_S3TC_DXT5_COMPRESSION; }
990   
991   
992    // set up colour space operation.
993    ColourSpaceOperation colourSpaceOperation = NO_COLOUR_SPACE_OPERATION;
994    osg::Vec4 colourModulate(0.25f,0.25f,0.25f,0.25f);
995    while(arguments.read("--modulate-alpha-by-luminance")) { colourSpaceOperation = MODULATE_ALPHA_BY_LUMINANCE; }
996    while(arguments.read("--modulate-alpha-by-colour", colourModulate.x(),colourModulate.y(),colourModulate.z(),colourModulate.w() )) { colourSpaceOperation = MODULATE_ALPHA_BY_COLOUR; }
997    while(arguments.read("--replace-alpha-with-luminance")) { colourSpaceOperation = REPLACE_ALPHA_WITH_LUMINANCE; }
998    while(arguments.read("--replace-rgb-with-luminance")) { colourSpaceOperation = REPLACE_RGB_WITH_LUMINANCE; }
999
1000
1001    enum RescaleOperation
1002    {
1003        NO_RESCALE,
1004        RESCALE_TO_ZERO_TO_ONE_RANGE,
1005        SHIFT_MIN_TO_ZERO
1006    };
1007   
1008    RescaleOperation rescaleOperation = RESCALE_TO_ZERO_TO_ONE_RANGE;
1009    while(arguments.read("--no-rescale")) rescaleOperation = NO_RESCALE;
1010    while(arguments.read("--rescale")) rescaleOperation = RESCALE_TO_ZERO_TO_ONE_RANGE;
1011    while(arguments.read("--shift-min-to-zero")) rescaleOperation = SHIFT_MIN_TO_ZERO;
1012
1013       
1014    bool resizeToPowerOfTwo = false;
1015   
1016    unsigned int numComponentsDesired = 0;
1017    while(arguments.read("--num-components", numComponentsDesired)) {}
1018
1019    bool useManipulator = false;
1020    while(arguments.read("--manipulator") || arguments.read("-m")) { useManipulator = true; }
1021
1022
1023    bool useShader = true;
1024    while(arguments.read("--shader")) { useShader = true; }
1025    while(arguments.read("--no-shader")) { useShader = false; }
1026
1027    bool gpuTransferFunction = true;
1028    while(arguments.read("--gpu-tf")) { gpuTransferFunction = true; }
1029    while(arguments.read("--cpu-tf")) { gpuTransferFunction = false; }
1030
1031    double sequenceLength = 10.0;
1032    while(arguments.read("--sequence-duration", sequenceLength) ||
1033          arguments.read("--sd", sequenceLength)) {}
1034
1035    typedef std::list< osg::ref_ptr<osg::Image> > Images;
1036    Images images;
1037
1038
1039    std::string vh_filename;
1040    while (arguments.read("--vh", vh_filename))
1041    {
1042        std::string raw_filename, transfer_filename;
1043        int xdim(0), ydim(0), zdim(0);
1044
1045        osgDB::ifstream header(vh_filename.c_str());
1046        if (header)
1047        {
1048            header >> raw_filename >> transfer_filename >> xdim >> ydim >> zdim >> xSize >> ySize >> zSize;
1049        }
1050       
1051        if (xdim*ydim*zdim==0)
1052        {
1053            std::cout<<"Error in reading volume header "<<vh_filename<<std::endl;
1054            return 1;
1055        }
1056       
1057        if (!raw_filename.empty())
1058        {
1059            images.push_back(readRaw(xdim, ydim, zdim, 1, 1, "little", raw_filename));
1060        }
1061       
1062        if (!transfer_filename.empty())
1063        {
1064            osgDB::ifstream fin(transfer_filename.c_str());
1065            if (fin)
1066            {
1067                osg::TransferFunction1D::ColorMap colorMap;
1068                float value = 0.0;
1069                while(fin && value<=1.0)
1070                {
1071                    float red, green, blue, alpha;
1072                    fin >> red >> green >> blue >> alpha;
1073                    if (fin)
1074                    {
1075                        colorMap[value] = osg::Vec4(red/255.0f,green/255.0f,blue/255.0f,alpha/255.0f);
1076                        std::cout<<"value = "<<value<<" ("<<red<<", "<<green<<", "<<blue<<", "<<alpha<<")";
1077                        std::cout<<"  ("<<colorMap[value]<<")"<<std::endl;
1078                    }
1079                    value += 1/255.0;
1080                }
1081
1082                if (colorMap.empty())
1083                {
1084                    std::cout<<"Error: No values read from transfer function file: "<<transfer_filename<<std::endl;
1085                    return 0;
1086                }
1087
1088                transferFunction = new osg::TransferFunction1D;
1089                transferFunction->assign(colorMap);
1090            }
1091        }
1092
1093    }
1094   
1095
1096    int sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents;
1097    std::string endian, raw_filename;
1098    while (arguments.read("--raw", sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents, endian, raw_filename))
1099    {
1100        images.push_back(readRaw(sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents, endian, raw_filename));
1101    }
1102
1103    int images_pos = arguments.find("--images");
1104    if (images_pos>=0)
1105    {
1106        ImageList imageList;
1107        int pos=images_pos+1;
1108        for(;pos<arguments.argc() && !arguments.isOption(pos);++pos)
1109        {
1110            // not an option so assume string is a filename.
1111            osg::Image *image = osgDB::readImageFile( arguments[pos]);
1112
1113            if(image)
1114            {
1115                imageList.push_back(image);
1116            }
1117        }
1118       
1119        arguments.remove(images_pos, pos-images_pos);
1120       
1121        // pack the textures into a single texture.
1122        ProcessRow processRow;
1123        images.push_back(createTexture3D(imageList, processRow, numComponentsDesired, s_maximumTextureSize, t_maximumTextureSize, r_maximumTextureSize, resizeToPowerOfTwo));
1124    }
1125
1126
1127    // any option left unread are converted into errors to write out later.
1128    arguments.reportRemainingOptionsAsUnrecognized();
1129
1130    // report any errors if they have occurred when parsing the program arguments.
1131    if (arguments.errors())
1132    {
1133        arguments.writeErrorMessages(std::cout);
1134        return 1;
1135    }
1136   
1137
1138    // assume remaining arguments are file names of textures.
1139    for(int pos=1;pos<arguments.argc();++pos)
1140    {
1141        if (!arguments.isOption(pos))
1142        {
1143            std::string filename = arguments[pos];
1144            if (osgDB::getLowerCaseFileExtension(filename)=="dicom")
1145            {
1146                // not an option so assume string is a filename.
1147                osg::Image *image = osgDB::readImageFile(filename);
1148                if(image)
1149                {
1150                    images.push_back(image);
1151                }
1152            }
1153            else
1154            {
1155                osgDB::FileType fileType = osgDB::fileType(filename);
1156                if (fileType == osgDB::FILE_NOT_FOUND)
1157                {
1158                    filename = osgDB::findDataFile(filename);
1159                    fileType = osgDB::fileType(filename);
1160                }
1161
1162                if (fileType == osgDB::DIRECTORY)
1163                {
1164                   osg::Image *image = osgDB::readImageFile(filename+".dicom");
1165                    if(image)
1166                    {
1167                        images.push_back(image);
1168                    }
1169                }
1170                else if (fileType == osgDB::REGULAR_FILE)
1171                {
1172                    // not an option so assume string is a filename.
1173                    images.push_back(osgDB::readImageFile( filename ));
1174                }
1175                else
1176                {
1177                    osg::notify(osg::NOTICE)<<"Error: could not find file: "<<filename<<std::endl;
1178                    return 1;
1179                }
1180            }           
1181        }
1182    }
1183   
1184    if (images.empty())
1185    {
1186        std::cout<<"No model loaded, please specify and volumetric image file on the command line."<<std::endl;
1187        return 1;
1188    }
1189
1190
1191    Images::iterator sizeItr = images.begin();
1192    int image_s = (*sizeItr)->s();
1193    int image_t = (*sizeItr)->t();
1194    int image_r = (*sizeItr)->r();
1195    ++sizeItr;
1196
1197    for(;sizeItr != images.end(); ++sizeItr)
1198    {
1199        if ((*sizeItr)->s() != image_s ||
1200            (*sizeItr)->t() != image_t ||
1201            (*sizeItr)->r() != image_r)
1202        {
1203            std::cout<<"Images in sequence are not of the same dimensions."<<std::endl;
1204            return 1;
1205        }
1206    }
1207
1208
1209    osg::ref_ptr<osg::RefMatrix> matrix = dynamic_cast<osg::RefMatrix*>(images.front()->getUserData());
1210
1211    if (!matrix)
1212    {
1213        if (xSize==0.0) xSize = static_cast<float>(image_s);
1214        if (ySize==0.0) ySize = static_cast<float>(image_t);
1215        if (zSize==0.0) zSize = static_cast<float>(image_r);
1216       
1217        matrix = new osg::RefMatrix(xSize, 0.0,   0.0,   0.0,
1218                                    0.0,   ySize, 0.0,   0.0,
1219                                    0.0,   0.0,   zSize, 0.0,
1220                                    0.0,   0.0,   0.0,   1.0);
1221    }
1222
1223    osg::Vec4 minValue(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);
1224    osg::Vec4 maxValue(-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX);
1225    bool computeMinMax = false;
1226    for(Images::iterator itr = images.begin();
1227        itr != images.end();
1228        ++itr)
1229    {
1230        osg::Vec4 localMinValue, localMaxValue;
1231        if (osg::computeMinMax(itr->get(), localMinValue, localMaxValue))
1232        {
1233            if (localMinValue.r()<minValue.r()) minValue.r() = localMinValue.r();
1234            if (localMinValue.g()<minValue.g()) minValue.g() = localMinValue.g();
1235            if (localMinValue.b()<minValue.b()) minValue.b() = localMinValue.b();
1236            if (localMinValue.a()<minValue.a()) minValue.a() = localMinValue.a();
1237
1238            if (localMaxValue.r()>maxValue.r()) maxValue.r() = localMaxValue.r();
1239            if (localMaxValue.g()>maxValue.g()) maxValue.g() = localMaxValue.g();
1240            if (localMaxValue.b()>maxValue.b()) maxValue.b() = localMaxValue.b();
1241            if (localMaxValue.a()>maxValue.a()) maxValue.a() = localMaxValue.a();
1242
1243            osg::notify(osg::NOTICE)<<"  ("<<localMinValue<<") ("<<localMaxValue<<") "<<(*itr)->getFileName()<<std::endl;
1244
1245            computeMinMax = true;
1246        }
1247    }
1248   
1249    if (computeMinMax)
1250    {
1251        osg::notify(osg::NOTICE)<<"Min value "<<minValue<<std::endl;
1252        osg::notify(osg::NOTICE)<<"Max value "<<maxValue<<std::endl;
1253
1254        float minComponent = minValue[0];
1255        minComponent = osg::minimum(minComponent,minValue[1]);
1256        minComponent = osg::minimum(minComponent,minValue[2]);
1257        minComponent = osg::minimum(minComponent,minValue[3]);
1258
1259        float maxComponent = maxValue[0];
1260        maxComponent = osg::maximum(maxComponent,maxValue[1]);
1261        maxComponent = osg::maximum(maxComponent,maxValue[2]);
1262        maxComponent = osg::maximum(maxComponent,maxValue[3]);
1263
1264
1265        switch(rescaleOperation)
1266        {
1267            case(NO_RESCALE):
1268                break;
1269
1270            case(RESCALE_TO_ZERO_TO_ONE_RANGE):
1271            {
1272                float scale = 0.99f/(maxComponent-minComponent);
1273                float offset = -minComponent * scale;
1274
1275                for(Images::iterator itr = images.begin();
1276                    itr != images.end();
1277                    ++itr)
1278                {       
1279                    osg::offsetAndScaleImage(itr->get(),
1280                        osg::Vec4(offset, offset, offset, offset),
1281                        osg::Vec4(scale, scale, scale, scale));
1282                }
1283                break;
1284            }
1285            case(SHIFT_MIN_TO_ZERO):
1286            {
1287                float offset = -minComponent;
1288
1289                for(Images::iterator itr = images.begin();
1290                    itr != images.end();
1291                    ++itr)
1292                {       
1293                    osg::offsetAndScaleImage(itr->get(),
1294                        osg::Vec4(offset, offset, offset, offset),
1295                        osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
1296                }
1297                break;
1298            }
1299        };
1300
1301    }
1302
1303   
1304    if (colourSpaceOperation!=NO_COLOUR_SPACE_OPERATION)
1305    {
1306        for(Images::iterator itr = images.begin();
1307            itr != images.end();
1308            ++itr)
1309        {       
1310            (*itr) = doColourSpaceConversion(colourSpaceOperation, itr->get(), colourModulate);
1311        }
1312    }
1313   
1314    if (!gpuTransferFunction && transferFunction.valid())
1315    {
1316        for(Images::iterator itr = images.begin();
1317            itr != images.end();
1318            ++itr)
1319        {       
1320            *itr = osgVolume::applyTransferFunction(itr->get(), transferFunction.get());
1321        }
1322    }
1323   
1324    osg::ref_ptr<osg::Image> image_3d = 0;
1325
1326    if (images.size()==1)
1327    {
1328        osg::notify(osg::NOTICE)<<"Single image "<<images.size()<<" volumes."<<std::endl;
1329        image_3d = images.front();
1330    }
1331    else
1332    {
1333        osg::notify(osg::NOTICE)<<"Creating sequence of "<<images.size()<<" volumes."<<std::endl;
1334   
1335        osg::ref_ptr<osg::ImageSequence> imageSequence = new osg::ImageSequence;
1336        imageSequence->setLength(sequenceLength);
1337        image_3d = imageSequence.get();
1338        for(Images::iterator itr = images.begin();
1339            itr != images.end();
1340            ++itr)
1341        {       
1342            imageSequence->addImage(itr->get());
1343        }
1344        imageSequence->play();
1345    }
1346   
1347    osg::ref_ptr<osgVolume::Volume> volume = new osgVolume::Volume;
1348    osg::ref_ptr<osgVolume::VolumeTile> tile = new osgVolume::VolumeTile;
1349    volume->addChild(tile.get());
1350
1351    osg::ref_ptr<osgVolume::Layer> layer = new osgVolume::ImageLayer(image_3d.get());
1352
1353    layer->setLocator(new osgVolume::Locator(*matrix));
1354    tile->setLocator(new osgVolume::Locator(*matrix));
1355
1356    tile->setLayer(layer.get());
1357
1358    tile->setEventCallback(new osgVolume::PropertyAdjustmentCallback());
1359
1360    if (useShader)
1361    {
1362
1363        osgVolume::SwitchProperty* sp = new osgVolume::SwitchProperty;
1364        sp->setActiveProperty(0);
1365
1366        osgVolume::AlphaFuncProperty* ap = new osgVolume::AlphaFuncProperty(alphaFunc);
1367        osgVolume::SampleDensityProperty* sd = new osgVolume::SampleDensityProperty(0.005);
1368        osgVolume::TransparencyProperty* tp = new osgVolume::TransparencyProperty(1.0);
1369        osgVolume::TransferFunctionProperty* tfp = transferFunction.valid() ? new osgVolume::TransferFunctionProperty(transferFunction.get()) : 0;
1370
1371        {
1372            // Standard
1373            osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1374            cp->addProperty(ap);
1375            cp->addProperty(sd);
1376            cp->addProperty(tp);
1377            if (tfp) cp->addProperty(tfp);
1378
1379            sp->addProperty(cp);
1380        }
1381
1382        {
1383            // Light
1384            osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1385            cp->addProperty(ap);
1386            cp->addProperty(sd);
1387            cp->addProperty(tp);
1388            cp->addProperty(new osgVolume::LightingProperty);
1389            if (tfp) cp->addProperty(tfp);
1390
1391            sp->addProperty(cp);
1392        }
1393
1394        {
1395            // Isosurface
1396            osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1397            cp->addProperty(sd);
1398            cp->addProperty(tp);
1399            cp->addProperty(new osgVolume::IsoSurfaceProperty(alphaFunc));
1400            if (tfp) cp->addProperty(tfp);
1401
1402            sp->addProperty(cp);
1403        }
1404
1405        {
1406            // MaximumIntensityProjection
1407            osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1408            cp->addProperty(ap);
1409            cp->addProperty(sd);
1410            cp->addProperty(tp);
1411            cp->addProperty(new osgVolume::MaximumIntensityProjectionProperty);
1412            if (tfp) cp->addProperty(tfp);
1413
1414            sp->addProperty(cp);
1415        }
1416
1417        switch(shadingModel)
1418        {
1419            case(Standard):                     sp->setActiveProperty(0); break;
1420            case(Light):                        sp->setActiveProperty(1); break;
1421            case(Isosurface):                   sp->setActiveProperty(2); break;
1422            case(MaximumIntensityProjection):   sp->setActiveProperty(3); break;
1423        }
1424        layer->addProperty(sp);
1425
1426
1427        tile->setVolumeTechnique(new osgVolume::RayTracedTechnique);
1428    }
1429    else
1430    {
1431        layer->addProperty(new osgVolume::AlphaFuncProperty(alphaFunc));
1432        tile->setVolumeTechnique(new osgVolume::FixedFunctionTechnique);
1433    }
1434       
1435    if (!outputFile.empty())
1436    {   
1437        std::string ext = osgDB::getFileExtension(outputFile);
1438        std::string name_no_ext = osgDB::getNameLessExtension(outputFile);
1439        if (ext=="osg")
1440        {
1441            if (image_3d.valid())
1442            {
1443                image_3d->setFileName(name_no_ext + ".dds");           
1444                osgDB::writeImageFile(*image_3d, image_3d->getFileName());
1445            }
1446            osgDB::writeNodeFile(*volume, outputFile);
1447        }
1448        else if (ext=="ive")
1449        {
1450            osgDB::writeNodeFile(*volume, outputFile);       
1451        }
1452        else if (ext=="dds")
1453        {
1454            osgDB::writeImageFile(*image_3d, outputFile);
1455        }
1456        else
1457        {
1458            std::cout<<"Extension not support for file output, not file written."<<std::endl;
1459        }
1460       
1461        return 0;
1462    }
1463
1464    if (volume.valid())
1465    {
1466
1467        osg::ref_ptr<osg::Node> loadedModel = volume.get();
1468
1469        if (useManipulator)
1470        {
1471            osg::ref_ptr<osg::Group> group = new osg::Group;
1472
1473#if 1
1474            osg::ref_ptr<osgManipulator::Dragger> dragger = new osgManipulator::TabBoxDragger;
1475#else
1476            osg::ref_ptr<osgManipulator::Dragger> dragger = new osgManipulator::TrackballDragger();
1477#endif
1478            dragger->setupDefaultGeometry();
1479            dragger->setHandleEvents(true);
1480            dragger->setActivationModKeyMask(osgGA::GUIEventAdapter::MODKEY_SHIFT);
1481            dragger->addDraggerCallback(new DraggerVolumeTileCallback(tile.get(), tile->getLocator()));
1482            dragger->setMatrix(osg::Matrix::translate(0.5,0.5,0.5)*tile->getLocator()->getTransform());
1483
1484
1485            group->addChild(dragger.get());
1486
1487            //dragger->addChild(volume.get());
1488
1489            group->addChild(volume.get());
1490
1491            loadedModel = group;
1492        }
1493
1494
1495        // set the scene to render
1496        viewer.setSceneData(loadedModel.get());
1497       
1498        // the the viewers main frame loop
1499        viewer.run();
1500    }   
1501   
1502    return 0;
1503
1504}
Note: See TracBrowser for help on using the browser.