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

Revision 8936, 76.8 kB (checked in by robert, 6 years ago)

Moved shaders into .cpp, with the shaders created by the new osg2cpp utility

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