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

Revision 4500, 58.9 kB (checked in by robert, 9 years ago)

Added all sides of the shader cube

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