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

Revision 13949, 45.8 kB (checked in by robert, 12 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#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    double sampleRatioWhenMoving = 0.0;
668    while(arguments.read("--srwm", sampleRatioWhenMoving)) {}
669
670    while(arguments.read("--lod")) { sampleDensityWhenMoving = 0.02; }
671
672    double sequenceLength = 10.0;
673    while(arguments.read("--sequence-duration", sequenceLength) ||
674          arguments.read("--sd", sequenceLength)) {}
675
676    typedef std::list< osg::ref_ptr<osg::Image> > Images;
677    Images images;
678
679
680    std::string vh_filename;
681    while (arguments.read("--vh", vh_filename))
682    {
683        std::string raw_filename, transfer_filename;
684        int xdim(0), ydim(0), zdim(0);
685
686        osgDB::ifstream header(vh_filename.c_str());
687        if (header)
688        {
689            header >> raw_filename >> transfer_filename >> xdim >> ydim >> zdim >> xSize >> ySize >> zSize;
690        }
691
692        if (xdim*ydim*zdim==0)
693        {
694            std::cout<<"Error in reading volume header "<<vh_filename<<std::endl;
695            return 1;
696        }
697
698        if (!raw_filename.empty())
699        {
700            images.push_back(readRaw(xdim, ydim, zdim, 1, 1, "little", raw_filename));
701        }
702
703        if (!transfer_filename.empty())
704        {
705            osgDB::ifstream fin(transfer_filename.c_str());
706            if (fin)
707            {
708                osg::TransferFunction1D::ColorMap colorMap;
709                float value = 0.0;
710                while(fin && value<=1.0)
711                {
712                    float red, green, blue, alpha;
713                    fin >> red >> green >> blue >> alpha;
714                    if (fin)
715                    {
716                        colorMap[value] = osg::Vec4(red/255.0f,green/255.0f,blue/255.0f,alpha/255.0f);
717                        std::cout<<"value = "<<value<<" ("<<red<<", "<<green<<", "<<blue<<", "<<alpha<<")";
718                        std::cout<<"  ("<<colorMap[value]<<")"<<std::endl;
719                    }
720                    value += 1/255.0;
721                }
722
723                if (colorMap.empty())
724                {
725                    std::cout<<"Error: No values read from transfer function file: "<<transfer_filename<<std::endl;
726                    return 0;
727                }
728
729                transferFunction = new osg::TransferFunction1D;
730                transferFunction->assign(colorMap);
731            }
732        }
733
734    }
735
736
737    int sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents;
738    std::string endian, raw_filename;
739    while (arguments.read("--raw", sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents, endian, raw_filename))
740    {
741        images.push_back(readRaw(sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents, endian, raw_filename));
742    }
743
744    int images_pos = arguments.find("--images");
745    if (images_pos>=0)
746    {
747        osg::ImageList imageList;
748        int pos=images_pos+1;
749        for(;pos<arguments.argc() && !arguments.isOption(pos);++pos)
750        {
751            std::string arg(arguments[pos]);
752            if (arg.find('*') != std::string::npos)
753            {
754                osgDB::DirectoryContents contents = osgDB::expandWildcardsInFilename(arg);
755                for (unsigned int i = 0; i < contents.size(); ++i)
756                {
757                    osg::Image *image = osgDB::readImageFile( contents[i] );
758
759                    if(image)
760                    {
761                        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;
762                        imageList.push_back(image);
763                    }
764                }
765            }
766            else
767            {
768                // not an option so assume string is a filename.
769                osg::Image *image = osgDB::readImageFile( arguments[pos] );
770
771                if(image)
772                {
773                    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;
774                    imageList.push_back(image);
775                }
776            }
777        }
778
779        arguments.remove(images_pos, pos-images_pos);
780
781        // pack the textures into a single texture.
782        osg::Image* image = createTexture3D(imageList, numComponentsDesired, s_maximumTextureSize, t_maximumTextureSize, r_maximumTextureSize, resizeToPowerOfTwo);
783        if (image)
784        {
785            images.push_back(image);
786        }
787        else
788        {
789            OSG_NOTICE<<"Unable to create 3D image from source files."<<std::endl;
790        }
791    }
792
793
794    // any option left unread are converted into errors to write out later.
795    arguments.reportRemainingOptionsAsUnrecognized();
796
797    // report any errors if they have occurred when parsing the program arguments.
798    if (arguments.errors())
799    {
800        arguments.writeErrorMessages(std::cout);
801        return 1;
802    }
803
804
805    // assume remaining arguments are file names of textures.
806    for(int pos=1;pos<arguments.argc();++pos)
807    {
808        if (!arguments.isOption(pos))
809        {
810            std::string filename = arguments[pos];
811            if (osgDB::getLowerCaseFileExtension(filename)=="dicom")
812            {
813                // not an option so assume string is a filename.
814                osg::Image* image = osgDB::readImageFile(filename);
815                if (image)
816                {
817                    images.push_back(image);
818                }
819            }
820            else
821            {
822                osgDB::FileType fileType = osgDB::fileType(filename);
823                if (fileType == osgDB::FILE_NOT_FOUND)
824                {
825                    filename = osgDB::findDataFile(filename);
826                    fileType = osgDB::fileType(filename);
827                }
828
829                if (fileType == osgDB::DIRECTORY)
830                {
831                    osg::Image* image = osgDB::readImageFile(filename+".dicom");
832                    if (image) images.push_back(image);
833                }
834                else if (fileType == osgDB::REGULAR_FILE)
835                {
836                    // not an option so assume string is a filename.
837                    osg::Image* image = osgDB::readImageFile( filename );
838                    if (image) images.push_back(image);
839                }
840                else
841                {
842                    osg::notify(osg::NOTICE)<<"Error: could not find file: "<<filename<<std::endl;
843                    return 1;
844                }
845            }
846        }
847    }
848
849    if (images.empty())
850    {
851        std::cout<<"No model loaded, please specify a volumetric image file on the command line."<<std::endl;
852        return 1;
853    }
854
855
856    Images::iterator sizeItr = images.begin();
857    int image_s = (*sizeItr)->s();
858    int image_t = (*sizeItr)->t();
859    int image_r = (*sizeItr)->r();
860    ++sizeItr;
861
862    for(;sizeItr != images.end(); ++sizeItr)
863    {
864        if ((*sizeItr)->s() != image_s ||
865            (*sizeItr)->t() != image_t ||
866            (*sizeItr)->r() != image_r)
867        {
868            std::cout<<"Images in sequence are not of the same dimensions."<<std::endl;
869            return 1;
870        }
871    }
872
873
874    osg::ref_ptr<osgVolume::ImageDetails> details = dynamic_cast<osgVolume::ImageDetails*>(images.front()->getUserData());
875    osg::ref_ptr<osg::RefMatrix> matrix = details ? details->getMatrix() : dynamic_cast<osg::RefMatrix*>(images.front()->getUserData());
876
877    if (!matrix)
878    {
879        if (xSize==0.0) xSize = static_cast<float>(image_s);
880        if (ySize==0.0) ySize = static_cast<float>(image_t);
881        if (zSize==0.0) zSize = static_cast<float>(image_r);
882
883        matrix = new osg::RefMatrix(xSize, 0.0,   0.0,   0.0,
884                                    0.0,   ySize, 0.0,   0.0,
885                                    0.0,   0.0,   zSize, 0.0,
886                                    0.0,   0.0,   0.0,   1.0);
887    }
888
889
890    if (xMultiplier!=1.0 || yMultiplier!=1.0 || zMultiplier!=1.0)
891    {
892        matrix->postMultScale(osg::Vec3d(fabs(xMultiplier), fabs(yMultiplier), fabs(zMultiplier)));
893    }
894
895    osg::Vec4 minValue(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);
896    osg::Vec4 maxValue(-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX);
897    bool computeMinMax = false;
898    for(Images::iterator itr = images.begin();
899        itr != images.end();
900        ++itr)
901    {
902        osg::Vec4 localMinValue, localMaxValue;
903        if (osg::computeMinMax(itr->get(), localMinValue, localMaxValue))
904        {
905            if (localMinValue.r()<minValue.r()) minValue.r() = localMinValue.r();
906            if (localMinValue.g()<minValue.g()) minValue.g() = localMinValue.g();
907            if (localMinValue.b()<minValue.b()) minValue.b() = localMinValue.b();
908            if (localMinValue.a()<minValue.a()) minValue.a() = localMinValue.a();
909
910            if (localMaxValue.r()>maxValue.r()) maxValue.r() = localMaxValue.r();
911            if (localMaxValue.g()>maxValue.g()) maxValue.g() = localMaxValue.g();
912            if (localMaxValue.b()>maxValue.b()) maxValue.b() = localMaxValue.b();
913            if (localMaxValue.a()>maxValue.a()) maxValue.a() = localMaxValue.a();
914
915            osg::notify(osg::NOTICE)<<"  ("<<localMinValue<<") ("<<localMaxValue<<") "<<(*itr)->getFileName()<<std::endl;
916
917            computeMinMax = true;
918        }
919    }
920
921    if (computeMinMax)
922    {
923        osg::notify(osg::NOTICE)<<"Min value "<<minValue<<std::endl;
924        osg::notify(osg::NOTICE)<<"Max value "<<maxValue<<std::endl;
925
926        float minComponent = minValue[0];
927        minComponent = osg::minimum(minComponent,minValue[1]);
928        minComponent = osg::minimum(minComponent,minValue[2]);
929        minComponent = osg::minimum(minComponent,minValue[3]);
930
931        float maxComponent = maxValue[0];
932        maxComponent = osg::maximum(maxComponent,maxValue[1]);
933        maxComponent = osg::maximum(maxComponent,maxValue[2]);
934        maxComponent = osg::maximum(maxComponent,maxValue[3]);
935
936#if 0
937        switch(rescaleOperation)
938        {
939            case(NO_RESCALE):
940                break;
941
942            case(RESCALE_TO_ZERO_TO_ONE_RANGE):
943            {
944                float scale = 0.99f/(maxComponent-minComponent);
945                float offset = -minComponent * scale;
946
947                for(Images::iterator itr = images.begin();
948                    itr != images.end();
949                    ++itr)
950                {
951                    osg::offsetAndScaleImage(itr->get(),
952                        osg::Vec4(offset, offset, offset, offset),
953                        osg::Vec4(scale, scale, scale, scale));
954                }
955                break;
956            }
957            case(SHIFT_MIN_TO_ZERO):
958            {
959                float offset = -minComponent;
960
961                for(Images::iterator itr = images.begin();
962                    itr != images.end();
963                    ++itr)
964                {
965                    osg::offsetAndScaleImage(itr->get(),
966                        osg::Vec4(offset, offset, offset, offset),
967                        osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
968                }
969                break;
970            }
971        };
972#endif
973    }
974
975
976    if (colourSpaceOperation!=osg::NO_COLOR_SPACE_OPERATION)
977    {
978        for(Images::iterator itr = images.begin();
979            itr != images.end();
980            ++itr)
981        {
982            (*itr) = osg::colorSpaceConversion(colourSpaceOperation, itr->get(), colourModulate);
983        }
984    }
985
986    if (!gpuTransferFunction && transferFunction.valid())
987    {
988        for(Images::iterator itr = images.begin();
989            itr != images.end();
990            ++itr)
991        {
992            *itr = osgVolume::applyTransferFunction(itr->get(), transferFunction.get());
993        }
994    }
995
996    osg::ref_ptr<osg::Image> image_3d = 0;
997
998    if (images.size()==1)
999    {
1000        osg::notify(osg::NOTICE)<<"Single image "<<images.size()<<" volumes."<<std::endl;
1001        image_3d = images.front();
1002    }
1003    else
1004    {
1005        osg::notify(osg::NOTICE)<<"Creating sequence of "<<images.size()<<" volumes."<<std::endl;
1006
1007        osg::ref_ptr<osg::ImageSequence> imageSequence = new osg::ImageSequence;
1008        imageSequence->setLength(sequenceLength);
1009        image_3d = imageSequence.get();
1010        for(Images::iterator itr = images.begin();
1011            itr != images.end();
1012            ++itr)
1013        {
1014            imageSequence->addImage(itr->get());
1015        }
1016        imageSequence->play();
1017    }
1018
1019    osg::ref_ptr<osgVolume::Volume> volume = new osgVolume::Volume;
1020    osg::ref_ptr<osgVolume::VolumeTile> tile = new osgVolume::VolumeTile;
1021    volume->addChild(tile.get());
1022
1023    osg::ref_ptr<osgVolume::ImageLayer> layer = new osgVolume::ImageLayer(image_3d.get());
1024
1025    if (details)
1026    {
1027        layer->setTexelOffset(details->getTexelOffset());
1028        layer->setTexelScale(details->getTexelScale());
1029    }
1030
1031    switch(rescaleOperation)
1032    {
1033        case(NO_RESCALE):
1034            break;
1035
1036        case(RESCALE_TO_ZERO_TO_ONE_RANGE):
1037        {
1038            layer->rescaleToZeroToOneRange();
1039            break;
1040        }
1041        case(SHIFT_MIN_TO_ZERO):
1042        {
1043            layer->translateMinToZero();
1044            break;
1045        }
1046    };
1047
1048    if (xMultiplier<0.0 || yMultiplier<0.0 || zMultiplier<0.0)
1049    {
1050        layer->setLocator(new osgVolume::Locator(
1051            osg::Matrix::translate(xMultiplier<0.0 ? -1.0 : 0.0, yMultiplier<0.0 ? -1.0 : 0.0, zMultiplier<0.0 ? -1.0 : 0.0) *
1052            osg::Matrix::scale(xMultiplier<0.0 ? -1.0 : 1.0, yMultiplier<0.0 ? -1.0 : 1.0, zMultiplier<0.0 ? -1.0 : 1.0) *
1053            (*matrix)
1054            ));;
1055    }
1056    else
1057    {
1058        layer->setLocator(new osgVolume::Locator(*matrix));
1059    }
1060    tile->setLocator(new osgVolume::Locator(*matrix));
1061
1062    tile->setLayer(layer.get());
1063
1064    tile->setEventCallback(new osgVolume::PropertyAdjustmentCallback());
1065
1066    if (useShader)
1067    {
1068
1069        osgVolume::SwitchProperty* sp = new osgVolume::SwitchProperty;
1070        sp->setActiveProperty(0);
1071
1072        osgVolume::AlphaFuncProperty* ap = new osgVolume::AlphaFuncProperty(alphaFunc);
1073        osgVolume::IsoSurfaceProperty* isop = new osgVolume::IsoSurfaceProperty(alphaFunc);
1074
1075        // SampleDensity is now deprecated
1076        osgVolume::SampleDensityProperty* sd = new osgVolume::SampleDensityProperty(0.005f);
1077        osgVolume::SampleDensityWhenMovingProperty* sdwm = sampleDensityWhenMoving!=0.0 ? new osgVolume::SampleDensityWhenMovingProperty(sampleDensityWhenMoving) : 0;
1078
1079        // use SampleRatio in place of SampleDensity
1080        osgVolume::SampleRatioProperty* sr = new osgVolume::SampleRatioProperty(1.0f);
1081        osgVolume::SampleRatioWhenMovingProperty* srwm = sampleRatioWhenMoving!=0.0 ? new osgVolume::SampleRatioWhenMovingProperty(sampleRatioWhenMoving) : 0;
1082
1083        osgVolume::TransparencyProperty* tp = new osgVolume::TransparencyProperty(1.0);
1084        osgVolume::TransferFunctionProperty* tfp = transferFunction.valid() ? new osgVolume::TransferFunctionProperty(transferFunction.get()) : 0;
1085
1086        {
1087            // Standard
1088            osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1089            cp->addProperty(ap);
1090            if (useMultipass)
1091            {
1092                cp->addProperty(sr);
1093                if (srwm) cp->addProperty(srwm);
1094            }
1095            else
1096            {
1097                cp->addProperty(sd);
1098                if (sdwm) cp->addProperty(sdwm);
1099            }
1100            cp->addProperty(tp);
1101
1102            if (tfp)
1103            {
1104                OSG_NOTICE<<"Adding TransferFunction"<<std::endl;
1105                cp->addProperty(tfp);
1106            }
1107
1108            sp->addProperty(cp);
1109        }
1110
1111        {
1112            // Light
1113            osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1114            cp->addProperty(ap);
1115            if (useMultipass) cp->addProperty(sr);
1116            else cp->addProperty(sd);
1117            cp->addProperty(tp);
1118            cp->addProperty(new osgVolume::LightingProperty);
1119            if (sdwm) cp->addProperty(sdwm);
1120            if (tfp) cp->addProperty(tfp);
1121
1122            sp->addProperty(cp);
1123        }
1124
1125        {
1126            // Isosurface
1127            osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1128            if (useMultipass) cp->addProperty(sr);
1129            else cp->addProperty(sd);
1130            cp->addProperty(tp);
1131            cp->addProperty(isop);
1132            if (sdwm) cp->addProperty(sdwm);
1133            if (tfp) cp->addProperty(tfp);
1134
1135            sp->addProperty(cp);
1136        }
1137
1138        {
1139            // MaximumIntensityProjection
1140            osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1141            cp->addProperty(ap);
1142
1143            if (useMultipass) cp->addProperty(sr);
1144            else cp->addProperty(sd);
1145
1146            cp->addProperty(tp);
1147            cp->addProperty(new osgVolume::MaximumIntensityProjectionProperty);
1148            if (sdwm) cp->addProperty(sdwm);
1149            if (tfp) cp->addProperty(tfp);
1150
1151            sp->addProperty(cp);
1152        }
1153
1154        switch(shadingModel)
1155        {
1156            case(Standard):                     sp->setActiveProperty(0); break;
1157            case(Light):                        sp->setActiveProperty(1); break;
1158            case(Isosurface):                   sp->setActiveProperty(2); break;
1159            case(MaximumIntensityProjection):   sp->setActiveProperty(3); break;
1160        }
1161        layer->addProperty(sp);
1162
1163
1164        if (useMultipass)
1165        {
1166            tile->setVolumeTechnique(new osgVolume::MultipassTechnique);
1167        }
1168        else
1169        {
1170            tile->setVolumeTechnique(new osgVolume::RayTracedTechnique);
1171        }
1172    }
1173    else
1174    {
1175        layer->addProperty(new osgVolume::AlphaFuncProperty(alphaFunc));
1176        tile->setVolumeTechnique(new osgVolume::FixedFunctionTechnique);
1177    }
1178
1179    if (!outputFile.empty())
1180    {
1181        std::string ext = osgDB::getFileExtension(outputFile);
1182        std::string name_no_ext = osgDB::getNameLessExtension(outputFile);
1183        if (ext=="osg" || ext=="osgt" || ext=="osgx" )
1184        {
1185            if (image_3d.valid())
1186            {
1187                image_3d->setFileName(name_no_ext + ".dds");
1188                osgDB::writeImageFile(*image_3d, image_3d->getFileName());
1189            }
1190            osgDB::writeNodeFile(*volume, outputFile);
1191        }
1192        else if (ext=="ive" || ext=="osgb" )
1193        {
1194            osgDB::writeNodeFile(*volume, outputFile);
1195        }
1196        else if (ext=="dds")
1197        {
1198            osgDB::writeImageFile(*image_3d, outputFile);
1199        }
1200        else
1201        {
1202            std::cout<<"Extension not support for file output, not file written."<<std::endl;
1203        }
1204
1205        return 0;
1206    }
1207
1208    if (volume.valid())
1209    {
1210
1211        osg::ref_ptr<osg::Node> loadedModel = volume.get();
1212
1213        if (useManipulator)
1214        {
1215            osg::ref_ptr<osg::Group> group = new osg::Group;
1216
1217#if 1
1218            osg::ref_ptr<osgManipulator::Dragger> dragger = new osgManipulator::TabBoxDragger;
1219#else
1220            osg::ref_ptr<osgManipulator::Dragger> dragger = new osgManipulator::TrackballDragger();
1221#endif
1222            dragger->setupDefaultGeometry();
1223            dragger->setHandleEvents(true);
1224            dragger->setActivationModKeyMask(osgGA::GUIEventAdapter::MODKEY_SHIFT);
1225            dragger->addDraggerCallback(new DraggerVolumeTileCallback(tile.get(), tile->getLocator()));
1226            dragger->setMatrix(osg::Matrix::translate(0.5,0.5,0.5)*tile->getLocator()->getTransform());
1227
1228
1229            group->addChild(dragger.get());
1230
1231            //dragger->addChild(volume.get());
1232
1233            group->addChild(volume.get());
1234
1235            loadedModel = group;
1236        }
1237
1238        if (hulls.get())
1239        {
1240            tile->addChild(hulls.get());
1241        }
1242
1243        // add add models into the scene alongside the volume
1244        if (models.get())
1245        {
1246            osg::ref_ptr<osg::Group> group = new osg::Group;
1247            group->addChild(models.get());
1248            group->addChild(loadedModel.get());
1249            loadedModel = group.get();
1250        }
1251
1252        // if we want to do multi-pass volume rendering we need decorate the whole scene with a VolumeScene node.
1253        if (useMultipass)
1254        {
1255            osg::ref_ptr<osgVolume::VolumeScene> volumeScene = new osgVolume::VolumeScene;
1256            volumeScene->addChild(loadedModel.get());
1257            loadedModel->getOrCreateStateSet();
1258            loadedModel = volumeScene.get();
1259        }
1260
1261
1262
1263        // set the scene to render
1264        viewer.setSceneData(loadedModel.get());
1265
1266        // the the viewers main frame loop
1267        viewer.run();
1268    }
1269
1270    return 0;
1271}
Note: See TracBrowser for help on using the browser.