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

Revision 4499, 56.7 kB (checked in by robert, 9 years ago)

Added preliminary GLSL shader path for volume rendering.

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