1 // Copyright (C) 2010 Frederic Bouvier
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
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 GNU
11 // Library General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # include <simgear_config.h>
22 #include "EffectBuilder.hxx"
30 #include <boost/lexical_cast.hpp>
31 #include <boost/tuple/tuple_comparison.hpp>
33 namespace simgear { namespace effect {
35 EffectNameValue<MipMapFunction> mipmapFunctionsInit[] =
44 EffectPropertyMap<MipMapFunction> mipmapFunctions(mipmapFunctionsInit);
46 MipMapTuple makeMipMapTuple(Effect* effect, const SGPropertyNode* props,
47 const SGReaderWriterOptions* options)
49 const SGPropertyNode* pMipmapR
50 = getEffectPropertyChild(effect, props, "function-r");
51 MipMapFunction mipmapR = AUTOMATIC;
53 findAttr(mipmapFunctions, pMipmapR, mipmapR);
54 const SGPropertyNode* pMipmapG
55 = getEffectPropertyChild(effect, props, "function-g");
56 MipMapFunction mipmapG = AUTOMATIC;
58 findAttr(mipmapFunctions, pMipmapG, mipmapG);
59 const SGPropertyNode* pMipmapB
60 = getEffectPropertyChild(effect, props, "function-b");
61 MipMapFunction mipmapB = AUTOMATIC;
63 findAttr(mipmapFunctions, pMipmapB, mipmapB);
64 const SGPropertyNode* pMipmapA
65 = getEffectPropertyChild(effect, props, "function-a");
66 MipMapFunction mipmapA = AUTOMATIC;
68 findAttr(mipmapFunctions, pMipmapA, mipmapA);
69 return MipMapTuple( mipmapR, mipmapG, mipmapB, mipmapA );
73 unsigned char* imageData(unsigned char* ptr, GLenum pixelFormat, GLenum dataType, int width, int height, int packing, int column, int row=0, int image=0)
75 if (!ptr) return NULL;
77 ( column * osg::Image::computePixelSizeInBits( pixelFormat, dataType ) ) / 8 +
78 row * osg::Image::computeRowWidthInBytes( width, pixelFormat, dataType, packing ) +
79 image * height * osg::Image::computeRowWidthInBytes( width, pixelFormat, dataType, packing );
83 void _writeColor(GLenum pixelFormat, T* data, float scale, osg::Vec4 value)
87 case(GL_DEPTH_COMPONENT): //intentionally fall through and execute the code for GL_LUMINANCE
88 case(GL_LUMINANCE): { *data++ = value.r()*scale; break; }
89 case(GL_ALPHA): { *data++ = value.a()*scale; break; }
90 case(GL_LUMINANCE_ALPHA): { *data++ = value.r()*scale; *data++ = value.a()*scale; break; }
91 case(GL_RGB): { *data++ = value.r()*scale; *data++ = value.g()*scale; *data++ = value.b()*scale; break; }
92 case(GL_RGBA): { *data++ = value.r()*scale; *data++ = value.g()*scale; *data++ = value.b()*scale; *data++ = value.a()*scale; break; }
93 case(GL_BGR): { *data++ = value.b()*scale; *data++ = value.g()*scale; *data++ = value.r()*scale; break; }
94 case(GL_BGRA): { *data++ = value.b()*scale; *data++ = value.g()*scale; *data++ = value.r()*scale; *data++ = value.a()*scale; break; }
98 void setColor(unsigned char *ptr, GLenum pixelFormat, GLenum dataType, osg::Vec4 color)
102 case(GL_BYTE): return _writeColor(pixelFormat, (char*)ptr, 128.0f, color);
103 case(GL_UNSIGNED_BYTE): return _writeColor(pixelFormat, (unsigned char*)ptr, 255.0f, color);
104 case(GL_SHORT): return _writeColor(pixelFormat, (short*)ptr, 32768.0f, color);
105 case(GL_UNSIGNED_SHORT): return _writeColor(pixelFormat, (unsigned short*)ptr, 65535.0f, color);
106 case(GL_INT): return _writeColor(pixelFormat, (int*)ptr, 2147483648.0f, color);
107 case(GL_UNSIGNED_INT): return _writeColor(pixelFormat, (unsigned int*)ptr, 4294967295.0f, color);
108 case(GL_FLOAT): return _writeColor(pixelFormat, (float*)ptr, 1.0f, color);
112 template <typename T>
113 osg::Vec4 _readColor(GLenum pixelFormat, T* data,float scale)
117 case(GL_DEPTH_COMPONENT): //intentionally fall through and execute the code for GL_LUMINANCE
118 case(GL_LUMINANCE): { float l = float(*data++)*scale; return osg::Vec4(l, l, l, 1.0f); }
119 case(GL_ALPHA): { float a = float(*data++)*scale; return osg::Vec4(1.0f, 1.0f, 1.0f, a); }
120 case(GL_LUMINANCE_ALPHA): { float l = float(*data++)*scale; float a = float(*data++)*scale; return osg::Vec4(l,l,l,a); }
121 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); }
122 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); }
123 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); }
124 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); }
126 return osg::Vec4(1.0f,1.0f,1.0f,1.0f);
129 osg::Vec4 getColor(const unsigned char* ptr, GLenum pixelFormat, GLenum dataType)
133 case(GL_BYTE): return _readColor(pixelFormat, (char*)ptr, 1.0f/128.0f);
134 case(GL_UNSIGNED_BYTE): return _readColor(pixelFormat, (unsigned char*)ptr, 1.0f/255.0f);
135 case(GL_SHORT): return _readColor(pixelFormat, (short*)ptr, 1.0f/32768.0f);
136 case(GL_UNSIGNED_SHORT): return _readColor(pixelFormat, (unsigned short*)ptr, 1.0f/65535.0f);
137 case(GL_INT): return _readColor(pixelFormat, (int*)ptr, 1.0f/2147483648.0f);
138 case(GL_UNSIGNED_INT): return _readColor(pixelFormat, (unsigned int*)ptr, 1.0f/4294967295.0f);
139 case(GL_FLOAT): return _readColor(pixelFormat, (float*)ptr, 1.0f);
141 return osg::Vec4(1.0f,1.0f,1.0f,1.0f);
144 osg::Vec4::value_type computeAverage( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
146 osg::Vec4::value_type r = 0;
147 osg::Vec4::value_type nb = 0;
148 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
150 if ( colorValid[i][j][k] )
152 r += colors[i][j][k][c];
159 osg::Vec4::value_type computeSum( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
161 osg::Vec4::value_type r = 0;
162 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
163 if ( colorValid[i][j][k] )
165 r += colors[i][j][k][c];
170 osg::Vec4::value_type computeProduct( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
172 osg::Vec4::value_type r = 1;
173 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
174 if ( colorValid[i][j][k] )
176 r *= colors[i][j][k][c];
181 osg::Vec4::value_type computeMin( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
183 osg::Vec4::value_type r = std::numeric_limits<osg::Vec4::value_type>::max();
184 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
185 if ( colorValid[i][j][k] )
187 r = std::min( r, colors[i][j][k][c] );
192 osg::Vec4::value_type computeMax( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
194 osg::Vec4::value_type r = std::numeric_limits<osg::Vec4::value_type>::min();
195 for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
196 if ( colorValid[i][j][k] )
198 r = std::max( r, colors[i][j][k][c] );
203 osg::Vec4::value_type computeComponent( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapFunction f )
207 case AVERAGE: return computeAverage( c, colors, colorValid );
208 case SUM: return computeSum( c, colors, colorValid );
209 case PRODUCT: return computeProduct( c, colors, colorValid );
210 case MIN: return computeMin( c, colors, colorValid );
211 case MAX: return computeMax( c, colors, colorValid );
217 osg::Vec4 computeColor( osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapTuple attrs, GLenum pixelFormat )
220 unsigned int nbComponents = osg::Image::computeNumComponents( pixelFormat );
221 result[0] = computeComponent( 0, colors, colorValid, attrs.get<0>() );
222 if ( nbComponents >= 2 )
223 result[1] = computeComponent( 1, colors, colorValid, attrs.get<1>() );
224 if ( nbComponents >= 3 )
225 result[2] = computeComponent( 2, colors, colorValid, attrs.get<2>() );
226 if ( nbComponents == 4 )
227 result[3] = computeComponent( 3, colors, colorValid, attrs.get<3>() );
231 void dumpMipmap( std::string n, int s, int t, int r, int c, unsigned char *d, const osg::Image::MipmapDataType &o )
233 std::ofstream ofs( (n + ".dump").c_str() );
234 for ( osg::Image::MipmapDataType::size_type i = 0; i < o.size()+1; ++i )
236 ofs << s << " " << t << " " << r << std::endl;
237 unsigned int offset = 0;
240 unsigned char *p = &d[offset];
241 for ( int l = 0; l < r; ++l )
243 for ( int k = 0; k < t; ++k )
245 for ( int j = 0; j < s; ++j )
248 for ( int m = 0; m < c; ++m )
252 ofs << std::setw(3) << (unsigned int)*p++;
261 s >>= 1; if ( s == 0 ) s = 1;
262 t >>= 1; if ( t == 0 ) t = 1;
263 r >>= 1; if ( r == 0 ) r = 1;
267 osg::Image* computeMipmap( osg::Image* image, MipMapTuple attrs )
269 bool computeMipmap = false;
270 unsigned int nbComponents = osg::Image::computeNumComponents( image->getPixelFormat() );
271 if ( attrs.get<0>() != AUTOMATIC &&
272 ( attrs.get<1>() != AUTOMATIC || nbComponents < 2 ) &&
273 ( attrs.get<2>() != AUTOMATIC || nbComponents < 3 ) &&
274 ( attrs.get<3>() != AUTOMATIC || nbComponents < 4 ) )
276 computeMipmap = true;
278 else if ( attrs.get<0>() != AUTOMATIC ||
279 ( attrs.get<1>() != AUTOMATIC && nbComponents >= 2 ) ||
280 ( attrs.get<2>() != AUTOMATIC && nbComponents >= 3 ) ||
281 ( attrs.get<3>() != AUTOMATIC && nbComponents == 4 ) )
283 throw BuilderException("invalid mipmap control function combination");
288 osg::ref_ptr<osg::Image> mipmaps = new osg::Image();
292 int nb = osg::Image::computeNumberOfMipmapLevels(s, t, r);
293 osg::Image::MipmapDataType mipmapOffsets;
294 unsigned int offset = 0;
295 for ( int i = 0; i < nb; ++i )
297 offset += t * r * osg::Image::computeRowWidthInBytes(s, image->getPixelFormat(), image->getDataType(), image->getPacking());
298 mipmapOffsets.push_back( offset );
299 s >>= 1; if ( s == 0 ) s = 1;
300 t >>= 1; if ( t == 0 ) t = 1;
301 r >>= 1; if ( r == 0 ) r = 1;
303 mipmapOffsets.pop_back();
304 unsigned char *data = new unsigned char[offset];
305 memcpy( data, image->data(), mipmapOffsets.front() );
309 for ( int m = 0; m < nb-1; ++m )
311 unsigned char *src = data;
313 src += mipmapOffsets[m-1];
315 unsigned char *dest = data + mipmapOffsets[m];
317 int ns = s >> 1; if ( ns == 0 ) ns = 1;
318 int nt = t >> 1; if ( nt == 0 ) nt = 1;
319 int nr = r >> 1; if ( nr == 0 ) nr = 1;
321 for ( int k = 0; k < r; k += 2 )
323 for ( int j = 0; j < t; j += 2 )
325 for ( int i = 0; i < s; i += 2 )
327 osg::Vec4 colors[2][2][2];
328 bool colorValid[2][2][2];
329 colorValid[0][0][0] = false; colorValid[0][0][1] = false; colorValid[0][1][0] = false; colorValid[0][1][1] = false;
330 colorValid[1][0][0] = false; colorValid[1][0][1] = false; colorValid[1][1][0] = false; colorValid[1][1][1] = false;
333 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j, k );
334 colors[0][0][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
335 colorValid[0][0][0] = true;
339 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j, k );
340 colors[0][0][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
341 colorValid[0][0][1] = true;
345 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j + 1, k );
346 colors[0][1][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
347 colorValid[0][1][0] = true;
349 if ( i + 1 < s && j + 1 < t )
351 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j + 1, k );
352 colors[0][1][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
353 colorValid[0][1][1] = true;
357 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j, k + 1 );
358 colors[1][0][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
359 colorValid[1][0][0] = true;
361 if ( i + 1 < s && k + 1 < r )
363 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j, k + 1 );
364 colors[1][0][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
365 colorValid[1][0][1] = true;
367 if ( j + 1 < t && k + 1 < r )
369 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j + 1, k + 1 );
370 colors[1][1][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
371 colorValid[1][1][0] = true;
373 if ( i + 1 < s && j + 1 < t && k + 1 < r )
375 unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j + 1, k + 1 );
376 colors[1][1][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
377 colorValid[1][1][1] = true;
380 unsigned char *ptr = imageData( dest, image->getPixelFormat(), image->getDataType(), ns, nt, image->getPacking(), i/2, j/2, k/2 );
381 osg::Vec4 color = computeColor( colors, colorValid, attrs, image->getPixelFormat() );
382 setColor( ptr, image->getPixelFormat(), image->getDataType(), color );
390 //dumpMipmap( image->getFileName(), image->s(), image->t(), image->r(), osg::Image::computeNumComponents(image->getPixelFormat()), data, mipmapOffsets );
391 mipmaps->setImage( image->s(), image->t(), image->r(),
392 image->getInternalTextureFormat(), image->getPixelFormat(),
393 image->getDataType(), data, osg::Image::USE_NEW_DELETE, image->getPacking() );
394 mipmaps->setMipmapLevels( mipmapOffsets );
396 return mipmaps.release();