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

Revision 8784, 67.2 kB (checked in by robert, 6 years ago)

Added command line arguments to Viewer constructor, and added meaningful error message when no 3d image is provided

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