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

Revision 12835, 45.3 kB (checked in by robert, 20 months ago)

Fixed typo in command line output, and add an explanation message for when createTexture3D fails to create an osg::Image from a list of input osg::Image.

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