osgEarth 2.1.1
|
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 }