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

Revision 13923, 44.6 kB (checked in by robert, 16 hours ago)

Changed the osgUI behaviour so that events are set to be handled by Widgets that have focus even if they don't directly use them.

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