00001
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "stdmisc.h"
00029
00030 #include <memory>
00031 #include <algorithm>
00032
00033
00034
00035
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,
00071 8,
00072 8,
00073 16,
00074 4,
00075 4,
00076 8,
00077 8,
00078 16
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
00086 NLMISC::IStream *JPGStream = NULL;
00087 const uint32 JPGBufferSize = 1000;
00088 char JPGBuffer[JPGBufferSize];
00089
00090
00091
00092
00093
00094 uint8 CBitmap::load(NLMISC::IStream &f, uint mipMapSkip)
00095 {
00096 nlassert(f.isReading());
00097
00098
00099 uint32 fileType = 0;;
00100 f.serial(fileType);
00101 if(fileType == DDS)
00102 {
00103 return readDDS(f, mipMapSkip);
00104 }
00105
00106 else
00107 {
00108 NLMISC::IStream::TSeekOrigin origin= f.begin;
00109 if(!f.seek (0, origin))
00110 {
00111 throw ESeekFailed();
00112 }
00113
00114
00115
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
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
00215
00216 uint8 CBitmap::readDDS(NLMISC::IStream &f, uint mipMapSkip)
00217 {
00218
00219
00220
00221
00222 uint32 size = 0;
00223 f.serial(size);
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
00238 uint32 flags = _DDSSurfaceDesc[1];
00239
00240
00241 if(!(flags & DDSD_LINEARSIZE))
00242 {
00243 throw EDDSBadHeader();
00244 }
00245
00246
00247
00248 _Height = _DDSSurfaceDesc[2];
00249 _Width = _DDSSurfaceDesc[3];
00250 _MipMapCount= (uint8) _DDSSurfaceDesc[6];
00251
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];
00268
00269 if(PixelFormat==DXTC1 && _DDSSurfaceDesc[21]>0)
00270 {
00271 PixelFormat = DXTC1Alpha;
00272 }
00273
00274 if(PixelFormat!= DXTC1 && PixelFormat!= DXTC1Alpha && PixelFormat!= DXTC3 && PixelFormat!= DXTC5)
00275 {
00276 throw EDDSBadHeader();
00277 }
00278
00279
00280 uint minSizeLevel= min(_Width, _Height);
00281 minSizeLevel= getPowerOf2(minSizeLevel);
00282
00283
00284 if(_MipMapCount>1 && mipMapSkip>0 && minSizeLevel>2)
00285 {
00286
00287 mipMapSkip= min(mipMapSkip, minSizeLevel-2);
00288
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
00299 seekSize+= mipMapSz;
00300
00301
00302 _Width>>=1;
00303 _Height>>=1;
00304 _MipMapCount--;
00305 mipMapSkip--;
00306 }
00307
00308 if(seekSize>0)
00309 {
00310 if(!f.seek(seekSize, IStream::current))
00311 {
00312 throw ESeekFailed();
00313 }
00314 }
00315
00316 }
00317
00318
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
00351 vector<uint8> pixData;
00352 pixData.resize(totalSize);
00353 f.serialBuffer(&(*pixData.begin()), totalSize);
00354
00355
00356
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
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
00386
00387 bool CBitmap::convertToDXTC5()
00388 {
00389
00390
00391
00392
00393
00394
00395
00396 return false;
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 }
00427
00428
00429
00430
00431
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
00992
00993 uint32 blockNum= i/8;
00994
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
01010 if(wtmp==width && htmp==height)
01011 {
01012
01013 _Data[m]= dataTmp[m];
01014 }
01015 else
01016 {
01017
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
01030 width = (width+1)/2;
01031 height = (height+1)/2;
01032 }
01033 PixelFormat = RGBA;
01034 return true;
01035 }
01036
01037
01038
01039
01040
01041
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
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
01098 c[2].blendFromui(c[0],c[1],85);
01099 c[3].blendFromui(c[0],c[1],171);
01100
01101
01102
01103 uint32 blockNum= i/16;
01104
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
01120 if(wtmp==width && htmp==height)
01121 {
01122
01123 _Data[m]= dataTmp[m];
01124 }
01125 else
01126 {
01127
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
01140 width = (width+1)/2;
01141 height = (height+1)/2;
01142 }
01143 PixelFormat = RGBA;
01144 return true;
01145 }
01146
01147
01148
01149
01150
01151
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
01231 c[2].blendFromui(c[0],c[1],85);
01232 c[3].blendFromui(c[0],c[1],171);
01233
01234
01235
01236 uint32 blockNum= i/16;
01237
01238
01239 uint32 pixelsCount= (blockNum/wBlockCount)*wtmp*4 + 4*(blockNum%wBlockCount);
01240
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
01257 if(wtmp==width && htmp==height)
01258 {
01259
01260 _Data[m]= dataTmp[m];
01261 }
01262 else
01263 {
01264
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
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
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
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
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
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
01364
01365 uint32 CBitmap::getSize(uint32 numMipMap) const
01366 {
01367 return getHeight(numMipMap)*getWidth(numMipMap);
01368 }
01369
01370
01371
01372
01373
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
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
01460
01461 void CBitmap::resample(sint32 nNewWidth, sint32 nNewHeight)
01462 {
01463 nlassert(PixelFormat == RGBA);
01464 bool needRebuild = false;
01465
01466
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]);
01483 _Data[0] = pDestui;
01484 _Width= nNewWidth;
01485 _Height= nNewHeight;
01486
01487
01488 if(needRebuild)
01489 {
01490 buildMipMaps();
01491 }
01492 }
01493
01494
01495
01496
01497
01498 void CBitmap::resize (sint32 nNewWidth, sint32 nNewHeight, TType newType)
01499 {
01500
01501 releaseMipMaps();
01502
01503
01504 if (newType!=DonTKnow)
01505 PixelFormat=newType;
01506
01507 _Width = nNewWidth;
01508 _Height = nNewHeight;
01509
01510
01511 resizeMipMap(0, nNewWidth, nNewHeight);
01512 }
01513
01514
01515
01516
01517
01518 void CBitmap::resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight)
01519 {
01520 nlassert(numMipMap<MAX_MIPMAP);
01521
01522
01523 NLMISC::contReset(_Data[numMipMap]);
01524
01525
01526 bool isDXTC= PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha || PixelFormat==DXTC3 || PixelFormat==DXTC5;
01527
01528 nNewWidth= 4*((nNewWidth+3)/4);
01529 nNewHeight= 4*((nNewHeight+3)/4);
01530
01531
01532 _Data[numMipMap].resize (((uint32)(nNewWidth*nNewHeight)*bitPerPixels[PixelFormat])/8);
01533 }
01534
01535
01536
01537
01538
01539 void CBitmap::setMipMapCount(uint32 mmc)
01540 {
01541 _MipMapCount= uint8(mmc);
01542 }
01543
01544
01545
01546
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
01559 PixelFormat=type;
01560 }
01561
01562
01563
01564
01565
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
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
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
01775 uint8 *imageID;
01776
01777
01778
01779
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
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
01834
01835 _Width = width;
01836 _Height = height;
01837 size = _Width * _Height * (imageDepth/8);
01838
01839 switch(imageType)
01840 {
01841
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
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
01875 r = scanline[x*mult+0];
01876 g = scanline[x*mult+1];
01877 b = scanline[x*mult+2];
01878
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
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
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
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)
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
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
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)
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
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
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;
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)
02143 {
02144 scanline[k++] = _Data[0][(height-y-1)*width + i];
02145 }
02146 else
02147 for(i=0; i<width*4; i+=4)
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
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241 void CBitmap::rotateCCW()
02242 {
02243
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], ©[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
02278
02279 const bool useDXTC = PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha || PixelFormat == DXTC3 || PixelFormat == DXTC5;
02280
02281
02282 const uint dxtcNumBits = PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha ? 64 : 128;
02283
02284
02285 if (useDXTC)
02286 {
02287
02288
02289 nlassert(! (x & 3 || y & 3) );
02290 if (x & 3 || y & 3) return false;
02291
02292 }
02293
02294 nlassert(PixelFormat != DonTKnow);
02295
02296
02297 sint width = src->_Width;
02298
02299 sint height = src->_Height;
02300
02301 uint destStartX, destStartY;
02302 uint srcStartX, srcStartY;
02303
02304
02305
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
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
02334 if ((destStartX + width - 1) >= _Width)
02335 {
02336 width = _Width - destStartX;
02337 if (width <= 0) return true;
02338 }
02339
02340
02341 if ((destStartY + height - 1) >= _Height)
02342 {
02343 height = _Height - destStartY;
02344 if (width <= 0) return true;
02345 }
02346
02347
02348
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
02361 const uint bytePerPixs = ( useDXTC ? dxtcNumBits : bitPerPixels[PixelFormat] ) >> 3 ;
02362
02363
02364 const uint destRealWidth = useDXTC ? (_Width >> 2) : _Width;
02365 const uint srcRealWidth = useDXTC ? (src->_Width >> 2) : src->_Width;
02366
02367
02368
02369 const uint destStride = destRealWidth * bytePerPixs;
02370
02371
02372 const uint srcStride = srcRealWidth * bytePerPixs;
02373
02374
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
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
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
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
02424
02425
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
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
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
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
02524 uint32 fileType = 0;
02525 f.serial(fileType);
02526 if(fileType == DDS)
02527 {
02528
02529 uint32 size = 0;
02530 f.serial(size);
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
02541 uint32 flags = _DDSSurfaceDesc[1];
02542
02543
02544 if(!(flags & DDSD_LINEARSIZE))
02545 {
02546 throw EDDSBadHeader();
02547 }
02548
02549
02550 retWidth = _DDSSurfaceDesc[2];
02551 retHeight = _DDSSurfaceDesc[3];
02552 }
02553
02554 else
02555 {
02556 if(!f.seek (0, NLMISC::IStream::begin))
02557 {
02558 throw ESeekFailed();
02559 }
02560
02561
02562
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
02592 retWidth= width;
02593 retHeight= height;
02594 }
02595
02596
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
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
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]);
02706 _Data[0] = pDestui;
02707
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]);
02741 _Data[0] = pDestui;
02742
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);
02759 nlassert(Bm0._Height == Bm1._Height);
02760
02761 const CBitmap *nBm0, *nBm1;
02762
02763 CBitmap cp0, cp1;
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;
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 ) 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;
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;
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;
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
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;
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
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;
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 ) 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 }