osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarth/ImageUtils.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 
00020 #include <osgEarth/ImageUtils>
00021 #include <osg/Notify>
00022 #include <osg/Texture>
00023 #include <osg/ImageSequence>
00024 #include <osg/Timer>
00025 #include <osgDB/Registry>
00026 #include <string.h>
00027 #include <memory.h>
00028 
00029 #define LC "[ImageUtils] "
00030 
00031 using namespace osgEarth;
00032 
00033 osg::Image*
00034 ImageUtils::cloneImage( const osg::Image* input )
00035 {
00036     // Why not just call image->clone()? Because, the osg::Image copy constructor does not
00037     // clear out the underlying BufferData/BufferObject's GL handles. This can cause 
00038     // exepected results if you are cloning an image that has already been used in GL.
00039     // Calling clone->dirty() might work, but we are not sure.
00040 
00041     if ( !input ) return 0L;
00042     
00043     osg::Image* clone = osg::clone( input, osg::CopyOp::DEEP_COPY_ALL );
00044     clone->dirty();
00045     return clone;
00046 }
00047 
00048 void
00049 ImageUtils::normalizeImage( osg::Image* image )
00050 {
00051     // OpenGL is lax about internal texture formats, and e.g. allows GL_RGBA to be used
00052     // instead of the proper GL_RGBA8, etc. Correct that here, since some of our compositors
00053     // rely on having a proper internal texture format.
00054     if ( image->getDataType() == GL_UNSIGNED_BYTE )
00055     {
00056         if ( image->getPixelFormat() == GL_RGB )
00057             image->setInternalTextureFormat( GL_RGB8 );
00058         else if ( image->getPixelFormat() == GL_RGBA )
00059             image->setInternalTextureFormat( GL_RGBA8 );
00060     }
00061 }
00062 
00063 bool
00064 ImageUtils::copyAsSubImage(const osg::Image* src, osg::Image* dst, int dst_start_col, int dst_start_row, int dst_img )
00065 {
00066     if (!src || !dst ||
00067         dst_start_col + src->s() > dst->s() ||
00068         dst_start_row + src->t() > dst->t() )
00069     {
00070         return false;
00071     }
00072 
00073     // check for fast bytewise copy:
00074     if (src->getPacking() == dst->getPacking() &&
00075         src->getDataType() == dst->getDataType() &&
00076         src->getPixelFormat() == dst->getPixelFormat() &&
00077         src->getInternalTextureFormat() == dst->getInternalTextureFormat() )
00078     {
00079         for( int src_row=0, dst_row=dst_start_row; src_row < src->t(); src_row++, dst_row++ )
00080         {
00081             const void* src_data = src->data( 0, src_row, 0 );
00082             void* dst_data = dst->data( dst_start_col, dst_row, dst_img );
00083             memcpy( dst_data, src_data, src->getRowSizeInBytes() );
00084         }
00085     }
00086 
00087     // otherwise loop through an convert pixel-by-pixel.
00088     else
00089     {
00090         PixelReader read(src);
00091         PixelWriter write(dst);
00092 
00093         for( int src_t=0, dst_t=dst_start_row; src_t < src->t(); src_t++, dst_t++ )
00094         {
00095             for( int src_s=0, dst_s=dst_start_col; src_s < src->s(); src_s++, dst_s++ )
00096             {           
00097                 write( read(src_s, src_t), dst_s, dst_t );
00098             }
00099         }
00100     }
00101 
00102     return true;
00103 }  
00104 
00105 bool
00106 ImageUtils::resizeImage(const osg::Image* input, 
00107                         unsigned int out_s, unsigned int out_t, 
00108                         osg::ref_ptr<osg::Image>& output,
00109                         unsigned int mipmapLevel )
00110 {
00111     if ( !input && out_s == 0 && out_t == 0 )
00112         return false;
00113 
00114     if ( !PixelReader::supports(input) )
00115     {
00116         OE_WARN << LC << "resizeImage: unsupported format" << std::endl;
00117         return false;
00118     }
00119 
00120     if ( output.valid() && !PixelWriter::supports(output.get()) )
00121     {
00122         OE_WARN << LC << "resizeImage: pre-allocated output image is in an unsupported format" << std::endl;
00123         return false;
00124     }
00125 
00126     unsigned int in_s = input->s();
00127     unsigned int in_t = input->t();
00128 
00129     if ( !output.valid() )
00130     {
00131         output = new osg::Image();
00132 
00133         if ( PixelWriter::supports(input) )
00134         {
00135             output->allocateImage( out_s, out_t, 1, input->getPixelFormat(), input->getDataType(), input->getPacking() );
00136             output->setInternalTextureFormat( input->getInternalTextureFormat() );
00137         }
00138         else
00139         {
00140             // for unsupported write formats, convert to RGBA8 automatically.
00141             output->allocateImage( out_s, out_t, 1, GL_RGBA, GL_UNSIGNED_BYTE );
00142             output->setInternalTextureFormat( GL_RGBA8 );
00143         }
00144     }
00145     else
00146     {
00147         // make sure they match up
00148         output->setInternalTextureFormat( input->getInternalTextureFormat() );
00149     }
00150 
00151     if ( in_s == out_s && in_t == out_t && mipmapLevel == 0 && input->getInternalTextureFormat() == output->getInternalTextureFormat() )
00152     {
00153         memcpy( output->data(), input->data(), input->getTotalSizeInBytes() );
00154     }
00155     else
00156     {       
00157         PixelReader read( input );
00158         PixelWriter write( output.get() );
00159 
00160         unsigned int pixel_size_bytes = input->getRowSizeInBytes() / in_s;
00161 
00162         unsigned char* dataOffset = output->getMipmapData(mipmapLevel);
00163         unsigned int   dataRowSizeBytes = output->getRowSizeInBytes() >> mipmapLevel;
00164 
00165         for( unsigned int output_row=0; output_row < out_t; output_row++ )
00166         {
00167             // get an appropriate input row
00168             float output_row_ratio = (float)output_row/(float)out_t;
00169             int input_row = (unsigned int)( output_row_ratio * (float)in_t );
00170             if ( input_row >= input->t() ) input_row = in_t-1;
00171             else if ( input_row < 0 ) input_row = 0;
00172 
00173             for( unsigned int output_col = 0; output_col < out_s; output_col++ )
00174             {
00175                 float output_col_ratio = (float)output_col/(float)out_s;
00176                 int input_col = (unsigned int)( output_col_ratio * (float)in_s );
00177                 if ( input_col >= (int)in_s ) input_col = in_s-1;
00178                 else if ( input_row < 0 ) input_row = 0;
00179 
00180                 osg::Vec4 color = read( input_col, input_row ); // read pixel from mip level 0
00181                 write( color, output_col, output_row, 0, mipmapLevel ); // write to target mip level
00182             }
00183         }
00184     }
00185 
00186     return true;
00187 }
00188 
00189 osg::Image*
00190 ImageUtils::createMipmapBlendedImage( const osg::Image* primary, const osg::Image* secondary )
00191 {
00192     // ASSUMPTION: primary and secondary are the same size, same format.
00193 
00194     // first, build the image that will hold all the mipmap levels.
00195     int numMipmapLevels = osg::Image::computeNumberOfMipmapLevels( primary->s(), primary->t() );
00196     int pixelSizeBytes  = osg::Image::computeRowWidthInBytes( primary->s(), primary->getPixelFormat(), primary->getDataType(), primary->getPacking() ) / primary->s();
00197     int totalSizeBytes  = 0;
00198     std::vector< unsigned int > mipmapDataOffsets;
00199 
00200     mipmapDataOffsets.reserve( numMipmapLevels-1 );
00201 
00202     for( int i=0; i<numMipmapLevels; ++i )
00203     {
00204         if ( i > 0 )
00205             mipmapDataOffsets.push_back( totalSizeBytes );
00206 
00207         int level_s = primary->s() >> i;
00208         int level_t = primary->t() >> i;
00209         int levelSizeBytes = level_s * level_t * pixelSizeBytes;
00210 
00211         totalSizeBytes += levelSizeBytes;
00212     }
00213 
00214     unsigned char* data = new unsigned char[totalSizeBytes];
00215 
00216     osg::ref_ptr<osg::Image> result = new osg::Image();
00217     result->setImage(
00218         primary->s(), primary->t(), 1,
00219         primary->getInternalTextureFormat(), 
00220         primary->getPixelFormat(), 
00221         primary->getDataType(), 
00222         data, osg::Image::USE_NEW_DELETE );
00223 
00224     result->setMipmapLevels( mipmapDataOffsets );
00225 
00226     // now, populate the image levels.
00227     int level_s = primary->s();
00228     int level_t = primary->t();
00229 
00230     for( int level=0; level<numMipmapLevels; ++level )
00231     {
00232         if ( secondary && level > 0 )
00233             ImageUtils::resizeImage( secondary, level_s, level_t, result, level );
00234         else
00235             ImageUtils::resizeImage( primary, level_s, level_t, result, level );
00236 
00237         level_s >>= 1;
00238         level_t >>= 1;
00239     }
00240 
00241     return result.release();
00242 }
00243 
00244 namespace
00245 {
00246     struct MixImage
00247     {
00248         float _a;
00249         bool _srcHasAlpha, _destHasAlpha;
00250 
00251         bool operator()( const osg::Vec4f& src, osg::Vec4f& dest )
00252         {
00253             float sa = _srcHasAlpha ? _a * src.a() : _a;
00254             float da = _destHasAlpha ? dest.a() : 1.0f;
00255             dest.set(
00256                 dest.r()*(1.0f-sa) + src.r()*sa,
00257                 dest.g()*(1.0f-sa) + src.g()*sa,
00258                 dest.b()*(1.0f-sa) + src.b()*sa,
00259                 osg::maximum(sa, da) );             
00260             return true;
00261         }
00262     };
00263 }
00264 
00265 bool
00266 ImageUtils::mix(osg::Image* dest, const osg::Image* src, float a)
00267 {
00268     if (!dest || !src || dest->s() != src->s() || dest->t() != src->t() )
00269         return false;
00270     
00271     PixelVisitor<MixImage> mixer;
00272     mixer._a = osg::clampBetween( a, 0.0f, 1.0f );
00273     mixer._srcHasAlpha = src->getPixelSizeInBits() == 32;
00274     mixer._destHasAlpha = src->getPixelSizeInBits() == 32;    
00275 
00276     mixer.accept( src, dest );  
00277 
00278     return true;
00279 }
00280 
00281 osg::Image*
00282 ImageUtils::cropImage(const osg::Image* image,
00283                       double src_minx, double src_miny, double src_maxx, double src_maxy,
00284                       double &dst_minx, double &dst_miny, double &dst_maxx, double &dst_maxy)
00285 {
00286     //Compute the desired cropping rectangle
00287     int windowX        = osg::clampBetween( (int)floor( (dst_minx - src_minx) / (src_maxx - src_minx) * (double)image->s()), 0, image->s()-1);
00288     int windowY        = osg::clampBetween( (int)floor( (dst_miny - src_miny) / (src_maxy - src_miny) * (double)image->t()), 0, image->t()-1);
00289     int windowWidth    = osg::clampBetween( (int)ceil(  (dst_maxx - src_minx) / (src_maxx - src_minx) * (double)image->s()) - windowX, 0, image->s());
00290     int windowHeight   = osg::clampBetween( (int)ceil(  (dst_maxy - src_miny) / (src_maxy - src_miny) * (double)image->t()) - windowY, 0, image->t());    
00291 
00292     if (windowX + windowWidth > image->s())
00293     {
00294         windowWidth = image->s() - windowX;        
00295     }
00296 
00297     if (windowY + windowHeight > image->t())
00298     {
00299         windowHeight = image->t() - windowY;
00300     }
00301     
00302     if ((windowWidth * windowHeight) == 0)
00303     {
00304         return NULL;
00305     }
00306 
00307     //Compute the actual bounds of the area we are computing
00308     double res_s = (src_maxx - src_minx) / (double)image->s();
00309     double res_t = (src_maxy - src_miny) / (double)image->t();
00310 
00311     dst_minx = src_minx + (double)windowX * res_s;
00312     dst_miny = src_miny + (double)windowY * res_t;
00313     dst_maxx = dst_minx + (double)windowWidth * res_s;
00314     dst_maxy = dst_miny + (double)windowHeight * res_t;
00315 
00316     //OE_NOTICE << "Copying from " << windowX << ", " << windowY << ", " << windowWidth << ", " << windowHeight << std::endl;
00317 
00318     //Allocate the croppped image
00319     osg::Image* cropped = new osg::Image;
00320     cropped->allocateImage(windowWidth, windowHeight, 1, image->getPixelFormat(), image->getDataType());
00321     cropped->setInternalTextureFormat( image->getInternalTextureFormat() );
00322     
00323     
00324     for (int src_row = windowY, dst_row=0; dst_row < windowHeight; src_row++, dst_row++)
00325     {
00326         if (src_row > image->t()-1) OE_NOTICE << "HeightBroke" << std::endl;
00327         const void* src_data = image->data(windowX, src_row, 0);
00328         void* dst_data = cropped->data(0, dst_row, 0);
00329         memcpy( dst_data, src_data, cropped->getRowSizeInBytes());
00330     }
00331 
00332     return cropped;
00333 }
00334 
00335 bool
00336 ImageUtils::isPowerOfTwo(const osg::Image* image)
00337 {
00338     return (((image->s() & (image->s()-1))==0) &&
00339             ((image->t() & (image->t()-1))==0));
00340 }
00341 
00342 
00343 osg::Image*
00344 ImageUtils::sharpenImage( const osg::Image* input )
00345 {
00346     int filter[9] = { 0, -1, 0, -1, 5, -1, 0, -1, 0 };
00347     osg::Image* output = ImageUtils::cloneImage(input);
00348     for( int t=1; t<input->t()-1; t++ )
00349     {
00350         for( int s=1; s<input->s()-1; s++ )
00351         {
00352             int pixels[9] = {
00353                 *(int*)input->data(s-1,t-1), *(int*)input->data(s,t-1), *(int*)input->data(s+1,t-1),
00354                 *(int*)input->data(s-1,t  ), *(int*)input->data(s,t  ), *(int*)input->data(s+1,t  ),
00355                 *(int*)input->data(s-1,t+1), *(int*)input->data(s,t+1), *(int*)input->data(s+1,t+1) };
00356 
00357             int shifts[4] = { 0, 8, 16, 32 };
00358 
00359             for( int c=0; c<4; c++ ) // components
00360             {
00361                 int mask = 0xff << shifts[c];
00362                 int sum = 0;
00363                 for( int i=0; i<9; i++ )
00364                 {
00365                     sum += ((pixels[i] & mask) >> shifts[c]) * filter[i];
00366                 }
00367                 sum = sum > 255? 255 : sum < 0? 0 : sum;
00368                 output->data(s,t)[c] = sum;
00369             }
00370         }
00371     }
00372     return output;
00373 }
00374 
00375 
00376 osg::Image*
00377 ImageUtils::createEmptyImage()
00378 {
00379     //TODO: Make this a static or store it in the registry to avoid creating it
00380     // each time.
00381     osg::Image* image = new osg::Image;
00382     image->allocateImage(1,1,1, GL_RGBA, GL_UNSIGNED_BYTE);
00383     image->setInternalTextureFormat( GL_RGBA8 );
00384     unsigned char *data = image->data(0,0);
00385     memset(data, 0, 4);
00386     return image;
00387 }
00388 
00389 bool
00390 ImageUtils::canConvert( const osg::Image* image, GLenum pixelFormat, GLenum dataType )
00391 {
00392     if ( !image ) return false;
00393     return PixelReader::supports( image ) && PixelWriter::supports(pixelFormat, dataType);
00394 }
00395 
00396 osg::Image*
00397 ImageUtils::convert(const osg::Image* image, GLenum pixelFormat, GLenum dataType)
00398 {
00399     if ( !image )
00400         return 0L;
00401 
00402     if ( image->getPixelFormat() == pixelFormat && image->getDataType() == dataType)
00403     {
00404         GLenum texFormat = image->getInternalTextureFormat();
00405         if (dataType != GL_UNSIGNED_BYTE
00406             || (pixelFormat == GL_RGB && texFormat == GL_RGB8)
00407             || (pixelFormat == GL_RGBA && texFormat == GL_RGBA8))
00408         return cloneImage(image);
00409     }
00410     if ( !canConvert(image, pixelFormat, dataType) )
00411         return 0L;
00412 
00413     osg::Image* result = new osg::Image();
00414     result->allocateImage(image->s(), image->t(), image->r(), pixelFormat, dataType);
00415 
00416     if ( pixelFormat == GL_RGB && dataType == GL_UNSIGNED_BYTE )
00417         result->setInternalTextureFormat( GL_RGB8 );
00418     else if ( pixelFormat == GL_RGBA && dataType == GL_UNSIGNED_BYTE )
00419         result->setInternalTextureFormat( GL_RGBA8 );
00420     else
00421         result->setInternalTextureFormat( pixelFormat );
00422 
00423     PixelVisitor<CopyImage>().accept( image, result );
00424 
00425     return result;
00426 }
00427 
00428 osg::Image*
00429 ImageUtils::convertToRGB8(const osg::Image *image)
00430 {
00431     return convert( image, GL_RGB, GL_UNSIGNED_BYTE );
00432 }
00433 
00434 osg::Image*
00435 ImageUtils::convertToRGBA8(const osg::Image* image)
00436 {
00437     return convert( image, GL_RGBA, GL_UNSIGNED_BYTE );
00438 }
00439 
00440 bool 
00441 ImageUtils::areEquivalent(const osg::Image *lhs, const osg::Image *rhs)
00442 {
00443         if (lhs == rhs) return true;
00444 
00445         if ((lhs->s() == rhs->s()) &&
00446                 (lhs->t() == rhs->t()) &&
00447                 (lhs->getInternalTextureFormat() == rhs->getInternalTextureFormat()) &&
00448                 (lhs->getPixelFormat() == rhs->getPixelFormat()) &&
00449                 (lhs->getDataType() == rhs->getDataType()) &&
00450                 (lhs->getPacking() == rhs->getPacking()) &&
00451                 (lhs->getImageSizeInBytes() == rhs->getImageSizeInBytes()))
00452         {
00453                 unsigned int size = lhs->getImageSizeInBytes();
00454         const unsigned char* ptr1 = lhs->data();
00455         const unsigned char* ptr2 = rhs->data();
00456                 for (unsigned int i = 0; i < size; ++i)
00457                 {
00458             if ( *ptr1++ != *ptr2++ )
00459                 return false;
00460                 }
00461 
00462         return true;
00463         }
00464 
00465         return false;
00466 }
00467 
00468 bool
00469 ImageUtils::hasAlphaChannel(const osg::Image* image) 
00470 {
00471     return image && (
00472         image->getPixelFormat() == GL_RGBA ||
00473         image->getPixelFormat() == GL_BGRA ||
00474         image->getPixelFormat() == GL_LUMINANCE_ALPHA );
00475 }
00476 
00477 bool
00478 ImageUtils::isCompressed(const osg::Image *image)
00479 {
00480     //Later versions of OSG have an Image::isCompressed function but earlier versions like 2.8.3 do not.  This is a workaround so that 
00481     //we can tell if an image is compressed on all versions of OSG.
00482     switch(image->getPixelFormat())
00483     {
00484         case(GL_COMPRESSED_ALPHA_ARB):
00485         case(GL_COMPRESSED_INTENSITY_ARB):
00486         case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB):
00487         case(GL_COMPRESSED_LUMINANCE_ARB):
00488         case(GL_COMPRESSED_RGBA_ARB):
00489         case(GL_COMPRESSED_RGB_ARB):
00490         case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
00491         case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
00492         case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
00493         case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
00494         case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT):
00495         case(GL_COMPRESSED_RED_RGTC1_EXT):
00496         case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
00497         case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
00498         case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): 
00499         case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG):
00500         case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG):
00501         case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG):
00502             return true;
00503         default:
00504             return false;
00505     }
00506 }
00507 
00508 //------------------------------------------------------------------------
00509 
00510 namespace
00511 {
00512     //static const float r10= 1.0f/1023.0f;
00513     //static const float r8 = 1.0f/255.0f;
00514     //static const float r6 = 1.0f/63.0f;
00515     static const float r5 = 1.0f/31.0f;
00516     //static const float r4 = 1.0f/15.0f;
00517     static const float r3 = 1.0f/7.0f;
00518     static const float r2 = 1.0f/3.0f;
00519 
00520     // The scale factors to convert from an image data type to a
00521     // float. This is copied from OSG; I think the factors for the signed
00522     // types are wrong, but need to investigate further.
00523 
00524     template<typename T> struct GLTypeTraits;
00525 
00526     template<> struct GLTypeTraits<GLbyte>
00527     {
00528         static float scale() { return 1.0f/128.0f; } // XXX
00529     };
00530 
00531     template<> struct GLTypeTraits<GLubyte>
00532     {
00533         static float scale() { return 1.0f/255.0f; }
00534     };
00535 
00536     template<> struct GLTypeTraits<GLshort>
00537     {
00538         static float scale() { return 1.0f/32768.0f; } // XXX
00539     };
00540 
00541     template<> struct GLTypeTraits<GLushort>
00542     {
00543         static float scale() { return 1.0f/65535.0f; }
00544     };
00545 
00546     template<> struct GLTypeTraits<GLint>
00547     {
00548         static float scale() { return 1.0f/2147483648.0f; } // XXX
00549     };
00550 
00551     template<> struct GLTypeTraits<GLuint>
00552     {
00553         static float scale() { return 1.0f/4294967295.0f; }
00554     };
00555 
00556     template<> struct GLTypeTraits<GLfloat>
00557     {
00558         static float scale() { return 1.0f; }
00559     };
00560 
00561     // The Reader function that performs the read.
00562     template<int Format, typename T> struct ColorReader;
00563     template<int Format, typename T> struct ColorWriter;
00564 
00565     template<typename T>
00566     struct ColorReader<GL_DEPTH_COMPONENT, T>
00567     {
00568         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00569         {
00570             const T* ptr = (const T*)ia->data(s, t, r, m);
00571             float l = float(*ptr) * GLTypeTraits<T>::scale();
00572             return osg::Vec4(l, l, l, 1.0f);
00573         }
00574     };
00575 
00576     template<typename T>
00577     struct ColorWriter<GL_DEPTH_COMPONENT, T>
00578     {
00579         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m)
00580         {
00581             T* ptr = (T*)iw->data(s, t, r, m);
00582             (*ptr) = (GLubyte)(c.r() / GLTypeTraits<T>::scale());
00583         }
00584     };
00585 
00586     template<typename T>
00587     struct ColorReader<GL_LUMINANCE, T>
00588     {
00589         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00590         {
00591             const T* ptr = (const T*)ia->data(s, t, r, m);
00592             float l = float(*ptr) * GLTypeTraits<T>::scale();
00593             return osg::Vec4(l, l, l, 1.0f);
00594         }
00595     };
00596 
00597     template<typename T>
00598     struct ColorWriter<GL_LUMINANCE, T>
00599     {
00600         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m)
00601         {
00602             T* ptr = (T*)iw->data(s, t, r, m);
00603             (*ptr) = (GLubyte)(c.r() / GLTypeTraits<T>::scale());
00604         }
00605     };
00606 
00607     template<typename T>
00608     struct ColorReader<GL_ALPHA, T>
00609     {
00610         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00611         {
00612             const T* ptr = (const T*)ia->data(s, t, r, m);
00613             float a = float(*ptr) * GLTypeTraits<T>::scale();
00614             return osg::Vec4(1.0f, 1.0f, 1.0f, a);
00615         }
00616     };
00617 
00618     template<typename T>
00619     struct ColorWriter<GL_ALPHA, T>
00620     {
00621         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m)
00622         {
00623             T* ptr = (T*)iw->data(s, t, r, m);
00624             (*ptr) = (GLubyte)(c.a() / GLTypeTraits<T>::scale());
00625         }
00626     };
00627 
00628     template<typename T>
00629     struct ColorReader<GL_LUMINANCE_ALPHA, T>
00630     {
00631         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00632         {
00633             const T* ptr = (const T*)ia->data(s, t, r, m);
00634             float l = float(*ptr++) * GLTypeTraits<T>::scale();
00635             float a = float(*ptr) * GLTypeTraits<T>::scale();
00636             return osg::Vec4(l, l, l, a);
00637         }
00638     };
00639 
00640     template<typename T>
00641     struct ColorWriter<GL_LUMINANCE_ALPHA, T>
00642     {
00643         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m )
00644         {
00645             T* ptr = (T*)iw->data(s, t, r, m);
00646             *ptr++ = (GLubyte)( c.r() / GLTypeTraits<T>::scale() );
00647             *ptr   = (GLubyte)( c.a() / GLTypeTraits<T>::scale() );
00648         }
00649     };
00650 
00651     template<typename T>
00652     struct ColorReader<GL_RGB, T>
00653     {
00654         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00655         {
00656             const T* ptr = (const T*)ia->data(s, t, r, m);
00657             float d = float(*ptr++) * GLTypeTraits<T>::scale();
00658             float g = float(*ptr++) * GLTypeTraits<T>::scale();
00659             float b = float(*ptr) * GLTypeTraits<T>::scale();
00660             return osg::Vec4(d, g, b, 1.0f);
00661         }
00662     };
00663 
00664     template<typename T>
00665     struct ColorWriter<GL_RGB, T>
00666     {
00667         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m )
00668         {
00669             T* ptr = (T*)iw->data(s, t, r, m);
00670             *ptr++ = (GLubyte)( c.r() / GLTypeTraits<T>::scale() );
00671             *ptr++ = (GLubyte)( c.g() / GLTypeTraits<T>::scale() );
00672             *ptr++ = (GLubyte)( c.b() / GLTypeTraits<T>::scale() );
00673         }
00674     };
00675 
00676     template<typename T>
00677     struct ColorReader<GL_RGBA, T>
00678     {
00679         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00680         {
00681             const T* ptr = (const T*)ia->data(s, t, r, m);
00682             float d = float(*ptr++) * GLTypeTraits<T>::scale();
00683             float g = float(*ptr++) * GLTypeTraits<T>::scale();
00684             float b = float(*ptr++) * GLTypeTraits<T>::scale();
00685             float a = float(*ptr) * GLTypeTraits<T>::scale();
00686             return osg::Vec4(d, g, b, a);
00687         }
00688     };
00689 
00690     template<typename T>
00691     struct ColorWriter<GL_RGBA, T>
00692     {
00693         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m)
00694         {
00695             T* ptr = (T*)iw->data(s, t, r, m);
00696             *ptr++ = (GLubyte)( c.r() / GLTypeTraits<T>::scale() );
00697             *ptr++ = (GLubyte)( c.g() / GLTypeTraits<T>::scale() );
00698             *ptr++ = (GLubyte)( c.b() / GLTypeTraits<T>::scale() );
00699             *ptr++ = (GLubyte)( c.a() / GLTypeTraits<T>::scale() );
00700         }
00701     };
00702 
00703     template<typename T>
00704     struct ColorReader<GL_BGR, T>
00705     {
00706         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00707         {
00708             const T* ptr = (const T*)ia->data(s, t, r, m);
00709             float b = float(*ptr) * GLTypeTraits<T>::scale();
00710             float g = float(*ptr++) * GLTypeTraits<T>::scale();
00711             float d = float(*ptr++) * GLTypeTraits<T>::scale();
00712             return osg::Vec4(d, g, b, 1.0f);
00713         }
00714     };
00715 
00716     template<typename T>
00717     struct ColorWriter<GL_BGR, T>
00718     {
00719         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m )
00720         {
00721             T* ptr = (T*)iw->data(s, t, r, m);
00722             *ptr++ = (GLubyte)( c.b() / GLTypeTraits<T>::scale() );
00723             *ptr++ = (GLubyte)( c.g() / GLTypeTraits<T>::scale() );
00724             *ptr++ = (GLubyte)( c.r() / GLTypeTraits<T>::scale() );
00725         }
00726     };
00727 
00728     template<typename T>
00729     struct ColorReader<GL_BGRA, T>
00730     {
00731         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00732         {
00733             const T* ptr = (const T*)ia->data(s, t, r, m);
00734             float b = float(*ptr++) * GLTypeTraits<T>::scale();
00735             float g = float(*ptr++) * GLTypeTraits<T>::scale();
00736             float d = float(*ptr++) * GLTypeTraits<T>::scale();
00737             float a = float(*ptr) * GLTypeTraits<T>::scale();
00738             return osg::Vec4(d, g, b, a);
00739         }
00740     };
00741 
00742     template<typename T>
00743     struct ColorWriter<GL_BGRA, T>
00744     {
00745         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m )
00746         {
00747             T* ptr = (T*)iw->data(s, t, r, m);
00748             *ptr++ = (GLubyte)( c.b() / GLTypeTraits<T>::scale() );
00749             *ptr++ = (GLubyte)( c.g() / GLTypeTraits<T>::scale() );
00750             *ptr++ = (GLubyte)( c.r() / GLTypeTraits<T>::scale() );
00751             *ptr++ = (GLubyte)( c.a() / GLTypeTraits<T>::scale() );
00752         }
00753     };
00754 
00755     template<typename T>
00756     struct ColorReader<0, T>
00757     {
00758         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00759         {
00760             return osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
00761         }
00762     };
00763 
00764     template<typename T>
00765     struct ColorWriter<0, T>
00766     {
00767         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m )
00768         {
00769             //nop
00770         }
00771     };
00772 
00773     template<>
00774     struct ColorReader<GL_UNSIGNED_SHORT_5_5_5_1, GLushort>
00775     {
00776         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00777         {
00778             GLushort p = *(const GLushort*)ia->data(s, t, r, m);
00779             //internal format GL_RGB5_A1 is implied
00780             return osg::Vec4( r5*(float)(p>>11), r5*(float)((p&0x7c0)>>6), r5*((p&0x3e)>>1), (float)(p&0x1));
00781         }
00782     };
00783 
00784     template<>
00785     struct ColorWriter<GL_UNSIGNED_SHORT_5_5_5_1, GLushort>
00786     {
00787         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m )
00788         {
00789             GLushort
00790                 red = (unsigned short)(c.r()*255),
00791                 g = (unsigned short)(c.g()*255),
00792                 b = (unsigned short)(c.b()*255),
00793                 a = c.a() < 0.15 ? 0 : 1;
00794 
00795             GLushort* ptr = (GLushort*)iw->data(s, t, r, m);
00796             *ptr = (((red) & (0xf8)) << 8) | (((g) & (0xf8)) << 3) | (((b) & (0xF8)) >> 2) | a;
00797         }
00798     };
00799 
00800     template<>
00801     struct ColorReader<GL_UNSIGNED_BYTE_3_3_2, GLubyte>
00802     {
00803         static osg::Vec4 read(const ImageUtils::PixelReader* ia, int s, int t, int r, int m)
00804         {
00805               GLubyte p = *(const GLubyte*)ia->data(s,t,r,m);
00806             // internal format GL_R3_G3_B2 is implied
00807             return osg::Vec4( r3*(float)(p>>5), r3*(float)((p&0x28)>>2), r2*(float)(p&0x3), 1.0f );
00808         }
00809     };
00810 
00811     template<>
00812     struct ColorWriter<GL_UNSIGNED_BYTE_3_3_2, GLubyte>
00813     {
00814         static void write(const ImageUtils::PixelWriter* iw, const osg::Vec4f& c, int s, int t, int r, int m )
00815         {
00816             GLubyte* ptr = (GLubyte*)iw->data(s,t,r,m);
00817             OE_WARN << LC << "Target GL_UNSIGNED_BYTE_3_3_2 not yet implemented" << std::endl;
00818         }
00819     };
00820 
00821     template<>
00822     struct ColorReader<GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GLubyte>
00823     {
00824         static osg::Vec4 read(const ImageUtils::PixelReader* pr, int s, int t, int r, int m)
00825         {
00826             static const int BLOCK_BYTES = 8;
00827 
00828             unsigned int blocksPerRow = pr->_image->s()/4;
00829             unsigned int bs = s/4, bt = t/4;
00830             unsigned int blockStart = (bt*blocksPerRow+bs) * BLOCK_BYTES;
00831 
00832             const GLushort* p = (const GLushort*)(pr->data() + blockStart);
00833 
00834             GLushort c0p = *p++;
00835             osg::Vec4f c0(
00836                 (float)(c0p >> 11)/31.0f,
00837                 (float)((c0p & 0x07E0) >> 5)/63.0f,
00838                 (float)((c0p & 0x001F))/31.0f,
00839                 1.0f );
00840 
00841             GLushort c1p = *p++;
00842             osg::Vec4f c1(
00843                 (float)(c1p >> 11)/31.0f,
00844                 (float)((c1p & 0x07E0) >> 5)/63.0f,
00845                 (float)((c1p & 0x001F))/31.0f,
00846                 1.0f );
00847 
00848             static const float one_third  = 1.0f/3.0f;
00849             static const float two_thirds = 2.0f/3.0f;
00850 
00851             osg::Vec4f c2, c3;
00852             if ( c0p > c1p )
00853             {
00854                 c2 = c0*two_thirds + c1*one_third;
00855                 c3 = c0*one_third  + c1*two_thirds;
00856             }
00857             else
00858             {
00859                 c2 = c0*0.5 + c1*0.5;
00860                 c3.set(0,0,0,1);
00861             }
00862 
00863             unsigned int table = *(unsigned int*)p;
00864             int ls = s-4*bs, lt = t-4*bt; //int ls = s % 4, lt = t % 4;
00865             int x = ls + (4 * lt);
00866 
00867             unsigned int index = (table >> (2*x)) & 0x00000003;
00868 
00869             return index==0? c0 : index==1? c1 : index==2? c2 : c3;
00870         }
00871     };
00872 
00873     template<int GLFormat>
00874     inline ImageUtils::PixelReader::ReaderFunc
00875     chooseReader(GLenum dataType)
00876     {
00877         switch (dataType)
00878         {
00879         case GL_BYTE:
00880             return &ColorReader<GLFormat, GLbyte>::read;
00881         case GL_UNSIGNED_BYTE:
00882             return &ColorReader<GLFormat, GLubyte>::read;
00883         case GL_SHORT:
00884             return &ColorReader<GLFormat, GLshort>::read;
00885         case GL_UNSIGNED_SHORT:
00886             return &ColorReader<GLFormat, GLushort>::read;
00887         case GL_INT:
00888             return &ColorReader<GLFormat, GLint>::read;
00889         case GL_UNSIGNED_INT:
00890             return &ColorReader<GLFormat, GLuint>::read;
00891         case GL_FLOAT:
00892             return &ColorReader<GLFormat, GLfloat>::read;       
00893         case GL_UNSIGNED_SHORT_5_5_5_1:
00894             return &ColorReader<GL_UNSIGNED_SHORT_5_5_5_1, GLushort>::read;
00895         case GL_UNSIGNED_BYTE_3_3_2:
00896             return &ColorReader<GL_UNSIGNED_BYTE_3_3_2, GLubyte>::read;
00897         default:
00898             return &ColorReader<0, GLbyte>::read;
00899         }
00900     }
00901 
00902     inline ImageUtils::PixelReader::ReaderFunc
00903     getReader( GLenum pixelFormat, GLenum dataType )
00904     {
00905         switch( pixelFormat )
00906         {
00907         case GL_DEPTH_COMPONENT:
00908             return chooseReader<GL_DEPTH_COMPONENT>(dataType);
00909             break;
00910         case GL_LUMINANCE:
00911             return chooseReader<GL_LUMINANCE>(dataType);
00912             break;        
00913         case GL_ALPHA:
00914             return chooseReader<GL_ALPHA>(dataType);
00915             break;        
00916         case GL_LUMINANCE_ALPHA:
00917             return chooseReader<GL_LUMINANCE_ALPHA>(dataType);
00918             break;        
00919         case GL_RGB:
00920             return chooseReader<GL_RGB>(dataType);
00921             break;        
00922         case GL_RGBA:
00923             return chooseReader<GL_RGBA>(dataType);
00924             break;        
00925         case GL_BGR:
00926             return chooseReader<GL_BGR>(dataType);
00927             break;        
00928         case GL_BGRA:
00929             return chooseReader<GL_BGRA>(dataType);
00930             break; 
00931         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
00932             return &ColorReader<GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GLubyte>::read;
00933             break;
00934         default:
00935             return 0L;
00936             break;
00937         }
00938     }
00939 }
00940     
00941 ImageUtils::PixelReader::PixelReader(const osg::Image* image) :
00942 _image(image)
00943 {
00944     _colMult = _image->getPixelSizeInBits() / 8;
00945     _rowMult = _image->getRowSizeInBytes();
00946     _imageSize = _image->getImageSizeInBytes();
00947     GLenum dataType = _image->getDataType();
00948     _reader = getReader( _image->getPixelFormat(), dataType );
00949     if ( !_reader )
00950     {
00951         OE_WARN << "[PixelReader] No reader found for pixel format " << std::hex << _image->getPixelFormat() << std::endl; 
00952         _reader = &ColorReader<0,GLbyte>::read;
00953     }
00954 }
00955 
00956 bool
00957 ImageUtils::PixelReader::supports( GLenum pixelFormat, GLenum dataType )
00958 {
00959     return getReader(pixelFormat, dataType) != 0L;
00960 }
00961 
00962 //------------------------------------------------------------------------
00963 
00964 namespace
00965 {
00966     template<int GLFormat>
00967     inline ImageUtils::PixelWriter::WriterFunc chooseWriter(GLenum dataType)
00968     {
00969         switch (dataType)
00970         {
00971         case GL_BYTE:
00972             return &ColorWriter<GLFormat, GLbyte>::write;
00973         case GL_UNSIGNED_BYTE:
00974             return &ColorWriter<GLFormat, GLubyte>::write;
00975         case GL_SHORT:
00976             return &ColorWriter<GLFormat, GLshort>::write;
00977         case GL_UNSIGNED_SHORT:
00978             return &ColorWriter<GLFormat, GLushort>::write;
00979         case GL_INT:
00980             return &ColorWriter<GLFormat, GLint>::write;
00981         case GL_UNSIGNED_INT:
00982             return &ColorWriter<GLFormat, GLuint>::write;
00983         case GL_FLOAT:
00984             return &ColorWriter<GLFormat, GLfloat>::write;       
00985         case GL_UNSIGNED_SHORT_5_5_5_1:
00986             return &ColorWriter<GL_UNSIGNED_SHORT_5_5_5_1, GLushort>::write;
00987         case GL_UNSIGNED_BYTE_3_3_2:
00988             return &ColorWriter<GL_UNSIGNED_BYTE_3_3_2, GLubyte>::write;
00989         default:
00990             return 0L;
00991         }
00992     }
00993 
00994     inline ImageUtils::PixelWriter::WriterFunc getWriter(GLenum pixelFormat, GLenum dataType)
00995     {
00996         switch( pixelFormat )
00997         {
00998         case GL_DEPTH_COMPONENT:
00999             return chooseWriter<GL_DEPTH_COMPONENT>(dataType);
01000             break;
01001         case GL_LUMINANCE:
01002             return chooseWriter<GL_LUMINANCE>(dataType);
01003             break;        
01004         case GL_ALPHA:
01005             return chooseWriter<GL_ALPHA>(dataType);
01006             break;        
01007         case GL_LUMINANCE_ALPHA:
01008             return chooseWriter<GL_LUMINANCE_ALPHA>(dataType);
01009             break;        
01010         case GL_RGB:
01011             return chooseWriter<GL_RGB>(dataType);
01012             break;        
01013         case GL_RGBA:
01014             return chooseWriter<GL_RGBA>(dataType);
01015             break;        
01016         case GL_BGR:
01017             return chooseWriter<GL_BGR>(dataType);
01018             break;        
01019         case GL_BGRA:
01020             return chooseWriter<GL_BGRA>(dataType);
01021             break; 
01022         default:
01023             return 0L;
01024             break;
01025         }
01026     }
01027 }
01028     
01029 ImageUtils::PixelWriter::PixelWriter(osg::Image* image) :
01030 _image(image)
01031 {
01032     _colMult = _image->getPixelSizeInBits() / 8;
01033     _rowMult = _image->getRowSizeInBytes();
01034     _imageSize = _image->getImageSizeInBytes();
01035     GLenum dataType = _image->getDataType();
01036     _writer = getWriter( _image->getPixelFormat(), dataType );
01037     if ( !_writer )
01038     {
01039         OE_WARN << "[PixelWriter] No writer found for pixel format " << std::hex << _image->getPixelFormat() << std::endl; 
01040         _writer = &ColorWriter<0, GLbyte>::write;
01041     }
01042 }
01043 
01044 bool
01045 ImageUtils::PixelWriter::supports( GLenum pixelFormat, GLenum dataType )
01046 {
01047     return getWriter(pixelFormat, dataType) != 0L;
01048 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines