Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlCore/Image.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
00007 /*  All rights reserved.                                                              */
00008 /*                                                                                    */
00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
00010 /*  are permitted provided that the following conditions are met:                     */
00011 /*                                                                                    */
00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
00013 /*  list of conditions and the following disclaimer.                                  */
00014 /*                                                                                    */
00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
00017 /*  other materials provided with the distribution.                                   */
00018 /*                                                                                    */
00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
00029 /*                                                                                    */
00030 /**************************************************************************************/
00031 
00032 #include <vlCore/Image.hpp>
00033 #include <vlCore/checks.hpp>
00034 #include <vlCore/Say.hpp>
00035 #include <vlCore/Log.hpp>
00036 #include <vlCore/VisualizationLibrary.hpp>
00037 #include <vlCore/FileSystem.hpp>
00038 #include <vlCore/VirtualFile.hpp>
00039 #include <vlCore/glsl_math.hpp>
00040 #include <vlCore/ResourceDatabase.hpp>
00041 #include <vlCore/LoadWriterManager.hpp>
00042 
00043 #include <map>
00044 #include <cmath>
00045 
00046 using namespace vl;
00047 
00048 //-----------------------------------------------------------------------------
00049 // Image
00050 //-----------------------------------------------------------------------------
00051 Image::~Image()
00052 {
00053   reset();
00054 }
00055 //-----------------------------------------------------------------------------
00056 Image::Image()
00057 {
00058   VL_DEBUG_SET_OBJECT_NAME()
00059   mPixels = new Buffer;
00060   reset();
00061 }
00062 //-----------------------------------------------------------------------------
00063 Image::Image(const Image& other): Object(other) 
00064 {
00065   VL_DEBUG_SET_OBJECT_NAME()
00066   mPixels = new Buffer;
00067   reset();
00068   *this = other; 
00069 }
00070 //-----------------------------------------------------------------------------
00071 Image::Image(const String& path)
00072 {
00073   VL_DEBUG_SET_OBJECT_NAME()
00074   mPixels = new Buffer;
00075   reset();
00076 
00077   setObjectName(path.toStdString().c_str());
00078   ref<Image> img = loadImage(path);
00079   if (!img)
00080   {
00081     mFilePath = path;
00082     return;
00083   }
00084   // quicker than *this = *img;
00085   mPixels->swap(*img->mPixels);
00086   mMipmaps.swap(img->mMipmaps);
00087   mWidth  = img->mWidth;
00088   mHeight = img->mHeight;
00089   mDepth  = img->mDepth;
00090   mPitch  = img->mPitch;
00091   mByteAlign = img->mByteAlign;
00092   mFormat    = img->mFormat;
00093   mType      = img->mType;
00094   mIsCubemap = img->mIsCubemap;
00095   mIsNormalMap = img->mIsNormalMap;
00096   mHasAlpha    = img->mHasAlpha;
00097   mFilePath    = img->mFilePath;
00098 }
00099 //-----------------------------------------------------------------------------
00101 Image::Image(int x, int y, int z, int bytealign, EImageFormat format, EImageType type):
00102   mWidth(x), mHeight(y), mDepth(z), mPitch(0), mByteAlign(1), mFormat(format), mType(type), mIsCubemap(false), mIsNormalMap(false), mHasAlpha(false)
00103 {
00104   VL_DEBUG_SET_OBJECT_NAME()
00105   mPixels = new Buffer;
00106   setByteAlignment(bytealign);
00107 
00108   if (x && y && z)
00109     allocate3D(x,y,z,bytealign,format,type);
00110   else
00111   if (x && y)
00112     allocate2D(x,y,bytealign,format,type);
00113   else
00114   if (x)
00115     allocate1D(x,format,type);
00116 }
00117 //-----------------------------------------------------------------------------
00127 bool Image::isValid() const
00128 {
00129   // size check
00130 
00131   bool x = mWidth > 0 && mHeight == 0 && mDepth == 0;
00132   bool y = mWidth > 0 && mHeight > 0 && mDepth == 0;
00133   bool z = mWidth > 0 && mHeight > 0 && mDepth > 0;
00134 
00135   // format check
00136 
00137   bool okformat = false;
00138 
00139   // these go well with all but compressed formats
00140 
00141   switch(type())
00142   {
00143     default:
00144     break;
00145 
00146     case IT_UNSIGNED_BYTE:
00147     case IT_BYTE:
00148     case IT_UNSIGNED_SHORT:
00149     case IT_SHORT:
00150     case IT_UNSIGNED_INT:
00151     case IT_INT:
00152     case IT_FLOAT:
00153     {
00154       switch(format())
00155       {
00156         case IF_COMPRESSED_RGB_S3TC_DXT1:
00157         case IF_COMPRESSED_RGBA_S3TC_DXT1:
00158         case IF_COMPRESSED_RGBA_S3TC_DXT3:
00159         case IF_COMPRESSED_RGBA_S3TC_DXT5:
00160         {
00161           break;
00162         }
00163 
00164         default:
00165         {
00166           okformat = true;
00167         }
00168       }
00169     }
00170   }
00171 
00172   // compressed type go well only with compressed formats
00173 
00174   switch(type())
00175   {
00176     default:
00177     break;
00178 
00179     case IT_IMPLICIT_TYPE:
00180     {
00181       switch(format())
00182       {
00183         case IF_COMPRESSED_RGB_S3TC_DXT1:
00184         case IF_COMPRESSED_RGBA_S3TC_DXT1:
00185         case IF_COMPRESSED_RGBA_S3TC_DXT3:
00186         case IF_COMPRESSED_RGBA_S3TC_DXT5:
00187         {
00188           okformat = true;
00189           break;
00190         }
00191 
00192         default:
00193         {
00194           break;
00195         }
00196       }
00197     }
00198   }
00199 
00200   switch(format())
00201   {
00202     default:
00203     break;
00204 
00205     // depth stencil
00206     case IF_DEPTH_STENCIL:
00207     {
00208       switch(type())
00209       {
00210         case IT_FLOAT_32_UNSIGNED_INT_24_8_REV:
00211         case IT_UNSIGNED_INT_24_8:
00212           okformat = true;
00213         default:
00214         break;
00215       }
00216     }
00217     break;
00218 
00219     // three components types
00220 
00221     case IF_RGB:
00222     case IF_BGR:
00223     {
00224       switch(type())
00225       {
00226         case IT_UNSIGNED_BYTE_3_3_2:
00227         case IT_UNSIGNED_BYTE_2_3_3_REV:
00228         case IT_UNSIGNED_SHORT_5_6_5:
00229         case IT_UNSIGNED_SHORT_5_6_5_REV:
00230         case IT_UNSIGNED_INT_5_9_9_9_REV: /* EXT_texture_shared_exponent, support only GL_RGB */
00231         case IT_UNSIGNED_INT_10F_11F_11F_REV: /* EXT_packed_float, supports only GL_RGB */
00232         {
00233           okformat = true;
00234           break;
00235         }
00236 
00237         default:
00238         {
00239           break;
00240         }
00241       }
00242       break;
00243     }
00244 
00245     // four components types
00246 
00247     case IF_RGBA:
00248     case IF_BGRA:
00249     {
00250       switch(type())
00251       {
00252         case IT_UNSIGNED_SHORT_4_4_4_4:
00253         case IT_UNSIGNED_SHORT_4_4_4_4_REV:
00254         case IT_UNSIGNED_SHORT_5_5_5_1:
00255         case IT_UNSIGNED_SHORT_1_5_5_5_REV:
00256         case IT_UNSIGNED_INT_8_8_8_8:
00257         case IT_UNSIGNED_INT_8_8_8_8_REV:
00258         case IT_UNSIGNED_INT_10_10_10_2:
00259         case IT_UNSIGNED_INT_2_10_10_10_REV:
00260         {
00261           okformat = true;
00262           break;
00263         }
00264 
00265         default:
00266         {
00267           break;
00268         }
00269       }
00270     }
00271   }
00272 
00273   #ifndef NDEBUG
00274     bool isvalid = okformat && (x|y|z) && (pitch() % mByteAlign == 0);
00275     Log::debug( isvalid ? "" : ( okformat ? "Image::isValid(): invalid dimensions or pitch/bytealign combination:\n" : "Image::isValid() reported an invalid format/type combination:\n") + print() );
00276   #endif
00277 
00278   return okformat && (x|y|z) && (pitch() % mByteAlign == 0);
00279 }
00280 //-----------------------------------------------------------------------------
00281 String Image::printType() const
00282 {
00283   std::map<int, const char*> ty;
00284 
00285   ty[IT_IMPLICIT_TYPE] = "IT_IMPLICIT_TYPE";
00286   ty[IT_UNSIGNED_BYTE] = "IT_UNSIGNED_BYTE";
00287   ty[IT_BYTE] = "IT_BYTE";
00288   ty[IT_UNSIGNED_SHORT] = "IT_UNSIGNED_SHORT";
00289   ty[IT_SHORT] = "IT_SHORT";
00290   ty[IT_UNSIGNED_INT] = "IT_UNSIGNED_INT";
00291   ty[IT_INT] = "IT_INT";
00292   ty[IT_FLOAT] = "IT_FLOAT";
00293   ty[IT_UNSIGNED_BYTE_3_3_2] = "IT_UNSIGNED_BYTE_3_3_2";
00294   ty[IT_UNSIGNED_BYTE_2_3_3_REV] = "IT_UNSIGNED_BYTE_2_3_3_REV";
00295   ty[IT_UNSIGNED_SHORT_5_6_5] = "IT_UNSIGNED_SHORT_5_6_5";
00296   ty[IT_UNSIGNED_SHORT_5_6_5_REV] = "IT_UNSIGNED_SHORT_5_6_5_REV";
00297   ty[IT_UNSIGNED_SHORT_4_4_4_4] = "IT_UNSIGNED_SHORT_4_4_4_4";
00298   ty[IT_UNSIGNED_SHORT_4_4_4_4_REV] = "IT_UNSIGNED_SHORT_4_4_4_4_REV";
00299   ty[IT_UNSIGNED_SHORT_5_5_5_1] = "IT_UNSIGNED_SHORT_5_5_5_1";
00300   ty[IT_UNSIGNED_SHORT_1_5_5_5_REV] = "IT_UNSIGNED_SHORT_1_5_5_5_REV";
00301   ty[IT_UNSIGNED_INT_8_8_8_8] = "IT_UNSIGNED_INT_8_8_8_8";
00302   ty[IT_UNSIGNED_INT_8_8_8_8_REV] = "IT_UNSIGNED_INT_8_8_8_8_REV";
00303   ty[IT_UNSIGNED_INT_10_10_10_2] = "IT_UNSIGNED_INT_10_10_10_2";
00304   ty[IT_UNSIGNED_INT_2_10_10_10_REV] = "IT_UNSIGNED_INT_2_10_10_10_REV";
00305   ty[IT_UNSIGNED_INT_5_9_9_9_REV] = "IT_UNSIGNED_INT_5_9_9_9_REV";
00306   ty[IT_UNSIGNED_INT_10F_11F_11F_REV] = "IT_UNSIGNED_INT_10F_11F_11F_REV";
00307   ty[IT_UNSIGNED_INT_24_8] = "IT_UNSIGNED_INT_24_8";
00308   ty[IT_FLOAT_32_UNSIGNED_INT_24_8_REV] = "IT_FLOAT_32_UNSIGNED_INT_24_8_REV";
00309 
00310   VL_CHECK(ty[type()] != NULL)
00311 
00312   return ty[type()];
00313 }
00314 //-----------------------------------------------------------------------------
00315 String Image::printFormat() const
00316 {
00317   std::map<int, const char*> fo;
00318 
00319   fo[IF_RGB] = "IF_RGB";
00320   fo[IF_RGBA] = "IF_RGBA";
00321   fo[IF_BGR] = "IF_BGR";
00322   fo[IF_BGRA] = "IF_BGRA";
00323   fo[IF_RED] = "IF_RED";
00324   fo[IF_GREEN] = "IF_GREEN";
00325   fo[IF_BLUE] = "IF_BLUE";
00326   fo[IF_ALPHA] = "IF_ALPHA";
00327   fo[IF_LUMINANCE] = "IF_LUMINANCE";
00328   fo[IF_LUMINANCE_ALPHA] = "IF_LUMINANCE_ALPHA";
00329   fo[IF_DEPTH_COMPONENT] = "IF_DEPTH_COMPONENT";
00330   fo[IF_STENCIL_INDEX] = "IF_STENCIL_INDEX";
00331   fo[IF_DEPTH_STENCIL] = "IF_DEPTH_STENCIL";
00332   fo[IF_COMPRESSED_RGB_S3TC_DXT1] = "IF_COMPRESSED_RGB_S3TC_DXT1";
00333   fo[IF_COMPRESSED_RGBA_S3TC_DXT1] = "IF_COMPRESSED_RGBA_S3TC_DXT1";
00334   fo[IF_COMPRESSED_RGBA_S3TC_DXT3] = "IF_COMPRESSED_RGBA_S3TC_DXT3";
00335   fo[IF_COMPRESSED_RGBA_S3TC_DXT5] = "IF_COMPRESSED_RGBA_S3TC_DXT5";
00336 
00337   VL_CHECK( fo[format()] != NULL );
00338 
00339   return fo[format()];
00340 }
00341 //-----------------------------------------------------------------------------
00342 String Image::print() const
00343 {
00344   return Say(
00345   "name   = %s\n"
00346   "width  = %n\n"
00347   "height = %n\n"
00348   "depth  = %n\n"
00349   "format = %s\n"
00350   "type   = %s\n"
00351   "pitch  = %n\n"
00352   "bytealign = %n\n"
00353   )
00354   << objectName().c_str()
00355   << width()
00356   << height()
00357   << depth()
00358   << printFormat()
00359   << printType()
00360   << pitch()
00361   << byteAlignment();
00362 }
00363 //-----------------------------------------------------------------------------
00364 EImageDimension Image::dimension() const
00365 {
00366   if(mWidth > 0 && mHeight == 0 && mDepth == 0 && !mIsCubemap) return ID_1D;
00367   if(mWidth > 0 && mHeight > 0  && mDepth == 0 && !mIsCubemap) return ID_2D;
00368   if(mWidth > 0 && mHeight > 0  && mDepth >  0 && !mIsCubemap) return ID_3D;
00369   if(mWidth > 0 && mHeight > 0  && mDepth == 0 &&  mIsCubemap) return ID_Cubemap;
00370   return ID_Error;
00371 }
00372 //-----------------------------------------------------------------------------
00374 int Image::bitsPerPixel(EImageType type, EImageFormat format)
00375 {
00376   int comp_size = 0;
00377 
00378   switch(type)
00379   {
00380     default:
00381     break;
00382 
00383     case IT_UNSIGNED_BYTE:  comp_size = sizeof(unsigned char)  * 8; break;
00384     case IT_BYTE:           comp_size = sizeof(GLbyte)   * 8; break;
00385     case IT_UNSIGNED_SHORT: comp_size = sizeof(GLushort) * 8; break;
00386     case IT_SHORT:          comp_size = sizeof(GLshort)  * 8; break;
00387     case IT_UNSIGNED_INT:   comp_size = sizeof(unsigned int)   * 8; break;
00388     case IT_INT:            comp_size = sizeof(int)    * 8; break;
00389     case IT_FLOAT:          comp_size = sizeof(float)  * 8; break;
00390 
00391     case IT_UNSIGNED_BYTE_3_3_2:          return 8;
00392     case IT_UNSIGNED_BYTE_2_3_3_REV:      return 8;
00393     case IT_UNSIGNED_SHORT_5_6_5:         return 16;
00394     case IT_UNSIGNED_SHORT_5_6_5_REV:     return 16;
00395     case IT_UNSIGNED_SHORT_4_4_4_4:       return 16;
00396     case IT_UNSIGNED_SHORT_4_4_4_4_REV:   return 16;
00397     case IT_UNSIGNED_SHORT_5_5_5_1:       return 16;
00398     case IT_UNSIGNED_SHORT_1_5_5_5_REV:   return 16;
00399     case IT_UNSIGNED_INT_8_8_8_8:         return 32;
00400     case IT_UNSIGNED_INT_8_8_8_8_REV:     return 32;
00401     case IT_UNSIGNED_INT_10_10_10_2:      return 32;
00402     case IT_UNSIGNED_INT_2_10_10_10_REV:  return 32;
00403     case IT_UNSIGNED_INT_5_9_9_9_REV:     return 32; /* EXT_texture_shared_exponent, support only IF_RGB */
00404     case IT_UNSIGNED_INT_10F_11F_11F_REV: return 32; /* EXT_packed_float, supports only IF_RGB */
00405     case IT_UNSIGNED_INT_24_8:            return 32; /* EXT_packed_depth_stencil, supports only IF_DEPTH_STENCIL */
00406     case IT_FLOAT_32_UNSIGNED_INT_24_8_REV: return 64; /* EXT_depth_buffer_float, supports only IF_DEPTH_STENCIL */
00407   }
00408 
00409   switch(format)
00410   {
00411     case IF_RED:             return comp_size * 1;
00412     case IF_GREEN:           return comp_size * 1;
00413     case IF_BLUE:            return comp_size * 1;
00414     case IF_ALPHA:           return comp_size * 1;
00415     case IF_DEPTH_COMPONENT: return comp_size * 1;
00416     case IF_STENCIL_INDEX:   return comp_size * 1;
00417     case IF_LUMINANCE:       return comp_size * 1;
00418     case IF_LUMINANCE_ALPHA: return comp_size * 2;
00419     case IF_DEPTH_STENCIL:   return comp_size * 0;
00420     case IF_RGB:             return comp_size * 3;
00421     case IF_BGR:             return comp_size * 3;
00422     case IF_RGBA:            return comp_size * 4;
00423     case IF_BGRA:            return comp_size * 4;
00424 
00425      // compressed formats
00426 
00427     case IF_COMPRESSED_RGB_S3TC_DXT1:  return 4; // 8 bytes (64 bits) per block per 16 pixels
00428     case IF_COMPRESSED_RGBA_S3TC_DXT1: return 4; // 8 bytes (64 bits) per block per 16 pixels
00429     case IF_COMPRESSED_RGBA_S3TC_DXT3: return 8; // 16 bytes (128 bits) per block per 16 pixels
00430     case IF_COMPRESSED_RGBA_S3TC_DXT5: return 8; // 16 bytes (128 bits) per block per 16 pixels
00431     default:
00432       break;
00433   }
00434 
00435   VL_TRAP()
00436   return 0;
00437 }
00438 //-----------------------------------------------------------------------------
00440 int Image::alphaBits() const
00441 {
00442   int comp_size = 0;
00443 
00444   switch(format())
00445   {
00446     case IF_RED:             return comp_size * 0;
00447     case IF_GREEN:           return comp_size * 0;
00448     case IF_BLUE:            return comp_size * 0;
00449     case IF_ALPHA:           return comp_size * 1;
00450     case IF_DEPTH_COMPONENT: return comp_size * 0;
00451     case IF_STENCIL_INDEX:   return comp_size * 0;
00452     case IF_LUMINANCE:       return comp_size * 0;
00453     case IF_LUMINANCE_ALPHA: return comp_size * 1;
00454     case IF_DEPTH_STENCIL:   return comp_size * 0;
00455     case IF_RGB:             return comp_size * 0;
00456     case IF_BGR:             return comp_size * 0;
00457     case IF_RGBA:            return comp_size * 1;
00458     case IF_BGRA:            return comp_size * 1;
00459 
00460      // compressed formats
00461 
00462     case IF_COMPRESSED_RGB_S3TC_DXT1:  return 0; // 8 bytes (64 bits) per block per 16 pixels
00463     case IF_COMPRESSED_RGBA_S3TC_DXT1: return 1; // 8 bytes (64 bits) per block per 16 pixels
00464     case IF_COMPRESSED_RGBA_S3TC_DXT3: return 4; // 16 bytes (64 bits for uncompressed alpha + 64 bits for RGB) per block per 16 pixels
00465     case IF_COMPRESSED_RGBA_S3TC_DXT5: return 4; // 16 bytes (64 bits for   compressed alpha + 64 bits for RGB) per block per 16 pixels
00466     default:
00467       break;
00468   }
00469 
00470   switch(type())
00471   {
00472     default:
00473     break;
00474 
00475     case IT_UNSIGNED_BYTE:  comp_size = sizeof(unsigned char)  * 8; break;
00476     case IT_BYTE:           comp_size = sizeof(GLbyte)   * 8; break;
00477     case IT_UNSIGNED_SHORT: comp_size = sizeof(GLushort) * 8; break;
00478     case IT_SHORT:          comp_size = sizeof(GLshort)  * 8; break;
00479     case IT_UNSIGNED_INT:   comp_size = sizeof(unsigned int)   * 8; break;
00480     case IT_INT:            comp_size = sizeof(int)    * 8; break;
00481     case IT_FLOAT:          comp_size = sizeof(float)  * 8; break;
00482 
00483     case IT_UNSIGNED_BYTE_3_3_2:          return 0;
00484     case IT_UNSIGNED_BYTE_2_3_3_REV:      return 0;
00485     case IT_UNSIGNED_SHORT_5_6_5:         return 0;
00486     case IT_UNSIGNED_SHORT_5_6_5_REV:     return 0;
00487     case IT_UNSIGNED_SHORT_4_4_4_4:       return 4;
00488     case IT_UNSIGNED_SHORT_4_4_4_4_REV:   return 4;
00489     case IT_UNSIGNED_SHORT_5_5_5_1:       return 1;
00490     case IT_UNSIGNED_SHORT_1_5_5_5_REV:   return 1;
00491     case IT_UNSIGNED_INT_8_8_8_8:         return 8;
00492     case IT_UNSIGNED_INT_8_8_8_8_REV:     return 8;
00493     case IT_UNSIGNED_INT_10_10_10_2:      return 2;
00494     case IT_UNSIGNED_INT_2_10_10_10_REV:  return 2;
00495     case IT_UNSIGNED_INT_5_9_9_9_REV:     return 0; /* EXT_texture_shared_exponent, support only GL_RGB */
00496     case IT_UNSIGNED_INT_10F_11F_11F_REV: return 0; /* EXT_packed_float, supports only GL_RGB */
00497     case IT_UNSIGNED_INT_24_8:            return 0; /* EXT_packed_depth_stencil, supports only GL_DEPTH_STENCIL */
00498     case IT_FLOAT_32_UNSIGNED_INT_24_8_REV: return 0; /* EXT_depth_buffer_float, supports only IF_DEPTH_STENCIL */
00499   }
00500 
00501   VL_TRAP()
00502 
00503   return 0;
00504 }
00505 //-----------------------------------------------------------------------------
00506 int Image::isCompressedFormat(EImageFormat fmt)
00507 {
00508   switch(fmt)
00509   {
00510   case IF_COMPRESSED_RGB_S3TC_DXT1:
00511   case IF_COMPRESSED_RGBA_S3TC_DXT1:
00512   case IF_COMPRESSED_RGBA_S3TC_DXT3:
00513   case IF_COMPRESSED_RGBA_S3TC_DXT5:
00514     return true;
00515 
00516   default:
00517     return false;
00518   }
00519 }
00520 //-----------------------------------------------------------------------------
00523 int Image::requiredMemory() const
00524 {
00525   VL_CHECK( isValid() )
00526   return requiredMemory(width(), height(), depth(), byteAlignment(), format(), type(), isCubemap());
00527 }
00528 //-----------------------------------------------------------------------------
00531 int Image::byteAlignment() const
00532 {
00533   return mByteAlign;
00534 }
00535 //-----------------------------------------------------------------------------
00541 void Image::setByteAlignment(int bytealign)
00542 {
00543   // cannot change the alignment when an image is already allocated
00544 
00545   VL_CHECK(mPixels->empty());
00546 
00547   if (!mPixels->empty())
00548     return;
00549 
00550   switch(bytealign)
00551   {
00552   case 0:
00553     bytealign = sizeof(unsigned char*);
00554   case 1:
00555   case 2:
00556   case 4:
00557   case 8:
00558     break;
00559   default:
00560     VL_TRAP()
00561   }
00562 
00563   mByteAlign = bytealign;
00564 
00565   updatePitch();
00566 }
00567 //-----------------------------------------------------------------------------
00568 void Image::updatePitch()
00569 {
00570   int xbits  = mWidth * bitsPerPixel();
00571   int xbytes = xbits/8 + ( (xbits % 8) ? 1 : 0 );
00572   mPitch     = xbytes/mByteAlign*mByteAlign + ( (xbytes % mByteAlign) ? mByteAlign : 0 );
00573 }
00574 //-----------------------------------------------------------------------------
00575 void Image::allocateCubemap(int x, int y, int bytealign, EImageFormat format, EImageType type)
00576 {
00577   reset();
00578 
00579   setWidth(x);
00580   setHeight(y);
00581   setDepth(0);
00582   setFormat(format);
00583   setType(type);
00584   setByteAlignment(bytealign);
00585   mIsCubemap = true;
00586 
00587   // mPixels.clear();
00588   mPixels->resize(requiredMemory());
00589 }
00590 //-----------------------------------------------------------------------------
00591 void Image::allocate()
00592 {
00593   mMipmaps.clear();
00594   mPixels->resize(requiredMemory());
00595 }
00596 //-----------------------------------------------------------------------------
00597 void Image::allocate1D(int x, EImageFormat format, EImageType type)
00598 {
00599   reset();
00600 
00601   VL_CHECK(x);
00602   setWidth(x);
00603   setHeight(0);
00604   setDepth(0);
00605   setFormat(format);
00606   setType(type);
00607   setByteAlignment(1);
00608   mIsCubemap = false;
00609 
00610   mPixels->resize(requiredMemory());
00611 }
00612 //-----------------------------------------------------------------------------
00613 void Image::allocate2D(int x, int y, int bytealign, EImageFormat format, EImageType type)
00614 {
00615   reset();
00616 
00617   VL_CHECK(x);
00618   VL_CHECK(y);
00619   setWidth(x);
00620   setHeight(y);
00621   setDepth(0);
00622   setFormat(format);
00623   setType(type);
00624   setByteAlignment(bytealign);
00625   mIsCubemap = false;
00626 
00627   int req_mem = requiredMemory();
00628   if (req_mem == 0)
00629     Log::bug("Image::allocate2D could not allocate memory, probably your image settings are invalid.\n");
00630   mPixels->resize(req_mem);
00631 }
00632 //-----------------------------------------------------------------------------
00633 void Image::allocate3D(int x, int y, int z, int bytealign, EImageFormat format, EImageType type)
00634 {
00635   reset();
00636 
00637   VL_CHECK(x);
00638   VL_CHECK(y);
00639   VL_CHECK(z);
00640   setWidth(x);
00641   setHeight(y);
00642   setDepth(z);
00643   setFormat(format);
00644   setType(type);
00645   setByteAlignment(bytealign);
00646   mIsCubemap = false;
00647 
00648   mPixels->resize(requiredMemory());
00649 }
00650 //-----------------------------------------------------------------------------
00651 void Image::reset(int x, int y, int z, int bytealign, EImageFormat format, EImageType type, bool is_cubemap)
00652 {
00653   reset();
00654 
00655   setWidth(x);
00656   setHeight(y);
00657   setDepth(z);
00658   setFormat(format);
00659   setType(type);
00660   setByteAlignment(bytealign);
00661   mIsCubemap = is_cubemap;
00662 }
00663 //-----------------------------------------------------------------------------
00664 void Image::reset()
00665 {
00666   mPixels->clear();
00667   mMipmaps.clear();
00668   mObjectName.clear();
00669   mWidth = 0;
00670   mHeight = 0;
00671   mDepth = 0;
00672   mPitch = 0;
00673   mFormat = IF_RGBA;
00674   mType = IT_UNSIGNED_BYTE;
00675   mByteAlign = 1;
00676   mIsCubemap   = false;
00677   mIsNormalMap = false;
00678   mHasAlpha    = false;
00679 }
00680 //-----------------------------------------------------------------------------
00681 Image& Image::operator=(const Image& other)
00682 {
00683   super::operator=(other);
00684 
00685   // deep copy of the pixels
00686   *mPixels = *other.mPixels;
00687 
00688   // copy image info
00689   mWidth  = other.mWidth;
00690   mHeight  = other.mHeight;
00691   mDepth  = other.mDepth;
00692   mPitch  = other.mPitch;
00693   mByteAlign = other.mByteAlign;
00694   mFormat    = other.mFormat;
00695   mType      = other.mType;
00696   mIsCubemap = other.mIsCubemap;
00697   mIsNormalMap = other.mIsNormalMap;
00698   mHasAlpha    = other.mHasAlpha;
00699 
00700   // deep copy of the mipmaps
00701   mMipmaps.resize(other.mMipmaps.size());
00702   for(int i=0; i<(int)mMipmaps.size(); ++i)
00703   {
00704     mMipmaps[i] = new Image;
00705     *mMipmaps[i] = *other.mMipmaps[i];
00706   }
00707   return *this;
00708 }
00709 //-----------------------------------------------------------------------------
00710 const unsigned char* Image::pixelsXP() const
00711 {
00712   VL_CHECK( dimension() == 4 )
00713   if( dimension() != 4 || !pixels())
00714     return NULL;
00715   else
00716     return pixels();
00717 }
00718 //-----------------------------------------------------------------------------
00719 unsigned char* Image::pixelsXP()
00720 {
00721   VL_CHECK( dimension() == 4 )
00722   if( dimension() != 4 || !pixels())
00723     return NULL;
00724   else
00725     return pixels();
00726 }
00727 //-----------------------------------------------------------------------------
00728 const unsigned char* Image::pixelsXN() const
00729 {
00730   VL_CHECK( dimension() == 4 )
00731   if( dimension() != 4 || !pixels())
00732     return NULL;
00733   else
00734     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 1;
00735 }
00736 //-----------------------------------------------------------------------------
00737 unsigned char* Image::pixelsXN()
00738 {
00739   VL_CHECK( dimension() == 4 )
00740   if( dimension() != 4 || !pixels())
00741     return NULL;
00742   else
00743     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 1;
00744 }
00745 //-----------------------------------------------------------------------------
00746 const unsigned char* Image::pixelsYP() const
00747 {
00748   VL_CHECK( dimension() == 4 )
00749   if( dimension() != 4 || !pixels())
00750     return NULL;
00751   else
00752     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 2;
00753 }
00754 //-----------------------------------------------------------------------------
00755 unsigned char* Image::pixelsYP()
00756 {
00757   VL_CHECK( dimension() == 4 )
00758   if( dimension() != 4 || !pixels())
00759     return NULL;
00760   else
00761     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 2;
00762 }
00763 //-----------------------------------------------------------------------------
00764 const unsigned char* Image::pixelsYN() const
00765 {
00766   VL_CHECK( dimension() == 4 )
00767   if( dimension() != 4 || !pixels())
00768     return NULL;
00769   else
00770     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 3;
00771 }
00772 //-----------------------------------------------------------------------------
00773 unsigned char* Image::pixelsYN()
00774 {
00775   VL_CHECK( dimension() == 4 )
00776   if( dimension() != 4 || !pixels())
00777     return NULL;
00778   else
00779     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 3;
00780 }
00781 //-----------------------------------------------------------------------------
00782 const unsigned char* Image::pixelsZP() const
00783 {
00784   VL_CHECK( dimension() == 4 )
00785   if( dimension() != 4 || !pixels())
00786     return NULL;
00787   else
00788     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 4;
00789 }
00790 //-----------------------------------------------------------------------------
00791 unsigned char* Image::pixelsZP()
00792 {
00793   VL_CHECK( dimension() == 4 )
00794   if( dimension() != 4 || !pixels())
00795     return NULL;
00796   else
00797     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 4;
00798 }
00799 //-----------------------------------------------------------------------------
00800 const unsigned char* Image::pixelsZN() const
00801 {
00802   VL_CHECK( dimension() == 4 )
00803   if( dimension() != 4 || !pixels())
00804     return NULL;
00805   else
00806     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 5;
00807 }
00808 //-----------------------------------------------------------------------------
00809 unsigned char* Image::pixelsZN()
00810 {
00811   VL_CHECK( dimension() == 4 )
00812   if( dimension() != 4 || !pixels())
00813     return NULL;
00814   else
00815     return (unsigned char*)pixels() + requiredMemory2D( width(), height(), byteAlignment(), format(), type() ) * 5;
00816 }
00817 //-----------------------------------------------------------------------------
00819 unsigned char* Image::pixelsZSlice(int slice)
00820 {
00821   VL_CHECK(slice < depth());
00822   VL_CHECK(slice >= 0 );
00823   if (mIsCubemap || !pixels())
00824     return NULL;
00825   else
00826   {
00827     return (unsigned char*)pixels() + pitch()*height()*slice;
00828   }
00829 }
00830 //-----------------------------------------------------------------------------
00831 ref<Image> vl::createCubemap(const Image* xp, const Image* xn, const Image* yp, const Image* yn, const Image* zp, const Image* zn)
00832 {
00833   // check validity of all the images
00834   // contract:
00835   // - they must be all isValid() images, must have been allocated, must be 2D images, must
00836   // - have exactly the same dimensions, format, type, byte alignment.
00837   // - they must be square
00838 
00839   const Image* img[] = {xp, xn, yp, yn, zp, zn};
00840 
00841   // check they are square (later we check they have the same size)
00842   if (img[0]->width() != img[0]->height())
00843   {
00844     Log::error("Cubemap creation failed: all the images must be square.\n");
00845     return NULL;
00846   }
00847 
00848   for(int i=0; i<6; ++i)
00849   {
00850     if (img[i] == NULL || !img[i]->isValid() || img[i]->pixels() == NULL || img[i]->dimension() != 2)
00851     {
00852       Log::error("Cubemap creation failed: one or more image is invalid (could be NULL, not allocated, not 2D, wrong internal_ configuration or other).\n");
00853       return NULL;
00854     }
00855 
00856     // check that they have the same size
00857     if (img[0]->width() != img[i]->width())
00858     {
00859       Log::error("Cubemap creation failed: the faces of the cube must have the very same dimensions.\n");
00860       return NULL;
00861     }
00862 
00863     // check that they have the same size
00864     if (img[0]->height() != img[i]->height())
00865     {
00866       Log::error("Cubemap creation failed: the faces of the cube must have the very same dimensions.\n");
00867       return NULL;
00868     }
00869 
00870     // check that they have the same format
00871     if (img[0]->format() != img[i]->format())
00872     {
00873       Log::error("Cubemap creation failed: the faces of the cube must have the very same format.\n");
00874       return NULL;
00875     }
00876 
00877     // check that they have the same type
00878     if (img[0]->type() != img[i]->type())
00879     {
00880       Log::error("Cubemap creation failed: the faces of the cube must have the very same type.\n");
00881       return NULL;
00882     }
00883 
00884     // check that they have the same byte alignment
00885     if (img[0]->byteAlignment() != img[i]->byteAlignment())
00886     {
00887       Log::error("Cubemap creation failed: the faces of the cube must have the very same byte alignment.\n");
00888       return NULL;
00889     }
00890 
00891     // check that they have the same required memory
00892     if (img[0]->requiredMemory() != img[i]->requiredMemory())
00893     {
00894       Log::error("Cubemap creation failed: the faces of the cube must require the very same amount of memory.\n");
00895       return NULL;
00896     }
00897   }
00898 
00899   // create a cube map image from the given 2D images
00900 
00901   ref<Image> cubemap = new Image;
00902 
00903   cubemap->allocateCubemap( img[0]->width(), img[0]->height(), img[0]->byteAlignment(), img[0]->format(), img[0]->type() );
00904 
00905   memcpy( cubemap->pixelsXP(), img[0]->pixels(), img[0]->requiredMemory() );
00906   memcpy( cubemap->pixelsXN(), img[1]->pixels(), img[0]->requiredMemory() );
00907   memcpy( cubemap->pixelsYP(), img[2]->pixels(), img[0]->requiredMemory() );
00908   memcpy( cubemap->pixelsYN(), img[3]->pixels(), img[0]->requiredMemory() );
00909   memcpy( cubemap->pixelsZP(), img[4]->pixels(), img[0]->requiredMemory() );
00910   memcpy( cubemap->pixelsZN(), img[5]->pixels(), img[0]->requiredMemory() );
00911 
00912   return cubemap.get();
00913 }
00914 //-----------------------------------------------------------------------------
00915 void Image::flipVertically()
00916 {
00917   if (dimension() == ID_1D)
00918     return;
00919 
00920   VL_CHECK(pixels());
00921   int row_size = pitch();
00922   std::vector<unsigned char> row1;
00923   row1.resize(row_size);
00924 
00925   std::vector<unsigned char*> pxl;
00926 
00927   if (dimension() == ID_2D)
00928   {
00929     pxl.push_back( (unsigned char*)pixels() );
00930   }
00931   else
00932   if (dimension() == ID_Cubemap)
00933   {
00934     pxl.push_back( (unsigned char*)pixelsXP() );
00935     pxl.push_back( (unsigned char*)pixelsXN() );
00936     pxl.push_back( (unsigned char*)pixelsYP() );
00937     pxl.push_back( (unsigned char*)pixelsYN() );
00938     pxl.push_back( (unsigned char*)pixelsZP() );
00939     pxl.push_back( (unsigned char*)pixelsZN() );
00940   }
00941   else
00942   if (dimension() == ID_3D)
00943   {
00944     for(int zslice=0; zslice<depth(); zslice++)
00945       pxl.push_back( (unsigned char*)pixelsZSlice(zslice) );
00946   }
00947 
00948   for(unsigned img=0; img<pxl.size(); img++)
00949   {
00950     for(int i=0; i<height()/2; ++i)
00951     {
00952       int j = height() - 1 - i;
00953       memcpy(&row1[0], pxl[img]+i*row_size, row_size);
00954       memcpy(pxl[img]+i*row_size, pxl[img]+j*row_size, row_size);
00955       memcpy(pxl[img]+j*row_size,  &row1[0], row_size);
00956     }
00957   }
00958 }
00959 //-----------------------------------------------------------------------------
00960 int Image::requiredMemory(int width, int height, int depth, int bytealign, EImageFormat format, EImageType type, bool is_cubemap)
00961 {
00962   // byte align
00963 
00964   switch(bytealign)
00965   {
00966   case 1:
00967   case 2:
00968   case 4:
00969   case 8:
00970     break;
00971   case 0:
00972   default:
00973     bytealign = sizeof(unsigned char*);
00974   }
00975 
00976   // fix width and height to match compression scheme
00977 
00978   switch(format)
00979   {
00980     case IF_COMPRESSED_RGB_S3TC_DXT1:
00981     case IF_COMPRESSED_RGBA_S3TC_DXT1:
00982     case IF_COMPRESSED_RGBA_S3TC_DXT3:
00983     case IF_COMPRESSED_RGBA_S3TC_DXT5:
00984       if (width % 4)
00985         width = width - width % 4 + 4;
00986       if (height % 4)
00987         height = height - height % 4 + 4;
00988     default:
00989       break;
00990   }
00991 
00992   // pitch
00993 
00994   int xbits = width * bitsPerPixel(type, format);
00995   int xbytes = xbits/8 + ( (xbits % 8) ? 1 : 0 );
00996   int pitch  = xbytes/bytealign*bytealign + ( (xbytes % bytealign) ? bytealign : 0 );
00997 
00998   // computation
00999 
01000   height = height ? height : 1;
01001   depth  = depth  ? depth  : 1;
01002   int req_mem = pitch * height * depth;
01003 
01004   // minimum memory taken by a compressed block
01005   if (req_mem < 8 && format == IF_COMPRESSED_RGB_S3TC_DXT1)
01006     req_mem = 8;
01007 
01008   if (req_mem < 8 && format == IF_COMPRESSED_RGBA_S3TC_DXT1)
01009     req_mem = 8;
01010 
01011   if (req_mem < 16 && format == IF_COMPRESSED_RGBA_S3TC_DXT3)
01012     req_mem = 16;
01013 
01014   if (req_mem < 16 && format == IF_COMPRESSED_RGBA_S3TC_DXT5)
01015     req_mem = 16;
01016 
01017   // todo: add other compression schemes
01018   // ...
01019 
01020   // cubemap
01021   if (is_cubemap)
01022     req_mem *= 6;
01023 
01024   return req_mem;
01025 }
01026 //-----------------------------------------------------------------------------
01027 ref<Image> vl::makeColorSpectrum(size_t width, const fvec4& c0, const fvec4& c1)
01028 {
01029   std::vector<fvec4> colors;
01030   colors.push_back(c0); colors.push_back(c1);
01031   return makeColorSpectrum(width, colors);
01032 }
01033 //-----------------------------------------------------------------------------
01034 ref<Image> vl::makeColorSpectrum(size_t width, const fvec4& c0, const fvec4& c1, const fvec4& c2)
01035 {
01036   std::vector<fvec4> colors;
01037   colors.push_back(c0); colors.push_back(c1); colors.push_back(c2);
01038   return makeColorSpectrum(width, colors);
01039 }
01040 //-----------------------------------------------------------------------------
01041 ref<Image> vl::makeColorSpectrum(size_t width, const fvec4& c0, const fvec4& c1, const fvec4& c2, const fvec4& c3)
01042 {
01043   std::vector<fvec4> colors;
01044   colors.push_back(c0); colors.push_back(c1); colors.push_back(c2); colors.push_back(c3);
01045   return makeColorSpectrum(width, colors);
01046 }
01047 //-----------------------------------------------------------------------------
01048 ref<Image> vl::makeColorSpectrum(size_t width, const fvec4& c0, const fvec4& c1, const fvec4& c2, const fvec4& c3, const fvec4& c4)
01049 {
01050   std::vector<fvec4> colors;
01051   colors.push_back(c0); colors.push_back(c1); colors.push_back(c2); colors.push_back(c3); colors.push_back(c4);
01052   return makeColorSpectrum(width, colors);
01053 }
01054 //-----------------------------------------------------------------------------
01055 ref<Image> vl::makeNonUniformColorSpectrum(size_t width, size_t col_count, const fvec4* colors, const float* col_pos)
01056 {
01057   //     c0    c1    c2    c4
01058   // |---t0----t1----t2----t4---|
01059   // before t0 the color is pure c0
01060   // after t4 the color is pure t4
01061 
01062   ref<Image> img = new Image(width, 0, 0, 1, IF_RGBA, IT_UNSIGNED_BYTE);
01063   ubvec4* px = (ubvec4*)img->pixels();
01064   int last = col_count-1;
01065   for(int i=0; i<img->width(); ++i)
01066   {
01067     float t = (float)i/(img->width()-1);
01068     if (t<=col_pos[0])
01069       px[i] = (ubvec4)(colors[0]*255.0f);
01070     else
01071     if (t>=col_pos[last])
01072       px[i] = (ubvec4)(colors[last]*255.0f);
01073     else
01074     {
01075       for(size_t j=0; j<col_count-1; ++j)
01076       {
01077         if (t>=col_pos[j] && t<=col_pos[j+1])
01078         {
01079           float tt = 0;
01080           if (col_pos[j+1]-col_pos[j] != 0)
01081             tt = (t-col_pos[j])/(col_pos[j+1]-col_pos[j]);
01082           VL_CHECK(tt>=0 && tt<=1.0f)
01083           px[i] = (ubvec4)((colors[j] * (1.0f-tt) + colors[j+1] * tt)*255.0f);
01084           break;
01085         }
01086       }
01087     }
01088   }
01089   return img;
01090 }
01091 //-----------------------------------------------------------------------------
01092 ref<Image> vl::makeNonUniformColorSpectrum(int width, const std::vector<fvec4>& colors, const std::vector<float>& col_pos)
01093 {
01094   if (colors.empty() || colors.size() != col_pos.size())
01095     return NULL;
01096   else
01097     return makeNonUniformColorSpectrum(width, colors.size(), &colors[0], &col_pos[0]);
01098 }
01099 //-----------------------------------------------------------------------------
01100 ref<Image> vl::makeColorSpectrum(size_t width, const std::vector<fvec4>& colors)
01101 {
01102   ref<Image> img = new Image(width, 0, 0, 1, IF_RGBA, IT_UNSIGNED_BYTE);
01103   int index = colors.size() - 1;
01104   for(int i=0; i<img->width(); ++i)
01105   {
01106     int   coli = (int)(index * (float)i/img->width());
01107     float colt = (index * (float)i/img->width()) - coli;
01108     img->pixels()[i*4 + 0] = (unsigned char)(255.0 * (colors[coli].r()*(1.0f-colt) + colors[coli+1].r()*colt));
01109     img->pixels()[i*4 + 1] = (unsigned char)(255.0 * (colors[coli].g()*(1.0f-colt) + colors[coli+1].g()*colt));
01110     img->pixels()[i*4 + 2] = (unsigned char)(255.0 * (colors[coli].b()*(1.0f-colt) + colors[coli+1].b()*colt));
01111     img->pixels()[i*4 + 3] = 255;
01112   }
01113   return img;
01114 }
01115 //-----------------------------------------------------------------------------
01117 ref<Image> vl::assemble3DImage(const std::vector< ref<Image> >& images)
01118 {
01119   if (images.empty())
01120     return NULL;
01121   // sanity checks
01122   for(unsigned i=1; i<images.size(); ++i)
01123   {
01124     if (images[i]->width()  != images[0]->width())  return NULL;
01125     if (images[i]->height() != images[0]->height()) return NULL;
01126     if (images[i]->depth()  != images[0]->depth())  return NULL;
01127     if (images[i]->type()   != images[0]->type())   return NULL;
01128     if (images[i]->format() != images[0]->format()) return NULL;
01129     if (images[i]->byteAlignment()  != images[0]->byteAlignment())  return NULL;
01130     if (images[i]->bitsPerPixel()   != images[0]->bitsPerPixel())   return NULL;
01131     if (images[i]->requiredMemory() != images[0]->requiredMemory()) return NULL;
01132   }
01133 
01134   ref<Image> img = new Image;
01135   img->allocate3D( images[0]->width(), images[0]->height(), images.size(), 1, images[0]->format(), images[0]->type() );
01136   VL_CHECK(img->requiredMemory() == images[0]->requiredMemory()*(int)images.size())
01137   for(unsigned i=0; i<images.size(); ++i)
01138   {
01139     VL_CHECK(images[i]->pixels())
01140     memcpy(img->pixelsZSlice(i), images[i]->pixels(), images[i]->requiredMemory());
01141   }
01142   return img;
01143 }
01144 //-----------------------------------------------------------------------------
01145 bool vl::loadImagesFromDir(const String& dir_path, const String& ext, std::vector< ref<Image> >& images)
01146 {
01147   images.clear();
01148   if (ext.empty() || dir_path.empty())
01149     return false;
01150   ref<VirtualDirectory> dir = defFileSystem()->locateDirectory(dir_path);
01151   if (!dir)
01152     return false;
01153   std::vector<String> files;
01154   dir->listFiles(files);
01155   std::sort(files.begin(), files.end());
01156   for(unsigned i=0; i<files.size(); ++i)
01157   {
01158     if (files[i].extractFileExtension().toLowerCase() == ext.toLowerCase())
01159     {
01160       images.push_back( loadImage(files[i]) );
01161       if (images.back().get() == NULL)
01162         return false;
01163     }
01164   }
01165   return true;
01166 }
01167 //-----------------------------------------------------------------------------
01168 ref<Image> vl::loadImage( const String& path )
01169 {
01170   ref<VirtualFile> file = defFileSystem()->locateFile(path);
01171   if ( !file )
01172   {
01173     Log::error( Say("File '%s' not found.\n") << path );
01174     return NULL;
01175   }
01176   else
01177     return loadImage(file.get());
01178 }
01179 //-----------------------------------------------------------------------------
01180 ref<Image> vl::loadImage( VirtualFile* file )
01181 {
01182   ref<ResourceDatabase> res_db = defLoadWriterManager()->loadResource(file);
01183 
01184   if (!res_db)
01185   {
01186     Log::error( Say("vl::loadImage('%s') failed.\n") << file->path() );
01187     return NULL;
01188   }
01189 
01190   ref<Image> img;
01191 
01192   img = res_db->get<Image>(0);
01193 
01194   VL_CHECK( !file->isOpen() )
01195   file->close();
01196 
01197   if (img)
01198   {
01199     img->setObjectName( file->path().toStdString().c_str() );
01200     img->setFilePath( file->path() );
01201   }
01202 
01203   return img;
01204 }
01205 //-----------------------------------------------------------------------------
01206 bool vl::saveImage( Image* img, const String& path)
01207 {
01208   ref<ResourceDatabase> res_db = new ResourceDatabase;
01209   res_db->resources().push_back(img);
01210   bool ok = defLoadWriterManager()->writeResource(path, res_db.get());
01211   if (!ok)
01212     Log::error( Say("vl::saveImage('%s') failed.\n") << path );
01213   return ok;
01214 }
01215 //-----------------------------------------------------------------------------
01216 bool vl::saveImage( Image* img, VirtualFile* file )
01217 {
01218   ref<ResourceDatabase> res_db = new ResourceDatabase;
01219   res_db->resources().push_back(img);
01220   bool ok = defLoadWriterManager()->writeResource(file, res_db.get());
01221   if (!ok)
01222     Log::error( Say("vl::saveImage('%s') failed.\n") << file->path() );
01223   return ok;
01224 }
01225 //-----------------------------------------------------------------------------
01226 ref<Image> vl::loadCubemap(const String& xp_file, const String& xn_file, const String& yp_file, const String& yn_file, const String& zp_file, const String& zn_file)
01227 {
01228   ref<Image> xp = loadImage(xp_file);
01229   ref<Image> xn = loadImage(xn_file);
01230   ref<Image> yp = loadImage(yp_file);
01231   ref<Image> yn = loadImage(yn_file);
01232   ref<Image> zp = loadImage(zp_file);
01233   ref<Image> zn = loadImage(zn_file);
01234 
01235   if (!xp || !xn || !yp || !yn || !zp || !zn)
01236   {
01237     Log::error("vl::loadCubemap() failed.\n");
01238     return NULL;
01239   }
01240 
01241   ref<Image> img = vl::createCubemap(xp.get(), xn.get(), yp.get(), yn.get(), zp.get(), zn.get());  
01242 
01243   return img;
01244 }
01245 //-----------------------------------------------------------------------------
01246 ref<Image> vl::loadRAW(VirtualFile* file, long long file_offset, int width, int height, int depth, int bytealign, EImageFormat format, EImageType type)
01247 {
01248   ref<Image> img = new Image(width, height, depth, bytealign, format, type);
01249   if ( file->isOpen() || file->open(OM_ReadOnly) )
01250   {
01251     bool ok = file_offset == -1 || file->seekSet(file_offset);
01252     if (!ok)
01253     {
01254       Log::error( Say("loadRAW('%s'): seek set to position %n failed.\n") << file_offset );
01255       return NULL;
01256     }
01257     int count = (int)file->read( img->pixels(), img->requiredMemory() );
01258     if (count != img->requiredMemory())
01259       Log::error( Say("loadRAW('%s'): error reading RAW file.\n") << file->path() );
01260     return img;
01261   }
01262   else
01263   {
01264     Log::error( Say("loadRAW('%s'): could not open file for reading.\n") << file->path() );
01265     return NULL;
01266   }
01267 }
01268 //-----------------------------------------------------------------------------
01269 ref<Image> vl::Image::convertType(EImageType new_type) const
01270 {
01271   switch(type())
01272   {
01273     case IT_UNSIGNED_BYTE:
01274     case IT_BYTE:         
01275     case IT_UNSIGNED_SHORT:
01276     case IT_SHORT:         
01277     case IT_UNSIGNED_INT:  
01278     case IT_INT:           
01279     case IT_FLOAT:
01280       break;
01281     default:
01282       Log::error("Image::convertType(): unsupported source image type.\n");
01283       return NULL;
01284   }
01285 
01286   switch(new_type)
01287   {
01288     case IT_UNSIGNED_BYTE:
01289     case IT_BYTE:         
01290     case IT_UNSIGNED_SHORT:
01291     case IT_SHORT:         
01292     case IT_UNSIGNED_INT:  
01293     case IT_INT:           
01294     case IT_FLOAT:
01295       break;
01296     default:
01297       Log::error("Image::convertType(): unsupported destination image type.\n");
01298       return NULL;
01299   }
01300 
01301   switch(format())
01302   {
01303     case IF_RGB:
01304     case IF_RGBA:
01305     case IF_BGR:
01306     case IF_BGRA:
01307     case IF_RED:
01308     case IF_GREEN:
01309     case IF_BLUE:
01310     case IF_ALPHA:
01311     case IF_LUMINANCE:
01312     case IF_LUMINANCE_ALPHA:
01313     case IF_DEPTH_COMPONENT:
01314       break;
01315     default:
01316       Log::error("Image::convertType(): unsupported image format.\n");
01317       return NULL;
01318   }
01319 
01320   ref<Image> img = new Image;
01321   img->setObjectName( objectName().c_str() );
01322   img->setFormat(format());
01323   img->setType(new_type);
01324   img->setWidth(width());
01325   img->setHeight(height());
01326   img->setDepth(depth());
01327   img->setByteAlignment(1);
01328   img->mIsCubemap = isCubemap();
01329   img->mIsNormalMap = mIsNormalMap;
01330   img->mHasAlpha    = mHasAlpha;
01331   img->allocate();
01332 
01333   int components = 0;
01334   switch(format())
01335   {
01336     case IF_RGB:   components = 3; break;
01337     case IF_RGBA:  components = 4; break;
01338     case IF_BGR:   components = 3; break;
01339     case IF_BGRA:  components = 4; break;
01340     case IF_RED:   components = 1; break;
01341     case IF_GREEN: components = 1; break;
01342     case IF_BLUE:  components = 1; break;
01343     case IF_ALPHA: components = 1; break;
01344     case IF_LUMINANCE:       components = 1; break;
01345     case IF_LUMINANCE_ALPHA: components = 2; break;
01346     case IF_DEPTH_COMPONENT: components = 1; break;
01347     default:
01348       break;
01349   }
01350 
01351   int line_count = img->height()?img->height():1;
01352   if (img->depth())
01353     line_count *= img->depth();
01354   else
01355   if (img->isCubemap())
01356     line_count *= 6;
01357 
01358   for(int i=0; i<line_count; ++i)
01359   {
01360     const void* srcLine = pixels()      + pitch()*i;
01361     void* dstLine = img->pixels() + img->pitch()*i;
01362 
01363     const unsigned char* srcUByte  = (const unsigned char*)srcLine;
01364     const GLbyte*        srcSByte  = (const GLbyte*)srcLine;
01365     const GLushort*      srcUShort = (const GLushort*)srcLine;
01366     const GLshort*       srcSShort = (const GLshort*)srcLine;
01367     const unsigned int*  srcUInt   = (const unsigned int*)srcLine;
01368     const int*           srcSInt   = (const int*)srcLine;
01369     const float*         srcFloat  = (const float*)srcLine;
01370 
01371     unsigned char* dstUByte  = (unsigned char*)dstLine;
01372     GLbyte*        dstSByte  = (GLbyte*)dstLine;
01373     GLushort*      dstUShort = (GLushort*)dstLine;
01374     GLshort*       dstSShort = (GLshort*)dstLine;
01375     unsigned int*  dstUInt   = (unsigned int*)dstLine;
01376     int*           dstSInt   = (int*)dstLine;
01377     float*         dstFloat  = (float*)dstLine;
01378 
01379     for(int j=0; j<img->width(); ++j)
01380     {
01381       for(int c=0; c<components; ++c)
01382       {
01383         double dval = 0;
01384         long long qint = 0;
01385 
01386         // convert dst format to double
01387 
01388         switch(type())
01389         {
01390           case IT_UNSIGNED_BYTE:  qint = *srcUByte;  dval = qint/255.0; ++srcUByte; break;
01391           case IT_BYTE:           qint = *srcSByte;  dval = qint/127.0; ++srcSByte; break;
01392           case IT_UNSIGNED_SHORT: qint = *srcUShort; dval = qint/65535.0; ++srcUShort; break;
01393           case IT_SHORT:          qint = *srcSShort; dval = qint/32767.0; ++srcSShort; break;
01394           case IT_UNSIGNED_INT:   qint = *srcUInt;   dval = qint/4294967295.0; ++srcUInt; break;
01395           case IT_INT:            qint = *srcSInt;   dval = qint/2147483647.0; ++srcSInt; break;
01396           case IT_FLOAT:          dval = *srcFloat;  ++srcFloat; break;
01397           default:
01398             return NULL;
01399         }
01400 
01401         // clamp 0.0 >= dval >= 1.0
01402         dval = dval < 0.0 ? 0.0 :
01403                dval > 1.0 ? 1.0 :
01404                dval;
01405 
01406         // convert double to dst format
01407 
01408         switch(img->type())
01409         {
01410           case IT_UNSIGNED_BYTE:  *dstUByte  = (unsigned char) (dval*255.0); ++dstUByte; break;
01411           case IT_BYTE:           *dstSByte  = (GLbyte)  (dval*127.0); ++dstSByte; break;
01412           case IT_UNSIGNED_SHORT: *dstUShort = (GLushort)(dval*65535.0); ++dstUShort; break;
01413           case IT_SHORT:          *dstSShort = (GLshort) (dval*32767.0); ++dstSShort; break;
01414           case IT_UNSIGNED_INT:   *dstUInt   = (unsigned int)  (dval*4294967295.0); ++dstUInt; break;
01415           case IT_INT:            *dstSInt   = (int)   (dval*2147483647.0); ++dstSInt; break;
01416           case IT_FLOAT:          *dstFloat  = (float)dval; ++dstFloat; break;
01417           default:
01418             return NULL;
01419         }
01420       }
01421     }
01422   }
01423 
01424   return img;
01425 }
01426 //-----------------------------------------------------------------------------
01427 namespace {
01428   template<typename T>
01429   void equalizeTemplate(void* ptr, int pitch, int comps, int w, int h, T max_val)
01430   {
01431     // find min/max
01432     T vmin = *((T*)ptr);
01433     T vmax = *((T*)ptr);
01434     for(int y=0; y<h; ++y)
01435     {
01436       T* px = (T*)((char*)ptr + pitch*y);
01437       for(int x=0; x<w; ++x)
01438       {
01439         for(int i=0; i<comps; ++i)
01440         {
01441           if (vmin > px[x*comps+i]) vmin = px[x*comps+i];
01442           if (vmax < px[x*comps+i]) vmax = px[x*comps+i];
01443         }
01444       }
01445     }
01446     // equalize
01447     T range = vmax-vmin;
01448     for(int y=0; y<h; ++y)
01449     {
01450       T* px = (T*)((char*)ptr + pitch*y);
01451       for(int x=0; x<w; ++x)
01452       {
01453         for(int i=0; i<comps; ++i)
01454           px[x*comps+i] = (T)(((float)px[x*comps+i]-vmin)/range*max_val);
01455       }
01456     }
01457   }
01458 }
01461 bool Image::equalize()
01462 {
01463   int comps = 0;
01464   switch(format())
01465   {
01466     case IF_RGB:   comps = 3; break;
01467     case IF_RGBA:  comps = 4; break;
01468     case IF_BGR:   comps = 3; break;
01469     case IF_BGRA:  comps = 4; break;
01470     case IF_RED:   comps = 1; break;
01471     case IF_GREEN: comps = 1; break;
01472     case IF_BLUE:  comps = 1; break;
01473     case IF_ALPHA: comps = 1; break;
01474     case IF_LUMINANCE: comps = 1; break;
01475     case IF_LUMINANCE_ALPHA: comps = 2; break;
01476     case IF_DEPTH_COMPONENT: comps = 1; break;
01477     default:
01478       Log::error("Image::equalize(): unsupported image format().\n");
01479       return false;
01480   }
01481   int w = width();
01482   int h = height()?height():1;
01483   int d = depth()?depth():1;
01484   if (isCubemap())
01485     h=h*6;
01486   else
01487     h=h*d;
01488 
01489   switch(type())
01490   {
01491     case IT_UNSIGNED_BYTE:  equalizeTemplate<unsigned char> (pixels(), pitch(), comps, w, h, 0xFF);      break;
01492     case IT_UNSIGNED_SHORT: equalizeTemplate<unsigned short>(pixels(), pitch(), comps, w, h, 0xFFFF);     break;
01493     case IT_UNSIGNED_INT:   equalizeTemplate<unsigned int>  (pixels(), pitch(), comps, w, h, 0xFFFFFFFF); break;
01494     case IT_FLOAT:          equalizeTemplate<float>         (pixels(), pitch(), comps, w, h, 1.0f);       break;
01495       break;
01496     default:
01497       Log::error("Image::equalize(): unsupported image type(). Types supported are IT_UNSIGNED_BYTE, IT_UNSIGNED_SHORT, IT_UNSIGNED_INT, IT_FLOAT.\n");
01498       return false;
01499   }
01500   return true;
01501 }
01502 //-----------------------------------------------------------------------------
01523 bool Image::contrastHounsfieldAuto()
01524 {
01525   if ( !tags()->has("WindowCenter") || !tags()->has("WindowWidth") || !tags()->has("BitsStored") || !tags()->has("RescaleIntercept"))
01526     return false;
01527 
01528   float center    = tags()->value("WindowCenter").toFloat();
01529   float width     = tags()->value("WindowWidth").toFloat();
01530   float range     = (1<<tags()->value("BitsStored").toInt()) - 1.0f;
01531   float intercept = tags()->value("RescaleIntercept").toFloat();
01532   float slope     = tags()->value("RescaleSlope").toFloat();
01533 
01534   // Hounsfield units: -1000 = air, +1000 = solid bone
01535   // Transform from Hounsfield units to normalized 0..1 units
01536   center = (center-intercept) / range / slope;
01537   width  = width / range / slope;
01538   return contrast( center-width/2.0f, center+width/2.0f );
01539 }
01540 //-----------------------------------------------------------------------------
01551 bool Image::contrastHounsfield(float center, float width, float intercept, float range)
01552 {
01553   // Hounsfield units: -1000 = air, +1000 = solid bone
01554   // Transform from Hounsfield units to normalized 0..1 units
01555   center = (center-intercept) / range;
01556   width  = width / range;
01557   return contrast( center-width/2.0f, center+width/2.0f );
01558 }
01559 //-----------------------------------------------------------------------------
01560 namespace {
01561   template<typename T>
01562   void contrastTemplate(void* ptr, int pitch, int w, int h, T max_val, float black, float white)
01563   {
01564     float range = white-black;
01565     for(int y=0; y<h; ++y)
01566     {
01567       T* px = (T*)((char*)ptr + pitch*y);
01568       for(int x=0; x<w; ++x)
01569       {
01570         float t = (float)px[x]/max_val; // 0..1
01571         t = (t-black)/range;
01572         t = vl::clamp(t, 0.0f, 1.0f);
01573         px[x] = (T)(t*max_val);
01574       }
01575     }
01576   }
01577 }
01580 bool Image::contrast(float black, float white)
01581 {
01582   switch(format())
01583   {
01584     case IF_RED:
01585     case IF_GREEN:
01586     case IF_BLUE:
01587     case IF_ALPHA:
01588     case IF_LUMINANCE:
01589     case IF_DEPTH_COMPONENT:
01590       break;
01591     default:
01592       Log::error("Image::equalize(): unsupported image format().\n");
01593       return false;
01594   }
01595   int w = width();
01596   int h = height()?height():1;
01597   int d = depth()?depth():1;
01598   if (isCubemap())
01599     h=h*6;
01600   else
01601     h=h*d;
01602 
01603   switch(type())
01604   {
01605     case IT_UNSIGNED_BYTE:  contrastTemplate<unsigned char> (pixels(), pitch(), w, h, 0xFF, black, white);       break;
01606     case IT_UNSIGNED_SHORT: contrastTemplate<unsigned short>(pixels(), pitch(), w, h, 0xFFFF, black, white);     break;
01607     case IT_UNSIGNED_INT:   contrastTemplate<unsigned int>  (pixels(), pitch(), w, h, 0xFFFFFFFF, black, white); break;
01608     case IT_FLOAT:          contrastTemplate<float>         (pixels(), pitch(), w, h, 1.0f, black, white);       break;
01609       break;
01610     default:
01611       Log::error("Image::equalize(): unsupported image type(). Types supported are IT_UNSIGNED_BYTE, IT_UNSIGNED_SHORT, IT_UNSIGNED_INT, IT_FLOAT.\n");
01612       return false;
01613   }
01614   return true;
01615 }
01616 //-----------------------------------------------------------------------------
01617 namespace
01618 {
01619   class rgbal
01620   {
01621   public:
01622     rgbal(): r(-1), g(-1), b(-1), a(-1), l(-1) {}
01623     int r,g,b,a,l;
01624   };
01625 
01626   template<typename T>
01627   void convert(const T*src_px, T*dst_px, T max_value, const rgbal& srco, const rgbal& dsto)
01628   {
01629     // set dst default values first
01630     if (dsto.r != -1)
01631       dst_px[dsto.r] = 0;
01632     if (dsto.g != -1)
01633       dst_px[dsto.g] = 0;
01634     if (dsto.b != -1)
01635       dst_px[dsto.b] = 0;
01636     if (dsto.a != -1)
01637       dst_px[dsto.a] = max_value;
01638     if (dsto.l != -1)
01639       dst_px[dsto.l] = 0;
01640 
01641     // try copy src -> dst
01642     if (dsto.r != -1 && srco.r != -1 )
01643       dst_px[dsto.r] = src_px[srco.r];
01644     if (dsto.g != -1 && srco.g != -1)
01645       dst_px[dsto.g] = src_px[srco.g];
01646     if (dsto.b != -1 && srco.b != -1)
01647       dst_px[dsto.b] = src_px[srco.b];
01648     if (dsto.a != -1 && srco.a != -1)
01649       dst_px[dsto.a] = src_px[srco.a];
01650     if (dsto.l != -1 && srco.l != -1)
01651       dst_px[dsto.l] = src_px[srco.l];
01652 
01653     // try rgb -> gray conversion
01654     if (dsto.l != -1 && srco.r != -1 && srco.g != -1 && srco.b != -1)
01655     {
01656       dvec3 col(src_px[srco.r], src_px[srco.g], src_px[srco.b]);
01657       double gray = dot(col / dvec3(max_value,max_value,max_value), dvec3(0.299,0.587,0.114));
01658       dst_px[dsto.l] = T(gray * max_value);
01659     }
01660     else
01661     // try r -> gray conversion
01662     if (dsto.l != -1 && srco.r != -1 && srco.g == -1 && srco.b == -1)
01663       dst_px[dsto.l] = src_px[srco.r];
01664     else
01665     // try g -> gray conversion
01666     if (dsto.l != -1 && srco.r == -1 && srco.g != -1 && srco.b == -1)
01667       dst_px[dsto.l] = src_px[srco.g];
01668     else
01669     // try b -> gray conversion
01670     if (dsto.l != -1 && srco.r == -1 && srco.g == -1 && srco.b != -1)
01671       dst_px[dsto.l] = src_px[srco.b];
01672     else
01673     // try gray -> r,g,b
01674     if (srco.l != -1)
01675     {
01676       if (dsto.r != -1)
01677         dst_px[dsto.r] = src_px[srco.l];
01678       if (dsto.g != -1)
01679         dst_px[dsto.g] = src_px[srco.l];
01680       if (dsto.b != -1)
01681         dst_px[dsto.b] = src_px[srco.l];
01682     }
01683   }
01684 }
01685 ref<Image> vl::Image::convertFormat(EImageFormat new_format) const
01686 {
01687   switch(type())
01688   {
01689     case IT_UNSIGNED_BYTE:
01690     case IT_BYTE:         
01691     case IT_UNSIGNED_SHORT:
01692     case IT_SHORT:         
01693     case IT_UNSIGNED_INT:  
01694     case IT_INT:           
01695     case IT_FLOAT:
01696       break;
01697     default:
01698       Log::error("Image::convertType(): unsupported image type.\n");
01699       return NULL;
01700   }
01701 
01702   switch(format())
01703   {
01704     case IF_RGB:
01705     case IF_RGBA:
01706     case IF_BGR:
01707     case IF_BGRA:
01708     case IF_RED:
01709     case IF_GREEN:
01710     case IF_BLUE:
01711     case IF_ALPHA:
01712     case IF_LUMINANCE:
01713     case IF_LUMINANCE_ALPHA:
01714       break;
01715     default:
01716       Log::error("Image::convertType(): unsupported source image format.\n");
01717       return NULL;
01718   }
01719 
01720   switch(new_format)
01721   {
01722     case IF_RGB:
01723     case IF_RGBA:
01724     case IF_BGR:
01725     case IF_BGRA:
01726     case IF_RED:
01727     case IF_GREEN:
01728     case IF_BLUE:
01729     case IF_ALPHA:
01730     case IF_LUMINANCE:
01731     case IF_LUMINANCE_ALPHA:
01732       break;
01733     default:
01734       Log::error("Image::convertType(): unsupported destination image format.\n");
01735       return NULL;
01736   }
01737 
01738   ref<Image> img = new Image;
01739   img->setObjectName( objectName().c_str() );
01740   img->setFormat(new_format);
01741   img->setType(type());
01742   img->setWidth(width());
01743   img->setHeight(height());
01744   img->setDepth(depth());
01745   img->setByteAlignment(1);
01746   img->mIsCubemap = isCubemap();
01747   img->mIsNormalMap = mIsNormalMap;
01748   img->mHasAlpha    = mHasAlpha;
01749   img->allocate();
01750 
01751   rgbal srco; // = {-1,-1,-1,-1,-1}, 
01752   rgbal dsto; // = {-1,-1,-1,-1,-1};
01753 
01754   // compute src and dst color component offsets
01755 
01756   switch(format())
01757   {
01758     case IF_RGB:             srco.r = 0; srco.g = 1; srco.b = 2; break;
01759     case IF_RGBA:            srco.r = 0; srco.g = 1; srco.b = 2; srco.a = 3; break;
01760     case IF_BGR:             srco.r = 2; srco.g = 1; srco.b = 0; break;
01761     case IF_BGRA:            srco.r = 2; srco.g = 1; srco.b = 0; srco.a = 3; break;
01762     case IF_RED:             srco.r = 0; break;
01763     case IF_GREEN:           srco.g = 0; break;
01764     case IF_BLUE:            srco.b = 0; break;
01765     case IF_ALPHA:           srco.a = 0; break;
01766     case IF_LUMINANCE:       srco.l = 0; break;
01767     case IF_LUMINANCE_ALPHA: srco.l = 0; srco.a = 1; break;
01768     default:
01769       return NULL;
01770   }
01771 
01772   switch(new_format)
01773   {
01774     case IF_RGB:             dsto.r = 0; dsto.g = 1; dsto.b = 2; break;
01775     case IF_RGBA:            dsto.r = 0; dsto.g = 1; dsto.b = 2; dsto.a = 3; break;
01776     case IF_BGR:             dsto.r = 2; dsto.g = 1; dsto.b = 0; break;
01777     case IF_BGRA:            dsto.r = 2; dsto.g = 1; dsto.b = 0; dsto.a = 3; break;
01778     case IF_RED:             dsto.r = 0; break;
01779     case IF_GREEN:           dsto.g = 0; break;
01780     case IF_BLUE:            dsto.b = 0; break;
01781     case IF_ALPHA:           dsto.a = 0; break;
01782     case IF_LUMINANCE:       dsto.l = 0; break;
01783     case IF_LUMINANCE_ALPHA: dsto.l = 0; dsto.a = 1; break;
01784     default:
01785       return NULL;
01786   }
01787 
01788   int src_comp = 0;
01789   switch(format())
01790   {
01791     case IF_RGB:   src_comp = 3; break;
01792     case IF_RGBA:  src_comp = 4; break;
01793     case IF_BGR:   src_comp = 3; break;
01794     case IF_BGRA:  src_comp = 4; break;
01795     case IF_RED:   src_comp = 1; break;
01796     case IF_GREEN: src_comp = 1; break;
01797     case IF_BLUE:  src_comp = 1; break;
01798     case IF_ALPHA: src_comp = 1; break;
01799     case IF_LUMINANCE:       src_comp = 1; break;
01800     case IF_LUMINANCE_ALPHA: src_comp = 2; break;
01801     default:
01802       break;
01803   }
01804 
01805   int dst_comp = 0;
01806   switch(new_format)
01807   {
01808     case IF_RGB:   dst_comp = 3; break;
01809     case IF_RGBA:  dst_comp = 4; break;
01810     case IF_BGR:   dst_comp = 3; break;
01811     case IF_BGRA:  dst_comp = 4; break;
01812     case IF_RED:   dst_comp = 1; break;
01813     case IF_GREEN: dst_comp = 1; break;
01814     case IF_BLUE:  dst_comp = 1; break;
01815     case IF_ALPHA: dst_comp = 1; break;
01816     case IF_LUMINANCE:       dst_comp = 1; break;
01817     case IF_LUMINANCE_ALPHA: dst_comp = 2; break;
01818     case IF_DEPTH_COMPONENT: dst_comp = 1; break;
01819     default:
01820       break;
01821   }
01822 
01823   int line_count = img->height()?img->height():1;
01824   if (img->depth())
01825     line_count *= img->depth();
01826   else
01827   if (img->isCubemap())
01828     line_count *= 6;
01829 
01830   for(int i=0; i<line_count; ++i)
01831   {
01832     const void* srcLine = pixels()      + pitch()*i;
01833     void* dstLine = img->pixels() + img->pitch()*i;
01834 
01835     const unsigned char* srcUByte  = (const unsigned char*)srcLine;
01836     const GLbyte*        srcSByte  = (const GLbyte*)srcLine;
01837     const GLushort*      srcUShort = (const GLushort*)srcLine;
01838     const GLshort*       srcSShort = (const GLshort*)srcLine;
01839     const unsigned int*  srcUInt   = (const unsigned int*)srcLine;
01840     const int*           srcSInt   = (const int*)srcLine;
01841     const float*         srcFloat  = (const float*)srcLine;
01842 
01843     unsigned char* dstUByte  = (unsigned char*)dstLine;
01844     GLbyte*        dstSByte  = (GLbyte*)dstLine;
01845     GLushort*      dstUShort = (GLushort*)dstLine;
01846     GLshort*       dstSShort = (GLshort*)dstLine;
01847     unsigned int*  dstUInt   = (unsigned int*)dstLine;
01848     int*           dstSInt   = (int*)dstLine;
01849     float*         dstFloat  = (float*)dstLine;
01850 
01851     for(int j=0; j<img->width(); ++j)
01852     {
01853       switch(type())
01854       {
01855         case IT_UNSIGNED_BYTE:  convert<unsigned char> (srcUByte,  dstUByte,  255,         srco, dsto); srcUByte+=src_comp;  dstUByte+=dst_comp;  break;
01856         case IT_BYTE:           convert<GLbyte>        (srcSByte,  dstSByte,  127,         srco, dsto); srcSByte+=src_comp;  dstSByte+=dst_comp;  break;
01857         case IT_UNSIGNED_SHORT: convert<GLushort>      (srcUShort, dstUShort, 65535,       srco, dsto); srcUShort+=src_comp; dstUShort+=dst_comp; break;
01858         case IT_SHORT:          convert<GLshort>       (srcSShort, dstSShort, 32767,       srco, dsto); srcSShort+=src_comp; dstSShort+=dst_comp; break;
01859         case IT_UNSIGNED_INT:   convert<unsigned int>  (srcUInt,   dstUInt,   4294967295U, srco, dsto); srcUInt+=src_comp;   dstUInt+=dst_comp;   break;
01860         case IT_INT:            convert<int>           (srcSInt,   dstSInt,   2147483647,  srco, dsto); srcSInt+=src_comp;   dstSInt+=dst_comp;   break;
01861         case IT_FLOAT:          convert<float>         (srcFloat,  dstFloat,  1.0f,        srco, dsto); srcFloat+=src_comp;  dstFloat+=dst_comp;  break;
01862         default:
01863           return NULL;
01864       }
01865     }
01866   }
01867 
01868   return img;
01869 }
01870 //-----------------------------------------------------------------------------
01871 fvec4 Image::sampleLinear(double x) const
01872 {
01873   if (x < 0)
01874     x = 0;
01875   if (x >= width()-1)
01876     x = (width()-1) - 0.000001;
01877 
01878   int ix1 = (int)x;
01879   int ix2 = ix1+1;
01880 
01881   VL_CHECK(ix2<(int)width())
01882 
01883   float w21 = (float)vl::fract(x);
01884   float w11 = 1.0f - w21;
01885 
01886   fvec4 c11 = sample(ix1);
01887   fvec4 c21 = sample(ix2);
01888 
01889   return c11*w11 + c21*w21;
01890 }
01891 //-----------------------------------------------------------------------------
01892 fvec4 Image::sampleLinear(double x, double y) const
01893 {
01894   int h = height()?height():1;
01895   if (x < 0)
01896     x = 0;
01897   if (y < 0)
01898     y = 0;
01899   if (x >= width()-1)
01900     x = (width()-1)  - 0.000001;
01901   if (y >= h-1)
01902     y = (h-1) - 0.000001;
01903 
01904   int ix1 = (int)x;
01905   int iy1 = (int)y;
01906   int ix2 = ix1+1;
01907   int iy2 = iy1+1;
01908 
01909   VL_CHECK(ix2<(int)width())
01910   VL_CHECK(iy2<(int)height())
01911 
01912   double tx  = vl::fract(x);
01913   double ty  = vl::fract(y);
01914   double tx1 = 1.0f - vl::fract(x);
01915   double ty1 = 1.0f - vl::fract(y);
01916 
01917   float w11 = float(tx1*ty1);
01918   float w12 = float(tx1*ty);
01919   float w22 = float(tx *ty);
01920   float w21 = float(tx *ty1);
01921 
01922   fvec4 c11 = sample(ix1, iy1);
01923   fvec4 c12 = sample(ix1, iy2);
01924   fvec4 c22 = sample(ix2, iy2);
01925   fvec4 c21 = sample(ix2, iy1);
01926 
01927   return c11*w11 + c12*w12 + c22*w22 + c21*w21;
01928 }
01929 //-----------------------------------------------------------------------------
01930 fvec4 Image::sampleLinear(double x, double y, double z) const
01931 {
01932   if (x>width() -1.000001) x = width() -1.000001;
01933   if (y>height()-1.000001) y = height()-1.000001;
01934   if (z>depth() -1.000001) z = depth() -1.000001;
01935   if (x<0) x=0;
01936   if (y<0) y=0;
01937   if (z<0) z=0;
01938   int ix = int(x); 
01939   float xt = float(x - ix);
01940   int iy = int(y); 
01941   float yt = float(y - iy);
01942   int iz = int(z); 
01943   float zt = float(z - iz);
01944   fvec4 val0 = sample(ix  , iy,   iz);
01945   fvec4 val1 = sample(ix+1, iy,   iz);
01946   fvec4 val2 = sample(ix+1, iy+1, iz);
01947   fvec4 val3 = sample(ix,   iy+1, iz);
01948   fvec4 val4 = sample(ix  , iy,   iz+1);
01949   fvec4 val5 = sample(ix+1, iy,   iz+1);
01950   fvec4 val6 = sample(ix+1, iy+1, iz+1);
01951   fvec4 val7 = sample(ix,   iy+1, iz+1);
01952   float xt1 = 1-xt;
01953   float yt1 = 1-yt;
01954   float zt1 = 1-zt;
01955   fvec4 v1 = val0*(yt1) + val3*yt;
01956   fvec4 v2 = val1*(yt1) + val2*yt;
01957   fvec4 a = v1*(xt1) + v2*xt;
01958   v1 = val4*(yt1) + val7*yt;
01959   v2 = val5*(yt1) + val6*yt;
01960   fvec4 b = v1*(xt1) + v2*xt;
01961   return a*(zt1) + b*zt;
01962 }
01963 //-----------------------------------------------------------------------------
01964 fvec4 Image::sample(int x, int y, int z) const
01965 {
01966   VL_CHECK(x<width())
01967   VL_CHECK(!y || y<height())
01968   VL_CHECK(!z || z<depth())
01969 
01970   // find the start of the line
01971   int h = height()?height():1;
01972   const unsigned char* px = pixels() + y*pitch() + h*pitch()*z;
01973 
01974   int comp = 0;
01975   switch(format())
01976   {
01977     case IF_RGB:   comp = 3; break;
01978     case IF_RGBA:  comp = 4; break;
01979     case IF_BGR:   comp = 3; break;
01980     case IF_BGRA:  comp = 4; break;
01981     case IF_RED:   comp = 1; break;
01982     case IF_GREEN: comp = 1; break;
01983     case IF_BLUE:  comp = 1; break;
01984     case IF_ALPHA: comp = 1; break;
01985     case IF_LUMINANCE:       comp = 1; break;
01986     case IF_LUMINANCE_ALPHA: comp = 2; break;
01987     case IF_DEPTH_COMPONENT: comp = 1; break;
01988     default:
01989       break;
01990   }
01991 
01992   switch(type())
01993   {
01994     case IT_UNSIGNED_BYTE:  px += x*comp*1; break;
01995     case IT_BYTE:           px += x*comp*1; break;
01996     case IT_UNSIGNED_SHORT: px += x*comp*2; break;
01997     case IT_SHORT:          px += x*comp*2; break;
01998     case IT_UNSIGNED_INT:   px += x*comp*4; break;
01999     case IT_INT:            px += x*comp*4; break;
02000     case IT_FLOAT:          px += x*comp*4; break;
02001     default:
02002       break;
02003   }
02004 
02005   // convert component by component
02006 
02007   fvec4 pixel(0,0,0,0);
02008 
02009   for(int i=0; i<comp; ++i)
02010   {
02011     double value = 0;
02012 
02013     switch(type())
02014     {
02015       case IT_UNSIGNED_BYTE:  value = (double)((unsigned char*)px)[i]; value/=255.0; break;
02016       case IT_BYTE:           value = (double)((char*)px)[i]; value/=127.0; break;
02017       case IT_UNSIGNED_SHORT: value = (double)((unsigned short*)px)[i]; value/=65535.0; break;
02018       case IT_SHORT:          value = (double)((short*)px)[i]; value/=32767.0; break;
02019       case IT_UNSIGNED_INT:   value = (double)((unsigned int*)px)[i]; value/=4294967295.0; break;
02020       case IT_INT:            value = (double)((int*)px)[i]; value/=2147483647.0; break;
02021       case IT_FLOAT:          value = (double)((float*)px)[i]; break;
02022       default:
02023         break;
02024     }
02025 
02026     pixel[i] = (float)value;
02027   }
02028 
02029   fvec4 p(0,0,0,0);
02030 
02031   // arrange values based on the format
02032   switch(format())
02033   {
02034     case IF_RGB:   p = pixel; break;
02035     case IF_RGBA:  p = pixel; break;
02036     case IF_BGR:   p = pixel; p.r() = pixel.b(); p.b() = pixel.r(); break;
02037     case IF_BGRA:  p = pixel; p.r() = pixel.b(); p.b() = pixel.r(); break;
02038     case IF_RED:   p = fvec4(pixel[0], 0, 0, 0); break;
02039     case IF_GREEN: p = fvec4(0, pixel[0], 0, 0); break;
02040     case IF_BLUE:  p = fvec4(0, 0, pixel[0], 0); break;
02041     case IF_ALPHA: p = fvec4(0, 0, 0, pixel[0]); break;
02042     case IF_LUMINANCE:       p = fvec4(pixel[0], pixel[0], pixel[0], 0); break;
02043     case IF_LUMINANCE_ALPHA: p = fvec4(pixel[0], pixel[0], pixel[0], pixel[1]); break;
02044     case IF_DEPTH_COMPONENT: p = fvec4(pixel[0], 0, 0, 0); break;
02045     default:
02046       break;
02047   }
02048 
02049   return p;
02050 }
02051 //-----------------------------------------------------------------------------
02052 ref<Image> Image::subImage(int xstart, int ystart, int width, int height)
02053 {
02054   VL_CHECK(xstart+width  <= this->width())
02055   VL_CHECK(ystart+height <= this->height())
02056 
02057   ref<Image> img = new Image;
02058   img->allocate2D(width, height, 1, format(), type());
02059   // copy line by line
02060   for(int i=0; i<height; ++i)
02061   {
02062     unsigned char* dst = img->pixels() + img->pitch()*i;
02063     unsigned char* src = pixels() + pitch()*(i+ystart) + xstart*bitsPerPixel()/8;
02064     memcpy(dst, src, width*bitsPerPixel()/8);
02065   }
02066   return img;
02067 }
02068 //-----------------------------------------------------------------------------
02069 void Image::copySubImage(Image* img_src, RectI src, ivec2 dst)
02070 {
02071   ref<Image> img = img_src;
02072   if (img->type() != this->type())
02073     img = img->convertType(this->type());
02074   if (img->format() != this->format())
02075     img = img->convertFormat(this->format());
02076   // tests
02077   VL_CHECK(dst.x()>=0)
02078   VL_CHECK(dst.y()>=0)
02079   VL_CHECK(dst.x() + src.width()  <= this->width() )
02080   VL_CHECK(dst.y() + src.height() <= this->height())
02081   VL_CHECK(src.x()>=0)
02082   VL_CHECK(src.y()>=0)
02083   VL_CHECK(src.right() < img->width() )
02084   VL_CHECK(src.top()   < img->height())
02085   for(int i=0; i<src.height(); ++i)
02086   {
02087     int ysrc = i+src.y();
02088     int ydst = i+dst.y();
02089     unsigned char* psrc = img->pixels() + img->pitch()*ysrc + (src.x()*img->bitsPerPixel()/8);
02090     unsigned char* pdst = this->pixels() + this->pitch()*ydst + (dst.x()*this->bitsPerPixel()/8);
02091     memcpy(pdst, psrc, src.width()*this->bitsPerPixel()/8);
02092   }
02093 }
02094 //-----------------------------------------------------------------------------
02095 void Image::substituteColorRGB_RGBA(unsigned int before, unsigned int after)
02096 {
02097   if (type() != IT_UNSIGNED_BYTE)
02098   {
02099     Log::error("Image::substituteColorRGB_RGBA(): this function can be called only on images whose type() is IT_UNSIGNED_BYTE\n");
02100     return;
02101   }
02102   if (format() != IF_RGBA && format() != IF_RGB)
02103   {
02104     Log::error("Image::substituteColorRGB_RGBA(): this function can be called only on images whose format() is either IF_RGBA or IF_RGB\n");
02105     return;
02106   }
02107   unsigned char bef[3];
02108   unsigned char aft[4];
02109   bef[0] = (unsigned char)((before >> 16) & 0xFF);
02110   bef[1] = (unsigned char)((before >>  8) & 0xFF);
02111   bef[2] = (unsigned char)((before >>  0) & 0xFF);
02112 
02113   aft[0] = (unsigned char)((after  >> 24) & 0xFF);
02114   aft[1] = (unsigned char)((after  >> 16) & 0xFF);
02115   aft[2] = (unsigned char)((after  >>  8) & 0xFF);
02116   aft[3] = (unsigned char)((after  >>  0) & 0xFF);
02117 
02118   int comps = format() == IF_RGBA ? 4 : 3;
02119   int d = depth() ? depth() : 1;
02120   for(int y=0; y<height()*d; ++y)
02121   {
02122     for(int x=0; x<width(); ++x)
02123     {
02124       unsigned char* px = pixels() + pitch()*y + x*comps;
02125       if (px[0] == bef[0] && px[1] == bef[1] && px[2] == bef[2])
02126       {
02127         px[0] = aft[0];
02128         px[1] = aft[1];
02129         px[2] = aft[2];
02130         if (comps == 4)
02131           px[3] = aft[3];
02132       }
02133     }
02134   }
02135 }
02136 //-----------------------------------------------------------------------------
02137 void Image::substituteColorRGB_RGB(unsigned int before, unsigned int after)
02138 {
02139   if (type() != IT_UNSIGNED_BYTE)
02140   {
02141     Log::error("Image::substituteColorRGB_RGB(): this function can be called only on images whose type() is IT_UNSIGNED_BYTE\n");
02142     return;
02143   }
02144   if (format() != IF_RGBA && format() != IF_RGB)
02145   {
02146     Log::error("Image::substituteColorRGB_RGB(): this function can be called only on images whose format() is either IF_RGBA or IF_RGB\n");
02147     return;
02148   }
02149   unsigned char bef[3];
02150   unsigned char aft[3];
02151   bef[0] = (unsigned char)((before >> 16) & 0xFF);
02152   bef[1] = (unsigned char)((before >>  8) & 0xFF);
02153   bef[2] = (unsigned char)((before >>  0) & 0xFF);
02154 
02155   aft[0] = (unsigned char)((after  >> 24) & 0xFF);
02156   aft[1] = (unsigned char)((after  >> 16) & 0xFF);
02157   aft[2] = (unsigned char)((after  >>  8) & 0xFF);
02158 
02159   int comps = format() == IF_RGBA ? 4 : 3;
02160   int d = depth() ? depth() : 1;
02161   for(int y=0; y<height()*d; ++y)
02162   {
02163     for(int x=0; x<width(); ++x)
02164     {
02165       unsigned char* px = pixels() + pitch()*y + x*comps;
02166       if (px[0] == bef[0] && px[1] == bef[1] && px[2] == bef[2])
02167       {
02168         px[0] = aft[0];
02169         px[1] = aft[1];
02170         px[2] = aft[2];
02171       }
02172     }
02173   }
02174 }
02175 //-----------------------------------------------------------------------------
02176 void Image::substituteColorGreenKey(unsigned int col0, unsigned int col1)
02177 {
02178   if (type() != IT_UNSIGNED_BYTE)
02179   {
02180     Log::error("Image::substituteColorRGB_RGB(): this function can be called only on images whose type() is IT_UNSIGNED_BYTE\n");
02181     return;
02182   }
02183   if (format() != IF_RGBA && format() != IF_RGB)
02184   {
02185     Log::error("Image::substituteColorRGB_RGB(): this function can be called only on images whose format() is either IF_RGBA or IF_RGB\n");
02186     return;
02187   }
02188   unsigned char c0[3];
02189   unsigned char c1[3];
02190   c0[0] = (unsigned char)((col0 >> 16) & 0xFF);
02191   c0[1] = (unsigned char)((col0 >>  8) & 0xFF);
02192   c0[2] = (unsigned char)((col0 >>  0) & 0xFF);
02193 
02194   c1[0] = (unsigned char)((col1 >> 16) & 0xFF);
02195   c1[1] = (unsigned char)((col1 >>  8) & 0xFF);
02196   c1[2] = (unsigned char)((col1 >>  0) & 0xFF);
02197 
02198   int comps = format() == IF_RGBA ? 4 : 3;
02199   int d = depth() ? depth() : 1;
02200   for(int y=0; y<height()*d; ++y)
02201   {
02202     for(int x=0; x<width(); ++x)
02203     {
02204       unsigned char* px = pixels() + pitch()*y + x*comps;
02205       double t = (double)px[1] / 0xFF;
02206       px[0] = (unsigned char)(c0[0]*(1.0-t) + c1[0]*t);
02207       px[1] = (unsigned char)(c0[1]*(1.0-t) + c1[1]*t);
02208       px[2] = (unsigned char)(c0[2]*(1.0-t) + c1[2]*t);
02209     }
02210   }
02211 }
02212 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:29.
Permission is granted to use this page to write and publish articles regarding Visualization Library.