]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/material/mipmap.cxx
Random buildings - initial commit.
[simgear.git] / simgear / scene / material / mipmap.cxx
index 9c087cf305b1bf41c6532ed932e6b3a8e5d536fe..59a800daaee2334531dea116e0459673f1b87972 100644 (file)
-// Copyright (C) 2010  Frederic Bouvier\r
-//\r
-// This library is free software; you can redistribute it and/or\r
-// modify it under the terms of the GNU Library General Public\r
-// License as published by the Free Software Foundation; either\r
-// version 2 of the License, or (at your option) any later version.\r
-//\r
-// This library is distributed in the hope that it will be useful,\r
-// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
-// Library General Public License for more details.\r
-//\r
-// You should have received a copy of the GNU General Public License\r
-// along with this program; if not, write to the Free Software\r
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-\r
-#ifdef HAVE_CONFIG_H\r
-#  include <simgear_config.h>\r
-#endif\r
-\r
-#include "mipmap.hxx"\r
-#include "EffectBuilder.hxx"\r
-\r
-#include <limits>\r
-\r
-#include <osg/Image>\r
-#include <osg/Vec4>\r
-\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/tuple/tuple_comparison.hpp>\r
-\r
-namespace simgear { namespace effect {\r
-\r
-EffectNameValue<MipMapFunction> mipmapFunctionsInit[] =\r
-{\r
-    {"auto", AUTOMATIC},\r
-    {"average", AVERAGE},\r
-    {"sum", SUM},\r
-    {"product", PRODUCT},\r
-    {"min", MIN},\r
-    {"max", MAX}\r
-};\r
-EffectPropertyMap<MipMapFunction> mipmapFunctions(mipmapFunctionsInit);\r
-\r
-MipMapTuple makeMipMapTuple(Effect* effect, const SGPropertyNode* props,\r
-                      const SGReaderWriterXMLOptions* options)\r
-{\r
-    const SGPropertyNode* pMipmapR\r
-        = getEffectPropertyChild(effect, props, "function-r");\r
-    MipMapFunction mipmapR = AUTOMATIC;\r
-    if (pMipmapR)\r
-        findAttr(mipmapFunctions, pMipmapR, mipmapR);\r
-    const SGPropertyNode* pMipmapG\r
-        = getEffectPropertyChild(effect, props, "function-g");\r
-    MipMapFunction mipmapG = AUTOMATIC;\r
-    if (pMipmapG)\r
-        findAttr(mipmapFunctions, pMipmapG, mipmapG);\r
-    const SGPropertyNode* pMipmapB\r
-        = getEffectPropertyChild(effect, props, "function-b");\r
-    MipMapFunction mipmapB = AUTOMATIC;\r
-    if (pMipmapB)\r
-        findAttr(mipmapFunctions, pMipmapB, mipmapB);\r
-    const SGPropertyNode* pMipmapA\r
-        = getEffectPropertyChild(effect, props, "function-a");\r
-    MipMapFunction mipmapA = AUTOMATIC;\r
-    if (pMipmapA)\r
-        findAttr(mipmapFunctions, pMipmapA, mipmapA);\r
-    return MipMapTuple( mipmapR, mipmapG, mipmapB, mipmapA );\r
-}\r
-\r
-\r
-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
-{\r
-    if (!ptr) return NULL;\r
-    return ptr +\r
-        ( column * osg::Image::computePixelSizeInBits( pixelFormat, dataType ) ) / 8 +\r
-        row * osg::Image::computeRowWidthInBytes( width, pixelFormat, dataType, packing ) +\r
-        image * height * osg::Image::computeRowWidthInBytes( width, pixelFormat, dataType, packing );\r
-}\r
-\r
-template <typename T>\r
-void _writeColor(GLenum pixelFormat, T* data, float scale, osg::Vec4 value)\r
-{\r
-    switch(pixelFormat)\r
-    {\r
-        case(GL_DEPTH_COMPONENT):   //intentionally fall through and execute the code for GL_LUMINANCE\r
-        case(GL_LUMINANCE):         { *data++ = value.r()*scale; break; }\r
-        case(GL_ALPHA):             { *data++ = value.a()*scale; break; }\r
-        case(GL_LUMINANCE_ALPHA):   { *data++ = value.r()*scale; *data++ = value.a()*scale; break; }\r
-        case(GL_RGB):               { *data++ = value.r()*scale; *data++ = value.g()*scale; *data++ = value.b()*scale; break; }\r
-        case(GL_RGBA):              { *data++ = value.r()*scale; *data++ = value.g()*scale; *data++ = value.b()*scale; *data++ = value.a()*scale; break; }\r
-        case(GL_BGR):               { *data++ = value.b()*scale; *data++ = value.g()*scale; *data++ = value.r()*scale; break; }\r
-        case(GL_BGRA):              { *data++ = value.b()*scale; *data++ = value.g()*scale; *data++ = value.r()*scale; *data++ = value.a()*scale; break; }\r
-    }\r
-}\r
-\r
-void setColor(unsigned char *ptr, GLenum pixelFormat, GLenum dataType, osg::Vec4 color)\r
-{\r
-    switch(dataType)\r
-    {\r
-        case(GL_BYTE):              return _writeColor(pixelFormat, (char*)ptr,             128.0f, color);\r
-        case(GL_UNSIGNED_BYTE):     return _writeColor(pixelFormat, (unsigned char*)ptr,    255.0f, color);\r
-        case(GL_SHORT):             return _writeColor(pixelFormat, (short*)ptr,            32768.0f, color);\r
-        case(GL_UNSIGNED_SHORT):    return _writeColor(pixelFormat, (unsigned short*)ptr,   65535.0f, color);\r
-        case(GL_INT):               return _writeColor(pixelFormat, (int*)ptr,              2147483648.0f, color);\r
-        case(GL_UNSIGNED_INT):      return _writeColor(pixelFormat, (unsigned int*)ptr,     4294967295.0f, color);\r
-        case(GL_FLOAT):             return _writeColor(pixelFormat, (float*)ptr,            1.0f, color);\r
-    }\r
-}\r
-\r
-template <typename T>    \r
-osg::Vec4 _readColor(GLenum pixelFormat, T* data,float scale)\r
-{\r
-    switch(pixelFormat)\r
-    {\r
-        case(GL_DEPTH_COMPONENT):   //intentionally fall through and execute the code for GL_LUMINANCE\r
-        case(GL_LUMINANCE):         { float l = float(*data++)*scale; return osg::Vec4(l, l, l, 1.0f); }\r
-        case(GL_ALPHA):             { float a = float(*data++)*scale; return osg::Vec4(1.0f, 1.0f, 1.0f, a); }\r
-        case(GL_LUMINANCE_ALPHA):   { float l = float(*data++)*scale; float a = float(*data++)*scale; return osg::Vec4(l,l,l,a); }\r
-        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
-        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
-        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
-        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
-    }\r
-    return osg::Vec4(1.0f,1.0f,1.0f,1.0f);\r
-}\r
-\r
-osg::Vec4 getColor(const unsigned char* ptr, GLenum pixelFormat, GLenum dataType)\r
-{\r
-    switch(dataType)\r
-    {\r
-        case(GL_BYTE):              return _readColor(pixelFormat, (char*)ptr,             1.0f/128.0f);\r
-        case(GL_UNSIGNED_BYTE):     return _readColor(pixelFormat, (unsigned char*)ptr,    1.0f/255.0f);\r
-        case(GL_SHORT):             return _readColor(pixelFormat, (short*)ptr,            1.0f/32768.0f);\r
-        case(GL_UNSIGNED_SHORT):    return _readColor(pixelFormat, (unsigned short*)ptr,   1.0f/65535.0f);\r
-        case(GL_INT):               return _readColor(pixelFormat, (int*)ptr,              1.0f/2147483648.0f);\r
-        case(GL_UNSIGNED_INT):      return _readColor(pixelFormat, (unsigned int*)ptr,     1.0f/4294967295.0f);\r
-        case(GL_FLOAT):             return _readColor(pixelFormat, (float*)ptr,            1.0f);\r
-    }\r
-    return osg::Vec4(1.0f,1.0f,1.0f,1.0f);\r
-}\r
-\r
-osg::Vec4::value_type computeAverage( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )\r
-{\r
-    osg::Vec4::value_type r = 0;\r
-    osg::Vec4::value_type nb = 0;\r
-    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )\r
-    {\r
-        if ( colorValid[i][j][k] )\r
-        {\r
-            r += colors[i][j][k][c];\r
-            nb += 1;\r
-        }\r
-    }\r
-    return r / nb;\r
-}\r
-\r
-osg::Vec4::value_type computeSum( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )\r
-{\r
-    osg::Vec4::value_type r = 0;\r
-    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )\r
-        if ( colorValid[i][j][k] )\r
-        {\r
-            r += colors[i][j][k][c];\r
-        }\r
-    return r;\r
-}\r
-\r
-osg::Vec4::value_type computeProduct( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )\r
-{\r
-    osg::Vec4::value_type r = 1;\r
-    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )\r
-        if ( colorValid[i][j][k] )\r
-        {\r
-            r *= colors[i][j][k][c];\r
-        }\r
-    return r;\r
-}\r
-\r
-osg::Vec4::value_type computeMin( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )\r
-{\r
-    osg::Vec4::value_type r = std::numeric_limits<osg::Vec4::value_type>::max();\r
-    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )\r
-        if ( colorValid[i][j][k] )\r
-        {\r
-            r = std::min( r, colors[i][j][k][c] );\r
-        }\r
-    return r;\r
-}\r
-\r
-osg::Vec4::value_type computeMax( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )\r
-{\r
-    osg::Vec4::value_type r = std::numeric_limits<osg::Vec4::value_type>::min();\r
-    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )\r
-        if ( colorValid[i][j][k] )\r
-        {\r
-            r = std::max( r, colors[i][j][k][c] );\r
-        }\r
-    return r;\r
-}\r
-\r
-osg::Vec4::value_type computeComponent( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapFunction f )\r
-{\r
-    switch ( f )\r
-    {\r
-    case AVERAGE: return computeAverage( c, colors, colorValid );\r
-    case SUM: return computeSum( c, colors, colorValid );\r
-    case PRODUCT: return computeProduct( c, colors, colorValid );\r
-    case MIN: return computeMin( c, colors, colorValid );\r
-    case MAX: return computeMax( c, colors, colorValid );\r
-    }\r
-    return 0;\r
-}\r
-\r
-osg::Vec4 computeColor( osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapTuple attrs, GLenum pixelFormat )\r
-{\r
-    osg::Vec4 result;\r
-    unsigned int nbComponents = osg::Image::computeNumComponents( pixelFormat );\r
-    result[0] = computeComponent( 0, colors, colorValid, attrs.get<0>() );\r
-    if ( nbComponents >= 2 )\r
-        result[1] = computeComponent( 1, colors, colorValid, attrs.get<1>() );\r
-    if ( nbComponents >= 3 )\r
-        result[2] = computeComponent( 2, colors, colorValid, attrs.get<2>() );\r
-    if ( nbComponents == 4 )\r
-        result[3] = computeComponent( 3, colors, colorValid, attrs.get<3>() );\r
-    return result;\r
-}\r
-\r
-osg::Image* computeMipmap( osg::Image* image, MipMapTuple attrs )\r
-{\r
-    bool computeMipmap = false;\r
-    unsigned int nbComponents = osg::Image::computeNumComponents( image->getPixelFormat() );\r
-    if ( attrs.get<0>() != AUTOMATIC &&\r
-        ( attrs.get<1>() != AUTOMATIC || nbComponents < 2 ) &&\r
-        ( attrs.get<2>() != AUTOMATIC || nbComponents < 3 ) &&\r
-        ( attrs.get<3>() != AUTOMATIC || nbComponents < 4 ) )\r
-    {\r
-        computeMipmap = true;\r
-    }\r
-    else if ( attrs.get<0>() != AUTOMATIC ||\r
-        ( attrs.get<1>() != AUTOMATIC && nbComponents >= 2 ) ||\r
-        ( attrs.get<2>() != AUTOMATIC && nbComponents >= 3 ) ||\r
-        ( attrs.get<3>() != AUTOMATIC && nbComponents == 4 ) )\r
-    {\r
-        throw BuilderException("invalid mipmap control function combination");\r
-    }\r
-\r
-    if ( computeMipmap )\r
-    {\r
-        osg::ref_ptr<osg::Image> mipmaps = new osg::Image();\r
-        int s = image->s(),\r
-            t = image->t(),\r
-            r = image->r();\r
-        int nb = osg::Image::computeNumberOfMipmapLevels(s, t, r);\r
-        osg::Image::MipmapDataType mipmapOffsets;\r
-        unsigned int offset = 0;\r
-        for ( int i = 0; i < nb; ++i )\r
-        {\r
-            offset += t * r * osg::Image::computeRowWidthInBytes(s, image->getPixelFormat(), image->getDataType(), image->getPacking());\r
-            mipmapOffsets.push_back( offset );\r
-            s >>= 1; if ( s == 0 ) s = 1;\r
-            t >>= 1; if ( t == 0 ) t = 1;\r
-            r >>= 1; if ( r == 0 ) r = 1;\r
-        }\r
-        mipmapOffsets.pop_back();\r
-        unsigned char *data = new unsigned char[offset];\r
-        memcpy( data, image->data(), mipmapOffsets.front() );\r
-        s = image->s();\r
-        t = image->t();\r
-        r = image->r();\r
-        for ( int m = 0; m < nb-1; ++m )\r
-        {\r
-            unsigned char *src = data;\r
-            if ( m > 0 )\r
-                src += mipmapOffsets[m-1];\r
-\r
-            unsigned char *dest = data + mipmapOffsets[m];\r
-\r
-            int ns = s >> 1; if ( ns == 0 ) ns = 1;\r
-            int nt = t >> 1; if ( nt == 0 ) nt = 1;\r
-            int nr = r >> 1; if ( nr == 0 ) nr = 1;\r
-\r
-            for ( int k = 0; k < r; k += 2 )\r
-            {\r
-                for ( int j = 0; j < t; j += 2 )\r
-                {\r
-                    for ( int i = 0; i < s; i += 2 )\r
-                    {\r
-                        osg::Vec4 colors[2][2][2];\r
-                        bool colorValid[2][2][2];\r
-                        colorValid[0][0][0] = false; colorValid[0][0][1] = false; colorValid[0][1][0] = false; colorValid[0][1][1] = false;\r
-                        colorValid[1][0][0] = false; colorValid[1][0][1] = false; colorValid[1][1][0] = false; colorValid[1][1][1] = false;\r
-                        if ( true )\r
-                        {\r
-                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j, k );\r
-                            colors[0][0][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );\r
-                            colorValid[0][0][0] = true;\r
-                        }\r
-                        if ( i + 1 < s )\r
-                        {\r
-                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j, k );\r
-                            colors[0][0][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );\r
-                            colorValid[0][0][1] = true;\r
-                        }\r
-                        if ( j + 1 < t )\r
-                        {\r
-                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j + 1, k );\r
-                            colors[0][1][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );\r
-                            colorValid[0][1][0] = true;\r
-                        }\r
-                        if ( i + 1 < s && j + 1 < t )\r
-                        {\r
-                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j + 1, k );\r
-                            colors[0][1][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );\r
-                            colorValid[0][1][1] = true;\r
-                        }\r
-                        if ( k + 1 < r )\r
-                        {\r
-                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j, k + 1 );\r
-                            colors[1][0][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );\r
-                            colorValid[1][0][0] = true;\r
-                        }\r
-                        if ( i + 1 < s && k + 1 < r )\r
-                        {\r
-                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j, k + 1 );\r
-                            colors[1][0][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );\r
-                            colorValid[1][0][1] = true;\r
-                        }\r
-                        if ( j + 1 < t && k + 1 < r )\r
-                        {\r
-                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j + 1, k + 1 );\r
-                            colors[1][1][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );\r
-                            colorValid[1][1][0] = true;\r
-                        }\r
-                        if ( i + 1 < s && j + 1 < t && k + 1 < r )\r
-                        {\r
-                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j + 1, k + 1 );\r
-                            colors[1][1][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );\r
-                            colorValid[1][1][1] = true;\r
-                        }\r
-\r
-                        unsigned char *ptr = imageData( dest, image->getPixelFormat(), image->getDataType(), ns, nt, image->getPacking(), i/2, j/2, k/2 );\r
-                        osg::Vec4 color = computeColor( colors, colorValid, attrs, image->getPixelFormat() );\r
-                        setColor( ptr, image->getPixelFormat(), image->getDataType(), color );\r
-                    }\r
-                }\r
-            }\r
-            s = ns;\r
-            t = nt;\r
-            r = nr;\r
-        }\r
-        mipmaps->setImage( image->s(), image->t(), image->r(), \r
-            image->getInternalTextureFormat(), image->getPixelFormat(),\r
-            image->getDataType(), data, osg::Image::USE_NEW_DELETE, image->getPacking() );\r
-        mipmaps->setMipmapLevels( mipmapOffsets );\r
-\r
-        return mipmaps.release();\r
-    }\r
-    return image;\r
-}\r
-} }\r
+// Copyright (C) 2010  Frederic Bouvier
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#  include <simgear_config.h>
+#endif
+
+#include "mipmap.hxx"
+#include "EffectBuilder.hxx"
+
+#include <limits>
+#include <iomanip>
+
+#include <osg/Image>
+#include <osg/Vec4>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+
+namespace simgear { namespace effect {
+
+EffectNameValue<MipMapFunction> mipmapFunctionsInit[] =
+{
+    {"auto", AUTOMATIC},
+    {"average", AVERAGE},
+    {"sum", SUM},
+    {"product", PRODUCT},
+    {"min", MIN},
+    {"max", MAX}
+};
+EffectPropertyMap<MipMapFunction> mipmapFunctions(mipmapFunctionsInit);
+
+MipMapTuple makeMipMapTuple(Effect* effect, const SGPropertyNode* props,
+                      const SGReaderWriterOptions* options)
+{
+    const SGPropertyNode* pMipmapR
+        = getEffectPropertyChild(effect, props, "function-r");
+    MipMapFunction mipmapR = AUTOMATIC;
+    if (pMipmapR)
+        findAttr(mipmapFunctions, pMipmapR, mipmapR);
+    const SGPropertyNode* pMipmapG
+        = getEffectPropertyChild(effect, props, "function-g");
+    MipMapFunction mipmapG = AUTOMATIC;
+    if (pMipmapG)
+        findAttr(mipmapFunctions, pMipmapG, mipmapG);
+    const SGPropertyNode* pMipmapB
+        = getEffectPropertyChild(effect, props, "function-b");
+    MipMapFunction mipmapB = AUTOMATIC;
+    if (pMipmapB)
+        findAttr(mipmapFunctions, pMipmapB, mipmapB);
+    const SGPropertyNode* pMipmapA
+        = getEffectPropertyChild(effect, props, "function-a");
+    MipMapFunction mipmapA = AUTOMATIC;
+    if (pMipmapA)
+        findAttr(mipmapFunctions, pMipmapA, mipmapA);
+    return MipMapTuple( mipmapR, mipmapG, mipmapB, mipmapA );
+}
+
+
+unsigned char* imageData(unsigned char* ptr, GLenum pixelFormat, GLenum dataType, int width, int height, int packing, int column, int row=0, int image=0)
+{
+    if (!ptr) return NULL;
+    return ptr +
+        ( column * osg::Image::computePixelSizeInBits( pixelFormat, dataType ) ) / 8 +
+        row * osg::Image::computeRowWidthInBytes( width, pixelFormat, dataType, packing ) +
+        image * height * osg::Image::computeRowWidthInBytes( width, pixelFormat, dataType, packing );
+}
+
+template <typename T>
+void _writeColor(GLenum pixelFormat, T* data, float scale, osg::Vec4 value)
+{
+    switch(pixelFormat)
+    {
+        case(GL_DEPTH_COMPONENT):   //intentionally fall through and execute the code for GL_LUMINANCE
+        case(GL_LUMINANCE):         { *data++ = value.r()*scale; break; }
+        case(GL_ALPHA):             { *data++ = value.a()*scale; break; }
+        case(GL_LUMINANCE_ALPHA):   { *data++ = value.r()*scale; *data++ = value.a()*scale; break; }
+        case(GL_RGB):               { *data++ = value.r()*scale; *data++ = value.g()*scale; *data++ = value.b()*scale; break; }
+        case(GL_RGBA):              { *data++ = value.r()*scale; *data++ = value.g()*scale; *data++ = value.b()*scale; *data++ = value.a()*scale; break; }
+        case(GL_BGR):               { *data++ = value.b()*scale; *data++ = value.g()*scale; *data++ = value.r()*scale; break; }
+        case(GL_BGRA):              { *data++ = value.b()*scale; *data++ = value.g()*scale; *data++ = value.r()*scale; *data++ = value.a()*scale; break; }
+    }
+}
+
+void setColor(unsigned char *ptr, GLenum pixelFormat, GLenum dataType, osg::Vec4 color)
+{
+    switch(dataType)
+    {
+        case(GL_BYTE):              return _writeColor(pixelFormat, (char*)ptr,             128.0f, color);
+        case(GL_UNSIGNED_BYTE):     return _writeColor(pixelFormat, (unsigned char*)ptr,    255.0f, color);
+        case(GL_SHORT):             return _writeColor(pixelFormat, (short*)ptr,            32768.0f, color);
+        case(GL_UNSIGNED_SHORT):    return _writeColor(pixelFormat, (unsigned short*)ptr,   65535.0f, color);
+        case(GL_INT):               return _writeColor(pixelFormat, (int*)ptr,              2147483648.0f, color);
+        case(GL_UNSIGNED_INT):      return _writeColor(pixelFormat, (unsigned int*)ptr,     4294967295.0f, color);
+        case(GL_FLOAT):             return _writeColor(pixelFormat, (float*)ptr,            1.0f, color);
+    }
+}
+
+template <typename T>    
+osg::Vec4 _readColor(GLenum pixelFormat, T* data,float scale)
+{
+    switch(pixelFormat)
+    {
+        case(GL_DEPTH_COMPONENT):   //intentionally fall through and execute the code for GL_LUMINANCE
+        case(GL_LUMINANCE):         { float l = float(*data++)*scale; return osg::Vec4(l, l, l, 1.0f); }
+        case(GL_ALPHA):             { float a = float(*data++)*scale; return osg::Vec4(1.0f, 1.0f, 1.0f, a); }
+        case(GL_LUMINANCE_ALPHA):   { float l = float(*data++)*scale; float a = float(*data++)*scale; return osg::Vec4(l,l,l,a); }
+        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); }
+        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); }
+        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); }
+        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); }
+    }
+    return osg::Vec4(1.0f,1.0f,1.0f,1.0f);
+}
+
+osg::Vec4 getColor(const unsigned char* ptr, GLenum pixelFormat, GLenum dataType)
+{
+    switch(dataType)
+    {
+        case(GL_BYTE):              return _readColor(pixelFormat, (char*)ptr,             1.0f/128.0f);
+        case(GL_UNSIGNED_BYTE):     return _readColor(pixelFormat, (unsigned char*)ptr,    1.0f/255.0f);
+        case(GL_SHORT):             return _readColor(pixelFormat, (short*)ptr,            1.0f/32768.0f);
+        case(GL_UNSIGNED_SHORT):    return _readColor(pixelFormat, (unsigned short*)ptr,   1.0f/65535.0f);
+        case(GL_INT):               return _readColor(pixelFormat, (int*)ptr,              1.0f/2147483648.0f);
+        case(GL_UNSIGNED_INT):      return _readColor(pixelFormat, (unsigned int*)ptr,     1.0f/4294967295.0f);
+        case(GL_FLOAT):             return _readColor(pixelFormat, (float*)ptr,            1.0f);
+    }
+    return osg::Vec4(1.0f,1.0f,1.0f,1.0f);
+}
+
+osg::Vec4::value_type computeAverage( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
+{
+    osg::Vec4::value_type r = 0;
+    osg::Vec4::value_type nb = 0;
+    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
+    {
+        if ( colorValid[i][j][k] )
+        {
+            r += colors[i][j][k][c];
+            nb += 1;
+        }
+    }
+    return r / nb;
+}
+
+osg::Vec4::value_type computeSum( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
+{
+    osg::Vec4::value_type r = 0;
+    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
+        if ( colorValid[i][j][k] )
+        {
+            r += colors[i][j][k][c];
+        }
+    return r;
+}
+
+osg::Vec4::value_type computeProduct( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
+{
+    osg::Vec4::value_type r = 1;
+    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
+        if ( colorValid[i][j][k] )
+        {
+            r *= colors[i][j][k][c];
+        }
+    return r;
+}
+
+osg::Vec4::value_type computeMin( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
+{
+    osg::Vec4::value_type r = std::numeric_limits<osg::Vec4::value_type>::max();
+    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
+        if ( colorValid[i][j][k] )
+        {
+            r = std::min( r, colors[i][j][k][c] );
+        }
+    return r;
+}
+
+osg::Vec4::value_type computeMax( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2] )
+{
+    osg::Vec4::value_type r = std::numeric_limits<osg::Vec4::value_type>::min();
+    for ( int k = 0; k < 2; ++k ) for ( int j = 0; j < 2; ++j ) for ( int i = 0; i < 2; ++i )
+        if ( colorValid[i][j][k] )
+        {
+            r = std::max( r, colors[i][j][k][c] );
+        }
+    return r;
+}
+
+osg::Vec4::value_type computeComponent( int c, osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapFunction f )
+{
+    switch ( f )
+    {
+    case AVERAGE: return computeAverage( c, colors, colorValid );
+    case SUM: return computeSum( c, colors, colorValid );
+    case PRODUCT: return computeProduct( c, colors, colorValid );
+    case MIN: return computeMin( c, colors, colorValid );
+    case MAX: return computeMax( c, colors, colorValid );
+    default: break;
+    }
+    return 0;
+}
+
+osg::Vec4 computeColor( osg::Vec4 colors[2][2][2], bool colorValid[2][2][2], MipMapTuple attrs, GLenum pixelFormat )
+{
+    osg::Vec4 result;
+    unsigned int nbComponents = osg::Image::computeNumComponents( pixelFormat );
+    result[0] = computeComponent( 0, colors, colorValid, attrs.get<0>() );
+    if ( nbComponents >= 2 )
+        result[1] = computeComponent( 1, colors, colorValid, attrs.get<1>() );
+    if ( nbComponents >= 3 )
+        result[2] = computeComponent( 2, colors, colorValid, attrs.get<2>() );
+    if ( nbComponents == 4 )
+        result[3] = computeComponent( 3, colors, colorValid, attrs.get<3>() );
+    return result;
+}
+
+void dumpMipmap( std::string n, int s, int t, int r, int c, unsigned char *d, const osg::Image::MipmapDataType &o )
+{
+    std::ofstream ofs( (n + ".dump").c_str() );
+    for ( osg::Image::MipmapDataType::size_type i = 0; i < o.size()+1; ++i )
+    {
+        ofs << s << " " << t << " " << r << std::endl;
+        unsigned int offset = 0;
+        if ( i > 0 )
+            offset = o[i-1];
+        unsigned char *p = &d[offset];
+        for ( int l = 0; l < r; ++l )
+        {
+            for ( int k = 0; k < t; ++k )
+            {
+                for ( int j = 0; j < s; ++j )
+                {
+                    ofs << "(";
+                    for ( int m = 0; m < c; ++m )
+                    {
+                        if ( m != 0 )
+                            ofs << " ";
+                        ofs << std::setw(3) << (unsigned int)*p++;
+                    }
+                    ofs << ")";
+                }
+                ofs << std::endl;
+            }
+            ofs << std::endl;
+        }
+        ofs << std::endl;
+        s >>= 1; if ( s == 0 ) s = 1;
+        t >>= 1; if ( t == 0 ) t = 1;
+        r >>= 1; if ( r == 0 ) r = 1;
+    }
+}
+
+osg::Image* computeMipmap( osg::Image* image, MipMapTuple attrs )
+{
+    bool computeMipmap = false;
+    unsigned int nbComponents = osg::Image::computeNumComponents( image->getPixelFormat() );
+    if ( attrs.get<0>() != AUTOMATIC &&
+        ( attrs.get<1>() != AUTOMATIC || nbComponents < 2 ) &&
+        ( attrs.get<2>() != AUTOMATIC || nbComponents < 3 ) &&
+        ( attrs.get<3>() != AUTOMATIC || nbComponents < 4 ) )
+    {
+        computeMipmap = true;
+    }
+    else if ( attrs.get<0>() != AUTOMATIC ||
+        ( attrs.get<1>() != AUTOMATIC && nbComponents >= 2 ) ||
+        ( attrs.get<2>() != AUTOMATIC && nbComponents >= 3 ) ||
+        ( attrs.get<3>() != AUTOMATIC && nbComponents == 4 ) )
+    {
+        throw BuilderException("invalid mipmap control function combination");
+    }
+
+    if ( computeMipmap )
+    {
+        osg::ref_ptr<osg::Image> mipmaps = new osg::Image();
+        int s = image->s(),
+            t = image->t(),
+            r = image->r();
+        int nb = osg::Image::computeNumberOfMipmapLevels(s, t, r);
+        osg::Image::MipmapDataType mipmapOffsets;
+        unsigned int offset = 0;
+        for ( int i = 0; i < nb; ++i )
+        {
+            offset += t * r * osg::Image::computeRowWidthInBytes(s, image->getPixelFormat(), image->getDataType(), image->getPacking());
+            mipmapOffsets.push_back( offset );
+            s >>= 1; if ( s == 0 ) s = 1;
+            t >>= 1; if ( t == 0 ) t = 1;
+            r >>= 1; if ( r == 0 ) r = 1;
+        }
+        mipmapOffsets.pop_back();
+        unsigned char *data = new unsigned char[offset];
+        memcpy( data, image->data(), mipmapOffsets.front() );
+        s = image->s();
+        t = image->t();
+        r = image->r();
+        for ( int m = 0; m < nb-1; ++m )
+        {
+            unsigned char *src = data;
+            if ( m > 0 )
+                src += mipmapOffsets[m-1];
+
+            unsigned char *dest = data + mipmapOffsets[m];
+
+            int ns = s >> 1; if ( ns == 0 ) ns = 1;
+            int nt = t >> 1; if ( nt == 0 ) nt = 1;
+            int nr = r >> 1; if ( nr == 0 ) nr = 1;
+
+            for ( int k = 0; k < r; k += 2 )
+            {
+                for ( int j = 0; j < t; j += 2 )
+                {
+                    for ( int i = 0; i < s; i += 2 )
+                    {
+                        osg::Vec4 colors[2][2][2];
+                        bool colorValid[2][2][2];
+                        colorValid[0][0][0] = false; colorValid[0][0][1] = false; colorValid[0][1][0] = false; colorValid[0][1][1] = false;
+                        colorValid[1][0][0] = false; colorValid[1][0][1] = false; colorValid[1][1][0] = false; colorValid[1][1][1] = false;
+                        if ( true )
+                        {
+                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j, k );
+                            colors[0][0][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
+                            colorValid[0][0][0] = true;
+                        }
+                        if ( i + 1 < s )
+                        {
+                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j, k );
+                            colors[0][0][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
+                            colorValid[0][0][1] = true;
+                        }
+                        if ( j + 1 < t )
+                        {
+                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j + 1, k );
+                            colors[0][1][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
+                            colorValid[0][1][0] = true;
+                        }
+                        if ( i + 1 < s && j + 1 < t )
+                        {
+                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j + 1, k );
+                            colors[0][1][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
+                            colorValid[0][1][1] = true;
+                        }
+                        if ( k + 1 < r )
+                        {
+                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j, k + 1 );
+                            colors[1][0][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
+                            colorValid[1][0][0] = true;
+                        }
+                        if ( i + 1 < s && k + 1 < r )
+                        {
+                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j, k + 1 );
+                            colors[1][0][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
+                            colorValid[1][0][1] = true;
+                        }
+                        if ( j + 1 < t && k + 1 < r )
+                        {
+                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i, j + 1, k + 1 );
+                            colors[1][1][0] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
+                            colorValid[1][1][0] = true;
+                        }
+                        if ( i + 1 < s && j + 1 < t && k + 1 < r )
+                        {
+                            unsigned char *ptr = imageData( src, image->getPixelFormat(), image->getDataType(), s, t, image->getPacking(), i + 1, j + 1, k + 1 );
+                            colors[1][1][1] = getColor( ptr, image->getPixelFormat(), image->getDataType() );
+                            colorValid[1][1][1] = true;
+                        }
+
+                        unsigned char *ptr = imageData( dest, image->getPixelFormat(), image->getDataType(), ns, nt, image->getPacking(), i/2, j/2, k/2 );
+                        osg::Vec4 color = computeColor( colors, colorValid, attrs, image->getPixelFormat() );
+                        setColor( ptr, image->getPixelFormat(), image->getDataType(), color );
+                    }
+                }
+            }
+            s = ns;
+            t = nt;
+            r = nr;
+        }
+        //dumpMipmap( image->getFileName(), image->s(), image->t(), image->r(), osg::Image::computeNumComponents(image->getPixelFormat()), data, mipmapOffsets );
+        mipmaps->setImage( image->s(), image->t(), image->r(), 
+            image->getInternalTextureFormat(), image->getPixelFormat(),
+            image->getDataType(), data, osg::Image::USE_NEW_DELETE, image->getPacking() );
+        mipmaps->setMipmapLevels( mipmapOffsets );
+
+        return mipmaps.release();
+    }
+    return image;
+}
+} }