1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#ifndef OSG_IMAGEUTILS
15#define OSG_IMAGEUTILS 1
16
17#include <osg/Export>
18
19#include <osg/Image>
20#include <osg/Vec3i>
21
22namespace osg {
23
24template <typename T, class O>
25void _readRow(unsigned int num, GLenum pixelFormat, const T* data, O& operation)
26{
27    switch(pixelFormat)
28    {
29        case(GL_INTENSITY):         { for(unsigned int i=0;i<num;++i) { T v=*data++; operation.rgba( operation.cast(v),operation.cast(v),operation.cast(v),operation.cast(v)); } }  break;
30        case(GL_LUMINANCE):         { for(unsigned int i=0;i<num;++i) { operation.luminance(operation.cast(*data++)); } }  break;
31        case(GL_ALPHA):             { for(unsigned int i=0;i<num;++i) { operation.alpha(operation.cast(*data++)); } }  break;
32        case(GL_LUMINANCE_ALPHA):   { for(unsigned int i=0;i<num;++i) { T l=*data++; T a = *data++; operation.luminance_alpha(operation.cast(l),operation.cast(a)); } }  break;
33        case(GL_RGB):               { for(unsigned int i=0;i<num;++i) { T r=*data++; T g=*data++; T b=*data++; operation.rgb(operation.cast(r),operation.cast(g),operation.cast(b)); } } break;
34        case(GL_RGBA):              { for(unsigned int i=0;i<num;++i) { T r=*data++; T g=*data++; T b=*data++; T a=*data++; operation.rgba(operation.cast(r),operation.cast(g),operation.cast(b),operation.cast(a)); } } break;
35        case(GL_BGR):               { for(unsigned int i=0;i<num;++i) { T b=*data++; T g=*data++; T r=*data++; operation.rgb(operation.cast(r),operation.cast(g),operation.cast(b)); } }  break;
36        case(GL_BGRA):              { for(unsigned int i=0;i<num;++i) { T b=*data++; T g=*data++; T r=*data++; T a=*data++; operation.rgba(operation.cast(r),operation.cast(g),operation.cast(b),operation.cast(a)); } }  break;
37    }
38}
39
40
41template <class O>
42void readRow(unsigned int num, GLenum pixelFormat, GLenum dataType, const unsigned char* data, O& operation)
43{
44    switch(dataType)
45    {
46        case(GL_BYTE):              _readRow(num, pixelFormat, (const char*)data,            operation); break;
47        case(GL_UNSIGNED_BYTE):     _readRow(num, pixelFormat, (const unsigned char*)data,   operation); break;
48        case(GL_SHORT):             _readRow(num, pixelFormat, (const short*) data,          operation); break;
49        case(GL_UNSIGNED_SHORT):    _readRow(num, pixelFormat, (const unsigned short*)data,  operation); break;
50        case(GL_INT):               _readRow(num, pixelFormat, (const int*) data,            operation); break;
51        case(GL_UNSIGNED_INT):      _readRow(num, pixelFormat, (const unsigned int*) data,   operation); break;
52        case(GL_FLOAT):             _readRow(num, pixelFormat, (const float*) data,          operation); break;
53        case(GL_DOUBLE):            _readRow(num, pixelFormat, (const double*) data,         operation); break;
54    }
55}
56
57
58template <class O>
59void readImage(const osg::Image* image, O& operation)
60{
61    if (!image) return;
62
63    for(int r=0;r<image->r();++r)
64    {
65        for(int t=0;t<image->t();++t)
66        {
67            readRow(image->s(), image->getPixelFormat(), image->getDataType(), image->data(0,t,r), operation);
68        }
69    }
70}
71
72/** Convenience method for making it easy to cast all pixel channels types to a unit float RGBA form.*/
73struct CastAndScaleToFloatOperation
74{
75    float cast(char v) { return static_cast<float>(v)*(1.0f/128.0f); }
76    float cast(unsigned char v) { return static_cast<float>(v)*(1.0f/255.0f); }
77    float cast(short v) { return static_cast<float>(v)*(1.0f/32768.0f); }
78    float cast(unsigned short v) { return static_cast<float>(v)*(1.0f/65535.0f); }
79    float cast(int v) { return static_cast<float>(v)*(1.0f/2147483648.0f); }
80    float cast(unsigned int v) { return static_cast<float>(v)*(1.0f/4294967295.0f); }
81    float cast(float v) { return v; }
82    float cast(double v) { return static_cast<double>(v); }
83};
84
85#if 0
86template <typename T, class O>
87void _readRow(unsigned int num, GLenum pixelFormat, const T* data,float scale, O& operation)
88{
89    switch(pixelFormat)
90    {
91        case(GL_LUMINANCE):         { for(unsigned int i=0;i<num;++i) { float l = float(*data++)*scale; operation.luminance(l); } }  break;
92        case(GL_ALPHA):             { for(unsigned int i=0;i<num;++i) { float a = float(*data++)*scale; operation.alpha(a); } }  break;
93        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;
94        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;
95        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;
96        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;
97        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;
98    }
99}
100
101template <class O>
102void readRow(unsigned int num, GLenum pixelFormat, GLenum dataType, const unsigned char* data, O& operation)
103{
104    switch(dataType)
105    {
106        case(GL_BYTE):              _readRow(num,pixelFormat, (const char*)data,            1.0f/128.0f,        operation); break;
107        case(GL_UNSIGNED_BYTE):     _readRow(num,pixelFormat, (const unsigned char*)data,   1.0f/255.0f,        operation); break;
108        case(GL_SHORT):             _readRow(num,pixelFormat, (const short*) data,          1.0f/32768.0f,      operation); break;
109        case(GL_UNSIGNED_SHORT):    _readRow(num,pixelFormat, (const unsigned short*)data,  1.0f/65535.0f,      operation); break;
110        case(GL_INT):               _readRow(num,pixelFormat, (const int*) data,            1.0f/2147483648.0f, operation); break;
111        case(GL_UNSIGNED_INT):      _readRow(num,pixelFormat, (const unsigned int*) data,   1.0f/4294967295.0f, operation); break;
112        case(GL_FLOAT):             _readRow(num,pixelFormat, (const float*) data,          1.0f,               operation); break;
113    }
114}
115
116template <class O>
117void readImage(const osg::Image* image, O& operation)
118{
119    if (!image) return;
120
121    for(int r=0;r<image->r();++r)
122    {
123        for(int t=0;t<image->t();++t)
124        {
125            readRow(image->s(), image->getPixelFormat(), image->getDataType(), image->data(0,t,r), operation);
126        }
127    }
128}
129#endif
130
131
132
133// example ModifyOperator
134// struct ModifyOperator
135// {
136//     inline void luminance(float& l) const {}
137//     inline void alpha(float& a) const {}
138//     inline void luminance_alpha(float& l,float& a) const {}
139//     inline void rgb(float& r,float& g,float& b) const {}
140//     inline void rgba(float& r,float& g,float& b,float& a) const {}
141// };
142
143
144template <typename T, class M>
145void _modifyRow(unsigned int num, GLenum pixelFormat, T* data,float scale, const M& operation)
146{
147    float inv_scale = 1.0f/scale;
148    switch(pixelFormat)
149    {
150        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;
151        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;
152        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;
153        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;
154        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(b*inv_scale); *data++ = T(a*inv_scale); } }  break;
155        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;
156        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(b*inv_scale); *data++ = T(g*inv_scale); *data++ = T(r*inv_scale); *data++ = T(a*inv_scale); } }  break;
157    }
158}
159
160template <class M>
161void modifyRow(unsigned int num, GLenum pixelFormat, GLenum dataType, unsigned char* data, const M& operation)
162{
163    switch(dataType)
164    {
165        case(GL_BYTE):              _modifyRow(num,pixelFormat, (char*)data,            1.0f/128.0f,        operation); break;
166        case(GL_UNSIGNED_BYTE):     _modifyRow(num,pixelFormat, (unsigned char*)data,   1.0f/255.0f,        operation); break;
167        case(GL_SHORT):             _modifyRow(num,pixelFormat, (short*) data,          1.0f/32768.0f,      operation); break;
168        case(GL_UNSIGNED_SHORT):    _modifyRow(num,pixelFormat, (unsigned short*)data,  1.0f/65535.0f,      operation); break;
169        case(GL_INT):               _modifyRow(num,pixelFormat, (int*) data,            1.0f/2147483648.0f, operation); break;
170        case(GL_UNSIGNED_INT):      _modifyRow(num,pixelFormat, (unsigned int*) data,   1.0f/4294967295.0f, operation); break;
171        case(GL_FLOAT):             _modifyRow(num,pixelFormat, (float*) data,          1.0f,               operation); break;
172    }
173}
174
175template <class M>
176void modifyImage(osg::Image* image, const M& operation)
177{
178    if (!image) return;
179
180    for(int r=0;r<image->r();++r)
181    {
182        for(int t=0;t<image->t();++t)
183        {
184            modifyRow(image->s(), image->getPixelFormat(), image->getDataType(), image->data(0,t,r), operation);
185        }
186    }
187}
188
189/** Compute the min max colour values in the image.*/
190extern OSG_EXPORT bool computeMinMax(const osg::Image* image, osg::Vec4& min, osg::Vec4& max);
191
192/** Compute the min max colour values in the image.*/
193extern OSG_EXPORT bool offsetAndScaleImage(osg::Image* image, const osg::Vec4& offset, const osg::Vec4& scale);
194
195/** Compute source image to destination image.*/
196extern OSG_EXPORT bool copyImage(const osg::Image* srcImage, int src_s, int src_t, int src_r, int width, int height, int depth,
197                                       osg::Image* destImage, int dest_s, int dest_t, int dest_r, bool doRescale = false);
198
199/** Compute the min max colour values in the image.*/
200extern OSG_EXPORT bool clearImageToColor(osg::Image* image, const osg::Vec4& colour);
201
202typedef std::vector< osg::ref_ptr<osg::Image> > ImageList;
203
204/** Search through the list of Images and find the maximum number of components used among the images.*/
205extern OSG_EXPORT unsigned int maximimNumOfComponents(const ImageList& imageList);
206
207/** create a 3D osg::Image from a list of osg::Image.*/
208extern OSG_EXPORT osg::Image* createImage3D(const ImageList& imageList,
209            GLenum desiredPixelFormat,
210            int s_maximumImageSize = 1024,
211            int t_maximumImageSize = 1024,
212            int r_maximumImageSize = 1024,
213            bool resizeToPowerOfTwo = false);
214
215/** create a 3D osg::Image from a list of osg::Image.*/
216extern OSG_EXPORT osg::Image* createImage3DWithAlpha(const ImageList& imageList,
217            int s_maximumImageSize = 1024,
218            int t_maximumImageSize = 1024,
219            int r_maximumImageSize = 1024,
220            bool resizeToPowerOfTwo = false);
221
222
223
224
225/** create a 2D osg::Image that provides a point at the center of the image.
226 *  The colour across th image is computed from a balance between the center color and the background color controlled by the power of the radius from the center.*/
227extern OSG_EXPORT osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power);
228
229
230enum ColorSpaceOperation
231{
232    NO_COLOR_SPACE_OPERATION,
233    MODULATE_ALPHA_BY_LUMINANCE,
234    MODULATE_ALPHA_BY_COLOR,
235    REPLACE_ALPHA_WITH_LUMINANCE,
236    REPLACE_RGB_WITH_LUMINANCE
237};
238
239/** Convert the RGBA values in a Image based on a ColorSpaceOperation defined scheme.*/
240extern OSG_EXPORT osg::Image* colorSpaceConversion(ColorSpaceOperation op, osg::Image* image, const osg::Vec4& colour);
241
242/** Create a copy of an osg::Image. converting the origin and orientation to standard lower left OpenGL style origin .*/
243extern OSG_EXPORT osg::Image* createImageWithOrientationConversion(const osg::Image* srcImage, const osg::Vec3i& srcOrigin, const osg::Vec3i& srcRow, const osg::Vec3i& srcColumn, const osg::Vec3i& srcLayer);
244
245}
246
247
248#endif
249