]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/mipmap.cxx
Work around apparent OSG 3.2.0 normal binding bug.
[simgear.git] / simgear / scene / material / mipmap.cxx
1 // Copyright (C) 2010  Frederic Bouvier
2 //
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.
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 GNU
11 // Library General Public License for more details.
12 //
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.
16
17 #ifdef HAVE_CONFIG_H
18 #  include <simgear_config.h>
19 #endif
20
21 #include "mipmap.hxx"
22 #include "EffectBuilder.hxx"
23
24 #include <limits>
25 #include <iomanip>
26
27 #include <osg/Image>
28 #include <osg/Vec4>
29
30 #include <boost/lexical_cast.hpp>
31 #include <boost/tuple/tuple_comparison.hpp>
32
33 namespace simgear { namespace effect {
34
35 EffectNameValue<MipMapFunction> mipmapFunctionsInit[] =
36 {
37     {"auto", AUTOMATIC},
38     {"average", AVERAGE},
39     {"sum", SUM},
40     {"product", PRODUCT},
41     {"min", MIN},
42     {"max", MAX}
43 };
44 EffectPropertyMap<MipMapFunction> mipmapFunctions(mipmapFunctionsInit);
45
46 MipMapTuple makeMipMapTuple(Effect* effect, const SGPropertyNode* props,
47                       const SGReaderWriterOptions* options)
48 {
49     const SGPropertyNode* pMipmapR
50         = getEffectPropertyChild(effect, props, "function-r");
51     MipMapFunction mipmapR = AUTOMATIC;
52     if (pMipmapR)
53         findAttr(mipmapFunctions, pMipmapR, mipmapR);
54     const SGPropertyNode* pMipmapG
55         = getEffectPropertyChild(effect, props, "function-g");
56     MipMapFunction mipmapG = AUTOMATIC;
57     if (pMipmapG)
58         findAttr(mipmapFunctions, pMipmapG, mipmapG);
59     const SGPropertyNode* pMipmapB
60         = getEffectPropertyChild(effect, props, "function-b");
61     MipMapFunction mipmapB = AUTOMATIC;
62     if (pMipmapB)
63         findAttr(mipmapFunctions, pMipmapB, mipmapB);
64     const SGPropertyNode* pMipmapA
65         = getEffectPropertyChild(effect, props, "function-a");
66     MipMapFunction mipmapA = AUTOMATIC;
67     if (pMipmapA)
68         findAttr(mipmapFunctions, pMipmapA, mipmapA);
69     return MipMapTuple( mipmapR, mipmapG, mipmapB, mipmapA );
70 }
71
72
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)
74 {
75     if (!ptr) return NULL;
76     return ptr +
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 );
80 }
81
82 template <typename T>
83 void _writeColor(GLenum pixelFormat, T* data, float scale, osg::Vec4 value)
84 {
85     switch(pixelFormat)
86     {
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; }
95     }
96 }
97
98 void setColor(unsigned char *ptr, GLenum pixelFormat, GLenum dataType, osg::Vec4 color)
99 {
100     switch(dataType)
101     {
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);
109     }
110 }
111
112 template <typename T>    
113 osg::Vec4 _readColor(GLenum pixelFormat, T* data,float scale)
114 {
115     switch(pixelFormat)
116     {
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); }
125     }
126     return osg::Vec4(1.0f,1.0f,1.0f,1.0f);
127 }
128
129 osg::Vec4 getColor(const unsigned char* ptr, GLenum pixelFormat, GLenum dataType)
130 {
131     switch(dataType)
132     {
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);
140     }
141     return osg::Vec4(1.0f,1.0f,1.0f,1.0f);
142 }
143
144 osg::Vec4::value_type computeAverage( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
145 {
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 )
149     {
150         if ( colorValid[i][j][k] )
151         {
152             r += colors[i][j][k][c];
153             nb += 1;
154         }
155     }
156     return r / nb;
157 }
158
159 osg::Vec4::value_type computeSum( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
160 {
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] )
164         {
165             r += colors[i][j][k][c];
166         }
167     return r;
168 }
169
170 osg::Vec4::value_type computeProduct( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
171 {
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] )
175         {
176             r *= colors[i][j][k][c];
177         }
178     return r;
179 }
180
181 osg::Vec4::value_type computeMin( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
182 {
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] )
186         {
187             r = std::min( r, colors[i][j][k][c] );
188         }
189     return r;
190 }
191
192 osg::Vec4::value_type computeMax( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
193 {
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] )
197         {
198             r = std::max( r, colors[i][j][k][c] );
199         }
200     return r;
201 }
202
203 osg::Vec4::value_type computeComponent( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapFunction f )
204 {
205     switch ( f )
206     {
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 );
212     default: break;
213     }
214     return 0;
215 }
216
217 osg::Vec4 computeColor( osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapTuple attrs, GLenum pixelFormat )
218 {
219     osg::Vec4 result;
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>() );
228     return result;
229 }
230
231 void dumpMipmap( std::string n, int s, int t, int r, int c, unsigned char *d, const osg::Image::MipmapDataType &o )
232 {
233     std::ofstream ofs( (n + ".dump").c_str() );
234     for ( osg::Image::MipmapDataType::size_type i = 0; i < o.size()+1; ++i )
235     {
236         ofs << s << " " << t << " " << r << std::endl;
237         unsigned int offset = 0;
238         if ( i > 0 )
239             offset = o[i-1];
240         unsigned char *p = &d[offset];
241         for ( int l = 0; l < r; ++l )
242         {
243             for ( int k = 0; k < t; ++k )
244             {
245                 for ( int j = 0; j < s; ++j )
246                 {
247                     ofs << "(";
248                     for ( int m = 0; m < c; ++m )
249                     {
250                         if ( m != 0 )
251                             ofs << " ";
252                         ofs << std::setw(3) << (unsigned int)*p++;
253                     }
254                     ofs << ")";
255                 }
256                 ofs << std::endl;
257             }
258             ofs << std::endl;
259         }
260         ofs << std::endl;
261         s >>= 1; if ( s == 0 ) s = 1;
262         t >>= 1; if ( t == 0 ) t = 1;
263         r >>= 1; if ( r == 0 ) r = 1;
264     }
265 }
266
267 osg::Image* computeMipmap( osg::Image* image, MipMapTuple attrs )
268 {
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 ) )
275     {
276         computeMipmap = true;
277     }
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 ) )
282     {
283         throw BuilderException("invalid mipmap control function combination");
284     }
285
286     if ( computeMipmap )
287     {
288         osg::ref_ptr<osg::Image> mipmaps = new osg::Image();
289         int s = image->s(),
290             t = image->t(),
291             r = image->r();
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 )
296         {
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;
302         }
303         mipmapOffsets.pop_back();
304         unsigned char *data = new unsigned char[offset];
305         memcpy( data, image->data(), mipmapOffsets.front() );
306         s = image->s();
307         t = image->t();
308         r = image->r();
309         for ( int m = 0; m < nb-1; ++m )
310         {
311             unsigned char *src = data;
312             if ( m > 0 )
313                 src += mipmapOffsets[m-1];
314
315             unsigned char *dest = data + mipmapOffsets[m];
316
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;
320
321             for ( int k = 0; k < r; k += 2 )
322             {
323                 for ( int j = 0; j < t; j += 2 )
324                 {
325                     for ( int i = 0; i < s; i += 2 )
326                     {
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;
331                         if ( true )
332                         {
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;
336                         }
337                         if ( i + 1 < s )
338                         {
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;
342                         }
343                         if ( j + 1 < t )
344                         {
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;
348                         }
349                         if ( i + 1 < s && j + 1 < t )
350                         {
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;
354                         }
355                         if ( k + 1 < r )
356                         {
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;
360                         }
361                         if ( i + 1 < s && k + 1 < r )
362                         {
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;
366                         }
367                         if ( j + 1 < t && k + 1 < r )
368                         {
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;
372                         }
373                         if ( i + 1 < s && j + 1 < t && k + 1 < r )
374                         {
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;
378                         }
379
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 );
383                     }
384                 }
385             }
386             s = ns;
387             t = nt;
388             r = nr;
389         }
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 );
395
396         return mipmaps.release();
397     }
398     return image;
399 }
400 } }