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

Revision 13944, 45.4 kB (checked in by robert, 17 hours ago)

From Jason Beverage, "It looks like the Callback header got accidentally removed from the CMakeLists.txt in the submission yesterday for the geometry instancing example."

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