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

Revision 8802, 71.4 kB (checked in by robert, 6 years ago)

Improved the GLSL implementation.

  • 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/TexGen>
24#include <osg/Geode>
25#include <osg/Billboard>
26#include <osg/PositionAttitudeTransform>
27#include <osg/ClipNode>
28#include <osg/AlphaFunc>
29#include <osg/TexGenNode>
30#include <osg/TexEnv>
31#include <osg/TexEnvCombine>
32#include <osg/Material>
33#include <osg/PrimitiveSet>
34#include <osg/Endian>
35#include <osg/BlendFunc>
36#include <osg/BlendEquation>
37
38#include <osgDB/Registry>
39#include <osgDB/ReadFile>
40#include <osgDB/WriteFile>
41#include <osgDB/FileUtils>
42#include <osgDB/FileNameUtils>
43
44#include <osgGA/EventVisitor>
45
46#include <osgUtil/CullVisitor>
47
48#include <osgViewer/Viewer>
49#include <osgViewer/ViewerEventHandlers>
50
51#include <osg/io_utils>
52
53#include <iostream>
54
55
56typedef std::vector< osg::ref_ptr<osg::Image> > ImageList;
57
58//  example ReadOperator
59// struct ReadOperator
60// {
61//     inline void luminance(float l) const { rgba(l,l,l,1.0f); }
62//     inline void alpha(float a) const { rgba(1.0f,1.0f,1.0f,a); }
63//     inline void luminance_alpha(float l,float a) const { rgba(l,l,l,a); }
64//     inline void rgb(float r,float g,float b) const { rgba(r,g,b,1.0f); }
65//     inline void rgba(float r,float g,float b,float a) const { std::cout<<"pixel("<<r<<", "<<g<<", "<<b<<", "<<a<<")"<<std::endl; }
66// };
67
68
69template <typename T, class O>   
70void _readRow(unsigned int num, GLenum pixelFormat, T* data,float scale, const O& operation)
71{
72    switch(pixelFormat)
73    {
74        case(GL_LUMINANCE):         { for(unsigned int i=0;i<num;++i) { float l = float(*data++)*scale; operation.luminance(l); } }  break;
75        case(GL_ALPHA):             { for(unsigned int i=0;i<num;++i) { float a = float(*data++)*scale; operation.alpha(a); } }  break;
76        case(GL_LUMINANCE_ALPHA):   { for(unsigned int i=0;i<num;++i) { float l = float(*data++)*scale; float a = float(*data++)*scale; operation.luminance_alpha(l,a); } }  break;
77        case(GL_RGB):               { for(unsigned int i=0;i<num;++i) { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; operation.rgb(r,g,b); } }  break;
78        case(GL_RGBA):              { for(unsigned int i=0;i<num;++i) { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; float a = float(*data++)*scale; operation.rgba(r,g,b,a); } }  break;
79        case(GL_BGR):               { for(unsigned int i=0;i<num;++i) { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; operation.rgb(r,g,b); } }  break;
80        case(GL_BGRA):              { for(unsigned int i=0;i<num;++i) { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; float a = float(*data++)*scale; operation.rgba(r,g,b,a); } }  break;
81    }
82}
83
84template <class O>   
85void readRow(unsigned int num, GLenum pixelFormat, GLenum dataType, unsigned char* data, const O& operation)
86{
87    switch(dataType)
88    {
89        case(GL_BYTE):              _readRow(num,pixelFormat, (char*)data,            1.0f/128.0f,        operation); break;
90        case(GL_UNSIGNED_BYTE):     _readRow(num,pixelFormat, (unsigned char*)data,   1.0f/255.0f,        operation); break;
91        case(GL_SHORT):             _readRow(num,pixelFormat, (short*) data,          1.0f/32768.0f,      operation); break;
92        case(GL_UNSIGNED_SHORT):    _readRow(num,pixelFormat, (unsigned short*)data,  1.0f/65535.0f,      operation); break;
93        case(GL_INT):               _readRow(num,pixelFormat, (int*) data,            1.0f/2147483648.0f, operation); break;
94        case(GL_UNSIGNED_INT):      _readRow(num,pixelFormat, (unsigned int*) data,   1.0f/4294967295.0f, operation); break;
95        case(GL_FLOAT):             _readRow(num,pixelFormat, (float*) data,          1.0f,               operation); break;
96    }
97}
98
99template <class O>   
100void readImage(osg::Image* image, const O& operation)
101{
102    if (!image) return;
103   
104    for(int r=0;r<image->r();++r)
105    {
106        for(int t=0;t<image->t();++t)
107        {
108            readRow(image->s(), image->getPixelFormat(), image->getDataType(), image->data(0,t,r), operation);
109        }
110    }
111}
112
113//  example ModifyOperator
114// struct ModifyOperator
115// {
116//     inline void luminance(float& l) const {}
117//     inline void alpha(float& a) const {}
118//     inline void luminance_alpha(float& l,float& a) const {}
119//     inline void rgb(float& r,float& g,float& b) const {}
120//     inline void rgba(float& r,float& g,float& b,float& a) const {}
121// };
122
123
124template <typename T, class M>   
125void _modifyRow(unsigned int num, GLenum pixelFormat, T* data,float scale, const M& operation)
126{
127    float inv_scale = 1.0f/scale;
128    switch(pixelFormat)
129    {
130        case(GL_LUMINANCE):         { for(unsigned int i=0;i<num;++i) { float l = float(*data)*scale; operation.luminance(l); *data++ = T(l*inv_scale); } }  break;
131        case(GL_ALPHA):             { for(unsigned int i=0;i<num;++i) { float a = float(*data)*scale; operation.alpha(a); *data++ = T(a*inv_scale); } }  break;
132        case(GL_LUMINANCE_ALPHA):   { for(unsigned int i=0;i<num;++i) { float l = float(*data)*scale; float a = float(*(data+1))*scale; operation.luminance_alpha(l,a); *data++ = T(l*inv_scale); *data++ = T(a*inv_scale); } }  break;
133        case(GL_RGB):               { for(unsigned int i=0;i<num;++i) { float r = float(*data)*scale; float g = float(*(data+1))*scale; float b = float(*(data+2))*scale; operation.rgb(r,g,b); *data++ = T(r*inv_scale); *data++ = T(g*inv_scale); *data++ = T(b*inv_scale); } }  break;
134        case(GL_RGBA):              { for(unsigned int i=0;i<num;++i) { float r = float(*data)*scale; float g = float(*(data+1))*scale; float b = float(*(data+2))*scale; float a = float(*(data+3))*scale; operation.rgba(r,g,b,a); *data++ = T(r*inv_scale); *data++ = T(g*inv_scale); *data++ = T(g*inv_scale); *data++ = T(a*inv_scale); } }  break;
135        case(GL_BGR):               { for(unsigned int i=0;i<num;++i) { float b = float(*data)*scale; float g = float(*(data+1))*scale; float r = float(*(data+2))*scale; operation.rgb(r,g,b); *data++ = T(b*inv_scale); *data++ = T(g*inv_scale); *data++ = T(r*inv_scale); } }  break;
136        case(GL_BGRA):              { for(unsigned int i=0;i<num;++i) { float b = float(*data)*scale; float g = float(*(data+1))*scale; float r = float(*(data+2))*scale; float a = float(*(data+3))*scale; operation.rgba(r,g,b,a); *data++ = T(g*inv_scale); *data++ = T(b*inv_scale); *data++ = T(r*inv_scale); *data++ = T(a*inv_scale); } }  break;
137    }
138}
139
140template <class M>   
141void modifyRow(unsigned int num, GLenum pixelFormat, GLenum dataType, unsigned char* data, const M& operation)
142{
143    switch(dataType)
144    {
145        case(GL_BYTE):              _modifyRow(num,pixelFormat, (char*)data,            1.0f/128.0f,        operation); break;
146        case(GL_UNSIGNED_BYTE):     _modifyRow(num,pixelFormat, (unsigned char*)data,   1.0f/255.0f,        operation); break;
147        case(GL_SHORT):             _modifyRow(num,pixelFormat, (short*) data,          1.0f/32768.0f,      operation); break;
148        case(GL_UNSIGNED_SHORT):    _modifyRow(num,pixelFormat, (unsigned short*)data,  1.0f/65535.0f,      operation); break;
149        case(GL_INT):               _modifyRow(num,pixelFormat, (int*) data,            1.0f/2147483648.0f, operation); break;
150        case(GL_UNSIGNED_INT):      _modifyRow(num,pixelFormat, (unsigned int*) data,   1.0f/4294967295.0f, operation); break;
151        case(GL_FLOAT):             _modifyRow(num,pixelFormat, (float*) data,          1.0f,               operation); break;
152    }
153}
154
155template <class M>   
156void modifyImage(osg::Image* image, const M& operation)
157{
158    if (!image) return;
159   
160    for(int r=0;r<image->r();++r)
161    {
162        for(int t=0;t<image->t();++t)
163        {
164            modifyRow(image->s(), image->getPixelFormat(), image->getDataType(), image->data(0,t,r), operation);
165        }
166    }
167}
168
169struct PassThroughTransformFunction
170{
171    unsigned char operator() (unsigned char c) const { return c; }
172};
173
174
175struct ProcessRow
176{
177    virtual ~ProcessRow() {}
178
179    virtual void operator() (unsigned int num,
180                    GLenum source_pixelFormat, unsigned char* source,
181                    GLenum dest_pixelFormat, unsigned char* dest) const 
182    {
183        switch(source_pixelFormat)
184        {
185        case(GL_LUMINANCE):
186        case(GL_ALPHA):
187            switch(dest_pixelFormat)
188            {
189            case(GL_LUMINANCE):
190            case(GL_ALPHA): A_to_A(num, source, dest); break;
191            case(GL_LUMINANCE_ALPHA): A_to_LA(num, source, dest); break;
192            case(GL_RGB): A_to_RGB(num, source, dest); break;
193            case(GL_RGBA): A_to_RGBA(num, source, dest); break;
194            }
195            break;
196        case(GL_LUMINANCE_ALPHA):
197            switch(dest_pixelFormat)
198            {
199            case(GL_LUMINANCE):
200            case(GL_ALPHA): LA_to_A(num, source, dest); break;
201            case(GL_LUMINANCE_ALPHA): LA_to_LA(num, source, dest); break;
202            case(GL_RGB): LA_to_RGB(num, source, dest); break;
203            case(GL_RGBA): LA_to_RGBA(num, source, dest); break;
204            }
205            break;
206        case(GL_RGB):
207            switch(dest_pixelFormat)
208            {
209            case(GL_LUMINANCE):
210            case(GL_ALPHA): RGB_to_A(num, source, dest); break;
211            case(GL_LUMINANCE_ALPHA): RGB_to_LA(num, source, dest); break;
212            case(GL_RGB): RGB_to_RGB(num, source, dest); break;
213            case(GL_RGBA): RGB_to_RGBA(num, source, dest); break;
214            }
215            break;
216        case(GL_RGBA):
217            switch(dest_pixelFormat)
218            {
219            case(GL_LUMINANCE):
220            case(GL_ALPHA): RGBA_to_A(num, source, dest); break;
221            case(GL_LUMINANCE_ALPHA): RGBA_to_LA(num, source, dest); break;
222            case(GL_RGB): RGBA_to_RGB(num, source, dest); break;
223            case(GL_RGBA): RGBA_to_RGBA(num, source, dest); break;
224            }
225            break;
226        }
227    }
228
229    ///////////////////////////////////////////////////////////////////////////////
230    // alpha sources..   
231    virtual void A_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
232    {
233        for(unsigned int i=0;i<num;++i)
234        {
235            *dest++ = *source++;
236        }
237    }
238
239    virtual void A_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
240    {
241        for(unsigned int i=0;i<num;++i)
242        {
243            *dest++ = *source;
244            *dest++ = *source++;
245        }
246    }
247                   
248    virtual void A_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
249    {
250        for(unsigned int i=0;i<num;++i)
251        {
252            *dest++ = *source;
253            *dest++ = *source;
254            *dest++ = *source++;
255        }
256    }
257
258    virtual void A_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
259    {
260        for(unsigned int i=0;i<num;++i)
261        {
262            *dest++ = *source;
263            *dest++ = *source;
264            *dest++ = *source;
265            *dest++ = *source++;
266        }
267    }
268
269    ///////////////////////////////////////////////////////////////////////////////
270    // alpha luminance sources..   
271    virtual void LA_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
272    {
273        for(unsigned int i=0;i<num;++i)
274        {
275            ++source;
276            *dest++ = *source++;
277        }
278    }
279
280    virtual void LA_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
281    {
282        for(unsigned int i=0;i<num;++i)
283        {
284            *dest++ = *source++;
285            *dest++ = *source++;
286        }
287    }
288                   
289    virtual void LA_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
290    {
291        for(unsigned int i=0;i<num;++i)
292        {
293            *dest++ = *source;
294            *dest++ = *source;
295            *dest++ = *source;
296            source+=2;
297        }
298    }
299
300    virtual void LA_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
301    {
302        for(unsigned int i=0;i<num;++i)
303        {
304            *dest++ = *source;
305            *dest++ = *source;
306            *dest++ = *source++;
307            *dest++ = *source++;
308        }
309    }
310
311    ///////////////////////////////////////////////////////////////////////////////
312    // RGB sources..   
313    virtual void RGB_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
314    {
315        for(unsigned int i=0;i<num;++i)
316        {
317            unsigned char val = *source;
318            *dest++ = val;
319            source += 3;
320        }
321    }
322
323    virtual void RGB_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
324    {
325        for(unsigned int i=0;i<num;++i)
326        {
327            unsigned char val = *source;
328            *dest++ = val;
329            *dest++ = val;
330            source += 3;
331        }
332    }
333                   
334    virtual void RGB_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
335    {
336        for(unsigned int i=0;i<num;++i)
337        {
338            *dest++ = *source++;
339            *dest++ = *source++;
340            *dest++ = *source++;
341        }
342    }
343
344    virtual void RGB_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
345    {
346        for(unsigned int i=0;i<num;++i)
347        {
348            unsigned char val = *source;
349            *dest++ = *source++;
350            *dest++ = *source++;
351            *dest++ = *source++;
352            *dest++ = val;
353        }
354    }
355
356    ///////////////////////////////////////////////////////////////////////////////
357    // RGBA sources..   
358    virtual void RGBA_to_A(unsigned int num, unsigned char* source, unsigned char* dest) const
359    {
360        for(unsigned int i=0;i<num;++i)
361        {
362            source += 3;
363            *dest++ = *source++;
364        }
365    }
366
367    virtual void RGBA_to_LA(unsigned int num, unsigned char* source, unsigned char* dest) const
368    {
369        for(unsigned int i=0;i<num;++i)
370        {
371            unsigned char val = *source;
372            source += 3;
373            *dest++ = val;
374            *dest++ = *source++;
375        }
376    }
377                   
378    virtual void RGBA_to_RGB(unsigned int num, unsigned char* source, unsigned char* dest) const
379    {
380        for(unsigned int i=0;i<num;++i)
381        {
382            *dest++ = *source++;
383            *dest++ = *source++;
384            *dest++ = *source++;
385            ++source;
386        }
387    }
388
389    virtual void RGBA_to_RGBA(unsigned int num, unsigned char* source, unsigned char* dest) const
390    {
391        for(unsigned int i=0;i<num;++i)
392        {
393            *dest++ = *source++;
394            *dest++ = *source++;
395            *dest++ = *source++;
396            *dest++ = *source++;
397        }
398    }
399};
400
401
402void clampToNearestValidPowerOfTwo(int& sizeX, int& sizeY, int& sizeZ, int s_maximumTextureSize, int t_maximumTextureSize, int r_maximumTextureSize)
403{
404    // compute nearest powers of two for each axis.
405    int s_nearestPowerOfTwo = 1;
406    while(s_nearestPowerOfTwo<sizeX && s_nearestPowerOfTwo<s_maximumTextureSize) s_nearestPowerOfTwo*=2;
407
408    int t_nearestPowerOfTwo = 1;
409    while(t_nearestPowerOfTwo<sizeY && t_nearestPowerOfTwo<t_maximumTextureSize) t_nearestPowerOfTwo*=2;
410
411    int r_nearestPowerOfTwo = 1;
412    while(r_nearestPowerOfTwo<sizeZ && r_nearestPowerOfTwo<r_maximumTextureSize) r_nearestPowerOfTwo*=2;
413
414    sizeX = s_nearestPowerOfTwo;
415    sizeY = t_nearestPowerOfTwo;
416    sizeZ = r_nearestPowerOfTwo;
417}
418
419osg::Image* createTexture3D(ImageList& imageList, ProcessRow& processRow,
420            unsigned int numComponentsDesired,
421            int s_maximumTextureSize,
422            int t_maximumTextureSize,
423            int r_maximumTextureSize )
424{
425    int max_s = 0;
426    int max_t = 0;
427    unsigned int max_components = 0;
428    int total_r = 0;
429    ImageList::iterator itr;
430    for(itr=imageList.begin();
431        itr!=imageList.end();
432        ++itr)
433    {
434        osg::Image* image = itr->get();
435        GLenum pixelFormat = image->getPixelFormat();
436        if (pixelFormat==GL_ALPHA ||
437            pixelFormat==GL_LUMINANCE ||
438            pixelFormat==GL_LUMINANCE_ALPHA ||
439            pixelFormat==GL_RGB ||
440            pixelFormat==GL_RGBA)
441        {
442            max_s = osg::maximum(image->s(), max_s);
443            max_t = osg::maximum(image->t(), max_t);
444            max_components = osg::maximum(osg::Image::computeNumComponents(pixelFormat), max_components);
445            total_r += image->r();
446        }
447        else
448        {
449            osg::notify(osg::NOTICE)<<"Image "<<image->getFileName()<<" has unsuitable pixel format"<< std::hex<< pixelFormat << std::dec << std::endl;
450        }
451    }
452   
453    if (numComponentsDesired!=0) max_components = numComponentsDesired;
454   
455    GLenum desiredPixelFormat = 0;
456    switch(max_components)
457    {
458    case(1):
459        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_LUMINANCE" << std::endl;
460        desiredPixelFormat = GL_LUMINANCE;
461        break;
462    case(2):
463        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_LUMINANCE_ALPHA" << std::endl;
464        desiredPixelFormat = GL_LUMINANCE_ALPHA;
465        break;
466    case(3):
467        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_RGB" << std::endl;
468        desiredPixelFormat = GL_RGB;
469        break;
470    case(4):
471        osg::notify(osg::NOTICE)<<"desiredPixelFormat = GL_RGBA" << std::endl;
472        desiredPixelFormat = GL_RGBA;
473        break;
474    }   
475    if (desiredPixelFormat==0) return 0;
476   
477    // compute nearest powers of two for each axis.
478    int s_nearestPowerOfTwo = 1;
479    while(s_nearestPowerOfTwo<max_s && s_nearestPowerOfTwo<s_maximumTextureSize) s_nearestPowerOfTwo*=2;
480
481    int t_nearestPowerOfTwo = 1;
482    while(t_nearestPowerOfTwo<max_t && t_nearestPowerOfTwo<t_maximumTextureSize) t_nearestPowerOfTwo*=2;
483
484    int r_nearestPowerOfTwo = 1;
485    while(r_nearestPowerOfTwo<total_r && r_nearestPowerOfTwo<r_maximumTextureSize) r_nearestPowerOfTwo*=2;
486
487
488    osg::notify(osg::NOTICE)<<"max image width = "<<max_s<<"  nearest power of two = "<<s_nearestPowerOfTwo<<std::endl;
489    osg::notify(osg::NOTICE)<<"max image height = "<<max_t<<"  nearest power of two = "<<t_nearestPowerOfTwo<<std::endl;
490    osg::notify(osg::NOTICE)<<"max image depth = "<<total_r<<"  nearest power of two = "<<r_nearestPowerOfTwo<<std::endl;
491   
492    // now allocate the 3d texture;
493    osg::ref_ptr<osg::Image> image_3d = new osg::Image;
494    image_3d->allocateImage(s_nearestPowerOfTwo,t_nearestPowerOfTwo,r_nearestPowerOfTwo,
495                            desiredPixelFormat,GL_UNSIGNED_BYTE);
496       
497
498    unsigned int r_offset = (total_r<r_nearestPowerOfTwo) ? r_nearestPowerOfTwo/2 - total_r/2 : 0;
499
500    int curr_dest_r = r_offset;
501
502    // copy across the values from the source images into the image_3d.
503    for(itr=imageList.begin();
504        itr!=imageList.end();
505        ++itr)
506    {
507        osg::Image* image = itr->get();
508        GLenum pixelFormat = image->getPixelFormat();
509        if (pixelFormat==GL_ALPHA ||
510            pixelFormat==GL_LUMINANCE ||
511            pixelFormat==GL_LUMINANCE_ALPHA ||
512            pixelFormat==GL_RGB ||
513            pixelFormat==GL_RGBA)
514        {
515       
516            int num_r = osg::minimum(image->r(), (image_3d->r() - curr_dest_r));
517            int num_t = osg::minimum(image->t(), image_3d->t());
518            int num_s = osg::minimum(image->s(), image_3d->s());
519       
520            unsigned int s_offset_dest = (image->s()<s_nearestPowerOfTwo) ? s_nearestPowerOfTwo/2 - image->s()/2 : 0;
521            unsigned int t_offset_dest = (image->t()<t_nearestPowerOfTwo) ? t_nearestPowerOfTwo/2 - image->t()/2 : 0;
522
523            for(int r=0;r<num_r;++r, ++curr_dest_r)
524            {
525                for(int t=0;t<num_t;++t)
526                {
527                    unsigned char* dest = image_3d->data(s_offset_dest,t+t_offset_dest,curr_dest_r);
528                    unsigned char* source = image->data(0,t,r);
529
530                    processRow(num_s, image->getPixelFormat(), source, image_3d->getPixelFormat(), dest);
531                }
532            }
533        }
534    }
535    return image_3d.release();
536}
537
538
539osg::Image* createNormalMapTexture(osg::Image* image_3d)
540{
541    unsigned int sourcePixelIncrement = 1;
542    unsigned int alphaOffset = 0;
543    switch(image_3d->getPixelFormat())
544    {
545    case(GL_ALPHA):
546    case(GL_LUMINANCE):
547        sourcePixelIncrement = 1;
548        alphaOffset = 0;
549        break;
550    case(GL_LUMINANCE_ALPHA):
551        sourcePixelIncrement = 2;
552        alphaOffset = 1;
553        break;
554    case(GL_RGB):
555        sourcePixelIncrement = 3;
556        alphaOffset = 0;
557        break;
558    case(GL_RGBA):
559        sourcePixelIncrement = 4;
560        alphaOffset = 3;
561        break;
562    default:
563        osg::notify(osg::NOTICE)<<"Source pixel format not support for normal map generation."<<std::endl;
564        return 0;
565    }
566   
567    osg::ref_ptr<osg::Image> normalmap_3d = new osg::Image;
568    normalmap_3d->allocateImage(image_3d->s(),image_3d->t(),image_3d->r(),
569                            GL_RGBA,GL_UNSIGNED_BYTE);
570
571    if (osg::getCpuByteOrder()==osg::LittleEndian) alphaOffset = sourcePixelIncrement-alphaOffset-1;
572
573    for(int r=1;r<image_3d->r()-1;++r)
574    {
575        for(int t=1;t<image_3d->t()-1;++t)
576        {
577            unsigned char* ptr = image_3d->data(1,t,r)+alphaOffset;
578            unsigned char* left = image_3d->data(0,t,r)+alphaOffset;
579            unsigned char* right = image_3d->data(2,t,r)+alphaOffset;
580            unsigned char* above = image_3d->data(1,t+1,r)+alphaOffset;
581            unsigned char* below = image_3d->data(1,t-1,r)+alphaOffset;
582            unsigned char* in = image_3d->data(1,t,r+1)+alphaOffset;
583            unsigned char* out = image_3d->data(1,t,r-1)+alphaOffset;
584
585            unsigned char* destination = (unsigned char*) normalmap_3d->data(1,t,r);
586
587            for(int s=1;s<image_3d->s()-1;++s)
588            {
589
590                osg::Vec3 grad((float)(*left)-(float)(*right),
591                               (float)(*below)-(float)(*above),
592                               (float)(*out) -(float)(*in));
593
594                grad.normalize();
595
596                if (grad.x()==0.0f && grad.y()==0.0f && grad.z()==0.0f)
597                {
598                    grad.set(128.0f,128.0f,128.0f);
599                }
600                else
601                {
602                    grad.x() = osg::clampBetween((grad.x()+1.0f)*128.0f,0.0f,255.0f);
603                    grad.y() = osg::clampBetween((grad.y()+1.0f)*128.0f,0.0f,255.0f);
604                    grad.z() = osg::clampBetween((grad.z()+1.0f)*128.0f,0.0f,255.0f);
605                }
606
607                *(destination++) = (unsigned char)(grad.x()); // scale and bias X.
608                *(destination++) = (unsigned char)(grad.y()); // scale and bias Y.
609                *(destination++) = (unsigned char)(grad.z()); // scale and bias Z.
610
611                *destination++ = *ptr;
612
613                ptr += sourcePixelIncrement;
614                left += sourcePixelIncrement;
615                right += sourcePixelIncrement;
616                above += sourcePixelIncrement;
617                below += sourcePixelIncrement;
618                in += sourcePixelIncrement;
619                out += sourcePixelIncrement;
620            }
621        }
622    }
623   
624    return normalmap_3d.release();
625}
626
627
628
629osg::Node* createCube(float size,float alpha, unsigned int numSlices, float sliceEnd=1.0f)
630{
631
632    // set up the Geometry.
633    osg::Geometry* geom = new osg::Geometry;
634
635    float halfSize = size*0.5f;
636    float y = halfSize;
637    float dy =-size/(float)(numSlices-1)*sliceEnd;
638
639    //y = -halfSize;
640    //dy *= 0.5;
641
642    osg::Vec3Array* coords = new osg::Vec3Array(4*numSlices);
643    geom->setVertexArray(coords);
644    for(unsigned int i=0;i<numSlices;++i, y+=dy)
645    {
646        (*coords)[i*4+0].set(-halfSize,y,halfSize);
647        (*coords)[i*4+1].set(-halfSize,y,-halfSize);
648        (*coords)[i*4+2].set(halfSize,y,-halfSize);
649        (*coords)[i*4+3].set(halfSize,y,halfSize);
650    }
651   
652    osg::Vec3Array* normals = new osg::Vec3Array(1);
653    (*normals)[0].set(0.0f,-1.0f,0.0f);
654    geom->setNormalArray(normals);
655    geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
656
657    osg::Vec4Array* colors = new osg::Vec4Array(1);
658    (*colors)[0].set(1.0f,1.0f,1.0f,alpha);
659    geom->setColorArray(colors);
660    geom->setColorBinding(osg::Geometry::BIND_OVERALL);
661
662    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,coords->size()));
663
664    osg::Billboard* billboard = new osg::Billboard;
665    billboard->setMode(osg::Billboard::POINT_ROT_WORLD);
666    billboard->addDrawable(geom);
667    billboard->setPosition(0,osg::Vec3(0.0f,0.0f,0.0f));
668   
669    return billboard;
670}
671
672class FollowMouseCallback : public osgGA::GUIEventHandler, public osg::StateSet::Callback
673{
674    public:
675   
676        FollowMouseCallback(bool shader = false):
677            _shader(shader)
678        {
679            _updateTransparency = false;
680            _updateAlphaCutOff = false;
681            _updateSampleDensity = false;
682        }
683
684        FollowMouseCallback(const FollowMouseCallback&,const osg::CopyOp&) {}
685
686        META_Object(osg,FollowMouseCallback);
687
688        virtual void operator() (osg::StateSet* stateset, osg::NodeVisitor* nv)
689        {
690            if (nv->getVisitorType()==osg::NodeVisitor::EVENT_VISITOR)
691            {
692                osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(nv);
693                if (ev)
694                {
695                    osgGA::GUIActionAdapter* aa = ev->getActionAdapter();
696                    osgGA::EventQueue::Events& events = ev->getEvents();
697                    for(osgGA::EventQueue::Events::iterator itr=events.begin();
698                        itr!=events.end();
699                        ++itr)
700                    {
701                        handle(*(*itr), *aa, stateset, ev);
702                    }
703                }
704            }
705        }
706       
707        virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&, osg::Object* object, osg::NodeVisitor*)
708        {
709            osg::StateSet* stateset = dynamic_cast<osg::StateSet*>(object);
710            if (!stateset) return false;
711           
712            switch(ea.getEventType())
713            {
714                case(osgGA::GUIEventAdapter::MOVE):
715                case(osgGA::GUIEventAdapter::DRAG):
716                {
717                    float v = (ea.getY()-ea.getYmin())/(ea.getYmax()-ea.getYmin());
718                    if (_shader)
719                    {
720                        osg::Uniform* uniform = 0;
721                        if (_updateTransparency && (uniform = stateset->getUniform("transparency"))) uniform->set(v);
722                        if (_updateAlphaCutOff && (uniform = stateset->getUniform("alphaCutOff"))) uniform->set(v);
723                        if (_updateSampleDensity && (uniform = stateset->getUniform("sampleDensity"))) uniform->set(powf(v,5));
724                    }
725                    else
726                    {                   
727                        if (_updateAlphaCutOff)
728                        {
729                            osg::AlphaFunc* alphaFunc = dynamic_cast<osg::AlphaFunc*>(stateset->getAttribute(osg::StateAttribute::ALPHAFUNC));
730                            if (alphaFunc)
731                            {
732                                alphaFunc->setReferenceValue(v);
733                            }
734                        }
735                       
736                        if (_updateTransparency)
737                        {
738                            osg::Material* material = dynamic_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
739                            if (material)
740                            {
741                                material->setAlpha(osg::Material::FRONT_AND_BACK,v);
742                            }
743                        }
744                    }
745
746                    break;
747                }
748                case(osgGA::GUIEventAdapter::KEYDOWN):
749                {
750                    if (ea.getKey()=='t') _updateTransparency = true;
751                    if (ea.getKey()=='a') _updateAlphaCutOff = true;
752                    if (ea.getKey()=='d') _updateSampleDensity = true;
753                    break;
754                }
755                case(osgGA::GUIEventAdapter::KEYUP):
756                {
757                    if (ea.getKey()=='t') _updateTransparency = false;
758                    if (ea.getKey()=='a') _updateAlphaCutOff = false;
759                    if (ea.getKey()=='d') _updateSampleDensity = false;
760                    break;
761                }
762                default:
763                    break;
764            }
765            return false;
766        }
767       
768        bool _shader;
769        bool _updateTransparency;
770        bool _updateAlphaCutOff;
771        bool _updateSampleDensity;
772
773};
774
775osg::Node* createShaderModel(osg::ref_ptr<osg::Image>& image_3d, osg::ref_ptr<osg::Image>& /*normalmap_3d*/,
776                       osg::Texture::InternalFormatMode internalFormatMode,
777                       float xSize, float ySize, float zSize,
778                       float /*xMultiplier*/, float /*yMultiplier*/, float /*zMultiplier*/,
779                       unsigned int /*numSlices*/=500, float /*sliceEnd*/=1.0f, float alphaFuncValue=0.02f, bool maximumIntensityProjection = false)
780{
781
782    osg::Group* root = new osg::Group;
783   
784    osg::Geode* geode = new osg::Geode;
785    root->addChild(geode);
786   
787    osg::StateSet* stateset = geode->getOrCreateStateSet();
788   
789    stateset->setEventCallback(new FollowMouseCallback(true));
790   
791    stateset->setMode(GL_ALPHA_TEST,osg::StateAttribute::ON);
792
793    // set up the 3d texture itself,
794    // note, well set the filtering up so that mip mapping is disabled,
795    // gluBuild3DMipsmaps doesn't do a very good job of handled the
796    // imbalanced dimensions of the 256x256x4 texture.
797    osg::Texture3D* texture3D = new osg::Texture3D;
798    texture3D->setResizeNonPowerOfTwoHint(false);
799    texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
800    texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
801    texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
802    texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
803    texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
804    if (image_3d->getPixelFormat()==GL_ALPHA ||
805        image_3d->getPixelFormat()==GL_LUMINANCE)
806    {
807        texture3D->setInternalFormatMode(osg::Texture3D::USE_USER_DEFINED_FORMAT);
808        texture3D->setInternalFormat(GL_INTENSITY);
809    }
810    else
811    {
812        texture3D->setInternalFormatMode(internalFormatMode);
813    }
814
815    texture3D->setImage(image_3d.get());
816
817    stateset->setTextureAttributeAndModes(0,texture3D,osg::StateAttribute::ON);
818
819    osg::Program* program = new osg::Program;
820    stateset->setAttribute(program);
821
822    // get shaders from source
823    std::string vertexShaderFile = osgDB::findDataFile("volume.vert");
824    if (!vertexShaderFile.empty())
825    {
826        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, vertexShaderFile));
827    }
828    else
829    {
830        char vertexShaderSource[] =
831            "varying vec4 cameraPos;\n"
832            "varying vec4 vertexPos;\n"
833            "varying mat4 texgen;\n"
834            "\n"
835            "void main(void)\n"
836            "{\n"
837            "        gl_Position = ftransform();\n"
838            "\n"
839            "        cameraPos = gl_ModelViewMatrixInverse*vec4(0,0,0,1);\n"
840            "        vertexPos = gl_Vertex;\n"
841            "\n"
842            "        texgen = mat4(gl_ObjectPlaneS[0], \n"
843            "                      gl_ObjectPlaneT[0],\n"
844            "                      gl_ObjectPlaneR[0],\n"
845            "                      gl_ObjectPlaneQ[0]);\n"
846            "}\n";
847
848        osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
849        program->addShader(vertex_shader);
850
851    }
852   
853    std::string fragmentShaderFile = osgDB::findDataFile("volume.frag");
854    if (!fragmentShaderFile.empty())
855    {
856        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, fragmentShaderFile));
857    }
858    else
859    {
860        //////////////////////////////////////////////////////////////////
861        // fragment shader
862        //
863        char fragmentShaderSource[] =
864            "uniform sampler3D baseTexture;\n"
865            "uniform float sampleDensity;\n"
866            "uniform float transparency;\n"
867            "uniform float alphaCutOff;\n"
868            "\n"
869            "varying vec4 cameraPos;\n"
870            "varying vec4 vertexPos;\n"
871            "varying mat4 texgen;\n"
872            "\n"
873            "void main(void)\n"
874            "{ \n"
875            "    vec3 t0 = (texgen * vertexPos).xyz;\n"
876            "    vec3 te = (texgen * cameraPos).xyz;\n"
877            "\n"
878            "    if (te.x>=0.0 && te.x<=1.0 &&\n"
879            "        te.y>=0.0 && te.y<=1.0 &&\n"
880            "        te.z>=0.0 && te.z<=1.0)\n"
881            "    {\n"
882            "        // do nothing... te inside volume\n"
883            "    }\n"
884            "    else\n"
885            "    {\n"
886            "        if (te.x<0.0)\n"
887            "        {\n"
888            "            float r = -te.x / (t0.x-te.x);\n"
889            "            te = te + (t0-te)*r;\n"
890            "        }\n"
891            "\n"
892            "        if (te.x>1.0)\n"
893            "        {\n"
894            "            float r = (1.0-te.x) / (t0.x-te.x);\n"
895            "            te = te + (t0-te)*r;\n"
896            "        }\n"
897            "\n"
898            "        if (te.y<0.0)\n"
899            "        {\n"
900            "            float r = -te.y / (t0.y-te.y);\n"
901            "            te = te + (t0-te)*r;\n"
902            "        }\n"
903            "\n"
904            "        if (te.y>1.0)\n"
905            "        {\n"
906            "            float r = (1.0-te.y) / (t0.y-te.y);\n"
907            "            te = te + (t0-te)*r;\n"
908            "        }\n"
909            "\n"
910            "        if (te.z<0.0)\n"
911            "        {\n"
912            "            float r = -te.z / (t0.z-te.z);\n"
913            "            te = te + (t0-te)*r;\n"
914            "        }\n"
915            "\n"
916            "        if (te.z>1.0)\n"
917            "        {\n"
918            "            float r = (1.0-te.z) / (t0.z-te.z);\n"
919            "            te = te + (t0-te)*r;\n"
920            "        }\n"
921            "    }\n"
922            "\n"
923            "    const int max_iteratrions = 256;\n"
924            "    int num_iterations = length(te-t0)/sampleDensity;\n"
925            "    if (num_iterations>max_iteratrions) \n"
926            "    {\n"
927            "        num_iterations = max_iteratrions;\n"
928            "    }\n"
929            "\n"
930            "    vec3 deltaTexCoord=(te-t0)/float(num_iterations-1);\n"
931            "    vec3 texcoord = t0;\n"
932            "\n"
933            "    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); \n"
934            "    while(num_iterations>0)\n"
935            "    {\n"
936            "        vec4 color = texture3D( baseTexture, texcoord);\n"
937            "        float r = color[3]*transparency;\n"
938            "        if (r>alphaCutOff)\n"
939            "        {\n"
940            "            gl_FragColor.xyz = gl_FragColor.xyz*(1.0-r)+color.xyz*r;\n"
941            "            gl_FragColor.w += r;\n"
942            "        }\n"
943            "        texcoord += deltaTexCoord; \n"
944            "\n"
945            "        --num_iterations;\n"
946            "    }\n"
947            "\n"
948            "    if (gl_FragColor.w>1.0) gl_FragColor.w = 1.0; \n"
949            "    if (gl_FragColor.w==0.0) discard;\n"
950            "}\n";
951
952        osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
953        program->addShader(fragment_shader);
954    }
955
956    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
957    stateset->addUniform(baseTextureSampler);
958
959    osg::Uniform* sampleDensity = new osg::Uniform("sampleDensity", 0.01f);
960    stateset->addUniform(sampleDensity);
961
962    osg::Uniform* transpancy = new osg::Uniform("transparency",0.5f);
963    stateset->addUniform(transpancy);
964
965    osg::Uniform* alphaCutOff = new osg::Uniform("alphaCutOff",alphaFuncValue);
966    stateset->addUniform(alphaCutOff);
967
968    stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
969
970    osg::TexGen* texgen = new osg::TexGen;
971    texgen->setMode(osg::TexGen::OBJECT_LINEAR);
972    texgen->setPlane(osg::TexGen::S, osg::Plane(1.0f/xSize,0.0f,0.0f,0.0f));
973    texgen->setPlane(osg::TexGen::T, osg::Plane(0.0f,1.0f/ySize,0.0f,0.0f));
974    texgen->setPlane(osg::TexGen::R, osg::Plane(0.0f,0.0f,1.0f/zSize,0.0f));
975    texgen->setPlane(osg::TexGen::Q, osg::Plane(0.0f,0.0f,0.0f,1.0f));
976   
977    stateset->setTextureAttributeAndModes(0, texgen, osg::StateAttribute::ON);
978
979    {
980        osg::Geometry* geom = new osg::Geometry;
981
982        osg::Vec3Array* coords = new osg::Vec3Array(8);
983        (*coords)[0].set(0,0,0);
984        (*coords)[1].set(xSize,0,0);
985        (*coords)[2].set(xSize,ySize,0);
986        (*coords)[3].set(0,ySize,0);
987        (*coords)[4].set(0,0,zSize);
988        (*coords)[5].set(xSize,0,zSize);
989        (*coords)[6].set(ySize,ySize,zSize);
990        (*coords)[7].set(0,ySize,zSize);
991        geom->setVertexArray(coords);
992
993        osg::Vec4Array* colours = new osg::Vec4Array(1);
994        (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
995        geom->setColorArray(colours);
996        geom->setColorBinding(osg::Geometry::BIND_OVERALL);
997
998        osg::DrawElementsUShort* drawElements = new osg::DrawElementsUShort(GL_QUADS);
999        // bottom
1000        drawElements->push_back(0);
1001        drawElements->push_back(1);
1002        drawElements->push_back(2);
1003        drawElements->push_back(3);
1004       
1005        // bottom
1006        drawElements->push_back(3);
1007        drawElements->push_back(2);
1008        drawElements->push_back(6);
1009        drawElements->push_back(7);
1010
1011        // left
1012        drawElements->push_back(0);
1013        drawElements->push_back(3);
1014        drawElements->push_back(7);
1015        drawElements->push_back(4);
1016
1017        // right
1018        drawElements->push_back(5);
1019        drawElements->push_back(6);
1020        drawElements->push_back(2);
1021        drawElements->push_back(1);
1022
1023        // front
1024        drawElements->push_back(1);
1025        drawElements->push_back(0);
1026        drawElements->push_back(4);
1027        drawElements->push_back(5);
1028
1029        // top
1030        drawElements->push_back(7);
1031        drawElements->push_back(6);
1032        drawElements->push_back(5);
1033        drawElements->push_back(4);
1034
1035        geom->addPrimitiveSet(drawElements);
1036
1037        geode->addDrawable(geom);
1038
1039    }
1040    return root;
1041}
1042
1043osg::Node* createModel(osg::ref_ptr<osg::Image>& image_3d, osg::ref_ptr<osg::Image>& normalmap_3d,
1044                       osg::Texture::InternalFormatMode internalFormatMode,
1045                       float xSize, float ySize, float zSize,
1046                       float xMultiplier, float yMultiplier, float zMultiplier,
1047                       unsigned int numSlices=500, float sliceEnd=1.0f, float alphaFuncValue=0.02f, bool maximumIntensityProjection = false)
1048{
1049    bool two_pass = normalmap_3d.valid() && (image_3d->getPixelFormat()==GL_RGB || image_3d->getPixelFormat()==GL_RGBA);
1050
1051    osg::BoundingBox bb(-xSize*0.5f,-ySize*0.5f,-zSize*0.5f,xSize*0.5f,ySize*0.5f,zSize*0.5f);
1052
1053    float maxAxis = xSize;
1054    if (ySize > maxAxis) maxAxis = ySize;
1055    if (zSize > maxAxis) maxAxis = zSize;
1056
1057    osg::Group* group = new osg::Group;
1058   
1059    osg::TexGenNode* texgenNode_0 = new osg::TexGenNode;
1060    texgenNode_0->setTextureUnit(0);
1061    texgenNode_0->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
1062    texgenNode_0->getTexGen()->setPlane(osg::TexGen::S, osg::Plane(xMultiplier/xSize,0.0f,0.0f,0.5f));
1063    texgenNode_0->getTexGen()->setPlane(osg::TexGen::T, osg::Plane(0.0f,yMultiplier/ySize,0.0f,0.5f));
1064    texgenNode_0->getTexGen()->setPlane(osg::TexGen::R, osg::Plane(0.0f,0.0f,zMultiplier/zSize,0.5f));
1065   
1066    if (two_pass)
1067    {
1068        osg::TexGenNode* texgenNode_1 = new osg::TexGenNode;
1069        texgenNode_1->setTextureUnit(1);
1070        texgenNode_1->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
1071        texgenNode_1->getTexGen()->setPlane(osg::TexGen::S, texgenNode_0->getTexGen()->getPlane(osg::TexGen::S));
1072        texgenNode_1->getTexGen()->setPlane(osg::TexGen::T, texgenNode_0->getTexGen()->getPlane(osg::TexGen::T));
1073        texgenNode_1->getTexGen()->setPlane(osg::TexGen::R, texgenNode_0->getTexGen()->getPlane(osg::TexGen::R));
1074
1075        texgenNode_1->addChild(texgenNode_0);
1076
1077        group->addChild(texgenNode_1);
1078    }
1079    else
1080    { 
1081        group->addChild(texgenNode_0);
1082    }
1083
1084    float cubeSize = sqrtf(xSize*xSize+ySize*ySize+zSize*zSize);
1085
1086    osg::ClipNode* clipnode = new osg::ClipNode;
1087    clipnode->addChild(createCube(cubeSize,1.0f, numSlices,sliceEnd));
1088    clipnode->createClipBox(bb);
1089
1090    {
1091        // set up the Geometry to enclose the clip volume to prevent near/far clipping from affecting billboard
1092        osg::Geometry* geom = new osg::Geometry;
1093
1094        osg::Vec3Array* coords = new osg::Vec3Array();
1095        coords->push_back(bb.corner(0));
1096        coords->push_back(bb.corner(1));
1097        coords->push_back(bb.corner(2));
1098        coords->push_back(bb.corner(3));
1099        coords->push_back(bb.corner(4));
1100        coords->push_back(bb.corner(5));
1101        coords->push_back(bb.corner(6));
1102        coords->push_back(bb.corner(7));
1103
1104        geom->setVertexArray(coords);
1105
1106        osg::Vec4Array* colors = new osg::Vec4Array(1);
1107        (*colors)[0].set(1.0f,1.0f,1.0f,1.0f);
1108        geom->setColorArray(colors);
1109        geom->setColorBinding(osg::Geometry::BIND_OVERALL);
1110
1111        geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS,0,coords->size()));
1112
1113        osg::Geode* geode = new osg::Geode;
1114        geode->addDrawable(geom);
1115       
1116        clipnode->addChild(geode);
1117       
1118    }
1119
1120    texgenNode_0->addChild(clipnode);
1121
1122    osg::StateSet* stateset = texgenNode_0->getOrCreateStateSet();
1123
1124    stateset->setEventCallback(new FollowMouseCallback(false));
1125 
1126    stateset->setMode(GL_LIGHTING,osg::StateAttribute::ON);
1127    stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
1128    stateset->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER,alphaFuncValue), osg::StateAttribute::ON);
1129   
1130    osg::Material* material = new osg::Material;
1131    material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1132    stateset->setAttributeAndModes(material);
1133   
1134    if (maximumIntensityProjection)
1135    {
1136        stateset->setAttribute(new osg::BlendFunc(osg::BlendFunc::ONE, osg::BlendFunc::ONE));
1137        stateset->setAttribute(new osg::BlendEquation(osg::BlendEquation::RGBA_MAX));
1138    }
1139   
1140    osg::Vec3 lightDirection(1.0f,-1.0f,1.0f);
1141    lightDirection.normalize();
1142
1143    if (normalmap_3d.valid())
1144    {
1145        if (two_pass)
1146        {
1147
1148            // set up normal texture
1149            osg::Texture3D* bump_texture3D = new osg::Texture3D;
1150            bump_texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
1151            bump_texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
1152            bump_texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
1153            bump_texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
1154            bump_texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
1155            bump_texture3D->setImage(normalmap_3d.get());
1156
1157            bump_texture3D->setInternalFormatMode(internalFormatMode);
1158
1159            stateset->setTextureAttributeAndModes(0,bump_texture3D,osg::StateAttribute::ON);
1160
1161            osg::TexEnvCombine* tec = new osg::TexEnvCombine;
1162            tec->setConstantColorAsLightDirection(lightDirection);
1163
1164            tec->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB);
1165            tec->setSource0_RGB(osg::TexEnvCombine::CONSTANT);
1166            tec->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
1167            tec->setSource1_RGB(osg::TexEnvCombine::TEXTURE);
1168
1169            tec->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
1170
1171            tec->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
1172            tec->setSource0_Alpha(osg::TexEnvCombine::PRIMARY_COLOR);
1173            tec->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);
1174            tec->setSource1_Alpha(osg::TexEnvCombine::TEXTURE);
1175            tec->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA);
1176
1177            stateset->setTextureAttributeAndModes(0, tec, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
1178
1179            stateset->setTextureMode(0,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
1180            stateset->setTextureMode(0,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
1181            stateset->setTextureMode(0,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
1182
1183
1184            // set up color texture
1185            osg::Texture3D* texture3D = new osg::Texture3D;
1186            texture3D->setResizeNonPowerOfTwoHint(false);
1187            texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
1188            texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
1189            texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
1190            texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
1191            texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
1192            if (image_3d->getPixelFormat()==GL_ALPHA ||
1193                image_3d->getPixelFormat()==GL_LUMINANCE)
1194            {
1195                texture3D->setInternalFormatMode(osg::Texture3D::USE_USER_DEFINED_FORMAT);
1196                texture3D->setInternalFormat(GL_INTENSITY);
1197            }
1198            else
1199            {
1200                texture3D->setInternalFormatMode(internalFormatMode);
1201            }
1202            texture3D->setImage(image_3d.get());
1203
1204            stateset->setTextureAttributeAndModes(1,texture3D,osg::StateAttribute::ON);
1205
1206            stateset->setTextureMode(1,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
1207            stateset->setTextureMode(1,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
1208            stateset->setTextureMode(1,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
1209
1210            stateset->setTextureAttributeAndModes(1,new osg::TexEnv(),osg::StateAttribute::ON);
1211
1212        }
1213        else
1214        {
1215            osg::ref_ptr<osg::Image> normalmap_3d = createNormalMapTexture(image_3d.get());
1216            osg::Texture3D* bump_texture3D = new osg::Texture3D;
1217            bump_texture3D->setResizeNonPowerOfTwoHint(false);
1218            bump_texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
1219            bump_texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
1220            bump_texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
1221            bump_texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
1222            bump_texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
1223            bump_texture3D->setImage(normalmap_3d.get());
1224
1225            bump_texture3D->setInternalFormatMode(internalFormatMode);
1226
1227            stateset->setTextureAttributeAndModes(0,bump_texture3D,osg::StateAttribute::ON);
1228
1229            osg::TexEnvCombine* tec = new osg::TexEnvCombine;
1230            tec->setConstantColorAsLightDirection(lightDirection);
1231
1232            tec->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB);
1233            tec->setSource0_RGB(osg::TexEnvCombine::CONSTANT);
1234            tec->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
1235            tec->setSource1_RGB(osg::TexEnvCombine::TEXTURE);
1236            tec->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
1237
1238            tec->setCombine_Alpha(osg::TexEnvCombine::MODULATE);
1239            tec->setSource0_Alpha(osg::TexEnvCombine::PRIMARY_COLOR);
1240            tec->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);
1241            tec->setSource1_Alpha(osg::TexEnvCombine::TEXTURE);
1242            tec->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA);
1243
1244            stateset->setTextureAttributeAndModes(0, tec, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
1245
1246            stateset->setTextureMode(0,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
1247            stateset->setTextureMode(0,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
1248            stateset->setTextureMode(0,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
1249
1250            image_3d = normalmap_3d;
1251        }
1252    }
1253    else
1254    {     
1255        // set up the 3d texture itself,
1256        // note, well set the filtering up so that mip mapping is disabled,
1257        // gluBuild3DMipsmaps doesn't do a very good job of handled the
1258        // imbalanced dimensions of the 256x256x4 texture.
1259        osg::Texture3D* texture3D = new osg::Texture3D;
1260        texture3D->setResizeNonPowerOfTwoHint(false);
1261        texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
1262        texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
1263        texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP);
1264        texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP);
1265        texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP);
1266        if (image_3d->getPixelFormat()==GL_ALPHA ||
1267            image_3d->getPixelFormat()==GL_LUMINANCE)
1268        {
1269            texture3D->setInternalFormatMode(osg::Texture3D::USE_USER_DEFINED_FORMAT);
1270            texture3D->setInternalFormat(GL_INTENSITY);
1271        }
1272        else
1273        {
1274            texture3D->setInternalFormatMode(internalFormatMode);
1275        }
1276
1277        texture3D->setImage(image_3d.get());
1278
1279        stateset->setTextureAttributeAndModes(0,texture3D,osg::StateAttribute::ON);
1280
1281        stateset->setTextureMode(0,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
1282        stateset->setTextureMode(0,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
1283        stateset->setTextureMode(0,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
1284
1285        stateset->setTextureAttributeAndModes(0,new osg::TexEnv(),osg::StateAttribute::ON);
1286    }
1287 
1288    return group;
1289}
1290
1291struct FindRangeOperator
1292{
1293    FindRangeOperator():
1294        _rmin(FLT_MAX),
1295        _rmax(-FLT_MAX),
1296        _gmin(FLT_MAX),
1297        _gmax(-FLT_MAX),
1298        _bmin(FLT_MAX),
1299        _bmax(-FLT_MAX),
1300        _amin(FLT_MAX),
1301        _amax(-FLT_MAX) {}
1302       
1303    mutable float _rmin, _rmax, _gmin, _gmax, _bmin, _bmax, _amin, _amax;
1304
1305    inline void luminance(float l) const { rgb(l,l,l); }
1306    inline void alpha(float a) const { _amin = osg::minimum(a,_amin); _amax = osg::maximum(a,_amax); }
1307    inline void luminance_alpha(float l,float a) const { rgb(l,l,l); alpha(a); }
1308    inline void rgb(float r,float g,float b) const { _rmin = osg::minimum(r,_rmin); _rmax = osg::maximum(r,_rmax); _gmin = osg::minimum(g,_gmin); _gmax = osg::maximum(g,_gmax); _bmin = osg::minimum(b,_bmin); _bmax = osg::maximum(b,_bmax);  }
1309    inline void rgba(float r,float g,float b,float a) const { rgb(r,g,b); alpha(a); }
1310};
1311 
1312struct ScaleOperator
1313{
1314    ScaleOperator():_scale(1.0f) {}
1315    ScaleOperator(float scale):_scale(scale) {}
1316    ScaleOperator(const ScaleOperator& so):_scale(so._scale) {}
1317   
1318    ScaleOperator& operator = (const ScaleOperator& so) { _scale = so._scale; return *this; }
1319
1320    float _scale;
1321
1322    inline void luminance(float& l) const { l*= _scale; }
1323    inline void alpha(float& a) const { a*= _scale; }
1324    inline void luminance_alpha(float& l,float& a) const { l*= _scale; a*= _scale;  }
1325    inline void rgb(float& r,float& g,float& b) const { r*= _scale; g*=_scale; b*=_scale; }
1326    inline void rgba(float& r,float& g,float& b,float& a) const { r*= _scale; g*=_scale; b*=_scale; a*=_scale; }
1327};
1328
1329struct RecordRowOperator
1330{
1331    RecordRowOperator(unsigned int num):_colours(num),_pos(0) {}
1332
1333    mutable std::vector<osg::Vec4>  _colours;
1334    mutable unsigned int            _pos;
1335   
1336    inline void luminance(float l) const { rgba(l,l,l,1.0f); }
1337    inline void alpha(float a) const { rgba(1.0f,1.0f,1.0f,a); }
1338    inline void luminance_alpha(float l,float a) const { rgba(l,l,l,a);  }
1339    inline void rgb(float r,float g,float b) const { rgba(r,g,b,1.0f); }
1340    inline void rgba(float r,float g,float b,float a) const { _colours[_pos++].set(r,g,b,a); }
1341};
1342
1343struct WriteRowOperator
1344{
1345    WriteRowOperator():_pos(0) {}
1346    WriteRowOperator(unsigned int num):_colours(num),_pos(0) {}
1347
1348    std::vector<osg::Vec4>  _colours;
1349    mutable unsigned int    _pos;
1350   
1351    inline void luminance(float& l) const { l = _colours[_pos++].r(); }
1352    inline void alpha(float& a) const { a = _colours[_pos++].a(); }
1353    inline void luminance_alpha(float& l,float& a) const { l = _colours[_pos].r(); a = _colours[_pos++].a(); }
1354    inline void rgb(float& r,float& g,float& b) const { r = _colours[_pos].r(); g = _colours[_pos].g(); b = _colours[_pos].b(); }
1355    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(); }
1356};
1357
1358osg::Image* readRaw(int sizeX, int sizeY, int sizeZ, int numberBytesPerComponent, int numberOfComponents, const std::string& endian, const std::string& raw_filename)
1359{
1360    std::ifstream fin(raw_filename.c_str(), std::ifstream::binary);
1361    if (!fin) return 0;
1362
1363    GLenum pixelFormat;
1364    switch(numberOfComponents)
1365    {
1366        case 1 : pixelFormat = GL_LUMINANCE; break;
1367        case 2 : pixelFormat = GL_LUMINANCE_ALPHA; break;
1368        case 3 : pixelFormat = GL_RGB; break;
1369        case 4 : pixelFormat = GL_RGBA; break;
1370        default :
1371            osg::notify(osg::NOTICE)<<"Error: numberOfComponents="<<numberOfComponents<<" not supported, only 1,2,3 or 4 are supported."<<std::endl;
1372            return 0;
1373    }
1374
1375   
1376    GLenum dataType;
1377    switch(numberBytesPerComponent)
1378    {
1379        case 1 : dataType = GL_UNSIGNED_BYTE; break;
1380        case 2 : dataType = GL_UNSIGNED_SHORT; break;
1381        case 4 : dataType = GL_UNSIGNED_INT; break;
1382        default :
1383            osg::notify(osg::NOTICE)<<"Error: numberBytesPerComponent="<<numberBytesPerComponent<<" not supported, only 1,2 or 4 are supported."<<std::endl;
1384            return 0;
1385    }
1386   
1387    int s_maximumTextureSize=256, t_maximumTextureSize=256, r_maximumTextureSize=256;
1388   
1389    int sizeS = sizeX;
1390    int sizeT = sizeY;
1391    int sizeR = sizeZ;
1392    clampToNearestValidPowerOfTwo(sizeS, sizeT, sizeR, s_maximumTextureSize, t_maximumTextureSize, r_maximumTextureSize);
1393
1394    osg::ref_ptr<osg::Image> image = new osg::Image;
1395    image->allocateImage(sizeS, sizeT, sizeR, pixelFormat, dataType);
1396   
1397   
1398    bool endianSwap = (osg::getCpuByteOrder()==osg::BigEndian) ? (endian!="big") : (endian=="big");
1399   
1400    unsigned int r_offset = (sizeZ<sizeR) ? sizeR/2 - sizeZ/2 : 0;
1401   
1402    int offset = endianSwap ? numberBytesPerComponent : 0;
1403    int delta = endianSwap ? -1 : 1;
1404    for(int r=0;r<sizeZ;++r)
1405    {
1406        for(int t=0;t<sizeY;++t)
1407        {
1408            char* data = (char*) image->data(0,t,r+r_offset);
1409            for(int s=0;s<sizeX;++s)
1410            {
1411                if (!fin) return 0;
1412               
1413                for(int c=0;c<numberOfComponents;++c)
1414                {
1415                    char* ptr = data+offset;
1416                    for(int b=0;b<numberBytesPerComponent;++b)
1417                    {
1418                        fin.read((char*)ptr, 1);
1419                        ptr += delta;
1420                    }
1421                    data += numberBytesPerComponent;
1422                }
1423            }
1424        }
1425    }
1426
1427
1428    // normalise texture
1429    {
1430        // compute range of values
1431        FindRangeOperator rangeOp;   
1432        readImage(image.get(), rangeOp);
1433        modifyImage(image.get(),ScaleOperator(1.0f/rangeOp._rmax));
1434    }
1435   
1436   
1437    fin.close();
1438
1439    if (dataType!=GL_UNSIGNED_BYTE)
1440    {
1441        // need to convert to ubyte
1442       
1443        osg::ref_ptr<osg::Image> new_image = new osg::Image;
1444        new_image->allocateImage(sizeS, sizeT, sizeR, pixelFormat, GL_UNSIGNED_BYTE);
1445       
1446        RecordRowOperator readOp(sizeS);
1447        WriteRowOperator writeOp;
1448
1449        for(int r=0;r<sizeR;++r)
1450        {
1451            for(int t=0;t<sizeT;++t)
1452            {
1453                // reset the indices to beginning
1454                readOp._pos = 0;
1455                writeOp._pos = 0;
1456           
1457                // read the pixels into readOp's _colour array
1458                readRow(sizeS, pixelFormat, dataType, image->data(0,t,r), readOp);
1459                               
1460                // pass readOp's _colour array contents over to writeOp (note this is just a pointer swap).
1461                writeOp._colours.swap(readOp._colours);
1462               
1463                modifyRow(sizeS, pixelFormat, GL_UNSIGNED_BYTE, new_image->data(0,t,r), writeOp);
1464
1465                // return readOp's _colour array contents back to its rightful owner.
1466                writeOp._colours.swap(readOp._colours);
1467            }
1468        }
1469       
1470        image = new_image;
1471    }
1472   
1473    return image.release();
1474   
1475   
1476}
1477
1478enum ColourSpaceOperation
1479{
1480    NO_COLOUR_SPACE_OPERATION,
1481    MODULATE_ALPHA_BY_LUMINANCE,
1482    MODULATE_ALPHA_BY_COLOUR,
1483    REPLACE_ALPHA_WITH_LUMINACE
1484};
1485
1486struct ModulateAlphaByLuminanceOperator
1487{
1488    ModulateAlphaByLuminanceOperator() {}
1489
1490    inline void luminance(float&) const {}
1491    inline void alpha(float&) const {}
1492    inline void luminance_alpha(float& l,float& a) const { a*= l; }
1493    inline void rgb(float&,float&,float&) const {}
1494    inline void rgba(float& r,float& g,float& b,float& a) const { float l = (r+g+b)*0.3333333; a *= l;}
1495};
1496
1497struct ModulateAlphaByColourOperator
1498{
1499    ModulateAlphaByColourOperator(const osg::Vec4& colour):_colour(colour) { _lum = _colour.length(); }
1500   
1501    osg::Vec4 _colour;
1502    float _lum;
1503
1504    inline void luminance(float&) const {}
1505    inline void alpha(float&) const {}
1506    inline void luminance_alpha(float& l,float& a) const { a*= l*_lum; }
1507    inline void rgb(float&,float&,float&) const {}
1508    inline void rgba(float& r,float& g,float& b,float& a) const { a = (r*_colour.r()+g*_colour.g()+b*_colour.b()+a*_colour.a()); }
1509};
1510
1511struct ReplaceAlphaWithLuminanceOperator
1512{
1513    ReplaceAlphaWithLuminanceOperator() {}
1514
1515    inline void luminance(float&) const {}
1516    inline void alpha(float&) const {}
1517    inline void luminance_alpha(float& l,float& a) const { a= l; }
1518    inline void rgb(float&,float&,float&) const { }
1519    inline void rgba(float& r,float& g,float& b,float& a) const { float l = (r+g+b)*0.3333333; a = l; }
1520};
1521
1522void doColourSpaceConversion(ColourSpaceOperation op, osg::Image* image, osg::Vec4& colour)
1523{
1524    switch(op)
1525    {
1526        case (MODULATE_ALPHA_BY_LUMINANCE):
1527            std::cout<<"doing conversion MODULATE_ALPHA_BY_LUMINANCE"<<std::endl;
1528            modifyImage(image,ModulateAlphaByLuminanceOperator());
1529            break;
1530        case (MODULATE_ALPHA_BY_COLOUR):
1531            std::cout<<"doing conversion MODULATE_ALPHA_BY_COLOUR"<<std::endl;
1532            modifyImage(image,ModulateAlphaByColourOperator(colour));
1533            break;
1534        case (REPLACE_ALPHA_WITH_LUMINACE):
1535            std::cout<<"doing conversion REPLACE_ALPHA_WITH_LUMINACE"<<std::endl;
1536            modifyImage(image,ReplaceAlphaWithLuminanceOperator());
1537            break;
1538        default:
1539            break;
1540    }
1541}
1542
1543class TestSupportOperation: public osg::GraphicsOperation
1544{
1545public:
1546
1547    TestSupportOperation():
1548        osg::GraphicsOperation("TestSupportOperation",false),
1549        supported(true),
1550        errorMessage(),
1551        maximumTextureSize(256) {}
1552
1553    virtual void operator () (osg::GraphicsContext* gc)
1554    {
1555        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mutex);
1556
1557        glGetIntegerv( GL_MAX_3D_TEXTURE_SIZE, &maximumTextureSize );
1558       
1559        osg::notify(osg::NOTICE)<<"Max texture size="<<maximumTextureSize<<std::endl;
1560    }
1561       
1562    OpenThreads::Mutex  mutex;
1563    bool                supported;
1564    std::string         errorMessage;
1565    GLint               maximumTextureSize;
1566};
1567
1568
1569
1570int main( int argc, char **argv )
1571{
1572    // use an ArgumentParser object to manage the program arguments.
1573    osg::ArgumentParser arguments(&argc,argv);
1574   
1575    // set up the usage document, in case we need to print out how to use this program.
1576    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of 3D textures.");
1577    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
1578    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
1579    arguments.getApplicationUsage()->addCommandLineOption("-n","Create normal map for per voxel lighting.");
1580    arguments.getApplicationUsage()->addCommandLineOption("-s <numSlices>","Number of slices to create.");
1581    arguments.getApplicationUsage()->addCommandLineOption("--images [filenames]","Specify a stack of 2d images to build the 3d volume from.");
1582    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use OpenGL Shading Language.");
1583    arguments.getApplicationUsage()->addCommandLineOption("--mip","Use Maximum Intensity Projection (MIP) filtering.");
1584    arguments.getApplicationUsage()->addCommandLineOption("--xSize <size>","Relative width of rendered brick.");
1585    arguments.getApplicationUsage()->addCommandLineOption("--ySize <size>","Relative length of rendered brick.");
1586    arguments.getApplicationUsage()->addCommandLineOption("--zSize <size>","Relative height of rendered brick.");
1587    arguments.getApplicationUsage()->addCommandLineOption("--xMultiplier <multiplier>","Tex coord x mulitplier.");
1588    arguments.getApplicationUsage()->addCommandLineOption("--yMultiplier <multiplier>","Tex coord y mulitplier.");
1589    arguments.getApplicationUsage()->addCommandLineOption("--zMultiplier <multiplier>","Tex coord z mulitplier.");
1590    arguments.getApplicationUsage()->addCommandLineOption("--clip <ratio>","clip volume as a ratio, 0.0 clip all, 1.0 clip none.");
1591    arguments.getApplicationUsage()->addCommandLineOption("--maxTextureSize <size>","Set the texture maximum resolution in the s,t,r (x,y,z) dimensions.");
1592    arguments.getApplicationUsage()->addCommandLineOption("--s_maxTextureSize <size>","Set the texture maximum resolution in the s (x) dimension.");
1593    arguments.getApplicationUsage()->addCommandLineOption("--t_maxTextureSize <size>","Set the texture maximum resolution in the t (y) dimension.");
1594    arguments.getApplicationUsage()->addCommandLineOption("--r_maxTextureSize <size>","Set the texture maximum resolution in the r (z) dimension.");
1595    arguments.getApplicationUsage()->addCommandLineOption("--compressed","Enable the usage of compressed textures.");
1596    arguments.getApplicationUsage()->addCommandLineOption("--compressed-arb","Enable the usage of OpenGL ARB compressed textures.");
1597    arguments.getApplicationUsage()->addCommandLineOption("--compressed-dxt1","Enable the usage of S3TC DXT1 compressed textures.");
1598    arguments.getApplicationUsage()->addCommandLineOption("--compressed-dxt3","Enable the usage of S3TC DXT3 compressed textures.");
1599    arguments.getApplicationUsage()->addCommandLineOption("--compressed-dxt5","Enable the usage of S3TC DXT5 compressed textures.");
1600    arguments.getApplicationUsage()->addCommandLineOption("--modulate-alpha-by-luminance","For each pixel multiple the alpha value by the luminance.");
1601    arguments.getApplicationUsage()->addCommandLineOption("--replace-alpha-with-luminance","For each pixel mSet the alpha value to the luminance.");
1602    arguments.getApplicationUsage()->addCommandLineOption("--num-components <num>","Set the number of components to in he target image.");
1603//    arguments.getApplicationUsage()->addCommandLineOption("--raw <sizeX> <sizeY> <sizeZ> <numberBytesPerComponent> <numberOfComponents> <endian> <filename>","read a raw image data");
1604
1605    // construct the viewer.
1606    osgViewer::Viewer viewer(arguments);
1607
1608    // add the window size toggle handler
1609    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
1610       
1611    // add the stats handler
1612    viewer.addEventHandler(new osgViewer::StatsHandler);
1613
1614    viewer.getCamera()->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
1615
1616    // if user request help write it out to cout.
1617    if (arguments.read("-h") || arguments.read("--help"))
1618    {
1619        arguments.getApplicationUsage()->write(std::cout);
1620        return 1;
1621    }
1622
1623    std::string outputFile;
1624    while (arguments.read("-o",outputFile)) {}
1625
1626
1627    unsigned int numSlices=500;
1628    while (arguments.read("-s",numSlices)) {}
1629   
1630   
1631    float sliceEnd=1.0f;
1632    while (arguments.read("--clip",sliceEnd)) {}
1633
1634    float alphaFunc=0.02f;
1635    while (arguments.read("--alphaFunc",alphaFunc)) {}
1636
1637
1638    bool createNormalMap = false;
1639    while (arguments.read("-n")) createNormalMap=true;
1640   
1641    bool maximumIntensityProjection = false;
1642    while(arguments.read("--mip")) maximumIntensityProjection = true;
1643
1644    float xSize=1.0f, ySize=1.0f, zSize=1.0f;
1645    while (arguments.read("--xSize",xSize)) {}
1646    while (arguments.read("--ySize",ySize)) {}
1647    while (arguments.read("--zSize",zSize)) {}
1648
1649    float xMultiplier=1.0f, yMultiplier=1.0f, zMultiplier=1.0f;
1650    while (arguments.read("--xMultiplier",xMultiplier)) {}
1651    while (arguments.read("--yMultiplier",yMultiplier)) {}
1652    while (arguments.read("--zMultiplier",zMultiplier)) {}
1653
1654    osg::ref_ptr<TestSupportOperation> testSupportOperation = new TestSupportOperation;
1655    viewer.setRealizeOperation(testSupportOperation.get());
1656   
1657    viewer.realize();
1658
1659    int maximumTextureSize = testSupportOperation->maximumTextureSize;
1660    int s_maximumTextureSize = 256;
1661    int t_maximumTextureSize = 256;
1662    int r_maximumTextureSize = 256;
1663    while(arguments.read("--maxTextureSize",maximumTextureSize))
1664    {
1665        s_maximumTextureSize = maximumTextureSize;
1666        t_maximumTextureSize = maximumTextureSize;
1667        r_maximumTextureSize = maximumTextureSize;
1668    }
1669    while(arguments.read("--s_maxTextureSize",s_maximumTextureSize)) {}
1670    while(arguments.read("--t_maxTextureSize",t_maximumTextureSize)) {}
1671    while(arguments.read("--r_maxTextureSize",r_maximumTextureSize)) {}
1672
1673    osg::Texture::InternalFormatMode internalFormatMode = osg::Texture::USE_IMAGE_DATA_FORMAT;
1674    while(arguments.read("--compressed") || arguments.read("--compressed-arb")) { internalFormatMode = osg::Texture::USE_ARB_COMPRESSION; }
1675
1676    while(arguments.read("--compressed-dxt1")) { internalFormatMode = osg::Texture::USE_S3TC_DXT1_COMPRESSION; }
1677    while(arguments.read("--compressed-dxt3")) { internalFormatMode = osg::Texture::USE_S3TC_DXT3_COMPRESSION; }
1678    while(arguments.read("--compressed-dxt5")) { internalFormatMode = osg::Texture::USE_S3TC_DXT5_COMPRESSION; }
1679   
1680   
1681    // set up colour space operation.
1682    ColourSpaceOperation colourSpaceOperation = NO_COLOUR_SPACE_OPERATION;
1683    osg::Vec4 colourModulate(0.25f,0.25f,0.25f,0.25f);
1684    while(arguments.read("--modulate-alpha-by-luminance")) { colourSpaceOperation = MODULATE_ALPHA_BY_LUMINANCE; }
1685    while(arguments.read("--modulate-alpha-by-colour", colourModulate.x(),colourModulate.y(),colourModulate.z(),colourModulate.w() )) { colourSpaceOperation = MODULATE_ALPHA_BY_COLOUR; }
1686    while(arguments.read("--replace-alpha-with-luminance")) { colourSpaceOperation = REPLACE_ALPHA_WITH_LUMINACE; }
1687       
1688   
1689    unsigned int numComponentsDesired = 0;
1690    while(arguments.read("--num-components", numComponentsDesired)) {}
1691
1692    bool useShader = false;
1693    while(arguments.read("--shader")) { useShader = true; }
1694
1695    osg::ref_ptr<osg::Image> image_3d;
1696
1697    int sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents;
1698    std::string endian, raw_filename;
1699    while (arguments.read("--raw", sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents, endian, raw_filename))
1700    {
1701        image_3d = readRaw(sizeX, sizeY, sizeZ, numberBytesPerComponent, numberOfComponents, endian, raw_filename);
1702    }
1703
1704    while (arguments.read("--images"))
1705    {
1706        ImageList imageList;
1707        for(int pos=1;pos<arguments.argc() && !arguments.isOption(pos);++pos)
1708        {
1709            // not an option so assume string is a filename.
1710            osg::Image *image = osgDB::readImageFile( arguments[pos]);
1711
1712            if(image)
1713            {
1714                imageList.push_back(image);
1715            }
1716        }
1717       
1718        // pack the textures into a single texture.
1719        ProcessRow processRow;
1720        image_3d = createTexture3D(imageList, processRow, numComponentsDesired, s_maximumTextureSize, t_maximumTextureSize, r_maximumTextureSize);
1721    }
1722
1723
1724    // any option left unread are converted into errors to write out later.
1725    arguments.reportRemainingOptionsAsUnrecognized();
1726
1727    // report any errors if they have occurred when parsing the program arguments.
1728    if (arguments.errors())
1729    {
1730        arguments.writeErrorMessages(std::cout);
1731        return 1;
1732    }
1733
1734    // assume remaining arguments are file names of textures.
1735    for(int pos=1;pos<arguments.argc() && !image_3d;++pos)
1736    {
1737        if (!arguments.isOption(pos))
1738        {
1739            // not an option so assume string is a filename.
1740            image_3d = osgDB::readImageFile( arguments[pos]);
1741        }
1742    }
1743   
1744    if (!image_3d)
1745    {
1746        std::cout<<"No model loaded, please specify and volumetric image file on the command line."<<std::endl;
1747        return 1;
1748    }
1749   
1750    if (colourSpaceOperation!=NO_COLOUR_SPACE_OPERATION)
1751    {
1752        doColourSpaceConversion(colourSpaceOperation, image_3d.get(), colourModulate);
1753    }
1754   
1755    osg::ref_ptr<osg::Image> normalmap_3d = createNormalMap ? createNormalMapTexture(image_3d.get()) : 0;
1756
1757
1758    osg::RefMatrix* matrix = dynamic_cast<osg::RefMatrix*>(image_3d->getUserData());
1759    if (matrix)
1760    {
1761        osg::notify(osg::NOTICE)<<"Image has Matrix = "<<*matrix<<std::endl;
1762        xSize = image_3d->s() * (*matrix)(0,0);
1763        ySize = image_3d->t() * (*matrix)(1,1);
1764        zSize = image_3d->r() * (*matrix)(2,2);
1765    }
1766
1767
1768    // create a model from the images.
1769    osg::Node* rootNode = 0;
1770   
1771    if (useShader)
1772    {
1773        rootNode = createShaderModel(image_3d, normalmap_3d,
1774                               internalFormatMode,
1775                               xSize, ySize, zSize,
1776                               xMultiplier, yMultiplier, zMultiplier,
1777                               numSlices, sliceEnd, alphaFunc, maximumIntensityProjection);
1778    }
1779    else
1780    {
1781        rootNode = createModel(image_3d, normalmap_3d,
1782                               internalFormatMode,
1783                               xSize, ySize, zSize,
1784                               xMultiplier, yMultiplier, zMultiplier,
1785                               numSlices, sliceEnd, alphaFunc, maximumIntensityProjection);
1786    }
1787   
1788    if (!outputFile.empty())
1789    {   
1790        std::string ext = osgDB::getFileExtension(outputFile);
1791        std::string name_no_ext = osgDB::getNameLessExtension(outputFile);
1792        if (ext=="osg")
1793        {
1794            if (image_3d.valid())
1795            {
1796                image_3d->setFileName(name_no_ext + ".dds");           
1797                osgDB::writeImageFile(*image_3d, image_3d->getFileName());
1798            }
1799            if (normalmap_3d.valid())
1800            {
1801                normalmap_3d->setFileName(name_no_ext + "_normalmap.dds");           
1802                osgDB::writeImageFile(*normalmap_3d, normalmap_3d->getFileName());
1803            }
1804           
1805            osgDB::writeNodeFile(*rootNode, outputFile);
1806        }
1807        else if (ext=="ive")
1808        {
1809            osgDB::writeNodeFile(*rootNode, outputFile);       
1810        }
1811        else if (ext=="dds")
1812        {
1813            osgDB::writeImageFile(*image_3d, outputFile);       
1814        }
1815        else
1816        {
1817            std::cout<<"Extension not support for file output, not file written."<<std::endl;
1818        }
1819       
1820        return 0;
1821    }
1822
1823
1824    if (rootNode)
1825    {
1826
1827        // set the scene to render
1828        viewer.setSceneData(rootNode);
1829       
1830        // the the viewers main frame loop
1831        viewer.run();
1832    }   
1833   
1834    return 0;
1835
1836}
Note: See TracBrowser for help on using the browser.