-// 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 <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 SGReaderWriterXMLOptions* 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 );
+ }
+ 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;
+}
+
+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;
+ }
+ 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;
+}
+} }