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

Revision 3806, 53.7 kB (checked in by robert, 10 years ago)

Added support for modulating alpha values

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