# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/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 v2011.09.1162 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu Jan 26 2012 00:43:28.
Permission is granted to use this page to write and publish articles regarding Visualization Library.