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

Revision 9514, 52.2 kB (checked in by robert, 5 years ago)

Added event key variables

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