1 // Copyright (C) 2010 Frederic Bouvier
\r
3 // This library is free software; you can redistribute it and/or
\r
4 // modify it under the terms of the GNU Library General Public
\r
5 // License as published by the Free Software Foundation; either
\r
6 // version 2 of the License, or (at your option) any later version.
\r
8 // This library is distributed in the hope that it will be useful,
\r
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
11 // Library General Public License for more details.
\r
13 // You should have received a copy of the GNU General Public License
\r
14 // along with this program; if not, write to the Free Software
\r
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
17 #ifdef HAVE_CONFIG_H
\r
18 # include <simgear_config.h>
\r
21 #include "mipmap.hxx"
\r
22 #include "EffectBuilder.hxx"
\r
26 #include <osg/Image>
\r
29 #include <boost/lexical_cast.hpp>
\r
30 #include <boost/tuple/tuple_comparison.hpp>
\r
32 namespace simgear { namespace effect {
\r
34 EffectNameValue<MipMapFunction> mipmapFunctionsInit[] =
\r
36 {"auto", AUTOMATIC},
\r
37 {"average", AVERAGE},
\r
39 {"product", PRODUCT},
\r
43 EffectPropertyMap<MipMapFunction> mipmapFunctions(mipmapFunctionsInit);
\r
45 MipMapTuple makeMipMapTuple(Effect* effect, const SGPropertyNode* props,
\r
46 const SGReaderWriterXMLOptions* options)
\r
48 const SGPropertyNode* pMipmapR
\r
49 = getEffectPropertyChild(effect, props, "function-r");
\r
50 MipMapFunction mipmapR = AUTOMATIC;
\r
52 findAttr(mipmapFunctions, pMipmapR, mipmapR);
\r
53 const SGPropertyNode* pMipmapG
\r
54 = getEffectPropertyChild(effect, props, "function-g");
\r
55 MipMapFunction mipmapG = AUTOMATIC;
\r
57 findAttr(mipmapFunctions, pMipmapG, mipmapG);
\r
58 const SGPropertyNode* pMipmapB
\r
59 = getEffectPropertyChild(effect, props, "function-b");
\r
60 MipMapFunction mipmapB = AUTOMATIC;
\r
62 findAttr(mipmapFunctions, pMipmapB, mipmapB);
\r
63 const SGPropertyNode* pMipmapA
\r
64 = getEffectPropertyChild(effect, props, "function-a");
\r
65 MipMapFunction mipmapA = AUTOMATIC;
\r
67 findAttr(mipmapFunctions, pMipmapA, mipmapA);
\r
68 return MipMapTuple( mipmapR, mipmapG, mipmapB, mipmapA );
\r
72 unsigned char* imageData(unsigned char* ptr, GLenum pixelFormat, GLenum dataType, int width, int height, int packing, int column, int row=0, int image=0)
\r
74 if (!ptr) return NULL;
\r
76 ( column * osg::Image::computePixelSizeInBits( pixelFormat, dataType ) ) / 8 +
\r
77 row * osg::Image::computeRowWidthInBytes( width, pixelFormat, dataType, packing ) +
\r
78 image * height * osg::Image::computeRowWidthInBytes( width, pixelFormat, dataType, packing );
\r
81 template <typename T>
\r
82 void _writeColor(GLenum pixelFormat, T* data, float scale, osg::Vec4 value)
\r
86 case(GL_DEPTH_COMPONENT): //intentionally fall through and execute the code for GL_LUMINANCE
\r
87 case(GL_LUMINANCE): { *data++ = value.r()*scale; break; }
\r
88 case(GL_ALPHA): { *data++ = value.a()*scale; break; }
\r
89 case(GL_LUMINANCE_ALPHA): { *data++ = value.r()*scale; *data++ = value.a()*scale; break; }
\r
90 case(GL_RGB): { *data++ = value.r()*scale; *data++ = value.g()*scale; *data++ = value.b()*scale; break; }
\r
91 case(GL_RGBA): { *data++ = value.r()*scale; *data++ = value.g()*scale; *data++ = value.b()*scale; *data++ = value.a()*scale; break; }
\r
92 case(GL_BGR): { *data++ = value.b()*scale; *data++ = value.g()*scale; *data++ = value.r()*scale; break; }
\r
93 case(GL_BGRA): { *data++ = value.b()*scale; *data++ = value.g()*scale; *data++ = value.r()*scale; *data++ = value.a()*scale; break; }
\r
97 void setColor(unsigned char *ptr, GLenum pixelFormat, GLenum dataType, osg::Vec4 color)
\r
101 case(GL_BYTE): return _writeColor(pixelFormat, (char*)ptr, 128.0f, color);
\r
102 case(GL_UNSIGNED_BYTE): return _writeColor(pixelFormat, (unsigned char*)ptr, 255.0f, color);
\r
103 case(GL_SHORT): return _writeColor(pixelFormat, (short*)ptr, 32768.0f, color);
\r
104 case(GL_UNSIGNED_SHORT): return _writeColor(pixelFormat, (unsigned short*)ptr, 65535.0f, color);
\r
105 case(GL_INT): return _writeColor(pixelFormat, (int*)ptr, 2147483648.0f, color);
\r
106 case(GL_UNSIGNED_INT): return _writeColor(pixelFormat, (unsigned int*)ptr, 4294967295.0f, color);
\r
107 case(GL_FLOAT): return _writeColor(pixelFormat, (float*)ptr, 1.0f, color);
\r
111 template <typename T>
\r
112 osg::Vec4 _readColor(GLenum pixelFormat, T* data,float scale)
\r
114 switch(pixelFormat)
\r
116 case(GL_DEPTH_COMPONENT): //intentionally fall through and execute the code for GL_LUMINANCE
\r
117 case(GL_LUMINANCE): { float l = float(*data++)*scale; return osg::Vec4(l, l, l, 1.0f); }
\r
118 case(GL_ALPHA): { float a = float(*data++)*scale; return osg::Vec4(1.0f, 1.0f, 1.0f, a); }
\r
119 case(GL_LUMINANCE_ALPHA): { float l = float(*data++)*scale; float a = float(*data++)*scale; return osg::Vec4(l,l,l,a); }
\r
120 case(GL_RGB): { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; return osg::Vec4(r,g,b,1.0f); }
\r
121 case(GL_RGBA): { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; float a = float(*data++)*scale; return osg::Vec4(r,g,b,a); }
\r
122 case(GL_BGR): { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; return osg::Vec4(r,g,b,1.0f); }
\r
123 case(GL_BGRA): { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; float a = float(*data++)*scale; return osg::Vec4(r,g,b,a); }
\r
125 return osg::Vec4(1.0f,1.0f,1.0f,1.0f);
\r
128 osg::Vec4 getColor(const unsigned char* ptr, GLenum pixelFormat, GLenum dataType)
\r
132 case(GL_BYTE): return _readColor(pixelFormat, (char*)ptr, 1.0f/128.0f);
\r
133 case(GL_UNSIGNED_BYTE): return _readColor(pixelFormat, (unsigned char*)ptr, 1.0f/255.0f);
\r
134 case(GL_SHORT): return _readColor(pixelFormat, (short*)ptr, 1.0f/32768.0f);
\r
135 case(GL_UNSIGNED_SHORT): return _readColor(pixelFormat, (unsigned short*)ptr, 1.0f/65535.0f);
\r
136 case(GL_INT): return _readColor(pixelFormat, (int*)ptr, 1.0f/2147483648.0f);
\r
137 case(GL_UNSIGNED_INT): return _readColor(pixelFormat, (unsigned int*)ptr, 1.0f/4294967295.0f);
\r
138 case(GL_FLOAT): return _readColor(pixelFormat, (float*)ptr, 1.0f);
\r
140 return osg::Vec4(1.0f,1.0f,1.0f,1.0f);
\r
143 osg::Vec4::value_type computeAverage( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
\r
145 osg::Vec4::value_type r = 0;
\r
146 osg::Vec4::value_type nb = 0;
\r
147 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
\r
149 if ( colorValid[i][j][k] )
\r
151 r += colors[i][j][k][c];
\r
158 osg::Vec4::value_type computeSum( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
\r
160 osg::Vec4::value_type r = 0;
\r
161 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
\r
162 if ( colorValid[i][j][k] )
\r
164 r += colors[i][j][k][c];
\r
169 osg::Vec4::value_type computeProduct( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
\r
171 osg::Vec4::value_type r = 1;
\r
172 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
\r
173 if ( colorValid[i][j][k] )
\r
175 r *= colors[i][j][k][c];
\r
180 osg::Vec4::value_type computeMin( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
\r
182 osg::Vec4::value_type r = std::numeric_limits<osg::Vec4::value_type>::max();
\r
183 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
\r
184 if ( colorValid[i][j][k] )
\r
186 r = std::min( r, colors[i][j][k][c] );
\r
191 osg::Vec4::value_type computeMax( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
\r
193 osg::Vec4::value_type r = std::numeric_limits<osg::Vec4::value_type>::min();
\r
194 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
\r
195 if ( colorValid[i][j][k] )
\r
197 r = std::max( r, colors[i][j][k][c] );
\r
202 osg::Vec4::value_type computeComponent( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapFunction f )
\r
206 case AVERAGE: return computeAverage( c, colors, colorValid );
\r
207 case SUM: return computeSum( c, colors, colorValid );
\r
208 case PRODUCT: return computeProduct( c, colors, colorValid );
\r
209 case MIN: return computeMin( c, colors, colorValid );
\r
210 case MAX: return computeMax( c, colors, colorValid );
\r
215 osg::Vec4 computeColor( osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapTuple attrs )
\r
218 result[0] = computeComponent( 0, colors, colorValid, attrs.get<0>() );
\r
219 result[1] = computeComponent( 1, colors, colorValid, attrs.get<1>() );
\r
220 result[2] = computeComponent( 2, colors, colorValid, attrs.get<2>() );
\r
221 result[3] = computeComponent( 3, colors, colorValid, attrs.get<3>() );
\r
225 osg::Image* computeMipmap( osg::Image* image, MipMapTuple attrs )
\r
227 bool computeMipmap = false;
\r
228 if ( attrs.get<0>() != AUTOMATIC &&
\r
229 attrs.get<1>() != AUTOMATIC &&
\r
230 attrs.get<2>() != AUTOMATIC &&
\r
231 attrs.get<3>() != AUTOMATIC )
\r
233 computeMipmap = true;
\r
235 else if ( attrs.get<0>() != AUTOMATIC ||
\r
236 attrs.get<1>() != AUTOMATIC ||
\r
237 attrs.get<2>() != AUTOMATIC ||
\r
238 attrs.get<3>() != AUTOMATIC )
\r
240 throw BuilderException("invalid mipmap control function combination");
\r
243 if ( computeMipmap )
\r
245 osg::ref_ptr<osg::Image> mipmaps = new osg::Image();
\r
246 int s = image->s(),
\r
249 int nb = osg::Image::computeNumberOfMipmapLevels(s, t, r);
\r
250 osg::Image::MipmapDataType mipmapOffsets;
\r
251 unsigned int offset = 0;
\r
252 for ( int i = 0; i < nb; ++i )
\r
254 offset += t * r * osg::Image::computeRowWidthInBytes(s, image->getPixelFormat(), image->getDataType(), image->getPacking());
\r
255 mipmapOffsets.push_back( offset );
\r
256 s >>= 1; if ( s == 0 ) s = 1;
\r
257 t >>= 1; if ( t == 0 ) t = 1;
\r
258 r >>= 1; if ( r == 0 ) r = 1;
\r
260 mipmapOffsets.pop_back();
\r
261 unsigned char *data = new unsigned char[offset];
\r
262 memcpy( data, image->data(), mipmapOffsets.front() );
\r
266 for ( int m = 0; m < nb-1; ++m )
\r
268 unsigned char *src = data;
\r
270 src += mipmapOffsets[m-1];
\r
272 unsigned char *dest = data + mipmapOffsets[m];
\r
274 int ns = s >> 1; if ( ns == 0 ) ns = 1;
\r
275 int nt = t >> 1; if ( nt == 0 ) nt = 1;
\r
276 int nr = r >> 1; if ( nr == 0 ) nr = 1;
\r
278 for ( int k = 0; k < r; k += 2 )
\r
280 for ( int j = 0; j < t; j += 2 )
\r
282 for ( int i = 0; i < s; i += 2 )
\r
284 osg::Vec4 colors[2][2][2];
\r
285 bool colorValid[2][2][2];
\r
286 colorValid[0][0][0] = false; colorValid[0][0][1] = false; colorValid[0][1][0] = false; colorValid[0][1][1] = false;
\r
287 colorValid[1][0][0] = false; colorValid[1][0][1] = false; colorValid[1][1][0] = false; colorValid[1][1][1] = false;
\r
290 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j, k );
\r
291 colors[0][0][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
\r
292 colorValid[0][0][0] = true;
\r
296 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j, k );
\r
297 colors[0][0][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
\r
298 colorValid[0][0][1] = true;
\r
302 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j + 1, k );
\r
303 colors[0][1][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
\r
304 colorValid[0][1][0] = true;
\r
306 if ( i + 1 < s && j + 1 < t )
\r
308 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j + 1, k );
\r
309 colors[0][1][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
\r
310 colorValid[0][1][1] = true;
\r
314 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j, k + 1 );
\r
315 colors[1][0][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
\r
316 colorValid[1][0][0] = true;
\r
318 if ( i + 1 < s && k + 1 < r )
\r
320 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j, k + 1 );
\r
321 colors[1][0][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
\r
322 colorValid[1][0][1] = true;
\r
324 if ( j + 1 < t && k + 1 < r )
\r
326 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j + 1, k + 1 );
\r
327 colors[1][1][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
\r
328 colorValid[1][1][0] = true;
\r
330 if ( i + 1 < s && j + 1 < t && k + 1 < r )
\r
332 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j + 1, k + 1 );
\r
333 colors[1][1][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
\r
334 colorValid[1][1][1] = true;
\r
337 unsigned char *ptr = imageData( dest, image->getPixelFormat(), image->getDataType(), ns, nt, image->getPacking(), i/2, j/2, k/2 );
\r
338 osg::Vec4 color = computeColor( colors, colorValid, attrs );
\r
339 setColor( ptr, image->getPixelFormat(), image->getDataType(), color );
\r
347 mipmaps->setImage( image->s(), image->t(), image->r(),
\r
348 image->getInternalTextureFormat(), image->getPixelFormat(),
\r
349 image->getDataType(), data, osg::Image::USE_NEW_DELETE, image->getPacking() );
\r
350 mipmaps->setMipmapLevels( mipmapOffsets );
\r
352 return mipmaps.release();
\r