# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

bitmap.cpp

Go to the documentation of this file.
00001 
00009 /* Copyright, 2000 Nevrax Ltd.
00010  *
00011  * This file is part of NEVRAX NEL.
00012  * NEVRAX NEL is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2, or (at your option)
00015  * any later version.
00016 
00017  * NEVRAX NEL is distributed in the hope that it will be useful, but
00018  * WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00020  * General Public License for more details.
00021 
00022  * You should have received a copy of the GNU General Public License
00023  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00024  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00025  * MA 02111-1307, USA.
00026  */
00027 
00028 #include "stdmisc.h"
00029 
00030 #include <memory>
00031 #include <algorithm>
00032 
00033 /*extern "C"
00034 {
00035 #include <jpeglib.h>
00036 }
00037 */
00038 
00039 #include "nel/misc/bitmap.h"
00040 #include "nel/misc/stream.h"
00041 #include "nel/misc/file.h"
00042 
00043 
00044 using namespace std;
00045 
00046 namespace NLMISC
00047 {
00048 
00049 
00050 struct EDDSBadHeader : public NLMISC::EStream
00051 {
00052         EDDSBadHeader() : EStream( "Bad or unrecognized DDS file header" ) {}
00053 };
00054 
00055 struct ESeekFailed : public NLMISC::EStream
00056 {
00057         ESeekFailed() : EStream( "Seek failed" ) {}
00058 };
00059 
00060 struct EAllocationFailure : public Exception
00061 {
00062         EAllocationFailure() : Exception( "Can't allocate memory" ) {}
00063 };
00064 
00065 void blendFromui(NLMISC::CRGBA &c0, NLMISC::CRGBA &c1, uint coef);
00066 uint32 blend(uint32 &n0, uint32 &n1, uint32 coef0);
00067 
00068 const uint32 CBitmap::bitPerPixels[ModeCount]=
00069 {
00070         32,             // RGBA
00071         8,              // Luminance
00072         8,              // Alpha
00073         16,             // AlphaLuminance
00074         4,              // DXTC1
00075         4,              // DXTC1Alpha
00076         8,              // DXTC3
00077         8,              // DXTC5
00078         16              // DsDt
00079 };
00080 
00081 const uint32 CBitmap::DXTC1HEADER = NL_MAKEFOURCC('D','X', 'T', '1');
00082 const uint32 CBitmap::DXTC3HEADER = NL_MAKEFOURCC('D','X', 'T', '3');
00083 const uint32 CBitmap::DXTC5HEADER = NL_MAKEFOURCC('D','X', 'T', '5');
00084 
00085 // static data for jpeg compression (used by writeJPG())
00086 NLMISC::IStream *JPGStream = NULL;
00087 const uint32 JPGBufferSize = 1000;
00088 char JPGBuffer[JPGBufferSize];
00089 
00090 
00091 /*-------------------------------------------------------------------*\
00092                                                                 load            
00093 \*-------------------------------------------------------------------*/
00094 uint8 CBitmap::load(NLMISC::IStream &f, uint mipMapSkip) 
00095 {
00096         nlassert(f.isReading()); 
00097         
00098         // testing if DDS
00099         uint32 fileType = 0;;
00100         f.serial(fileType);
00101         if(fileType == DDS)
00102         {
00103                 return readDDS(f, mipMapSkip);
00104         }
00105         // assuming it's TGA
00106         else 
00107         {
00108                 NLMISC::IStream::TSeekOrigin origin= f.begin;
00109                 if(!f.seek (0, origin))
00110                 {
00111                         throw ESeekFailed();
00112                 }
00113 
00114                 // Reading header, 
00115                 // To make sure that the bitmap is TGA, we check imageType and imageDepth.
00116                 uint8   lengthID;
00117                 uint8   cMapType;
00118                 uint8   imageType;
00119                 uint16  tgaOrigin;
00120                 uint16  length;
00121                 uint8   depth;
00122                 uint16  xOrg;
00123                 uint16  yOrg;
00124                 uint16  width;
00125                 uint16  height;
00126                 uint8   imageDepth;
00127                 uint8   desc;
00128                 
00129                 f.serial(lengthID);
00130                 f.serial(cMapType);
00131                 f.serial(imageType);
00132                 if(imageType!=2 && imageType!=3 && imageType!=10 && imageType!=11) return 0;
00133                 f.serial(tgaOrigin);
00134                 f.serial(length);
00135                 f.serial(depth);
00136                 f.serial(xOrg);
00137                 f.serial(yOrg);
00138                 f.serial(width);
00139                 f.serial(height);
00140                 f.serial(imageDepth);
00141                 if(imageDepth!=8 && imageDepth!=16 && imageDepth!=24 && imageDepth!=32) return 0;
00142                 f.serial(desc);
00143 
00144                 if(!f.seek (0, origin))
00145                 {
00146                         throw ESeekFailed();
00147                 }
00148                 return readTGA(f);
00149         }       
00150 }
00151 
00152 
00153 /*-------------------------------------------------------------------*\
00154                                                                 makeDummy               
00155 \*-------------------------------------------------------------------*/
00156 void    CBitmap::makeDummy()
00157 {
00158         static  const uint8     bitmap[1024]= {  
00159                 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00160                 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
00161                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00162                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00163                 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
00164                 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
00165                 0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
00166                 0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
00167                 0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,
00168                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00169                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00170                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00171                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00172                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00173                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00174                 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00175                 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00176                 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
00177                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00178                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00179                 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
00180                 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
00181                 0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
00182                 0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
00183                 0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,
00184                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00185                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00186                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00187                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00188                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00189                 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
00190                 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00191         }; 
00192 
00193         PixelFormat = RGBA;
00194         _MipMapCount = 1;
00195         _Width= 32;
00196         _Height= 32;
00197         _Data[0].resize(_Width*_Height*sizeof(NLMISC::CRGBA));
00198         NLMISC::CRGBA   *pix= (NLMISC::CRGBA*)(&(*_Data[0].begin()));
00199 
00200         for(sint i=0;i<(sint)(_Width*_Height);i++)
00201         {
00202                 if(bitmap[i])
00203                         pix[i].set(255,255,255,255);
00204                 else
00205                         pix[i].set(0,0,0,255);
00206         }
00207 
00208 }
00209 
00210 
00211 
00212 
00213 /*-------------------------------------------------------------------*\
00214                                                                 readDDS         
00215 \*-------------------------------------------------------------------*/
00216 uint8 CBitmap::readDDS(NLMISC::IStream &f, uint mipMapSkip)
00217 {
00218         //------------------ Reading Header ------------------------
00219 
00220         //-------------- reading entire header
00221         
00222         uint32 size = 0;
00223         f.serial(size); // size in Bytes of header(without "DDS")
00224          uint32 * _DDSSurfaceDesc = new uint32[size]; 
00225          std::auto_ptr<uint32> _DDSSurfaceDescAuto(_DDSSurfaceDesc);
00226         _DDSSurfaceDesc[0]= size;
00227 
00228 #ifdef NL_LITTLE_ENDIAN
00229         f.serialBuffer((uint8*)(_DDSSurfaceDesc+1), size-4);
00230 #else
00231         for(uint i= 0; i<size/4 - 1; i++)
00232         {
00233                 f.serial(_DDSSurfaceDesc[i+1]);
00234         }
00235 #endif
00236         
00237         // flags determines which members of the header structure contain valid data
00238         uint32 flags = _DDSSurfaceDesc[1];
00239 
00240         //verify if file have linearsize set
00241         if(!(flags & DDSD_LINEARSIZE)) 
00242     {
00243                 throw EDDSBadHeader();
00244         }
00245         
00246         //-------------- extracting and testing useful info
00247 
00248         _Height = _DDSSurfaceDesc[2];
00249         _Width  = _DDSSurfaceDesc[3];
00250         _MipMapCount= (uint8) _DDSSurfaceDesc[6];
00251         // If no mipmap.
00252         if(_MipMapCount==0)
00253                 _MipMapCount=1;
00254         switch (_DDSSurfaceDesc[20])
00255         {
00256         case DXTC1HEADER:
00257                 PixelFormat=DXTC1;
00258                 break;
00259         case DXTC3HEADER:
00260                 PixelFormat=DXTC3;
00261                 break;
00262         case DXTC5HEADER:
00263                 PixelFormat=DXTC5;
00264                 break;
00265         }
00266         
00267         flags = _DDSSurfaceDesc[19]; //PixelFormat flags
00268         
00269         if(PixelFormat==DXTC1 && _DDSSurfaceDesc[21]>0) //AlphaBitDepth
00270         {
00271                 PixelFormat = DXTC1Alpha;
00272         }
00273         
00274         if(PixelFormat!= DXTC1 && PixelFormat!= DXTC1Alpha && PixelFormat!= DXTC3 && PixelFormat!= DXTC5)
00275         {
00276                 throw EDDSBadHeader();
00277         }
00278 
00279         // compute the min power of 2 between width and height
00280         uint    minSizeLevel= min(_Width, _Height);
00281         minSizeLevel= getPowerOf2(minSizeLevel);
00282 
00283         //------------- manage mipMapSkip 
00284         if(_MipMapCount>1 && mipMapSkip>0 && minSizeLevel>2)
00285         {
00286                 // Keep at least the level where width and height are at leat 4.
00287                 mipMapSkip= min(mipMapSkip, minSizeLevel-2);
00288                 // skip any mipmap
00289                 uint    seekSize= 0;
00290                 while(mipMapSkip>0)
00291                 {
00292                         uint32 mipMapSz;
00293                         if(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)
00294                                 mipMapSz = _Width*_Height/2;
00295                         else
00296                                 mipMapSz = _Width*_Height;
00297 
00298                         // add to how many to skip
00299                         seekSize+= mipMapSz;
00300 
00301                         // Size of final bitmap is reduced.
00302                         _Width>>=1;
00303                         _Height>>=1;
00304                         _MipMapCount--;
00305                         mipMapSkip--;
00306                 }
00307                 // skip data in file
00308                 if(seekSize>0)
00309                 {
00310                         if(!f.seek(seekSize, IStream::current))
00311                         {
00312                                 throw ESeekFailed();
00313                         }
00314                 }
00315 
00316         }
00317 
00318         //------------- preload all the mipmaps (one serialBuffer() is faster)
00319         uint32 w = _Width;
00320         uint32 h = _Height;
00321         uint32  totalSize= 0;
00322 
00323         uint8   m;
00324         for(m= 0; m<_MipMapCount; m++)
00325         {
00326                 uint32 wtmp, htmp;
00327                 if(w<4)
00328                         wtmp = 4;
00329                 else
00330                         wtmp = w;
00331                 if(h < 4)
00332                         htmp = 4;
00333                 else
00334                         htmp = h;
00335                 
00336                 uint32 mipMapSz;
00337                 if(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)
00338                         mipMapSz = wtmp*htmp/2;
00339                 else
00340                         mipMapSz = wtmp*htmp;
00341 
00342 
00343                 _Data[m].resize(mipMapSz);
00344                 totalSize+= mipMapSz;
00345 
00346                 w = (w+1)/2;
00347                 h = (h+1)/2;
00348         }
00349 
00350         // Read all the data in one block.
00351         vector<uint8>   pixData;
00352         pixData.resize(totalSize);
00353         f.serialBuffer(&(*pixData.begin()), totalSize);
00354 
00355 
00356         //------------- reading mipmap levels from pixData
00357         
00358         uint32 pixIndex= 0;
00359 
00360         for(m= 0; m<_MipMapCount; m++)
00361         {
00362                 uint32  mipMapSz= _Data[m].size();
00363                 memcpy(&(*_Data[m].begin()), &(pixData[pixIndex]), mipMapSz);
00364                 pixIndex+= mipMapSz;
00365         }
00366 
00367         //------------- End
00368 
00369         switch(PixelFormat)
00370         {
00371                 case DXTC1  : return 24;
00372                 case DXTC1Alpha : return 32;
00373                 case DXTC3  : return 32;
00374                 case DXTC5  : return 32;
00375                 default  : break;
00376         }
00377 
00378         return 0;
00379 }
00380 
00381 
00382 
00383 
00384 /*-------------------------------------------------------------------*\
00385                                                         convertToDXTC5
00386 \*-------------------------------------------------------------------*/
00387 bool CBitmap::convertToDXTC5()
00388 {
00389         /* Yoyo: RGB encoding for DXTC1 and DXTC5/3 are actually different!!
00390                 DXTC3/5 don't rely on sign of color0>color1 to setup special encoding (ie use a special compression for Black)
00391                 Since this can arise if the src is DXTC1 , we can't simply compress it into DXTC5 without doing a 
00392                 heavy compression...
00393                 (the inverse is false: DXTC5 to DXTC1 is possible, with maybe swap color0/color1 and bits).
00394         */
00395 
00396         return false;
00397 
00398 /*      uint32 i,j;
00399 
00400         if(PixelFormat!=DXTC1) return false;
00401 
00402         for(uint8 m= 0; m<_MipMapCount; m++)
00403         {
00404                 std::vector<uint8> dataTmp;
00405                 dataTmp.reserve(2*_Data[m].size());
00406 
00407                 for(i=0; i<_Data[m].size(); i+=8)
00408                 {
00409                         //64 bits alpha
00410                         for(j=0; j<8; j++)
00411                         {
00412                                 dataTmp.push_back(255);
00413                         }
00414 
00415                         //64 bits RGB
00416                         for(j=0; j<8; j++)
00417                         {
00418                                 dataTmp.push_back(_Data[m][i+j]);
00419                         }
00420                 }
00421                 _Data[m] = dataTmp;
00422         }
00423         PixelFormat = DXTC5;
00424         return true;
00425 */
00426 }
00427 
00428 
00429 
00430 /*-------------------------------------------------------------------*\
00431                                                         luminanceToRGBA()
00432 \*-------------------------------------------------------------------*/
00433 bool CBitmap::luminanceToRGBA()
00434 {
00435         uint32 i;
00436 
00437         if(_Width*_Height == 0)  return false;
00438         
00439         for(uint8 m= 0; m<_MipMapCount; m++)
00440         {
00441                 std::vector<uint8> dataTmp;
00442                 dataTmp.reserve(_Data[m].size()*4);
00443 
00444                 for(i=0; i<_Data[m].size(); i++)
00445                 {
00446                         dataTmp.push_back(_Data[m][i]);
00447                         dataTmp.push_back(_Data[m][i]);
00448                         dataTmp.push_back(_Data[m][i]);
00449                         dataTmp.push_back(255);
00450                 }
00451                 _Data[m] = dataTmp;
00452         }
00453         PixelFormat = RGBA;
00454         return true;
00455 }
00456 
00457 /*-------------------------------------------------------------------*\
00458                                                         alphaToRGBA()
00459 \*-------------------------------------------------------------------*/
00460 bool CBitmap::alphaToRGBA()
00461 {
00462         uint32 i;
00463 
00464         if(_Width*_Height == 0)  return false;
00465         
00466         for(uint8 m= 0; m<_MipMapCount; m++)
00467         {
00468                 std::vector<uint8> dataTmp;
00469                 dataTmp.reserve(_Data[m].size()*4);
00470 
00471                 for(i=0; i<_Data[m].size(); i++)
00472                 {
00473                         dataTmp.push_back(255);
00474                         dataTmp.push_back(255);
00475                         dataTmp.push_back(255);
00476                         dataTmp.push_back(_Data[m][i]);
00477                 }
00478                 _Data[m] = dataTmp;
00479         }
00480         PixelFormat = RGBA;
00481         return true;
00482 }
00483 
00484 
00485 /*-------------------------------------------------------------------*\
00486                                                         alphaLuminanceToRGBA()
00487 \*-------------------------------------------------------------------*/
00488 bool CBitmap::alphaLuminanceToRGBA()
00489 {
00490         uint32 i;
00491 
00492         if(_Width*_Height == 0)  return false;
00493         
00494         for(uint8 m= 0; m<_MipMapCount; m++)
00495         {
00496                 std::vector<uint8> dataTmp;
00497                 dataTmp.reserve(_Data[m].size()*2);
00498 
00499                 for(i=0; i<_Data[m].size(); i+=2)
00500                 {
00501                         dataTmp.push_back(_Data[m][i]);
00502                         dataTmp.push_back(_Data[m][i]);
00503                         dataTmp.push_back(_Data[m][i]);
00504                         dataTmp.push_back(_Data[m][i+1]);
00505                 }
00506                 _Data[m] = dataTmp;
00507         }
00508         PixelFormat = RGBA;
00509         return true;
00510 }
00511 
00512 
00513 
00514 
00515 /*-------------------------------------------------------------------*\
00516                                                         rgbaToAlphaLuminance
00517 \*-------------------------------------------------------------------*/
00518 bool CBitmap::rgbaToAlphaLuminance()
00519 {
00520         uint32 i;
00521 
00522         if(_Width*_Height == 0)  return false;
00523         
00524         for(uint8 m= 0; m<_MipMapCount; m++)
00525         {
00526                 std::vector<uint8> dataTmp;
00527                 dataTmp.reserve(_Data[m].size()/2);
00528 
00529                 for(i=0; i<_Data[m].size(); i+=4)
00530                 {
00531                         dataTmp.push_back((_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255);
00532                         dataTmp.push_back(_Data[m][i+3]);
00533                 }
00534                 NLMISC::contReset(_Data[m]); 
00535                 _Data[m].resize(0);
00536                 _Data[m] = dataTmp;
00537         }
00538         PixelFormat = AlphaLuminance;
00539         return true;
00540 }
00541 
00542 
00543 /*-------------------------------------------------------------------*\
00544                                                         luminanceToAlphaLuminance
00545 \*-------------------------------------------------------------------*/
00546 bool CBitmap::luminanceToAlphaLuminance()
00547 {
00548         uint32 i;
00549 
00550         if(_Width*_Height == 0)  return false;
00551                 
00552         for(uint8 m= 0; m<_MipMapCount; m++)
00553         {
00554                 std::vector<uint8> dataTmp;
00555                 dataTmp.reserve(_Data[m].size()*2);
00556 
00557                 for(i=0; i<_Data[m].size(); i++)
00558                 {
00559                         dataTmp.push_back(_Data[m][i]);
00560                         dataTmp.push_back(255);
00561                 }
00562                 _Data[m] = dataTmp;
00563         }
00564         PixelFormat = AlphaLuminance;
00565         return true;
00566 }
00567 
00568 
00569 
00570 /*-------------------------------------------------------------------*\
00571                                                         alphaToAlphaLuminance
00572 \*-------------------------------------------------------------------*/
00573 bool CBitmap::alphaToAlphaLuminance()
00574 {
00575         uint32 i;
00576 
00577         if(_Width*_Height == 0)  return false;
00578                 
00579         for(uint8 m= 0; m<_MipMapCount; m++)
00580         {
00581                 std::vector<uint8> dataTmp;
00582                 dataTmp.reserve(_Data[m].size()*2);
00583 
00584                 for(i=0; i<_Data[m].size(); i++)
00585                 {
00586                         dataTmp.push_back(0);
00587                         dataTmp.push_back(_Data[m][i]);
00588                 }
00589                 _Data[m] = dataTmp;
00590         }
00591         PixelFormat = AlphaLuminance;
00592         return true;
00593 }
00594 
00595 
00596 
00597 /*-------------------------------------------------------------------*\
00598                                                         rgbaToLuminance
00599 \*-------------------------------------------------------------------*/
00600 bool CBitmap::rgbaToLuminance()
00601 {
00602         uint32 i;
00603 
00604         if(_Width*_Height == 0)  return false;
00605                 
00606         for(uint8 m= 0; m<_MipMapCount; m++)
00607         {
00608                 std::vector<uint8> dataTmp;
00609                 dataTmp.reserve(_Data[m].size()/4);
00610 
00611                 for(i=0; i<_Data[m].size(); i+=4)
00612                 {
00613                         dataTmp.push_back((_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255);
00614                 }
00615                 NLMISC::contReset(_Data[m]); 
00616                 _Data[m].resize(0);
00617                 _Data[m] = dataTmp;
00618         }
00619         PixelFormat = Luminance;
00620         return true;
00621 }
00622 
00623 
00624 
00625 /*-------------------------------------------------------------------*\
00626                                                         alphaToLuminance
00627 \*-------------------------------------------------------------------*/
00628 bool CBitmap::alphaToLuminance()
00629 {
00630         if(_Width*_Height == 0)  return false;
00631                 
00632         PixelFormat = Luminance;
00633         return true;
00634 }
00635 
00636 
00637 
00638 /*-------------------------------------------------------------------*\
00639                                                         alphaLuminanceToLuminance
00640 \*-------------------------------------------------------------------*/
00641 bool CBitmap::alphaLuminanceToLuminance()
00642 {
00643         uint32 i;
00644 
00645         if(_Width*_Height == 0)  return false;
00646                 
00647         for(uint8 m= 0; m<_MipMapCount; m++)
00648         {
00649                 std::vector<uint8> dataTmp;
00650                 dataTmp.reserve(_Data[m].size()/2);
00651 
00652                 for(i=0; i<_Data[m].size(); i+=2)
00653                 {
00654                         dataTmp.push_back(0);
00655                         dataTmp.push_back(0);
00656                         dataTmp.push_back(0);
00657                         dataTmp.push_back(_Data[m][i]);
00658                 }
00659                 NLMISC::contReset(_Data[m]); 
00660                 _Data[m].resize(0);
00661                 _Data[m] = dataTmp;
00662         }
00663         PixelFormat = Luminance;
00664         return true;
00665 }
00666 
00667 
00668 /*-------------------------------------------------------------------*\
00669                                                         rgbaToAlpha
00670 \*-------------------------------------------------------------------*/
00671 bool CBitmap::rgbaToAlpha()
00672 {
00673         uint32 i;
00674 
00675         if(_Width*_Height == 0)  return false;
00676                 
00677         for(uint8 m= 0; m<_MipMapCount; m++)
00678         {
00679                 std::vector<uint8> dataTmp;
00680                 dataTmp.reserve(_Data[m].size()/4);
00681 
00682                 for(i=0; i<_Data[m].size(); i+=4)
00683                 {
00684                         dataTmp.push_back(0);
00685                         dataTmp.push_back(0);
00686                         dataTmp.push_back(0);
00687                         dataTmp.push_back(_Data[m][i+3]);
00688                 }
00689                 NLMISC::contReset(_Data[m]); 
00690                 _Data[m].resize(0);
00691                 _Data[m] = dataTmp;
00692         }
00693         PixelFormat = Alpha;
00694         return true;
00695 }
00696 
00697 
00698 /*-------------------------------------------------------------------*\
00699                                                         luminanceToAlpha
00700 \*-------------------------------------------------------------------*/
00701 bool CBitmap::luminanceToAlpha()
00702 {
00703         uint32 i;
00704 
00705         if(_Width*_Height == 0)  return false;
00706                 
00707         for(uint8 m= 0; m<_MipMapCount; m++)
00708         {
00709                 std::vector<uint8> dataTmp;
00710                 dataTmp.reserve(_Data[m].size());
00711 
00712                 for(i=0; i<_Data[m].size(); i++)
00713                 {
00714                         dataTmp.push_back(_Data[m][i]);
00715                 }
00716                 _Data[m] = dataTmp;
00717         }
00718         PixelFormat = Alpha;
00719         return true;
00720 }
00721 
00722 
00723 /*-------------------------------------------------------------------*\
00724                                                         alphaLuminanceToAlpha
00725 \*-------------------------------------------------------------------*/
00726 bool CBitmap::alphaLuminanceToAlpha()
00727 {
00728         uint32 i;
00729 
00730         if(_Width*_Height == 0)  return false;
00731                 
00732         for(uint8 m= 0; m<_MipMapCount; m++)
00733         {
00734                 std::vector<uint8> dataTmp;
00735                 dataTmp.reserve(_Data[m].size()/2);
00736 
00737                 for(i=0; i<_Data[m].size(); i+=2)
00738                 {
00739                         dataTmp.push_back(_Data[m][i+1]);
00740                 }
00741                 NLMISC::contReset(_Data[m]); 
00742                 _Data[m].resize(0);
00743                 _Data[m] = dataTmp;
00744         }
00745         PixelFormat = Alpha;
00746         return true;
00747 }
00748 
00749 
00750 /*-------------------------------------------------------------------*\
00751                                                         convertToLuminance
00752 \*-------------------------------------------------------------------*/
00753 bool CBitmap::convertToLuminance()
00754 {
00755         switch(PixelFormat)
00756         {
00757                 case RGBA :
00758                         return rgbaToLuminance();
00759                         break;
00760 
00761                 case Luminance :
00762                         return true;
00763                         break;
00764 
00765                 case Alpha :
00766                         return alphaToLuminance();
00767                         break;
00768 
00769                 case AlphaLuminance :
00770                         return alphaLuminanceToLuminance();
00771                         break;
00772 
00773                 default:
00774                         break;
00775         }
00776         return false;
00777 }
00778 
00779 
00780 
00781 /*-------------------------------------------------------------------*\
00782                                                         convertToAlpha
00783 \*-------------------------------------------------------------------*/
00784 bool CBitmap::convertToAlpha()
00785 {
00786         switch(PixelFormat)
00787         {
00788                 case RGBA :
00789                         return rgbaToAlpha();
00790                         break;
00791 
00792                 case Luminance :
00793                         return luminanceToAlpha();
00794                         break;
00795 
00796                 case Alpha :
00797                         return true;
00798                         break;
00799 
00800                 case AlphaLuminance :
00801                         return alphaLuminanceToAlpha();
00802                         break;
00803 
00804                 default:
00805                         break;
00806         }
00807         return false;
00808 }
00809 
00810 
00811 
00812 /*-------------------------------------------------------------------*\
00813                                                         convertToAlphaLuminance
00814 \*-------------------------------------------------------------------*/
00815 bool CBitmap::convertToAlphaLuminance()
00816 {
00817         switch(PixelFormat)
00818         {
00819                 case RGBA :
00820                         return rgbaToAlphaLuminance();
00821                         break;
00822 
00823                 case Luminance :
00824                         return luminanceToAlphaLuminance();
00825                         break;
00826 
00827                 case Alpha :
00828                         return alphaToAlphaLuminance();
00829                         break;
00830 
00831                 case AlphaLuminance :
00832                         return true;
00833                         break;
00834 
00835                 default:
00836                         break;
00837         }
00838         return false;
00839 }
00840 
00841 
00842 /*-------------------------------------------------------------------*\
00843                                                         convertToRGBA
00844 \*-------------------------------------------------------------------*/
00845 bool CBitmap::convertToRGBA()
00846 {
00847         switch(PixelFormat)
00848         {
00849                 case DXTC1 :
00850                         return decompressDXT1(false);
00851                         break;
00852 
00853                 case DXTC1Alpha :
00854                         return decompressDXT1(true);
00855                         break;
00856 
00857                 case DXTC3 :
00858                         return decompressDXT3();        
00859                         break;
00860 
00861                 case DXTC5 :
00862                         return decompressDXT5();                
00863                         break;
00864 
00865                 case Luminance :
00866                         return luminanceToRGBA();
00867                         break;
00868 
00869                 case Alpha :
00870                         return alphaToRGBA();
00871                         break;
00872 
00873                 case AlphaLuminance :
00874                         return alphaLuminanceToRGBA();
00875                         break;
00876                 case RGBA:
00877                         return true;
00878                 break;
00879                 default:
00880                         break;
00881         }
00882         return false;
00883 }
00884 
00885 
00886 /*-------------------------------------------------------------------*\
00887                                                         convertToType
00888 \*-------------------------------------------------------------------*/
00889 bool CBitmap::convertToType(CBitmap::TType type)
00890 {
00891         if(PixelFormat==type) return true;
00892 
00893         switch(type)
00894         {
00895                 case RGBA :
00896                         return convertToRGBA();
00897                         break;
00898 
00899                 case DXTC5 :
00900                         return convertToDXTC5();                
00901                         break;
00902 
00903                 case Luminance :
00904                         return convertToLuminance();
00905                         break;
00906 
00907                 case Alpha :
00908                         return convertToAlpha();
00909                         break;
00910 
00911                 case AlphaLuminance :
00912                         return convertToAlphaLuminance();
00913                         break;
00914 
00915                 default:
00916                         break;
00917         }
00918         
00919         return false;
00920 }
00921 
00922 
00923 
00924 
00925 /*-------------------------------------------------------------------*\
00926                                                         decompressDXT1
00927 \*-------------------------------------------------------------------*/
00928 bool CBitmap::decompressDXT1(bool alpha)
00929 {
00930         uint32 i,j,k;
00931         NLMISC::CRGBA   c[4];
00932         std::vector<uint8> dataTmp[MAX_MIPMAP];
00933         
00934         uint32 width= _Width;
00935         uint32 height= _Height;
00936 
00937         for(uint8 m= 0; m<_MipMapCount; m++)
00938         {
00939                 uint32 wtmp, htmp;
00940                 if(width<4)
00941                         wtmp = 4;
00942                 else
00943                         wtmp = width;
00944                 if(height < 4)
00945                         htmp = 4;
00946                 else
00947                         htmp = height;
00948                 uint32 mipMapSz = wtmp*htmp*4;
00949                 dataTmp[m].resize(mipMapSz); 
00950                 if(dataTmp[m].capacity()<mipMapSz)
00951                 {
00952                         throw EAllocationFailure();
00953                 }
00954                 uint32 wBlockCount= wtmp/4;
00955                 
00956 
00957 
00958                 for(i=0; i < _Data[m].size(); i+=8)
00959                 {
00960                         uint16 color0;
00961                         uint16 color1;
00962                         uint32 bits;
00963                         memcpy(&color0,&_Data[m][i],2);
00964                         memcpy(&color1,&_Data[m][i+2],2);
00965                         memcpy(&bits,&_Data[m][i+4],4);
00966 
00967                         uncompress(color0,c[0]);
00968                         uncompress(color1,c[1]);        
00969                         
00970                         c[0].A= 0;
00971                         c[1].A= 0;
00972                         c[2].A= 0;
00973                         c[3].A= 0;
00974                         
00975                         if(color0>color1)
00976                         {
00977                                 c[2].blendFromui(c[0],c[1],85);
00978                                 if(alpha) c[2].A= 255;
00979 
00980                                 c[3].blendFromui(c[0],c[1],171);        
00981                                 if(alpha) c[3].A= 255;
00982                         }
00983                         else
00984                         {
00985                                 c[2].blendFromui(c[0],c[1],128);
00986                                 if(alpha) c[2].A= 255;
00987 
00988                                 c[3].set(0,0,0,0);
00989                         }
00990 
00991                         // computing the 16 RGBA of the block
00992                         
00993                         uint32 blockNum= i/8; //(64 bits)
00994                         // <previous blocks in above lines> * 4 (rows) * _Width (columns) + 4pix*4rgba*<same line previous blocks>
00995                         uint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);
00996                         for(j=0; j<4; j++)
00997                         {
00998                                 for(k=0; k<4; k++)
00999                                 {
01000                                         dataTmp[m][pixelsCount + j*wtmp*4 + 4*k]= c[bits&3].R;
01001                                         dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+1]= c[bits&3].G;
01002                                         dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+2]= c[bits&3].B;
01003                                         dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+3]= c[bits&3].A;
01004                                         bits>>=2;
01005                                 }
01006                         }
01007                 }
01008 
01009                 // Copy result into the mipmap level.
01010                 if(wtmp==width && htmp==height)
01011                 {
01012                         // For mipmaps level >4 pixels.
01013                         _Data[m]= dataTmp[m];
01014                 }
01015                 else
01016                 {
01017                         // For last mipmaps, level <4 pixels.
01018                         _Data[m].resize(width*height*4);
01019                         CRGBA   *src= (CRGBA*)&dataTmp[m][0];
01020                         CRGBA   *dst= (CRGBA*)&_Data[m][0];
01021                         uint    x,y;
01022                         for(y=0;y<height;y++)
01023                         {
01024                                 for(x=0;x<width;x++)
01025                                         dst[y*width+x]= src[y*wtmp+x];
01026                         }
01027                 }
01028 
01029                 // Next mipmap size.
01030                 width = (width+1)/2;
01031                 height = (height+1)/2;
01032         }
01033         PixelFormat = RGBA;
01034         return true;
01035 }
01036 
01037 
01038 
01039 
01040 /*-------------------------------------------------------------------*\
01041                                                         decompressDXT3
01042 \*-------------------------------------------------------------------*/
01043 bool CBitmap::decompressDXT3()
01044 {
01045         uint32 i,j,k;
01046         NLMISC::CRGBA   c[4];
01047         std::vector<uint8> dataTmp[MAX_MIPMAP];
01048         
01049         uint32 width= _Width;
01050         uint32 height= _Height;
01051 
01052         for(uint8 m= 0; m<_MipMapCount; m++)
01053         {
01054                 uint32 wtmp, htmp;
01055                 if(width<4)
01056                         wtmp = 4;
01057                 else
01058                         wtmp = width;
01059                 if(height < 4)
01060                         htmp = 4;
01061                 else
01062                         htmp = height;
01063                 uint32 mipMapSz = wtmp*htmp*4;
01064                 dataTmp[m].resize(mipMapSz); 
01065                 if(dataTmp[m].capacity()<mipMapSz)
01066                 {
01067                         throw EAllocationFailure();
01068                 }
01069                 uint32 wBlockCount= wtmp/4;
01070                 
01071 
01072                 for(i=0; i < _Data[m].size(); i+=16)
01073                 {
01074                         uint8 alpha[16];
01075                         uint64 alphatmp;
01076                         memcpy(&alphatmp,&_Data[m][i],8);
01077 
01078                         for(j=0; j<16; j++)
01079                         {
01080                                 uint8   a= (uint8)(alphatmp&15);
01081                                 // expand to 0-255.
01082                                 alpha[j]= a+(a<<4);
01083                                 alphatmp>>=4;
01084                         }
01085 
01086 
01087                         uint16 color0;
01088                         uint16 color1;
01089                         uint32 bits;
01090                         memcpy(&color0,&_Data[m][i+8],2);
01091                         memcpy(&color1,&_Data[m][i+10],2);
01092                         memcpy(&bits,&_Data[m][i+12],4);
01093 
01094                         uncompress(color0,c[0]);
01095                         uncompress(color1,c[1]);        
01096                                                 
01097                         // ignore color0>color1 for DXT3 and DXT5.
01098                         c[2].blendFromui(c[0],c[1],85);
01099                         c[3].blendFromui(c[0],c[1],171);        
01100 
01101                         // computing the 16 RGBA of the block
01102                         
01103                         uint32 blockNum= i/16; //(128 bits)
01104                         // <previous blocks in above lines> * 4 (rows) * wtmp (columns) + 4pix*4rgba*<same line previous blocks>
01105                         uint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);
01106                         for(j=0; j<4; j++)
01107                         {
01108                                 for(k=0; k<4; k++)
01109                                 {
01110                                         dataTmp[m][pixelsCount + j*wtmp*4 + 4*k]= c[bits&3].R;
01111                                         dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+1]= c[bits&3].G;
01112                                         dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+2]= c[bits&3].B;
01113                                         dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+3]= alpha[4*j+k];
01114                                         bits>>=2;
01115                                 }
01116                         }
01117                 }
01118 
01119                 // Copy result into the mipmap level.
01120                 if(wtmp==width && htmp==height)
01121                 {
01122                         // For mipmaps level >4 pixels.
01123                         _Data[m]= dataTmp[m];
01124                 }
01125                 else
01126                 {
01127                         // For last mipmaps, level <4 pixels.
01128                         _Data[m].resize(width*height*4);
01129                         CRGBA   *src= (CRGBA*)&dataTmp[m][0];
01130                         CRGBA   *dst= (CRGBA*)&_Data[m][0];
01131                         uint    x,y;
01132                         for(y=0;y<height;y++)
01133                         {
01134                                 for(x=0;x<width;x++)
01135                                         dst[y*width+x]= src[y*wtmp+x];
01136                         }
01137                 }
01138 
01139                 // Next mipmap size.
01140                 width = (width+1)/2;
01141                 height = (height+1)/2;
01142         }
01143         PixelFormat = RGBA;
01144         return true;
01145 }
01146 
01147 
01148 
01149 
01150 /*-------------------------------------------------------------------*\
01151                                                         decompressDXT5
01152 \*-------------------------------------------------------------------*/
01153 bool CBitmap::decompressDXT5()
01154 {
01155         uint32 i,j,k;
01156         NLMISC::CRGBA   c[4];
01157         std::vector<uint8> dataTmp[MAX_MIPMAP];
01158         
01159         uint32 width= _Width;
01160         uint32 height= _Height;
01161 
01162         for(uint8 m= 0; m<_MipMapCount; m++)
01163         {
01164                 uint32 wtmp, htmp;
01165                 if(width<4)
01166                         wtmp = 4;
01167                 else
01168                         wtmp = width;
01169                 if(height < 4)
01170                         htmp = 4;
01171                 else
01172                         htmp = height;
01173                 uint32 mipMapSz = wtmp*htmp*4;
01174                 dataTmp[m].resize(mipMapSz); 
01175                 if(dataTmp[m].capacity()<mipMapSz)
01176                 {
01177                         throw EAllocationFailure();
01178                 }
01179                 uint32 wBlockCount= wtmp/4;
01180                 
01181 
01182 
01183                 for(i=0; i < _Data[m].size(); i+=16)
01184                 {
01185                         uint64 bitsAlpha;
01186                         memcpy(&bitsAlpha,&_Data[m][i],8);
01187                         bitsAlpha>>= 16;
01188 
01189                         uint32 alpha[8];
01190                         alpha[0]= _Data[m][i+0];
01191                         alpha[1]= _Data[m][i+1];
01192                         
01193                         if(alpha[0]>alpha[1])
01194                         {
01195                                 alpha[2]= blend(alpha[0], alpha[1], 219);
01196                                 alpha[3]= blend(alpha[0], alpha[1], 183);
01197                                 alpha[4]= blend(alpha[0], alpha[1], 146);
01198                                 alpha[5]= blend(alpha[0], alpha[1], 110);
01199                                 alpha[6]= blend(alpha[0], alpha[1], 73);
01200                                 alpha[7]= blend(alpha[0], alpha[1], 37);
01201                         }
01202                         else
01203                         {
01204                                 alpha[2]= blend(alpha[0], alpha[1], 204);
01205                                 alpha[3]= blend(alpha[0], alpha[1], 154);
01206                                 alpha[4]= blend(alpha[0], alpha[1], 102);
01207                                 alpha[5]= blend(alpha[0], alpha[1], 51);
01208                                 alpha[6]= 0;
01209                                 alpha[7]= 255;
01210                         }
01211 
01212                         uint8 codeAlpha[16];
01213                         for(j=0; j<16; j++)
01214                         {
01215                                 codeAlpha[j] = (uint8)bitsAlpha & 7;
01216                                 bitsAlpha>>=3;
01217                         }
01218 
01219 
01220                         uint16 color0;
01221                         uint16 color1;
01222                         uint32 bits;
01223                         memcpy(&color0,&_Data[m][i+8],2);
01224                         memcpy(&color1,&_Data[m][i+10],2);
01225                         memcpy(&bits,&_Data[m][i+12],4);
01226 
01227                         uncompress(color0,c[0]);
01228                         uncompress(color1,c[1]);        
01229                         
01230                         // ignore color0>color1 for DXT3 and DXT5.
01231                         c[2].blendFromui(c[0],c[1],85);
01232                         c[3].blendFromui(c[0],c[1],171);        
01233 
01234                         // computing the 16 RGBA of the block
01235                         
01236                         uint32 blockNum= i/16; //(128 bits)
01237 
01238                         // <previous blocks in above lines> * 4 (rows) * wtmp (columns) + 4pix*<same line previous blocks>
01239                         uint32 pixelsCount= (blockNum/wBlockCount)*wtmp*4 + 4*(blockNum%wBlockCount);
01240                         // *sizeof(RGBA)
01241                         pixelsCount*=4;
01242                         for(j=0; j<4; j++)
01243                         {
01244                                 for(k=0; k<4; k++)
01245                                 {
01246                                         dataTmp[m][pixelsCount + (j*wtmp+k)*4 +0]= c[bits&3].R;
01247                                         dataTmp[m][pixelsCount + (j*wtmp+k)*4 +1]= c[bits&3].G;
01248                                         dataTmp[m][pixelsCount + (j*wtmp+k)*4 +2]= c[bits&3].B;
01249                                         dataTmp[m][pixelsCount + (j*wtmp+k)*4 +3]= (uint8) alpha[codeAlpha[4*j+k]];
01250                                         bits>>=2;
01251                                 }
01252                         }
01253 
01254                 }
01255 
01256                 // Copy result into the mipmap level.
01257                 if(wtmp==width && htmp==height)
01258                 {
01259                         // For mipmaps level >4 pixels.
01260                         _Data[m]= dataTmp[m];
01261                 }
01262                 else
01263                 {
01264                         // For last mipmaps, level <4 pixels.
01265                         _Data[m].resize(width*height*4);
01266                         CRGBA   *src= (CRGBA*)&dataTmp[m][0];
01267                         CRGBA   *dst= (CRGBA*)&_Data[m][0];
01268                         uint    x,y;
01269                         for(y=0;y<height;y++)
01270                         {
01271                                 for(x=0;x<width;x++)
01272                                         dst[y*width+x]= src[y*wtmp+x];
01273                         }
01274                 }
01275 
01276                 // Next mipmap size.
01277                 width = (width+1)/2;
01278                 height = (height+1)/2;
01279         }
01280         PixelFormat = RGBA;
01281         return true;
01282 
01283 }
01284 
01285 
01286 
01287 
01288 /*-------------------------------------------------------------------*\
01289                                                         blend
01290 \*-------------------------------------------------------------------*/
01291 uint32 CBitmap::blend(uint32 &n0, uint32 &n1, uint32 coef0) 
01292 {
01293         int     a0 = coef0;
01294         int     a1 = 256-a0;
01295         return ((n0*a0 + n1*a1) >>8);
01296 }
01297 
01298 
01299 
01300 /*-------------------------------------------------------------------*\
01301                                                         uncompress
01302 \*-------------------------------------------------------------------*/
01303 inline void CBitmap::uncompress(uint16 color, NLMISC::CRGBA &r)
01304 {
01305         r.A= 0;
01306         r.R= ((color>>11)&31) << 3; r.R+= r.R>>5;
01307         r.G= ((color>>5)&63) << 2;  r.G+= r.G>>6;
01308         r.B= ((color)&31) << 3;     r.B+= r.B>>5;
01309 }
01310 
01311 
01312 
01313 /*-------------------------------------------------------------------*\
01314                                                         getWidth
01315 \*-------------------------------------------------------------------*/
01316 uint32 CBitmap::getWidth(uint32 mipMap) const
01317 {
01318         if(mipMap==0) return _Width;
01319         
01320         uint32 w = _Width;
01321         uint32 h = _Height;
01322         uint32 m = 0;
01323         
01324         do
01325         {
01326                 m++;
01327                 w = (w+1)/2;
01328                 h = (h+1)/2;
01329                 if(m==mipMap) return w;
01330         }
01331         while(w!=1 || h!=1);
01332 
01333         return 0;
01334 }
01335 
01336 
01337 
01338 /*-------------------------------------------------------------------*\
01339                                                         getHeight
01340 \*-------------------------------------------------------------------*/
01341 uint32 CBitmap::getHeight(uint32 mipMap) const
01342 {
01343         if(mipMap==0) return _Height;
01344         
01345         uint32 w = _Width;
01346         uint32 h = _Height;
01347         uint32 m = 0;
01348 
01349         do
01350         {
01351                 m++;
01352                 w = (w+1)/2;
01353                 h = (h+1)/2;
01354                 if(m==mipMap) return h;
01355         }
01356         while(w!=1 || h!=1);
01357 
01358         return 0;
01359 }
01360 
01361 
01362 /*-------------------------------------------------------------------*\
01363                                                         getHeight
01364 \*-------------------------------------------------------------------*/
01365 uint32 CBitmap::getSize(uint32 numMipMap) const
01366 {
01367         return getHeight(numMipMap)*getWidth(numMipMap);
01368 }
01369 
01370 
01371 
01372 /*-------------------------------------------------------------------*\
01373                                                         buildMipMaps
01374 \*-------------------------------------------------------------------*/
01375 void CBitmap::buildMipMaps()
01376 {
01377         uint32 i,j;
01378 
01379         if(PixelFormat!=RGBA) return;
01380         if(_MipMapCount!=1) return;
01381         if(!NLMISC::isPowerOf2(_Width)) return;
01382         if(!NLMISC::isPowerOf2(_Height)) return;
01383         
01384         uint32 w = _Width;
01385         uint32 h = _Height;
01386 
01387         while(w>1 || h>1)
01388         {
01389                 uint32 precw = w;
01390                 uint32 prech = h;
01391                 w = (w+1)/2;
01392                 h = (h+1)/2;
01393                 uint32  mulw= precw/w;
01394                 uint32  mulh= prech/h;
01395 
01396                 _Data[_MipMapCount].resize(w*h*4);
01397                 
01398         
01399                 NLMISC::CRGBA *pRgba = (NLMISC::CRGBA*)&_Data[_MipMapCount][0];
01400                 NLMISC::CRGBA *pRgbaPrev = (NLMISC::CRGBA*)&_Data[_MipMapCount-1][0];
01401                 for(i=0; i<h; i++)
01402                 {
01403                         sint    i0= mulh*i;
01404                         sint    i1= mulh*i+1;
01405                         if(mulh==1)
01406                                 i1=i0;
01407                         i0*=precw;
01408                         i1*=precw;
01409                         for(j=0; j<w; j++)
01410                         {
01411                                 sint    j0= mulw*j;
01412                                 sint    j1= mulw*j+1;
01413                                 if(mulh==1)
01414                                         j1=j0;
01415                                 CRGBA   &c0= pRgbaPrev[i0+j0];
01416                                 CRGBA   &c1= pRgbaPrev[i0+j1];
01417                                 CRGBA   &c2= pRgbaPrev[i1+j0];
01418                                 CRGBA   &c3= pRgbaPrev[i1+j1];
01419                                 pRgba[i*w + j].R = (c0.R +
01420                                                                         c1.R +
01421                                                                         c2.R +
01422                                                                         c3.R + 2 ) /4;
01423                                 pRgba[i*w + j].G = (c0.G +
01424                                                                         c1.G +
01425                                                                         c2.G +
01426                                                                         c3.G + 2 ) /4;
01427                                 pRgba[i*w + j].B = (c0.B +
01428                                                                         c1.B +
01429                                                                         c2.B +
01430                                                                         c3.B + 2 ) /4;
01431                                 pRgba[i*w + j].A = (c0.A +
01432                                                                         c1.A +
01433                                                                         c2.A +
01434                                                                         c3.A + 2 ) /4;
01435                         }
01436                 }
01437 
01438                 _MipMapCount++;
01439         }
01440 }
01441 
01442 
01443 /*-------------------------------------------------------------------*\
01444                                                         releaseMipMaps
01445 \*-------------------------------------------------------------------*/
01446 void CBitmap::releaseMipMaps()
01447 {
01448         if(_MipMapCount<=1) return;
01449 
01450         _MipMapCount=1;
01451         for(sint i=1;i<MAX_MIPMAP;i++)
01452         {
01453                 NLMISC::contReset(_Data[i]); 
01454         }
01455 }
01456 
01457 
01458 /*-------------------------------------------------------------------*\
01459                                                         resample
01460 \*-------------------------------------------------------------------*/
01461 void CBitmap::resample(sint32 nNewWidth, sint32 nNewHeight)
01462 {
01463         nlassert(PixelFormat == RGBA);
01464         bool needRebuild = false;
01465 
01466         // Deleting mipmaps
01467         if(_MipMapCount>1)
01468                 needRebuild = true;
01469         releaseMipMaps();
01470 
01471         if(nNewWidth==0 || nNewHeight==0)
01472         {
01473                 _Width = _Height = 0;
01474                 return;
01475         }
01476         
01477         std::vector<uint8> pDestui;
01478         pDestui.resize(nNewWidth*nNewHeight*4);
01479         NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
01480 
01481         resamplePicture32 ((NLMISC::CRGBA*)&_Data[0][0], pDestRgba, _Width, _Height, nNewWidth, nNewHeight);
01482         NLMISC::contReset(_Data[0]); // free memory
01483         _Data[0] =  pDestui;
01484         _Width= nNewWidth;
01485         _Height= nNewHeight;
01486 
01487         // Rebuilding mipmaps
01488         if(needRebuild)
01489         {
01490                 buildMipMaps();
01491         }
01492 }
01493 
01494 
01495 /*-------------------------------------------------------------------*\
01496                                                         resize
01497 \*-------------------------------------------------------------------*/
01498 void CBitmap::resize (sint32 nNewWidth, sint32 nNewHeight, TType newType)
01499 {
01500         // Deleting mipmaps
01501         releaseMipMaps();
01502 
01503         // Change type of bitmap ?
01504         if (newType!=DonTKnow)
01505                 PixelFormat=newType;
01506 
01507         _Width = nNewWidth;
01508         _Height = nNewHeight;
01509 
01510         // resize the level 0 only.
01511         resizeMipMap(0, nNewWidth, nNewHeight);
01512 }
01513 
01514 
01515 /*-------------------------------------------------------------------*\
01516                                                         resizeMipMap
01517 \*-------------------------------------------------------------------*/
01518 void CBitmap::resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight)
01519 {
01520         nlassert(numMipMap<MAX_MIPMAP);
01521 
01522         // free memory
01523         NLMISC::contReset(_Data[numMipMap]);
01524 
01525         // DXTC compressed??
01526         bool    isDXTC= PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha || PixelFormat==DXTC3 || PixelFormat==DXTC5;
01527         // if yes, must round up width and height to 4, for allocation
01528         nNewWidth= 4*((nNewWidth+3)/4);
01529         nNewHeight= 4*((nNewHeight+3)/4);
01530 
01531         // resize the buffer
01532         _Data[numMipMap].resize (((uint32)(nNewWidth*nNewHeight)*bitPerPixels[PixelFormat])/8);
01533 }
01534 
01535 
01536 /*-------------------------------------------------------------------*\
01537                                                         reset
01538 \*-------------------------------------------------------------------*/
01539 void CBitmap::setMipMapCount(uint32 mmc)
01540 {
01541         _MipMapCount= uint8(mmc);
01542 }
01543 
01544 
01545 /*-------------------------------------------------------------------*\
01546                                                         reset
01547 \*-------------------------------------------------------------------*/
01548 void CBitmap::reset(TType type)
01549 {
01550         for(uint i=0; i<_MipMapCount; i++)
01551         {
01552                 NLMISC::contReset(_Data[i]);
01553                 _Data[i].resize(0);
01554         }
01555         _Width = _Height = 0;
01556         _MipMapCount= 1;
01557         
01558         // Change pixel format
01559         PixelFormat=type;
01560 }
01561 
01562 
01563 
01564 /*-------------------------------------------------------------------*\
01565                                                         resamplePicture32
01566 \*-------------------------------------------------------------------*/
01567 void CBitmap::resamplePicture32 (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest, 
01568                                                                  sint32 nSrcWidth, sint32 nSrcHeight, 
01569                                                                  sint32 nDestWidth, sint32 nDestHeight)
01570 {
01571         if ((nSrcWidth<=0)||(nSrcHeight<=0)||(nDestHeight<=0)||(nDestHeight<=0))
01572                 return;
01573         bool bXMag=(nDestWidth>=nSrcWidth);
01574         bool bYMag=(nDestHeight>=nSrcHeight);
01575         bool bXEq=(nDestWidth==nSrcWidth);
01576         bool bYEq=(nDestHeight==nSrcHeight);
01577         std::vector<NLMISC::CRGBAF> pIterm (nDestWidth*nSrcHeight);
01578         
01579         if (bXMag)
01580         {
01581                 float fXdelta=(float)(nSrcWidth)/(float)(nDestWidth);
01582                 NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
01583                 sint32 nY;
01584                 for (nY=0; nY<nSrcHeight; nY++)
01585                 {
01586                         const NLMISC::CRGBA *pSrcLine=pSrc;
01587                         float fX=0.f;
01588                         sint32 nX;
01589                         for (nX=0; nX<nDestWidth; nX++)
01590                         {
01591                                 float fVirgule=fX-(float)floor(fX);
01592                                 nlassert (fVirgule>=0.f);
01593                                 NLMISC::CRGBAF vColor;
01594                                 if (fVirgule>=0.5f)
01595                                 {
01596                                         if (fX<(float)(nSrcWidth-1))
01597                                         {
01598                                                 NLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);
01599                                                 NLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)+1]);
01600                                                 vColor=vColor1*(1.5f-fVirgule)+vColor2*(fVirgule-0.5f);
01601                                         }
01602                                         else
01603                                                 vColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
01604                                 }
01605                                 else
01606                                 {
01607                                         if (fX>=1.f)
01608                                         {
01609                                                 NLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);
01610                                                 NLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)-1]);
01611                                                 vColor=vColor1*(0.5f+fVirgule)+vColor2*(0.5f-fVirgule);
01612                                         }
01613                                         else
01614                                                 vColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
01615                                 }
01616                                 *(pItermPtr++)=vColor;
01617                                 fX+=fXdelta;
01618                         }
01619                         pSrc+=nSrcWidth;
01620                 }
01621         }
01622         else if (bXEq)
01623         {
01624                 NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
01625                 for (sint32 nY=0; nY<nSrcHeight; nY++)
01626                 {
01627                         const NLMISC::CRGBA *pSrcLine=pSrc;
01628                         sint32 nX;
01629                         for (nX=0; nX<nDestWidth; nX++)
01630                                 *(pItermPtr++)=NLMISC::CRGBAF (pSrcLine[nX]);
01631                         pSrc+=nSrcWidth;
01632                 }
01633         }
01634         else
01635         {
01636                 double fXdelta=(double)(nSrcWidth)/(double)(nDestWidth);
01637                 nlassert (fXdelta>1.f);
01638                 NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
01639                 sint32 nY;
01640                 for (nY=0; nY<nSrcHeight; nY++)
01641                 {
01642                         const NLMISC::CRGBA *pSrcLine=pSrc;
01643                         double fX=0.f;
01644                         sint32 nX;
01645                         for (nX=0; nX<nDestWidth; nX++)
01646                         {
01647                                 NLMISC::CRGBAF vColor (0.f, 0.f, 0.f, 0.f);
01648                                 double fFinal=fX+fXdelta;
01649                                 while (fX<fFinal)
01650                                 {
01651                                         double fNext=(double)floor (fX)+1.f;
01652                                         if (fNext>fFinal)
01653                                                 fNext=fFinal;
01654                                         vColor+=((float)(fNext-fX))*NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
01655                                         fX=fNext;
01656                                 }
01657                                 nlassert (fX==fFinal);
01658                                 vColor/=(float)fXdelta;
01659                                 *(pItermPtr++)=vColor;
01660                         }
01661                         pSrc+=nSrcWidth;
01662                 }
01663         }
01664                                 
01665         if (bYMag)
01666         {
01667                 double fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);
01668                 sint32 nX;
01669                 for (nX=0; nX<nDestWidth; nX++)
01670                 {
01671                         double fY=0.f;
01672                         sint32 nY;
01673                         for (nY=0; nY<nDestHeight; nY++)
01674                         {
01675                                 double fVirgule=fY-(double)floor(fY);
01676                                 nlassert (fVirgule>=0.f);
01677                                 NLMISC::CRGBAF vColor;
01678                                 if (fVirgule>=0.5f)
01679                                 {
01680                                         if (fY<(double)(nSrcHeight-1))
01681                                         {
01682                                                 NLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
01683                                                 NLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))+1)*nDestWidth+nX];
01684                                                 vColor=vColor1*(1.5f-(float)fVirgule)+vColor2*((float)fVirgule-0.5f);
01685                                         }
01686                                         else
01687                                                 vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
01688                                 }
01689                                 else
01690                                 {
01691                                         if (fY>=1.f)
01692                                         {
01693                                                 NLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
01694                                                 NLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))-1)*nDestWidth+nX];
01695                                                 vColor=vColor1*(0.5f+(float)fVirgule)+vColor2*(0.5f-(float)fVirgule);
01696                                         }
01697                                         else
01698                                                 vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
01699                                 }
01700                                 pDest[nX+nY*nDestWidth]=vColor;
01701                                 fY+=fYdelta;
01702                         }
01703                 }
01704         }
01705         else if (bYEq)
01706         {
01707                 for (sint32 nX=0; nX<nDestWidth; nX++)
01708                 {
01709                         sint32 nY;
01710                         for (nY=0; nY<nDestHeight; nY++)
01711                         {
01712                                 pDest[nX+nY*nDestWidth]=pIterm[nY*nDestWidth+nX];
01713                         }
01714                 }
01715         }
01716         else
01717         {
01718                 double fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);
01719                 nlassert (fYdelta>1.f);
01720                 sint32 nX;
01721                 for (nX=0; nX<nDestWidth; nX++)
01722                 {
01723                         double fY=0.f;
01724                         sint32 nY;
01725                         for (nY=0; nY<nDestHeight; nY++)
01726                         {
01727                                 NLMISC::CRGBAF vColor (0.f, 0.f, 0.f, 0.f);
01728                                 double fFinal=fY+fYdelta;
01729                                 while ((fY<fFinal)&&((sint32)fY!=nSrcHeight))
01730                                 {
01731                                         double fNext=(double)floor (fY)+1.f;
01732                                         if (fNext>fFinal)
01733                                                 fNext=fFinal;
01734                                         vColor+=((float)(fNext-fY))*pIterm[((sint32)floor(fY))*nDestWidth+nX];
01735                                         fY=fNext;
01736                                 }
01737                                 vColor/=(float)fYdelta;
01738                                 pDest[nX+nY*nDestWidth]=vColor;
01739                         }
01740                 }
01741         }
01742 }
01743 
01744 
01745 
01746 /*-------------------------------------------------------------------*\
01747                                                         readTGA
01748 \*-------------------------------------------------------------------*/
01749 uint8 CBitmap::readTGA( NLMISC::IStream &f)
01750 {
01751         if(!f.isReading()) return 0;
01752 
01753         uint32                  size;
01754         uint32                  x,y;
01755         sint32                  slsize;
01756         uint8                   *scanline;
01757         uint8                   r,g,b;
01758         sint32                  i,j,k;
01759 
01760         // TGA file header fields
01761         uint8   lengthID;
01762         uint8   cMapType;
01763         uint8   imageType;
01764         uint16  origin;
01765         uint16  length;
01766         uint8   depth;
01767         uint16  xOrg;
01768         uint16  yOrg;
01769         uint16  width;
01770         uint16  height;
01771         uint8   imageDepth;
01772         uint8   desc;
01773 
01774         // Image/Color map data
01775         uint8 *imageID;
01776         
01777         
01778         
01779         // Determining whether file is in Original or New TGA format
01780         
01781         bool newTgaFormat;
01782         uint32 extAreaOffset;
01783         uint32 devDirectoryOffset;
01784         char signature[16];
01785 
01786         f.seek (0, f.end);
01787         newTgaFormat = false;
01788         if (f.getPos() >= 26)
01789         {
01790                 f.seek (-26, f.end);
01791                 f.serial(extAreaOffset);
01792                 f.serial(devDirectoryOffset);
01793                 for(i=0; i<16; i++)
01794                 {
01795                         f.serial(signature[i]);
01796                 }
01797                 if(strncmp(signature,"TRUEVISION-XFILE",16)==0)
01798                         newTgaFormat = true;
01799         }
01800 
01801 
01802 
01803         // Reading TGA file header
01804         f.seek (0, f.begin);
01805                 
01806         f.serial(lengthID);
01807         f.serial(cMapType);
01808         f.serial(imageType);
01809         f.serial(origin);
01810         f.serial(length);
01811         f.serial(depth);
01812         f.serial(xOrg);
01813         f.serial(yOrg);
01814         f.serial(width);
01815         f.serial(height);
01816         f.serial(imageDepth);
01817         f.serial(desc);
01818 
01819         if(cMapType!=0)
01820         {
01821                 nlinfo("readTga : color-map not supported");
01822         }
01823 
01824         if(lengthID>0)
01825         {
01826                 imageID = new uint8[lengthID];
01827                 for(i=0; i<lengthID; i++)
01828                         f.serial(imageID[i]);
01829         }
01830 
01831 
01832 
01833         // Reading TGA image data
01834         
01835         _Width = width;
01836         _Height = height;
01837         size = _Width * _Height * (imageDepth/8);
01838         
01839         switch(imageType)
01840         {
01841                 // Uncompressed RGB or RGBA
01842                 case 2:
01843                 {
01844                         _Data[0].resize(_Width*_Height*4);
01845                         uint8 upSideDown = ((desc & (1 << 5))==0);
01846                         slsize = _Width * imageDepth / 8;
01847 
01848                         scanline = new uint8[slsize];
01849                         if(!scanline)
01850                         {
01851                                 throw EAllocationFailure();
01852                         }
01853 
01854                         for(y=0; y<_Height;y++)
01855                         {
01856                                 // Serial buffer: more efficient way to load.
01857                                 f.serialBuffer (scanline, slsize);
01858 
01859                                 if(imageDepth==24 || imageDepth==32)
01860                                 {
01861                                         sint32 mult = 3;
01862                                         if(imageDepth==16)
01863                                         {
01864                                                 mult = 2;
01865                                         }
01866                                         if(imageDepth==32)  
01867                                         {
01868                                                 mult = 4;
01869                                         }
01870                                         if(imageDepth!=16)
01871                                         {
01872                                                 for(x=0; x<_Width; x++)
01873                                                 {
01874                                                         // RGB(A)
01875                                                         r = scanline[x*mult+0];
01876                                                         g = scanline[x*mult+1];
01877                                                         b = scanline[x*mult+2];
01878                                                         // Switching to BGR(A)
01879                                                         scanline[x*mult+0] = b;
01880                                                         scanline[x*mult+1] = g;
01881                                                         scanline[x*mult+2] = r;
01882                                                 }
01883                                         }
01884                                 }
01885                                 
01886                                 k=0;
01887                                 for(i=0; i<width; i++) 
01888                                 {
01889                                         if(upSideDown)
01890                                         {
01891                                                 if(imageDepth==16)
01892                                                 {
01893                                                         uint16 toto = (uint16)scanline[k++];
01894                                                         toto |= scanline[k++]<<8;
01895                                                         uint r = toto>>10;
01896                                                         uint g = (toto>>5)&0x1f;
01897                                                         uint b = toto&0x1f;
01898                                                         _Data[0][(height-y-1)*width*4 + 4*i] = (r<<3) | (r>>2);
01899                                                         _Data[0][(height-y-1)*width*4 + 4*i + 1] = (g<<3) | (g>>2);
01900                                                         _Data[0][(height-y-1)*width*4 + 4*i + 2] = (b<<3) | (b>>2);
01901                                                         _Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;
01902                                                 }
01903                                                 else
01904                                                 {
01905                                                         _Data[0][(height-y-1)*width*4 + 4*i] = scanline[k++];
01906                                                         _Data[0][(height-y-1)*width*4 + 4*i + 1] = scanline[k++];
01907                                                         _Data[0][(height-y-1)*width*4 + 4*i + 2] = scanline[k++];
01908                                                         if(imageDepth==32)
01909                                                                 _Data[0][(height-y-1)*width*4 + 4*i + 3] = scanline[k++];
01910                                                         else
01911                                                                 _Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;
01912                                                 }
01913                                         }
01914                                         else
01915                                         {
01916                                                 if(imageDepth==16)
01917                                                 {
01918                                                         uint16 toto = (uint16)scanline[k++];
01919                                                         toto |= scanline[k++]<<8;
01920                                                         int r = toto>>10;
01921                                                         int g = toto&(0x3e0)>>5;
01922                                                         int b = toto&0x1f;
01923                                                         _Data[0][y*width*4 + 4*i] = (r<<3) | (r>>2);
01924                                                         _Data[0][y*width*4 + 4*i + 1] = (g<<3) | (g>>2);
01925                                                         _Data[0][y*width*4 + 4*i + 2] = (b<<3) | (b>>2);
01926                                                         _Data[0][y*width*4 + 4*i + 3] = 255;
01927                                                 }
01928                                                 else
01929                                                 {
01930                                                         _Data[0][y*width*4 + 4*i] = scanline[k++];
01931                                                         _Data[0][y*width*4 + 4*i + 1] = scanline[k++];
01932                                                         _Data[0][y*width*4 + 4*i + 2] = scanline[k++];
01933                                                         if(imageDepth==32)
01934                                                                 _Data[0][y*width*4 + 4*i + 3] = scanline[k++];
01935                                                         else
01936                                                                 _Data[0][y*width*4 + 4*i + 3] = 255;
01937                                                 }
01938                                         }       
01939                                 }
01940                         }
01941 
01942                         PixelFormat = RGBA;
01943                         delete scanline;
01944                 };
01945                 break;
01946                 
01947                 // Uncompressed Grayscale bitmap
01948                 case 3:
01949                 {
01950                         _Data[0].resize(_Width*_Height);
01951                         uint8 upSideDown = ((desc & (1 << 5))==0);
01952                         slsize = _Width;
01953 
01954                         scanline = new uint8[slsize];
01955                         if(!scanline)
01956                         {
01957                                 throw EAllocationFailure();
01958                         }
01959 
01960                         for(y=0; y<_Height;y++)
01961                         {
01962                                 // Serial buffer: more efficient way to load.
01963                                 f.serialBuffer (scanline, slsize);
01964 
01965                                 k=0;
01966                                 for(i=0; i<width; i++) 
01967                                 {
01968                                         if(upSideDown)
01969                                                 _Data[0][(height-y-1)*width + i] = scanline[k++];
01970                                         else
01971                                                 _Data[0][y*width + i] = scanline[k++];
01972                                 }
01973                         }
01974 
01975                         PixelFormat = _LoadGrayscaleAsAlpha?Alpha:Luminance;
01976                         delete scanline;
01977                 };
01978                 break;
01979 
01980                 // Compressed RGB or RGBA
01981                 case 10:
01982                 {
01983                         uint8 packet;
01984                         uint8 pixel[4];
01985                         uint32 imageSize = width*height;
01986                         uint32 readSize = 0;
01987                         _Data[0].reserve(_Width*_Height*4);
01988 
01989                         while(readSize < imageSize)
01990                         {
01991                                 f.serial(packet);
01992                                 if((packet & 0x80) > 0) // packet RLE 
01993                                 { 
01994                                         for(i=0; i<imageDepth/8; i++)
01995                                         {
01996                                                 f.serial(pixel[i]);
01997                                         }
01998                                         for (i=0; i < (packet & 0x7F) + 1; i++)
01999                                         {
02000                                                 for(j=0; j<imageDepth/8; j++)
02001                                                 {
02002                                                         _Data[0].push_back(pixel[j]);
02003                                                 }
02004                                                 if(imageDepth==24)
02005                                                 {
02006                                                         _Data[0].push_back(0);
02007                                                 }
02008                                         }
02009                                 }
02010                                 else    // packet Raw 
02011                                 { 
02012                                         for(i=0; i<((packet & 0x7F) + 1); i++)
02013                                         {
02014                                                 for(j=0; j<imageDepth/8; j++)
02015                                                 {
02016                                                         f.serial(pixel[j]);
02017                                                 }
02018                                                 if(imageDepth==32)
02019                                                 {
02020                                                         _Data[0].push_back(pixel[2]);
02021                                                         _Data[0].push_back(pixel[1]);
02022                                                         _Data[0].push_back(pixel[0]);
02023                                                         _Data[0].push_back(pixel[3]);
02024                                                 }
02025                                                 if(imageDepth==24)
02026                                                 {
02027                                                         _Data[0].push_back(pixel[2]);
02028                                                         _Data[0].push_back(pixel[1]);
02029                                                         _Data[0].push_back(pixel[0]);
02030                                                         _Data[0].push_back(0);
02031                                                 }
02032                                         }
02033                                 }
02034                                 readSize += (packet & 0x7F) + 1;
02035                         }
02036                         PixelFormat = RGBA;
02037                 };
02038                 break;
02039 
02040                 // Compressed Grayscale bitmap (not tested)
02041                 case 11:
02042                 {
02043                         uint8 packet;
02044                         uint8 pixel[4];
02045                         uint32 imageSize = width*height;
02046                         uint32 readSize = 0;
02047                         _Data[0].reserve(_Width*_Height);
02048 
02049                         while(readSize < imageSize)
02050                         {
02051                                 f.serial(packet);
02052                                 if((packet & 0x80) > 0) // packet RLE 
02053                                 { 
02054                                         f.serial(pixel[0]);
02055                                         for (i=0; i < (packet & 0x7F) + 1; i++)
02056                                         {
02057                                                 _Data[0].push_back(pixel[0]);
02058                                         }
02059                                 }
02060                                 else    // packet Raw 
02061                                 { 
02062                                         for(i=0; i<((packet & 0x7F) + 1); i++)
02063                                         {
02064                                                 f.serial(pixel[0]);
02065                                                 _Data[0].push_back(pixel[0]);
02066                                         }
02067                                 }
02068                                 readSize += (packet & 0x7F) + 1;
02069                         }
02070                         PixelFormat = _LoadGrayscaleAsAlpha?Alpha:Luminance;
02071                 };
02072                 break;
02073 
02074                 default:
02075                         return 0;
02076         }
02077 
02078         _MipMapCount = 1;
02079         return(imageDepth);
02080 
02081 }
02082 
02083 /*-------------------------------------------------------------------*\
02084                                                         writeTGA
02085 \*-------------------------------------------------------------------*/
02086 bool CBitmap::writeTGA( NLMISC::IStream &f, uint32 d, bool upsideDown)
02087 {
02088         if(f.isReading()) return false;
02089         if(d!=24 && d!=32 && d!=16 && d!=8) return false;
02090         if ((PixelFormat != RGBA)&&(PixelFormat != Alpha)) return false;
02091         if ((PixelFormat == Alpha) && (d != 8)) return false;
02092 
02093         sint32  i,j,x,y;
02094         uint8   * scanline;
02095         uint8   r,g,b,a;
02096 
02097         uint8   lengthID = 0;
02098         uint8   cMapType = 0;
02099         uint8   imageType = 2;
02100         uint16  origin = 0;
02101         uint16  length = 0;
02102         uint8   depth = 0;
02103         uint16  xOrg = 0;
02104         uint16  yOrg = 0;
02105         uint16  width = (uint16)_Width;
02106         uint16  height = (uint16)_Height;
02107         uint8   imageDepth = (uint8)d;
02108         uint8   desc = 0;
02109         if (upsideDown)
02110                 desc |= 1<<5;
02111 
02112         if (PixelFormat == Alpha)
02113                 imageType = 3; // Uncompressed grayscale
02114 
02115         f.serial(lengthID);
02116         f.serial(cMapType);
02117         f.serial(imageType);
02118         f.serial(origin);
02119         f.serial(length);
02120         f.serial(depth);
02121         f.serial(xOrg);
02122         f.serial(yOrg);
02123         f.serial(width);
02124         f.serial(height);
02125         f.serial(imageDepth);
02126         f.serial(desc);
02127 
02128         if (PixelFormat == Alpha)
02129                 scanline = new uint8[width];
02130         else
02131                 scanline = new uint8[width*4];
02132         if(!scanline)
02133         {
02134                 throw EAllocationFailure();
02135         }
02136 
02137         for(y=0; y<(sint32)height; y++)
02138         {
02139                 
02140                 uint32 k=0;
02141                 if (PixelFormat == Alpha)
02142                 for(i=0; i<width; ++i) // Alpha
02143                 {
02144                         scanline[k++] = _Data[0][(height-y-1)*width + i];
02145                 }
02146                 else
02147                 for(i=0; i<width*4; i+=4) // 4:RGBA
02148                 {
02149                         if(d==16)
02150                         {
02151                                 for(j=0; j<(sint32)4; j++)
02152                                 {
02153                                         scanline[k++] = _Data[0][(height-y-1)*width*4 + i + j];
02154                                 }
02155                         }
02156                         else
02157                         {
02158                                 for(j=0; j<(sint32)d/8; j++)
02159                                 {
02160                                         scanline[k++] = _Data[0][(height-y-1)*width*4 + i + j];
02161                                 }
02162                         }
02163                 }
02164                 
02165                 if(d==16)
02166                 {
02167                         for(x=0; x<(sint32)width; x++)
02168                         {
02169                                 r = scanline[x*4+0];
02170                                 g = scanline[x*4+1];
02171                                 b = scanline[x*4+2];
02172                                 int rr = r >>3;
02173                                 int gg = g >>3;
02174                                 int bb = b >>3;
02175                                 uint16 c16 = (rr<<10) | (gg<<5) | bb;
02176                                 scanline[x*2+0] = c16&0xff;
02177                                 scanline[x*2+1] = c16>>8;
02178                         }
02179                 }
02180                 if(d==24)
02181                 {
02182                         for(x=0; x<(sint32)width; x++)
02183                         {
02184                                 r = scanline[x*3+0];
02185                                 g = scanline[x*3+1];
02186                                 b = scanline[x*3+2];
02187                                 scanline[x*3+0] = b;
02188                                 scanline[x*3+1] = g;
02189                                 scanline[x*3+2] = r;
02190                         }
02191                 }
02192                 if(d==32)
02193                 {
02194                         for(x=0; x<(sint32)width; x++)
02195                         {
02196                                 r = scanline[x*4+0];
02197                                 g = scanline[x*4+1];
02198                                 b = scanline[x*4+2];
02199                                 a= scanline[x*4+3];
02200                                 scanline[x*4+0] = b;
02201                                 scanline[x*4+1] = g;
02202                                 scanline[x*4+2] = r;                            
02203                                 scanline[x*4+3] = a;
02204                         }
02205                 }
02206                 
02207                 int finaleSize=width*d/8;
02208                 for(i=0; i<finaleSize; i++)
02209                 {
02210                         f.serial(scanline[i]);
02211                 }               
02212         }
02213         delete scanline;
02214         return true;
02215 }
02216 
02217 template<class T>
02218 void rotateCCW (const T* src, T* dst, uint srcWidth, uint srcHeight)
02219 {
02220         for (uint y=0; y<srcHeight; y++)
02221         for (uint x=0; x<srcWidth; x++)
02222         {
02223                 uint dstX=y;
02224                 uint dstY=srcWidth-x-1;
02225                 dst[dstX+dstY*srcHeight]=src[x+y*srcWidth];
02226         }
02227 }
02228 
02229 /*template<class T>
02230 void rotateCCW (const vector<T>& src, vector<T>& dst, uint srcWidth, uint srcHeight)
02231 {
02232         for (uint y=0; y<srcHeight; y++)
02233         for (uint x=0; x<srcWidth; x++)
02234         {
02235                 uint dstX=y;
02236                 uint dstY=srcWidth-x;
02237                 dst[dstX+dstY*srcHeight]=src[x+y*srcWidth];
02238         }
02239 }
02240 */
02241 void CBitmap::rotateCCW()
02242 {
02243         // Copy the array
02244         std::vector<uint8> copy=_Data[0];
02245 
02246         switch (PixelFormat)
02247         {
02248         case RGBA:
02249                 NLMISC::rotateCCW ((uint32*)&(_Data[0][0]), (uint32*)&(copy[0]), _Width, _Height);
02250                 break;
02251         case Luminance:
02252         case Alpha:
02253                 NLMISC::rotateCCW (&_Data[0][0], &copy[0], _Width, _Height);
02254                 break;
02255         case AlphaLuminance:
02256                 NLMISC::rotateCCW ((uint16*)&(_Data[0][0]), (uint16*)&(copy[0]), _Width, _Height);;
02257                 break;
02258         default: break;
02259         }
02260 
02261         uint32 tmp=_Width;
02262         _Width=_Height;
02263         _Height=tmp;
02264         _Data[0]=copy;
02265 }
02266 
02267 bool CBitmap::blit(const CBitmap *src, sint32 x, sint32 y)
02268 {
02269         
02270         nlassert(this->PixelFormat == src->PixelFormat);
02271         if (this->PixelFormat != src->PixelFormat)
02272         {
02273                 return false;
02274         }
02275 
02276 
02277         // check for dxtc use
02278 
02279         const bool useDXTC   =  PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha || PixelFormat == DXTC3 || PixelFormat ==     DXTC5;
02280 
02281         // number of bits for a 4x4 pix block
02282         const uint dxtcNumBits  =  PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha ? 64 : 128;
02283         
02284 
02285         if (useDXTC)
02286         {
02287                 // blit pos must be multiple of 4
02288 
02289                 nlassert(! (x & 3 || y & 3) );
02290                 if (x & 3 || y & 3) return false;
02291 
02292         }
02293 
02294         nlassert(PixelFormat != DonTKnow);
02295 
02296         // the width to copy
02297         sint width = src->_Width;
02298         // the height to copy
02299         sint height = src->_Height;
02300 
02301         uint destStartX, destStartY;
02302         uint srcStartX, srcStartY;
02303 
02304 
02305         // clip against left
02306         if (x < 0)
02307         {
02308                 width += x;
02309                 if (width <= 0) return true;
02310                 destStartX = 0;
02311                 srcStartX = -x;
02312         }
02313         else
02314         {
02315                 destStartX = x;
02316                 srcStartX = 0;
02317         }
02318 
02319         // clip against top
02320         if (y < 0)
02321         {
02322                 height += y;
02323                 if (height <= 0) return true;
02324                 srcStartY = -y;
02325                 destStartY = 0;
02326         }
02327         else
02328         {
02329                 destStartY = y;
02330                 srcStartY = 0;
02331         }
02332 
02333         // clip against right
02334         if ((destStartX + width - 1) >= _Width)
02335         {
02336                 width = _Width - destStartX;
02337                 if (width <= 0) return true;
02338         }
02339 
02340         // clip against bottom
02341         if ((destStartY + height - 1) >= _Height)
02342         {
02343                 height = _Height - destStartY;
02344                 if (width <= 0) return true;
02345         }
02346 
02347 
02348         // divide all distance by 4 when using DXTC
02349         if (useDXTC)
02350         {
02351                 destStartX >>= 2;
02352                 destStartY >>= 2;
02353                 srcStartX >>= 2;
02354                 srcStartY >>= 2;
02355                 width >>= 2;
02356                 height >>= 2;
02357         }
02358         
02359 
02360         // bytes per pixs is for either one pixel or 16 (a 4x4 block in DXTC)
02361         const uint bytePerPixs = ( useDXTC ? dxtcNumBits : bitPerPixels[PixelFormat] ) >> 3 /* divide by 8 to get the number of bytes */;
02362 
02363 
02364         const uint destRealWidth = useDXTC ? (_Width >> 2) : _Width;
02365         const uint srcRealWidth = useDXTC ? (src->_Width >> 2) : src->_Width;
02366         
02367 
02368         // size to go to the next line in the destination
02369         const uint destStride = destRealWidth * bytePerPixs;
02370 
02371         // size to go to the next line in the source
02372         const uint srcStride = srcRealWidth * bytePerPixs;
02373         
02374         // length in bytes of a line to copy
02375         const uint lineLength = width * bytePerPixs;
02376 
02377 
02378         uint8  *destPos = &(_Data[0][0]) + destStride * destStartY + bytePerPixs * destStartX;
02379         const uint8 *srcPos = &(src->_Data[0][0]) + srcStride * srcStartY + bytePerPixs * srcStartX;
02380 
02381         // copy each hline
02382         for (sint k = 0; k < height; ++k)
02383         {
02384                 ::memcpy(destPos, srcPos, lineLength);
02385                 destPos += destStride;
02386                 srcPos += srcStride;
02387         }
02388 
02389         
02390         return true;
02391 }
02392 
02393 // Private :
02394 float CBitmap::getColorInterp (float x, float y, float colorInXY00, float colorInXY10, float colorInXY01, float colorInXY11) const
02395 {
02396         float res =     colorInXY00*(1.0f-x)*(1.0f-y) +
02397                                 colorInXY10*(     x)*(1.0f-y) +
02398                                 colorInXY01*(1.0f-x)*(     y) +
02399                                 colorInXY11*(     x)*(     y);
02400         clamp (res, 0.0f, 255.0f);
02401         return res;
02402 }
02403 
02404 // Public:
02405 CRGBAF CBitmap::getColor (float x, float y) const
02406 {
02407         if (x < 0.0f) x = 0.0f;
02408         if (x > 1.0f) x = 1.0f;
02409         if (y < 0.0f) y = 0.0f;
02410         if (y > 1.0f) y = 1.0f;
02411 
02412         sint32 nWidth = getWidth(0);
02413         sint32 nHeight = getHeight(0);
02414 
02415         if (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);
02416 
02417         const std::vector<uint8> &rBitmap = getPixels(0);
02418         sint32 nX[4], nY[4];
02419 
02420         x *= nWidth-1;
02421         y *= nHeight-1;
02422 
02423         // Integer part of (x,y)
02424         //nX[0] = ((sint32)floor(x-0.5f));
02425         //nY[0] = ((sint32)floor(y-0.5f));
02426         nX[0] = ((sint32)floor(x));
02427         nY[0] = ((sint32)floor(y));
02428 
02429         nX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);
02430         nY[1] = nY[0];
02431 
02432         nX[2] = nX[0];
02433         nY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);
02434 
02435         nX[3] = nX[1];
02436         nY[3] = nY[2];
02437 
02438         uint32 i;
02439 
02440         for (i = 0; i < 4; ++i)
02441         {
02442                 nlassert (nX[i] >= 0);
02443                 nlassert (nY[i] >= 0 );
02444                 nlassert (nX[i] < nWidth);
02445                 nlassert (nY[i] < nHeight);
02446         }
02447 
02448         // Decimal part of (x,y)
02449         x = x - (float)nX[0]; 
02450         y = y - (float)nY[0];
02451 
02452         switch (this->PixelFormat)
02453         {
02454                 case RGBA:
02455                 case DXTC1:
02456                 case DXTC1Alpha:
02457                 case DXTC3:
02458                 case DXTC5:
02459                 {                                                                       
02460                         CRGBAF finalVal;
02461                         CRGBA val[4];
02462 
02463                         if (this->PixelFormat == RGBA)
02464                         {
02465                                 for (i = 0; i < 4; ++i)
02466                                 {
02467                                         val[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],
02468                                                                         rBitmap[(nX[i]+nY[i]*nWidth)*4+1],
02469                                                                         rBitmap[(nX[i]+nY[i]*nWidth)*4+2],
02470                                                                         rBitmap[(nX[i]+nY[i]*nWidth)*4+3]);
02471                                 }
02472                         }
02473                         else
02474                         {
02475                                 // slower version : get from DXT
02476                                 for (i = 0; i < 4; ++i)
02477                                 {
02478                                         val[i] = getPixelColor(nX[i], nY[i]);
02479                                 }
02480                         }
02481 
02482                         finalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);
02483                         finalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);
02484                         finalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);
02485                         finalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);
02486 
02487                         return finalVal;                        
02488                 }
02489                 break;
02490                 case Alpha:
02491                 case Luminance:
02492                 {
02493                         
02494                         float finalVal;
02495                         float val[4];
02496 
02497                         for (i = 0; i < 4; ++i)
02498                                 val[i] = rBitmap[(nX[i]+nY[i]*nWidth)];
02499 
02500                         finalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);
02501 
02502                         if (this->PixelFormat == Alpha)
02503                                 return CRGBAF (255.0f, 255.0f, 255.0f, finalVal);
02504                         else // Luminance
02505                                 return CRGBAF (finalVal, finalVal, finalVal, 255.0f);
02506                 }
02507                 break;
02508                 default: break;
02509         }
02510 
02511         return CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);
02512 }
02513 
02514 
02515 void    CBitmap::loadSize(NLMISC::IStream &f, uint32 &retWidth, uint32 &retHeight)
02516 {
02517         retWidth= 0;
02518         retHeight= 0;
02519 
02520 
02521         nlassert(f.isReading()); 
02522         
02523         // testing if DDS
02524         uint32 fileType = 0;
02525         f.serial(fileType);
02526         if(fileType == DDS)
02527         {
02528                 // read entire DDS header.
02529                 uint32 size = 0;
02530                 f.serial(size); // size in Bytes of header(without "DDS")
02531                 uint32 * _DDSSurfaceDesc = new uint32[size]; 
02532                 std::auto_ptr<uint32> _DDSSurfaceDescAuto(_DDSSurfaceDesc);
02533                 _DDSSurfaceDesc[0]= size;
02534 
02535                 for(uint i= 0; i<size/4 - 1; i++)
02536                 {
02537                         f.serial(_DDSSurfaceDesc[i+1]);
02538                 }
02539                 
02540                 // flags determines which members of the header structure contain valid data
02541                 uint32 flags = _DDSSurfaceDesc[1];
02542 
02543                 //verify if file have linearsize set
02544                 if(!(flags & DDSD_LINEARSIZE)) 
02545                 {
02546                         throw EDDSBadHeader();
02547                 }
02548                 
02549                 //-------------- extracting and testing useful info
02550                 retWidth = _DDSSurfaceDesc[2];
02551                 retHeight  = _DDSSurfaceDesc[3];
02552         }
02553         // assuming it's TGA
02554         else 
02555         {
02556                 if(!f.seek (0, NLMISC::IStream::begin))
02557                 {
02558                         throw ESeekFailed();
02559                 }
02560 
02561                 // Reading header, 
02562                 // To make sure that the bitmap is TGA, we check imageType and imageDepth.
02563                 uint8   lengthID;
02564                 uint8   cMapType;
02565                 uint8   imageType;
02566                 uint16  tgaOrigin;
02567                 uint16  length;
02568                 uint8   depth;
02569                 uint16  xOrg;
02570                 uint16  yOrg;
02571                 uint16  width;
02572                 uint16  height;
02573                 uint8   imageDepth;
02574                 uint8   desc;
02575                 
02576                 f.serial(lengthID);
02577                 f.serial(cMapType);
02578                 f.serial(imageType);
02579                 if(imageType!=2 && imageType!=3 && imageType!=10 && imageType!=11) return;
02580                 f.serial(tgaOrigin);
02581                 f.serial(length);
02582                 f.serial(depth);
02583                 f.serial(xOrg);
02584                 f.serial(yOrg);
02585                 f.serial(width);
02586                 f.serial(height);
02587                 f.serial(imageDepth);
02588                 if(imageDepth!=8 && imageDepth!=24 && imageDepth!=32) return;
02589                 f.serial(desc);
02590 
02591                 // Ok, we have width and height.
02592                 retWidth= width;
02593                 retHeight= height;
02594         }
02595 
02596         // reset stream.
02597         if(!f.seek (0, NLMISC::IStream::begin))
02598         {
02599                 throw ESeekFailed();
02600         }
02601 }
02602 
02603 
02604 void    CBitmap::loadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight)
02605 {
02606         retWidth= 0;
02607         retHeight= 0;
02608 
02609         CIFile          f(path);
02610         if(f.open(path))
02611                 loadSize(f, retWidth, retHeight);
02612 }
02613 
02614 
02615 void    CBitmap::flipH()
02616 {
02617         if (PixelFormat != RGBA)
02618                 return;
02619 
02620         sint32 nWidth = getWidth(0);
02621         sint32 nHeight = getHeight(0);
02622         sint32 i, j;
02623         NLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];
02624         bool needRebuild = false;
02625         CRGBA temp;
02626 
02627         if(_MipMapCount>1)
02628                 needRebuild = true;
02629         releaseMipMaps();
02630 
02631         for( i = 0; i < nHeight; ++i )
02632                 for( j = 0; j < nWidth/2; ++j )
02633                 {
02634                         temp = pBitmap[i*nWidth+j];
02635                         pBitmap[i*nWidth+j] = pBitmap[i*nWidth+nWidth-j-1];
02636                         pBitmap[i*nWidth+nWidth-j-1] = temp;
02637                 }
02638 
02639         // Rebuilding mipmaps
02640         if(needRebuild)
02641         {
02642                 buildMipMaps();
02643         }
02644 }
02645 
02646 
02647 void    CBitmap::flipV()
02648 {
02649         if (PixelFormat != RGBA)
02650                 return;
02651 
02652         sint32 nWidth = getWidth(0);
02653         sint32 nHeight = getHeight(0);
02654         sint32 i, j;
02655         NLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];
02656         bool needRebuild = false;
02657         CRGBA temp;
02658 
02659         if(_MipMapCount>1)
02660                 needRebuild = true;
02661         releaseMipMaps();
02662 
02663         for( j = 0; j < nHeight/2; ++j )
02664                 for( i = 0; i < nWidth; ++i )
02665                 {
02666                         temp = pBitmap[j*nWidth+i];
02667                         pBitmap[j*nWidth+i] = pBitmap[(nHeight-j-1)*nWidth+i];
02668                         pBitmap[(nHeight-j-1)*nWidth+i] = temp;
02669                 }
02670 
02671         // Rebuilding mipmaps
02672         if(needRebuild)
02673         {
02674                 buildMipMaps();
02675         }
02676 }
02677 
02678 
02679 void    CBitmap::rot90CW()
02680 {
02681         if (PixelFormat != RGBA)
02682                 return;
02683         sint32 nWidth = getWidth(0);
02684         sint32 nHeight = getHeight(0);
02685         sint32 i, j;
02686         NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
02687         bool needRebuild = false;
02688 
02689         if(_MipMapCount>1)
02690                 needRebuild = true;
02691         releaseMipMaps();
02692 
02693         std::vector<uint8> pDestui;
02694         pDestui.resize(nWidth*nHeight*4);
02695         NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
02696 
02697         for( j = 0; j < nHeight; ++j )
02698         for( i = 0; i < nWidth;  ++i )
02699                 pDestRgba[j+i*nHeight] = pSrcRgba[i+(nHeight-1-j)*nWidth];
02700 
02701         uint32 nTemp = _Width;
02702         _Width = _Height;
02703         _Height = nTemp;
02704 
02705         NLMISC::contReset(_Data[0]); // free memory
02706         _Data[0] =  pDestui;
02707         // Rebuilding mipmaps
02708         if(needRebuild)
02709         {
02710                 buildMipMaps();
02711         }
02712 }
02713 
02714 void    CBitmap::rot90CCW()
02715 {
02716         if (PixelFormat != RGBA)
02717                 return;
02718         sint32 nWidth = getWidth(0);
02719         sint32 nHeight = getHeight(0);
02720         sint32 i, j;
02721         NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
02722         bool needRebuild = false;
02723 
02724         if(_MipMapCount>1)
02725                 needRebuild = true;
02726         releaseMipMaps();
02727 
02728         std::vector<uint8> pDestui;
02729         pDestui.resize(nWidth*nHeight*4);
02730         NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
02731 
02732         for( j = 0; j < nHeight; ++j )
02733         for( i = 0; i < nWidth;  ++i )
02734                 pDestRgba[j+i*nHeight] = pSrcRgba[nWidth-1-i+j*nWidth];
02735 
02736         uint32 nTemp = _Width;
02737         _Width = _Height;
02738         _Height = nTemp;
02739 
02740         NLMISC::contReset(_Data[0]); // free memory
02741         _Data[0] =  pDestui;
02742         // Rebuilding mipmaps
02743         if(needRebuild)
02744         {
02745                 buildMipMaps();
02746         }
02747 }
02748 
02749 //===========================================================================
02750 
02751 void CBitmap::blend(const CBitmap &Bm0, const CBitmap &Bm1, uint16 factor)
02752 {
02753         nlassert(factor <= 256);
02754 
02755         nlassert(Bm0._Width != 0 && Bm0._Height != 0
02756                          && Bm1._Width != 0 && Bm1._Height != 0);
02757 
02758         nlassert(Bm0._Width  == Bm1._Width);    // the bitmap should have the same size
02759         nlassert(Bm0._Height == Bm1._Height);
02760 
02761         const CBitmap *nBm0, *nBm1; // pointer to the bitmap that is used for blending, or to a copy is a conversion wa required
02762 
02763         CBitmap cp0, cp1; // these bitmap are copies of Bm1 and Bm0 if a conversion was needed
02764 
02765         if (Bm0.PixelFormat != RGBA)
02766         {
02767                 cp0 = Bm0;
02768                 cp0.convertToRGBA();
02769                 nBm0 = &cp0;
02770         }
02771         else
02772         {
02773                 nBm0 = &Bm0;
02774         }
02775 
02776 
02777         if (Bm1.PixelFormat != RGBA)
02778         {
02779                 cp1 = Bm1;
02780                 cp1.convertToRGBA();
02781                 nBm1 = &cp1;
02782         }
02783         else
02784         {
02785                 nBm1 = &Bm1;
02786         }
02787 
02788         this->resize(Bm0._Width, Bm0._Height, RGBA);
02789 
02790         const  uint numPix = _Width * _Height; // 4 component per pixels
02791 
02792 
02793         const uint8 *src0               = &(nBm0->_Data[0][0]);
02794         const uint8 *src1               = &(nBm1->_Data[0][0]);
02795         uint8 *dest                             = &(this->_Data[0][0]);
02796         uint8 *endPix                   = dest + (numPix << 2);
02797 
02798 
02799         uint blendFact    = (uint) factor;
02800         uint invblendFact = 256 - blendFact;
02801 
02802         do
02803         {
02805                 *dest = (uint8) (((blendFact * *src1)           + (invblendFact * *src0)) >> 8);
02806                 *(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);
02807                 *(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);
02808                 *(dest + 3)  = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);
02809 
02810                 src0 = src0 + 4;
02811                 src1 = src1 + 4;
02812                 dest = dest + 4;        
02813         }
02814         while (dest != endPix);
02815 }
02816 
02817 
02818 
02819 //-----------------------------------------------
02820 CRGBA CBitmap::getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const
02821 {
02822         uint w = getWidth(numMipMap);
02823         uint h = getHeight(numMipMap);
02824         if (w == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
02825         const uint8 *pix = &getPixels(numMipMap)[(x + y * w) << 2];
02826         return CRGBA(pix[0], pix[1], pix[2], pix[3]);
02827 }
02828 
02829 //-----------------------------------------------
02830 CRGBA CBitmap::getDXTCColorFromBlock(const uint8 *block, sint x, sint y)
02831 {
02832         uint16  col0;
02833         uint16  col1;
02834         memcpy(&col0, block, sizeof(uint16));
02835         memcpy(&col1, block + 2, sizeof(uint16));
02836         uint    colIndex = (block[4 + (y & 3)] >> ((x & 3) << 1)) & 3;
02837         CRGBA   result, c0, c1;
02838         if (col0 > col1)
02839         {       
02840                 switch(colIndex)
02841                 {
02842                         case 0:
02843                                 uncompress(col0, result);                               
02844                         break;
02845                         case 1:
02846                                 uncompress(col1, result);
02847                         break;
02848                         case 2:
02849                                 uncompress(col0, c0);
02850                                 uncompress(col1, c1);
02851                                 result.blendFromui(c0, c1, 85);
02852                         break;
02853                         case 3:
02854                                 uncompress(col0, c0);
02855                                 uncompress(col1, c1);
02856                                 result.blendFromui(c0, c1, 171);
02857                         break;
02858                 }
02859                 result.A = 255;
02860         }
02861         else
02862         {
02863                 switch(colIndex)
02864                 {
02865                         case 0:
02866                                 uncompress(col0, result);
02867                                 result.A = 255;
02868                         break;
02869                         case 1:
02870                                 uncompress(col1, result);
02871                                 result.A = 255;
02872                         break;
02873                         case 2:
02874                                 uncompress(col0, c0);
02875                                 uncompress(col1, c1);
02876                                 result.blendFromui(c0, c1, 128);
02877                                 result.A = 255;
02878                         break;
02879                         case 3:
02880                                 result.set(0, 0, 0, 0);                         
02881                         break;
02882                 }
02883         }       
02884         return result;
02885 }
02886 
02887 //-----------------------------------------------
02888 CRGBA CBitmap::getDXTC1Texel(sint x, sint y, uint32 numMipMap) const
02889 {
02890         uint w = getWidth(numMipMap);
02891         uint h = getHeight(numMipMap);
02892         if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases  
02893         uint numRowBlocks   = std::max((w + 3) >> 2, 1u);
02894         const uint8 *pix    = &getPixels(numMipMap)[0];
02895         const uint8 *block  = pix + ((y >> 2) * (numRowBlocks << 3) + ((x >> 2) << 3)); 
02896         return getDXTCColorFromBlock(block, x, y);
02897 }
02898 
02899 
02900 //-----------------------------------------------
02901 CRGBA CBitmap::getDXTC3Texel(sint x, sint y, uint32 numMipMap) const
02902 {
02903         uint w = getWidth(numMipMap);
02904         uint h = getHeight(numMipMap);
02905         if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases  
02906         uint numRowBlocks   = std::max((w + 3) >> 2, 1u);
02907         const uint8 *pix    = &getPixels(numMipMap)[0];
02908         const uint8 *block  = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4)); 
02909         CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
02910         // get alpha part
02911         uint8 alphaByte = block[((y & 3) << 1) + ((x & 2) >> 1)];
02912         result.A = (x & 1) ?  (alphaByte & 0xf0) : (alphaByte << 4);
02913         return result;
02914 }
02915 
02916 //-----------------------------------------------
02917 CRGBA CBitmap::getDXTC5Texel(sint x, sint y, uint32 numMipMap) const
02918 {
02919         uint w = getWidth(numMipMap);
02920         uint h = getHeight(numMipMap);
02921         if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases  
02922         uint numRowBlocks   = std::max((w + 3) >> 2, 1u);
02923         const uint8 *pix    = &getPixels(numMipMap)[0];
02924         const uint8 *block  = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4)); 
02925         CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
02926         // get alpha part
02927         uint8 alpha0 = block[0];
02928         uint8 alpha1 = block[1];
02929         
02930         uint alphaIndex;
02931         uint tripletIndex = (x & 3) + ((y & 3) << 2);
02932         if (tripletIndex < 8)
02933         {
02934                 alphaIndex = (((uint32 &) block[2]) >> (tripletIndex * 3)) & 7;
02935         }
02936         else
02937         {
02938                 alphaIndex = (((uint32 &) block[5]) >> ((tripletIndex - 8) * 3)) & 7; // we can read a dword there because there are color datas following he alpha datas
02939         }
02940 
02941         if (alpha0 > alpha1)
02942         {
02943                 switch (alphaIndex)
02944                 {
02945                         case 0: result.A = alpha0; break;
02946                         case 1: result.A = alpha1; break;
02947                         case 2: result.A = (uint8) ((6 * (uint) alpha0 + (uint) alpha1) / 7); break;
02948                         case 3: result.A = (uint8) ((5 * (uint) alpha0 + 2 * (uint) alpha1) / 7); break;
02949                         case 4: result.A = (uint8) ((4 * (uint) alpha0 + 3 * (uint) alpha1) / 7); break;
02950                         case 5: result.A = (uint8) ((3 * (uint) alpha0 + 4 * (uint) alpha1) / 7); break;
02951                         case 6: result.A = (uint8) ((2 * (uint) alpha0 + 5 * (uint) alpha1) / 7); break;
02952                         case 7: result.A = (uint8) (((uint) alpha0 + (uint) 6 * alpha1) / 7); break;
02953                 }
02954         }
02955         else
02956         {
02957                 switch (alphaIndex)
02958                 {
02959                         case 0: result.A = alpha0; break;
02960                         case 1: result.A = alpha1; break;
02961                         case 2: result.A = (uint8) ((4 * (uint) alpha0 + (uint) alpha1) / 5); break;
02962                         case 3: result.A = (uint8) ((3 * (uint) alpha0 + 2 * (uint) alpha1) / 5); break;
02963                         case 4: result.A = (uint8) ((2 * (uint) alpha0 + 3 * (uint) alpha1) / 5); break;
02964                         case 5: result.A = (uint8) (((uint) alpha0 + 4 * (uint) alpha1) / 5); break;
02965                         case 6: result.A = 0;   break;
02966                         case 7: result.A = 255; break;
02967                 }
02968         }
02969         return result;  
02970 }
02971 
02972 
02973 //-----------------------------------------------
02974 CRGBA CBitmap::getPixelColor(sint x, sint y, uint32 numMipMap /*=0*/) const
02975 {
02976         
02977         switch (PixelFormat)
02978         {
02979                 case RGBA:      
02980                         return getRGBAPixel(x, y, numMipMap);           
02981                 case DXTC1:
02982                 case DXTC1Alpha: 
02983                         return getDXTC1Texel(x, y, numMipMap);
02984                 case DXTC3:
02985                         return getDXTC3Texel(x, y, numMipMap);
02986                 case DXTC5:
02987                         return getDXTC5Texel(x, y, numMipMap);
02988                 default:
02989                         nlstop;
02990                 break;
02991         }
02992         return CRGBA::Black;
02993 }
02994 
02995 
02996 } // NLMISC