diff -r 4ea92975a277 code/nel/src/misc/bitmap.cpp
--- a/code/nel/src/misc/bitmap.cpp Tue Feb 01 18:56:55 2011 +0100
+++ b/code/nel/src/misc/bitmap.cpp Tue Feb 08 16:39:22 2011 +0100
@@ -1,4108 +1,4108 @@
-// NeL - MMORPG Framework
-// Copyright (C) 2010 Winch Gate Property Limited
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-#include "stdmisc.h"
-
-#include "nel/misc/bitmap.h"
-#include "nel/misc/stream.h"
-#include "nel/misc/file.h"
-
-// Define this to force all bitmap white (debug)
-// #define NEL_ALL_BITMAP_WHITE
-
-
-using namespace std;
-
-
-namespace NLMISC
-{
-
-struct EDDSBadHeader : public NLMISC::EStream
-{
- EDDSBadHeader() : EStream( "Bad or unrecognized DDS file header" ) {}
-};
-
-struct ESeekFailed : public NLMISC::EStream
-{
- ESeekFailed() : EStream( "Seek failed" ) {}
-};
-
-struct EAllocationFailure : public Exception
-{
- EAllocationFailure() : Exception( "Can't allocate memory" ) {}
-};
-
-void blendFromui(NLMISC::CRGBA &c0, NLMISC::CRGBA &c1, uint coef);
-uint32 blend(uint32 &n0, uint32 &n1, uint32 coef0);
-
-const uint32 CBitmap::bitPerPixels[ModeCount]=
-{
- 32, // RGBA
- 8, // Luminance
- 8, // Alpha
- 16, // AlphaLuminance
- 4, // DXTC1
- 4, // DXTC1Alpha
- 8, // DXTC3
- 8, // DXTC5
- 16 // DsDt
-};
-
-const uint32 CBitmap::DXTC1HEADER = NL_MAKEFOURCC('D','X', 'T', '1');
-const uint32 CBitmap::DXTC3HEADER = NL_MAKEFOURCC('D','X', 'T', '3');
-const uint32 CBitmap::DXTC5HEADER = NL_MAKEFOURCC('D','X', 'T', '5');
-
-
-#ifdef NEL_ALL_BITMAP_WHITE
-// Make all the textures white
-void MakeWhite(CBitmap &bitmaps)
-{
- for (uint i=0; i0) //AlphaBitDepth
- {
- PixelFormat = DXTC1Alpha;
- }
-//#endif
-
- if(PixelFormat!= DXTC1 && PixelFormat!= DXTC1Alpha && PixelFormat!= DXTC3 && PixelFormat!= DXTC5)
- {
- delete [] _DDSSurfaceDesc;
- throw EDDSBadHeader();
- }
-
- // compute the min power of 2 between width and height
- uint minSizeLevel= min(_Width, _Height);
- minSizeLevel= getPowerOf2(minSizeLevel);
-
- //------------- manage mipMapSkip
- if(_MipMapCount>1 && mipMapSkip>0 && minSizeLevel>2)
- {
- // Keep at least the level where width and height are at least 4.
- mipMapSkip= min(mipMapSkip, minSizeLevel-2);
- // skip any mipmap
- uint seekSize= 0;
- while(mipMapSkip>0 && _MipMapCount>1)
- {
- // raise to next multiple of 4
- uint32 wtmp= (_Width+3)&(~3);
- uint32 htmp= (_Height+3)&(~3);
- wtmp= max(wtmp, uint32(4));
- htmp= max(htmp, uint32(4));
-
- uint32 mipMapSz;
- if(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)
- mipMapSz = wtmp*htmp/2;
- else
- mipMapSz = wtmp*htmp;
-
- // add to how many to skip
- seekSize+= mipMapSz;
-
- // Size of final bitmap is reduced.
- _Width>>=1;
- _Height>>=1;
- _MipMapCount--;
- mipMapSkip--;
- }
- // skip data in file
- if(seekSize>0)
- {
- if(!f.seek(seekSize, IStream::current))
- {
- delete [] _DDSSurfaceDesc;
- throw ESeekFailed();
- }
- }
-
- }
-
- //------------- preload all the mipmaps (one serialBuffer() is faster)
- uint32 w = _Width;
- uint32 h = _Height;
- uint32 totalSize= 0;
-
- uint8 m;
- for(m= 0; m<_MipMapCount; m++)
- {
- // raise to next multiple of 4
- uint32 wtmp= (w+3)&(~3);
- uint32 htmp= (h+3)&(~3);
- wtmp= max(wtmp, uint32(4));
- htmp= max(htmp, uint32(4));
-
- uint32 mipMapSz;
- if(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)
- mipMapSz = wtmp*htmp/2;
- else
- mipMapSz = wtmp*htmp;
-
-
- _Data[m].resize(mipMapSz);
- totalSize+= mipMapSz;
-
- w = (w+1)/2;
- h = (h+1)/2;
- }
-
- // Read all the data in one block.
- vector pixData;
- pixData.resize(totalSize);
- f.serialBuffer(&(*pixData.begin()), totalSize);
-
-
- //------------- reading mipmap levels from pixData
-
- uint32 pixIndex= 0;
-
- for(m= 0; m<_MipMapCount; m++)
- {
- uint32 mipMapSz= _Data[m].size();
- memcpy(_Data[m].getPtr(), &(pixData[pixIndex]), mipMapSz);
- pixIndex+= mipMapSz;
- }
-
- //------------- End
-
- delete [] _DDSSurfaceDesc;
-
- switch(PixelFormat)
- {
- case DXTC1 : return 24;
- case DXTC1Alpha : return 32;
- case DXTC3 : return 32;
- case DXTC5 : return 32;
- default : break;
- }
-
- return 0;
-}
-
-
-
-
-/*-------------------------------------------------------------------*\
- convertToDXTC5
-\*-------------------------------------------------------------------*/
-bool CBitmap::convertToDXTC5()
-{
- /* Yoyo: RGB encoding for DXTC1 and DXTC5/3 are actually different!!
- DXTC3/5 don't rely on sign of color0>color1 to setup special encoding (ie use a special compression for Black)
- Since this can arise if the src is DXTC1 , we can't simply compress it into DXTC5 without doing a
- heavy compression...
- (the inverse is false: DXTC5 to DXTC1 is possible, with maybe swap color0/color1 and bits).
- */
-
- return false;
-
-/* uint32 i,j;
-
- if(PixelFormat!=DXTC1) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(2*_Data[m].size());
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i+=8)
- {
- //64 bits alpha
- for(j=0; j<8; j++)
- {
- dataTmp[dstId++]= 255;
- }
-
- //64 bits RGB
- for(j=0; j<8; j++)
- {
- dataTmp[dstId++]= _Data[m][i+j];
- }
- }
- _Data[m] = dataTmp;
- }
- PixelFormat = DXTC5;
- return true;
-*/
-}
-
-
-
-/*-------------------------------------------------------------------*\
- luminanceToRGBA()
-\*-------------------------------------------------------------------*/
-bool CBitmap::luminanceToRGBA()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()*4);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i++)
- {
- dataTmp[dstId++]= _Data[m][i];
- dataTmp[dstId++]= _Data[m][i];
- dataTmp[dstId++]= _Data[m][i];
- dataTmp[dstId++]= 255;
- }
- _Data[m] = dataTmp;
- }
- PixelFormat = RGBA;
- return true;
-}
-
-/*-------------------------------------------------------------------*\
- alphaToRGBA()
-\*-------------------------------------------------------------------*/
-bool CBitmap::alphaToRGBA()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()*4);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i++)
- {
- dataTmp[dstId++]= 255;
- dataTmp[dstId++]= 255;
- dataTmp[dstId++]= 255;
- dataTmp[dstId++]= _Data[m][i];
- }
- _Data[m] = dataTmp;
- }
- PixelFormat = RGBA;
- return true;
-}
-
-
-/*-------------------------------------------------------------------*\
- alphaLuminanceToRGBA()
-\*-------------------------------------------------------------------*/
-bool CBitmap::alphaLuminanceToRGBA()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()*2);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i+=2)
- {
- dataTmp[dstId++]= _Data[m][i];
- dataTmp[dstId++]= _Data[m][i];
- dataTmp[dstId++]= _Data[m][i];
- dataTmp[dstId++]= _Data[m][i+1];
- }
- _Data[m] = dataTmp;
- }
- PixelFormat = RGBA;
- return true;
-}
-
-
-
-
-/*-------------------------------------------------------------------*\
- rgbaToAlphaLuminance
-\*-------------------------------------------------------------------*/
-bool CBitmap::rgbaToAlphaLuminance()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()/2);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i+=4)
- {
- dataTmp[dstId++]= (_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255;
- dataTmp[dstId++]= _Data[m][i+3];
- }
- NLMISC::contReset(_Data[m]);
- _Data[m].resize(0);
- _Data[m] = dataTmp;
- }
- PixelFormat = AlphaLuminance;
- return true;
-}
-
-
-/*-------------------------------------------------------------------*\
- luminanceToAlphaLuminance
-\*-------------------------------------------------------------------*/
-bool CBitmap::luminanceToAlphaLuminance()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()*2);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i++)
- {
- dataTmp[dstId++]= _Data[m][i];
- dataTmp[dstId++]= 255;
- }
- _Data[m] = dataTmp;
- }
- PixelFormat = AlphaLuminance;
- return true;
-}
-
-
-
-/*-------------------------------------------------------------------*\
- alphaToAlphaLuminance
-\*-------------------------------------------------------------------*/
-bool CBitmap::alphaToAlphaLuminance()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()*2);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i++)
- {
- dataTmp[dstId++]= 0;
- dataTmp[dstId++]= _Data[m][i];
- }
- _Data[m] = dataTmp;
- }
- PixelFormat = AlphaLuminance;
- return true;
-}
-
-
-
-/*-------------------------------------------------------------------*\
- rgbaToLuminance
-\*-------------------------------------------------------------------*/
-bool CBitmap::rgbaToLuminance()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()/4);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i+=4)
- {
- dataTmp[dstId++]= (_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255;
- }
- NLMISC::contReset(_Data[m]);
- _Data[m].resize(0);
- _Data[m] = dataTmp;
- }
- PixelFormat = Luminance;
- return true;
-}
-
-
-
-/*-------------------------------------------------------------------*\
- alphaToLuminance
-\*-------------------------------------------------------------------*/
-bool CBitmap::alphaToLuminance()
-{
- if(_Width*_Height == 0) return false;
-
- PixelFormat = Luminance;
- return true;
-}
-
-
-
-/*-------------------------------------------------------------------*\
- alphaLuminanceToLuminance
-\*-------------------------------------------------------------------*/
-bool CBitmap::alphaLuminanceToLuminance()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()/2);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i+=2)
- {
- dataTmp[dstId++]= 0;
- dataTmp[dstId++]= 0;
- dataTmp[dstId++]= 0;
- dataTmp[dstId++]= _Data[m][i];
- }
- NLMISC::contReset(_Data[m]);
- _Data[m].resize(0);
- _Data[m] = dataTmp;
- }
- PixelFormat = Luminance;
- return true;
-}
-
-
-/*-------------------------------------------------------------------*\
- rgbaToAlpha
-\*-------------------------------------------------------------------*/
-bool CBitmap::rgbaToAlpha()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()/4);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i+=4)
- {
- dataTmp[dstId++]= _Data[m][i+3];
- }
- NLMISC::contReset(_Data[m]);
- _Data[m].resize(0);
- _Data[m] = dataTmp;
- }
- PixelFormat = Alpha;
- return true;
-}
-
-
-/*-------------------------------------------------------------------*\
- luminanceToAlpha
-\*-------------------------------------------------------------------*/
-bool CBitmap::luminanceToAlpha()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size());
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i++)
- {
- dataTmp[dstId++]= _Data[m][i];
- }
- _Data[m] = dataTmp;
- }
- PixelFormat = Alpha;
- return true;
-}
-
-
-/*-------------------------------------------------------------------*\
- alphaLuminanceToAlpha
-\*-------------------------------------------------------------------*/
-bool CBitmap::alphaLuminanceToAlpha()
-{
- uint32 i;
-
- if(_Width*_Height == 0) return false;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- CObjectVector dataTmp;
- dataTmp.resize(_Data[m].size()/2);
- uint dstId= 0;
-
- for(i=0; i<_Data[m].size(); i+=2)
- {
- dataTmp[dstId++]= _Data[m][i+1];
- }
- NLMISC::contReset(_Data[m]);
- _Data[m].resize(0);
- _Data[m] = dataTmp;
- }
- PixelFormat = Alpha;
- return true;
-}
-
-
-/*-------------------------------------------------------------------*\
- convertToLuminance
-\*-------------------------------------------------------------------*/
-bool CBitmap::convertToLuminance()
-{
- switch(PixelFormat)
- {
- case RGBA :
- return rgbaToLuminance();
- break;
-
- case Luminance :
- return true;
- break;
-
- case Alpha :
- return alphaToLuminance();
- break;
-
- case AlphaLuminance :
- return alphaLuminanceToLuminance();
- break;
-
- default:
- break;
- }
- return false;
-}
-
-
-
-/*-------------------------------------------------------------------*\
- convertToAlpha
-\*-------------------------------------------------------------------*/
-bool CBitmap::convertToAlpha()
-{
- switch(PixelFormat)
- {
- case RGBA :
- return rgbaToAlpha();
- break;
-
- case Luminance :
- return luminanceToAlpha();
- break;
-
- case Alpha :
- return true;
- break;
-
- case AlphaLuminance :
- return alphaLuminanceToAlpha();
- break;
-
- default:
- break;
- }
- return false;
-}
-
-
-
-/*-------------------------------------------------------------------*\
- convertToAlphaLuminance
-\*-------------------------------------------------------------------*/
-bool CBitmap::convertToAlphaLuminance()
-{
- switch(PixelFormat)
- {
- case RGBA :
- return rgbaToAlphaLuminance();
- break;
-
- case Luminance :
- return luminanceToAlphaLuminance();
- break;
-
- case Alpha :
- return alphaToAlphaLuminance();
- break;
-
- case AlphaLuminance :
- return true;
- break;
-
- default:
- break;
- }
- return false;
-}
-
-
-/*-------------------------------------------------------------------*\
- convertToRGBA
-\*-------------------------------------------------------------------*/
-bool CBitmap::convertToRGBA()
-{
- switch(PixelFormat)
- {
- case DXTC1 :
- return decompressDXT1(false);
- break;
-
- case DXTC1Alpha :
- return decompressDXT1(true);
- break;
-
- case DXTC3 :
- return decompressDXT3();
- break;
-
- case DXTC5 :
- return decompressDXT5();
- break;
-
- case Luminance :
- return luminanceToRGBA();
- break;
-
- case Alpha :
- return alphaToRGBA();
- break;
-
- case AlphaLuminance :
- return alphaLuminanceToRGBA();
- break;
- case RGBA:
- return true;
- break;
- default:
- break;
- }
- return false;
-}
-
-
-/*-------------------------------------------------------------------*\
- convertToType
-\*-------------------------------------------------------------------*/
-bool CBitmap::convertToType(CBitmap::TType type)
-{
- if(PixelFormat==type) return true;
-
- switch(type)
- {
- case RGBA :
- return convertToRGBA();
- break;
-
- case DXTC5 :
- return convertToDXTC5();
- break;
-
- case Luminance :
- return convertToLuminance();
- break;
-
- case Alpha :
- return convertToAlpha();
- break;
-
- case AlphaLuminance :
- return convertToAlphaLuminance();
- break;
-
- default:
- break;
- }
-
- return false;
-}
-
-
-
-
-/*-------------------------------------------------------------------*\
- decompressDXT1
-\*-------------------------------------------------------------------*/
-bool CBitmap::decompressDXT1(bool alpha)
-{
- uint32 i,j,k;
- NLMISC::CRGBA c[4];
- CObjectVector dataTmp[MAX_MIPMAP];
-
- uint32 width= _Width;
- uint32 height= _Height;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- uint32 wtmp, htmp;
- if(width<4)
- wtmp = 4;
- else
- wtmp = width;
- if(height < 4)
- htmp = 4;
- else
- htmp = height;
- uint32 mipMapSz = wtmp*htmp*4;
- dataTmp[m].resize(mipMapSz);
- if(dataTmp[m].size()color1)
- {
- c[2].blendFromui(c[0],c[1],85);
- if(alpha) c[2].A= 255;
-
- c[3].blendFromui(c[0],c[1],171);
- if(alpha) c[3].A= 255;
- }
- else
- {
- c[2].blendFromui(c[0],c[1],128);
- if(alpha) c[2].A= 255;
-
- c[3].set(0,0,0,0);
- }
-
- // computing the 16 RGBA of the block
-
- uint32 blockNum= i/8; //(64 bits)
- // * 4 (rows) * _Width (columns) + 4pix*4rgba*
- uint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);
- for(j=0; j<4; j++)
- {
- for(k=0; k<4; k++)
- {
- dataTmp[m][pixelsCount + j*wtmp*4 + 4*k]= c[bits&3].R;
- dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+1]= c[bits&3].G;
- dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+2]= c[bits&3].B;
- dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+3]= c[bits&3].A;
- bits>>=2;
- }
- }
- }
-
- // Copy result into the mipmap level.
- if(wtmp==width && htmp==height)
- {
- // For mipmaps level >4 pixels.
- _Data[m]= dataTmp[m];
- }
- else
- {
- // For last mipmaps, level <4 pixels.
- _Data[m].resize(width*height*4);
- CRGBA *src= (CRGBA*)&dataTmp[m][0];
- CRGBA *dst= (CRGBA*)&_Data[m][0];
- uint x,y;
- for(y=0;y dataTmp[MAX_MIPMAP];
-
- uint32 width= _Width;
- uint32 height= _Height;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- uint32 wtmp, htmp;
- if(width<4)
- wtmp = 4;
- else
- wtmp = width;
- if(height < 4)
- htmp = 4;
- else
- htmp = height;
- uint32 mipMapSz = wtmp*htmp*4;
- dataTmp[m].resize(mipMapSz);
- if(dataTmp[m].size()>=4;
- }
-
-
- uint16 color0;
- uint16 color1;
- uint32 bits;
- memcpy(&color0,&_Data[m][i+8],2);
- memcpy(&color1,&_Data[m][i+10],2);
- memcpy(&bits,&_Data[m][i+12],4);
-
- uncompress(color0,c[0]);
- uncompress(color1,c[1]);
-
- // ignore color0>color1 for DXT3 and DXT5.
- c[2].blendFromui(c[0],c[1],85);
- c[3].blendFromui(c[0],c[1],171);
-
- // computing the 16 RGBA of the block
-
- uint32 blockNum= i/16; //(128 bits)
- // * 4 (rows) * wtmp (columns) + 4pix*4rgba*
- uint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);
- for(j=0; j<4; j++)
- {
- for(k=0; k<4; k++)
- {
- dataTmp[m][pixelsCount + j*wtmp*4 + 4*k]= c[bits&3].R;
- dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+1]= c[bits&3].G;
- dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+2]= c[bits&3].B;
- dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+3]= alpha[4*j+k];
- bits>>=2;
- }
- }
- }
-
- // Copy result into the mipmap level.
- if(wtmp==width && htmp==height)
- {
- // For mipmaps level >4 pixels.
- _Data[m]= dataTmp[m];
- }
- else
- {
- // For last mipmaps, level <4 pixels.
- _Data[m].resize(width*height*4);
- CRGBA *src= (CRGBA*)&dataTmp[m][0];
- CRGBA *dst= (CRGBA*)&_Data[m][0];
- uint x,y;
- for(y=0;y dataTmp[MAX_MIPMAP];
-
- uint32 width= _Width;
- uint32 height= _Height;
-
- for(uint8 m= 0; m<_MipMapCount; m++)
- {
- uint32 wtmp, htmp;
- if(width<4)
- wtmp = 4;
- else
- wtmp = width;
- if(height < 4)
- htmp = 4;
- else
- htmp = height;
- uint32 mipMapSz = wtmp*htmp*4;
- dataTmp[m].resize(mipMapSz);
- if(dataTmp[m].size()>= 16;
-
- uint32 alpha[8];
- alpha[0]= _Data[m][i+0];
- alpha[1]= _Data[m][i+1];
-
- if(alpha[0]>alpha[1])
- {
- alpha[2]= blend(alpha[0], alpha[1], 219);
- alpha[3]= blend(alpha[0], alpha[1], 183);
- alpha[4]= blend(alpha[0], alpha[1], 146);
- alpha[5]= blend(alpha[0], alpha[1], 110);
- alpha[6]= blend(alpha[0], alpha[1], 73);
- alpha[7]= blend(alpha[0], alpha[1], 37);
- }
- else
- {
- alpha[2]= blend(alpha[0], alpha[1], 204);
- alpha[3]= blend(alpha[0], alpha[1], 154);
- alpha[4]= blend(alpha[0], alpha[1], 102);
- alpha[5]= blend(alpha[0], alpha[1], 51);
- alpha[6]= 0;
- alpha[7]= 255;
- }
-
- uint8 codeAlpha[16];
- for(j=0; j<16; j++)
- {
- codeAlpha[j] = (uint8)(bitsAlpha & 7);
- bitsAlpha>>=3;
- }
-
-
- uint16 color0;
- uint16 color1;
- uint32 bits;
- memcpy(&color0,&_Data[m][i+8],2);
- memcpy(&color1,&_Data[m][i+10],2);
- memcpy(&bits,&_Data[m][i+12],4);
-
- uncompress(color0,c[0]);
- uncompress(color1,c[1]);
-
- // ignore color0>color1 for DXT3 and DXT5.
- c[2].blendFromui(c[0],c[1],85);
- c[3].blendFromui(c[0],c[1],171);
-
- // computing the 16 RGBA of the block
-
- uint32 blockNum= i/16; //(128 bits)
-
- // * 4 (rows) * wtmp (columns) + 4pix*
- uint32 pixelsCount= (blockNum/wBlockCount)*wtmp*4 + 4*(blockNum%wBlockCount);
- // *sizeof(RGBA)
- pixelsCount*=4;
- for(j=0; j<4; j++)
- {
- for(k=0; k<4; k++)
- {
- dataTmp[m][pixelsCount + (j*wtmp+k)*4 +0]= c[bits&3].R;
- dataTmp[m][pixelsCount + (j*wtmp+k)*4 +1]= c[bits&3].G;
- dataTmp[m][pixelsCount + (j*wtmp+k)*4 +2]= c[bits&3].B;
- dataTmp[m][pixelsCount + (j*wtmp+k)*4 +3]= (uint8) alpha[codeAlpha[4*j+k]];
- bits>>=2;
- }
- }
-
- }
-
- // Copy result into the mipmap level.
- if(wtmp==width && htmp==height)
- {
- // For mipmaps level >4 pixels.
- _Data[m]= dataTmp[m];
- }
- else
- {
- // For last mipmaps, level <4 pixels.
- _Data[m].resize(width*height*4);
- CRGBA *src= (CRGBA*)&dataTmp[m][0];
- CRGBA *dst= (CRGBA*)&_Data[m][0];
- uint x,y;
- for(y=0;y>8);
-}
-
-
-
-/*-------------------------------------------------------------------*\
- uncompress
-\*-------------------------------------------------------------------*/
-inline void CBitmap::uncompress(uint16 color, NLMISC::CRGBA &r)
-{
- r.A= 0;
- r.R= ((color>>11)&31) << 3; r.R+= r.R>>5;
- r.G= ((color>>5)&63) << 2; r.G+= r.G>>6;
- r.B= ((color)&31) << 3; r.B+= r.B>>5;
-}
-
-
-
-/*-------------------------------------------------------------------*\
- getWidth
-\*-------------------------------------------------------------------*/
-uint32 CBitmap::getWidth(uint32 mipMap) const
-{
- if(mipMap==0) return _Width;
-
- uint32 w = _Width;
- uint32 h = _Height;
- uint32 m = 0;
-
- do
- {
- m++;
- w = (w+1)/2;
- h = (h+1)/2;
- if(m==mipMap) return w;
- }
- while(w!=1 || h!=1);
-
- return 0;
-}
-
-
-
-/*-------------------------------------------------------------------*\
- getHeight
-\*-------------------------------------------------------------------*/
-uint32 CBitmap::getHeight(uint32 mipMap) const
-{
- if(mipMap==0) return _Height;
-
- uint32 w = _Width;
- uint32 h = _Height;
- uint32 m = 0;
-
- do
- {
- m++;
- w = (w+1)/2;
- h = (h+1)/2;
- if(m==mipMap) return h;
- }
- while(w!=1 || h!=1);
-
- return 0;
-}
-
-
-/*-------------------------------------------------------------------*\
- getSize
-\*-------------------------------------------------------------------*/
-uint32 CBitmap::getSize(uint32 numMipMap) const
-{
- return getHeight(numMipMap)*getWidth(numMipMap);
-}
-
-
-
-/*-------------------------------------------------------------------*\
- buildMipMaps
-\*-------------------------------------------------------------------*/
-void CBitmap::buildMipMaps()
-{
- uint32 i,j;
-
- if(PixelFormat!=RGBA) return;
- if(_MipMapCount!=1) return;
- if(!NLMISC::isPowerOf2(_Width)) return;
- if(!NLMISC::isPowerOf2(_Height)) return;
-
- uint32 w = _Width;
- uint32 h = _Height;
-
- while(w>1 || h>1)
- {
- uint32 precw = w;
- uint32 prech = h;
- w = (w+1)/2;
- h = (h+1)/2;
- uint32 mulw= precw/w;
- uint32 mulh= prech/h;
-
- _Data[_MipMapCount].resize(w*h*4);
-
- NLMISC::CRGBA *pRgba = (NLMISC::CRGBA*)&_Data[_MipMapCount][0];
- NLMISC::CRGBA *pRgbaPrev = (NLMISC::CRGBA*)&_Data[_MipMapCount-1][0];
- for(i=0; i1 || h>1)
- {
- w = (w+1)/2;
- h = (h+1)/2;
- ++mipMapCount;
- }
- return mipMapCount;
-}
-
-/*-------------------------------------------------------------------*\
- releaseMipMaps
-\*-------------------------------------------------------------------*/
-void CBitmap::releaseMipMaps()
-{
- if(_MipMapCount<=1) return;
-
- _MipMapCount=1;
- for(sint i=1;i1)
- needRebuild = true;
- releaseMipMaps();
- //logResample("Resample: 20");
-
- if(nNewWidth==0 || nNewHeight==0)
- {
- _Width = _Height = 0;
- //logResample("Resample: 25");
- return;
- }
-
- //logResample("Resample: 30");
- CObjectVector pDestui;
- pDestui.resize(nNewWidth*nNewHeight*4);
- //logResample("Resample: 40");
- NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
- //logResample("Resample: 50");
-
- resamplePicture32 ((NLMISC::CRGBA*)&_Data[0][0], pDestRgba, _Width, _Height, nNewWidth, nNewHeight);
- //logResample("Resample: 60");
-
- NLMISC::contReset(_Data[0]); // free memory
- //logResample("Resample: 70");
-
- _Data[0] = pDestui;
- //logResample("Resample: 80");
- _Width= nNewWidth;
- _Height= nNewHeight;
-
- // Rebuilding mipmaps
- //logResample("Resample: 90");
- if(needRebuild)
- {
- buildMipMaps();
- //logResample("Resample: 95");
- }
- //logResample("Resample: 100");
-}
-
-
-/*-------------------------------------------------------------------*\
- resize
-\*-------------------------------------------------------------------*/
-void CBitmap::resize (sint32 nNewWidth, sint32 nNewHeight, TType newType, bool resetTo0)
-{
- // Deleting mipmaps
- releaseMipMaps();
-
- // Change type of bitmap ?
- if (newType!=DonTKnow)
- PixelFormat=newType;
-
- _Width = nNewWidth;
- _Height = nNewHeight;
-
- // resize the level 0 only.
- resizeMipMap(0, nNewWidth, nNewHeight, resetTo0);
-}
-
-
-/*-------------------------------------------------------------------*\
- resizeMipMap
-\*-------------------------------------------------------------------*/
-void CBitmap::resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight, bool resetTo0)
-{
- nlassert(numMipMap=nSrcWidth);
- bool bYMag=(nDestHeight>=nSrcHeight);
- bool bXEq=(nDestWidth==nSrcWidth);
- bool bYEq=(nDestHeight==nSrcHeight);
- std::vector pIterm (nDestWidth*nSrcHeight);
-
- if (bXMag)
- {
- float fXdelta=(float)(nSrcWidth)/(float)(nDestWidth);
- NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
- sint32 nY;
- for (nY=0; nY=0.f);
- NLMISC::CRGBAF vColor;
- if (fVirgule>=0.5f)
- {
- if (fX<(float)(nSrcWidth-1))
- {
- NLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);
- NLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)+1]);
- vColor=vColor1*(1.5f-fVirgule)+vColor2*(fVirgule-0.5f);
- }
- else
- vColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
- }
- else
- {
- if (fX>=1.f)
- {
- NLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);
- NLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)-1]);
- vColor=vColor1*(0.5f+fVirgule)+vColor2*(0.5f-fVirgule);
- }
- else
- vColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
- }
- *(pItermPtr++)=vColor;
- fX+=fXdelta;
- }
- pSrc+=nSrcWidth;
- }
- }
- else if (bXEq)
- {
- NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
- for (sint32 nY=0; nY1.f);
- NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
- sint32 nY;
- for (nY=0; nYfFinal)
- fNext=fFinal;
- vColor+=((float)(fNext-fX))*NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
- fX=fNext;
- }
- fX = fFinal; // ensure fX == fFinal
- vColor/=(float)fXdelta;
- *(pItermPtr++)=vColor;
- }
- pSrc+=nSrcWidth;
- }
- }
-
- if (bYMag)
- {
- double fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);
- sint32 nX;
- for (nX=0; nX=0.f);
- NLMISC::CRGBAF vColor;
- if (fVirgule>=0.5f)
- {
- if (fY<(double)(nSrcHeight-1))
- {
- NLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
- NLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))+1)*nDestWidth+nX];
- vColor=vColor1*(1.5f-(float)fVirgule)+vColor2*((float)fVirgule-0.5f);
- }
- else
- vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
- }
- else
- {
- if (fY>=1.f)
- {
- NLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
- NLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))-1)*nDestWidth+nX];
- vColor=vColor1*(0.5f+(float)fVirgule)+vColor2*(0.5f-(float)fVirgule);
- }
- else
- vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
- }
- pDest[nX+nY*nDestWidth]=vColor;
- fY+=fYdelta;
- }
- }
- }
- else if (bYEq)
- {
- for (sint32 nX=0; nX1.f);
- sint32 nX;
- for (nX=0; nXfFinal)
- fNext=fFinal;
- vColor+=((float)(fNext-fY))*pIterm[((sint32)floor(fY))*nDestWidth+nX];
- fY=fNext;
- }
- vColor/=(float)fYdelta;
- pDest[nX+nY*nDestWidth]=vColor;
- }
- }
- }
-}
-
-/*-------------------------------------------------------------------*\
- resamplePicture32Fast
-\*-------------------------------------------------------------------*/
-void CBitmap::resamplePicture32Fast (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest,
- sint32 nSrcWidth, sint32 nSrcHeight,
- sint32 nDestWidth, sint32 nDestHeight)
-{
- // the image is divided by two : 1 pixel in dest = 4 pixels in src
- // the resulting pixel in dest is an average of the four pixels in src
-
- nlassert(nSrcWidth % 2 == 0);
- nlassert(nSrcHeight % 2 == 0);
- nlassert(nSrcWidth / 2 == nDestWidth);
- nlassert(nSrcHeight / 2 == nDestHeight);
-
- sint32 x, y, twoX, twoSrcWidthByY;
-
- for (y=0 ; y= 26)
- {
- f.seek (-26, f.end);
- f.serial(extAreaOffset);
- f.serial(devDirectoryOffset);
- for(i=0; i<16; i++)
- {
- f.serial(signature[i]);
- }
- if(strncmp(signature,"TRUEVISION-XFILE",16)==0)
- newTgaFormat = true;
- }
-
-
-
- // Reading TGA file header
- f.seek (0, f.begin);
-
- f.serial(lengthID);
- f.serial(cMapType);
- f.serial(imageType);
- f.serial(origin);
- f.serial(length);
- f.serial(depth);
- f.serial(xOrg);
- f.serial(yOrg);
- f.serial(width);
- f.serial(height);
- f.serial(imageDepth);
- f.serial(desc);
-
- if(cMapType!=0)
- {
- nlinfo("readTga : color-map not supported");
- }
-
- if(lengthID>0)
- {
- uint8 dummy;
- for(i=0; i>10;
- uint _g = (toto>>5)&0x1f;
- uint _b = toto&0x1f;
- _Data[0][(height-y-1)*width*4 + 4*i] = uint8((_r<<3) | (_r>>2));
- _Data[0][(height-y-1)*width*4 + 4*i + 1] = uint8((_g<<3) | (_g>>2));
- _Data[0][(height-y-1)*width*4 + 4*i + 2] = uint8((_b<<3) | (_b>>2));
- _Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;
- }
- else
- {
- _Data[0][(height-y-1)*width*4 + 4*i] = scanline[k++];
- _Data[0][(height-y-1)*width*4 + 4*i + 1] = scanline[k++];
- _Data[0][(height-y-1)*width*4 + 4*i + 2] = scanline[k++];
- if(imageDepth==32)
- _Data[0][(height-y-1)*width*4 + 4*i + 3] = scanline[k++];
- else
- _Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;
- }
- }
- else
- {
- if(imageDepth==16)
- {
- uint16 toto = (uint16)scanline[k++];
- toto |= scanline[k++]<<8;
- int _r = toto>>10;
- int _g = toto&(0x3e0)>>5;
- int _b = toto&0x1f;
- _Data[0][y*width*4 + 4*i] = uint8((_r<<3) | (_r>>2));
- _Data[0][y*width*4 + 4*i + 1] = uint8((_g<<3) | (_g>>2));
- _Data[0][y*width*4 + 4*i + 2] = uint8((_b<<3) | (_b>>2));
- _Data[0][y*width*4 + 4*i + 3] = 255;
- }
- else
- {
- _Data[0][y*width*4 + 4*i] = scanline[k++];
- _Data[0][y*width*4 + 4*i + 1] = scanline[k++];
- _Data[0][y*width*4 + 4*i + 2] = scanline[k++];
- if(imageDepth==32)
- _Data[0][y*width*4 + 4*i + 3] = scanline[k++];
- else
- _Data[0][y*width*4 + 4*i + 3] = 255;
- }
- }
- }
- }
-
- PixelFormat = RGBA;
- delete []scanline;
- };
- break;
-
- // Uncompressed Grayscale bitmap
- case 3:
- {
- _Data[0].resize(_Width*_Height);
- uint8 upSideDown = ((desc & (1 << 5))==0);
- slsize = _Width;
-
- scanline = new uint8[slsize];
- if(!scanline)
- {
- throw EAllocationFailure();
- }
-
- for(y=0; y<_Height;y++)
- {
- // Serial buffer: more efficient way to load.
- f.serialBuffer (scanline, slsize);
-
- k=0;
- for(i=0; i 0) // packet RLE
- {
- for(i=0; i 0) // packet RLE
- {
- f.serial(pixel[0]);
- for (i=0; i < (packet & 0x7F) + 1; i++)
- {
- _Data[0][dstId++]= pixel[0];
- }
- }
- else // packet Raw
- {
- for(i=0; i<((packet & 0x7F) + 1); i++)
- {
- f.serial(pixel[0]);
- _Data[0][dstId++]= pixel[0];
- }
- }
- readSize += (packet & 0x7F) + 1;
- }
- PixelFormat = _LoadGrayscaleAsAlpha?Alpha:Luminance;
- };
- break;
-
- default:
- return 0;
- }
-
- _MipMapCount = 1;
- return(imageDepth);
-
-}
-
-/*-------------------------------------------------------------------*\
- writeTGA
-\*-------------------------------------------------------------------*/
-bool CBitmap::writeTGA( NLMISC::IStream &f, uint32 d, bool upsideDown)
-{
- if(f.isReading()) return false;
- if (d==0)
- {
- switch (PixelFormat)
- {
- case RGBA:
- d = 32;
- break;
- case Luminance:
- d = 8;
- break;
- case Alpha:
- d = 8;
- break;
- default:
- ;
- }
- }
- if(d!=24 && d!=32 && d!=16 && d!=8) return false;
- if ((PixelFormat != RGBA)&&(PixelFormat != Alpha)&&(PixelFormat != Luminance)) return false;
- if ((PixelFormat == Alpha) && (d != 8)) return false;
- if ((PixelFormat == Luminance) && (d != 8)) return false;
-
- sint32 i,j,x,y;
- uint8 * scanline;
- uint8 r,g,b,a;
-
- uint8 lengthID = 0;
- uint8 cMapType = 0;
- uint8 imageType = 2;
- uint16 origin = 0;
- uint16 length = 0;
- uint8 depth = 0;
- uint16 xOrg = 0;
- uint16 yOrg = 0;
- uint16 width = (uint16)_Width;
- uint16 height = (uint16)_Height;
- uint8 imageDepth = (uint8)d;
- uint8 desc = 0;
- if (upsideDown)
- desc |= 1<<5;
-
- if ((PixelFormat == Alpha) || (PixelFormat == Luminance))
- imageType = 3; // Uncompressed grayscale
-
- f.serial(lengthID);
- f.serial(cMapType);
- f.serial(imageType);
- f.serial(origin);
- f.serial(length);
- f.serial(depth);
- f.serial(xOrg);
- f.serial(yOrg);
- f.serial(width);
- f.serial(height);
- f.serial(imageDepth);
- f.serial(desc);
-
- if ((PixelFormat == Alpha)||(PixelFormat == Luminance))
- scanline = new uint8[width];
- else
- scanline = new uint8[width*4];
- if(!scanline)
- {
- throw EAllocationFailure();
- }
-
- for(y=0; y<(sint32)height; y++)
- {
-
- uint32 k=0;
- if (PixelFormat == Alpha)
- {
- for(i=0; i>3;
- int gg = g >>3;
- int bb = b >>3;
- uint16 c16 = uint16((rr<<10) | (gg<<5) | bb);
- scanline[x*2+0] = c16&0xff;
- scanline[x*2+1] = c16>>8;
- }
- }
- if(d==24)
- {
- for(x=0; x<(sint32)width; x++)
- {
- r = scanline[x*3+0];
- g = scanline[x*3+1];
- b = scanline[x*3+2];
- scanline[x*3+0] = b;
- scanline[x*3+1] = g;
- scanline[x*3+2] = r;
- }
- }
- if(d==32)
- {
- for(x=0; x<(sint32)width; x++)
- {
- r = scanline[x*4+0];
- g = scanline[x*4+1];
- b = scanline[x*4+2];
- a= scanline[x*4+3];
- scanline[x*4+0] = b;
- scanline[x*4+1] = g;
- scanline[x*4+2] = r;
- scanline[x*4+3] = a;
- }
- }
-
- int finaleSize=width*d/8;
- for(i=0; i
-void rotateCCW (const T* src, T* dst, uint srcWidth, uint srcHeight)
-{
- for (uint y=0; y
-void rotateCCW (const vector& src, vector& dst, uint srcWidth, uint srcHeight)
-{
- for (uint y=0; y copy=_Data[0];
-
- switch (PixelFormat)
- {
- case RGBA:
- NLMISC::rotateCCW ((uint32*)&(_Data[0][0]), (uint32*)&(copy[0]), _Width, _Height);
- break;
- case Luminance:
- case Alpha:
- NLMISC::rotateCCW (&_Data[0][0], ©[0], _Width, _Height);
- break;
- case AlphaLuminance:
- NLMISC::rotateCCW ((uint16*)&(_Data[0][0]), (uint16*)&(copy[0]), _Width, _Height);;
- break;
- default: break;
- }
-
- uint32 tmp=_Width;
- _Width=_Height;
- _Height=tmp;
- _Data[0]=copy;
-}
-
-void CBitmap::blit(const CBitmap &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint destX, sint destY)
-{
- nlassert(PixelFormat == RGBA);
- nlassert(src.PixelFormat == RGBA);
- // clip x
- if (srcX < 0)
- {
- srcWidth += srcX;
- if (srcWidth <= 0) return;
- destX -= srcX;
- srcX = 0;
- }
- if (srcX + srcWidth > (sint) src.getWidth())
- {
- srcWidth = src.getWidth() - srcX;
- if (srcWidth <= 0) return;
- }
- if (destX < 0)
- {
- srcWidth += destX;
- if (srcWidth <= 0) return;
- srcX -= destX;
- destX = 0;
- }
- if (destX + srcWidth > (sint) getWidth())
- {
- srcWidth = getWidth() - destX;
- if (srcWidth <= 0) return;
- }
- // clip y
- if (srcY < 0)
- {
- srcHeight += srcY;
- if (srcHeight <= 0) return;
- destY -= srcY;
- srcY = 0;
- }
- if (srcY + srcHeight > (sint) src.getHeight())
- {
- srcHeight = src.getHeight() - srcY;
- if (srcHeight <= 0) return;
- }
- if (destY < 0)
- {
- srcHeight += destY;
- if (srcHeight <= 0) return;
- srcY -= destY;
- destY = 0;
- }
- if (destY + srcHeight > (sint) getHeight())
- {
- srcHeight = getHeight() - destY;
- if (srcHeight <= 0) return;
- }
- uint32 *srcPixels = (uint32 *) &src.getPixels()[0];
- uint32 *srcPtr = &(srcPixels[srcX + srcY * src.getWidth()]);
- uint32 *srcEndPtr = srcPtr + srcHeight * src.getWidth();
- uint32 *destPixels = (uint32 *) &getPixels()[0];
- uint32 *destPtr = &(destPixels[destX + destY * getWidth()]);
- while (srcPtr != srcEndPtr)
- {
- memcpy(destPtr, srcPtr, sizeof(uint32) * srcWidth);
- srcPtr += src.getWidth();
- destPtr += getWidth();
- }
-
-}
-
-
-bool CBitmap::blit(const CBitmap *src, sint32 x, sint32 y)
-{
-
- nlassert(this->PixelFormat == src->PixelFormat);
- if (this->PixelFormat != src->PixelFormat)
- {
- return false;
- }
-
-
- // check for dxtc use
-
- const bool useDXTC = PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha || PixelFormat == DXTC3 || PixelFormat == DXTC5;
-
- // number of bits for a 4x4 pix block
- const uint dxtcNumBits = PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha ? 64 : 128;
-
-
- if (useDXTC)
- {
- // blit pos must be multiple of 4
-
- nlassert(! (x & 3 || y & 3) );
- if (x & 3 || y & 3) return false;
-
- }
-
- nlassert(PixelFormat != DonTKnow);
-
- // the width to copy
- sint width = src->_Width;
- // the height to copy
- sint height = src->_Height;
-
- uint destStartX, destStartY;
- uint srcStartX, srcStartY;
-
-
- // clip against left
- if (x < 0)
- {
- width += x;
- if (width <= 0) return true;
- destStartX = 0;
- srcStartX = -x;
- }
- else
- {
- destStartX = x;
- srcStartX = 0;
- }
-
- // clip against top
- if (y < 0)
- {
- height += y;
- if (height <= 0) return true;
- srcStartY = -y;
- destStartY = 0;
- }
- else
- {
- destStartY = y;
- srcStartY = 0;
- }
-
- // clip against right
- if ((destStartX + width - 1) >= _Width)
- {
- width = _Width - destStartX;
- if (width <= 0) return true;
- }
-
- // clip against bottom
- if ((destStartY + height - 1) >= _Height)
- {
- height = _Height - destStartY;
- if (width <= 0) return true;
- }
-
-
- // divide all distance by 4 when using DXTC
- if (useDXTC)
- {
- destStartX >>= 2;
- destStartY >>= 2;
- srcStartX >>= 2;
- srcStartY >>= 2;
- width >>= 2;
- height >>= 2;
- }
-
-
- // bytes per pixs is for either one pixel or 16 (a 4x4 block in DXTC)
- const uint bytePerPixs = ( useDXTC ? dxtcNumBits : bitPerPixels[PixelFormat] ) >> 3 /* divide by 8 to get the number of bytes */;
-
-
- const uint destRealWidth = useDXTC ? (_Width >> 2) : _Width;
- const uint srcRealWidth = useDXTC ? (src->_Width >> 2) : src->_Width;
-
-
- // size to go to the next line in the destination
- const uint destStride = destRealWidth * bytePerPixs;
-
- // size to go to the next line in the source
- const uint srcStride = srcRealWidth * bytePerPixs;
-
- // length in bytes of a line to copy
- const uint lineLength = width * bytePerPixs;
-
-
- uint8 *destPos = &(_Data[0][0]) + destStride * destStartY + bytePerPixs * destStartX;
- const uint8 *srcPos = &(src->_Data[0][0]) + srcStride * srcStartY + bytePerPixs * srcStartX;
-
- // copy each hline
- for (sint k = 0; k < height; ++k)
- {
- ::memcpy(destPos, srcPos, lineLength);
- destPos += destStride;
- srcPos += srcStride;
- }
-
-
- return true;
-}
-
-// Private :
-float CBitmap::getColorInterp (float x, float y, float colorInXY00, float colorInXY10, float colorInXY01, float colorInXY11) const
-{
- float res = colorInXY00*(1.0f-x)*(1.0f-y) +
- colorInXY10*( x)*(1.0f-y) +
- colorInXY01*(1.0f-x)*( y) +
- colorInXY11*( x)*( y);
- clamp (res, 0.0f, 255.0f);
- return res;
-}
-
-// Public:
-CRGBAF CBitmap::getColor (float x, float y) const
-{
- if (x < 0.0f) x = 0.0f;
- if (x > 1.0f) x = 1.0f;
- if (y < 0.0f) y = 0.0f;
- if (y > 1.0f) y = 1.0f;
-
- sint32 nWidth = getWidth(0);
- sint32 nHeight = getHeight(0);
-
- if (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);
-
- const CObjectVector &rBitmap = getPixels(0);
- sint32 nX[4], nY[4];
-
- x *= nWidth-1;
- y *= nHeight-1;
-
- // Integer part of (x,y)
- //nX[0] = ((sint32)floor(x-0.5f));
- //nY[0] = ((sint32)floor(y-0.5f));
- nX[0] = ((sint32)floor(x));
- nY[0] = ((sint32)floor(y));
-
- nX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);
- nY[1] = nY[0];
-
- nX[2] = nX[0];
- nY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);
-
- nX[3] = nX[1];
- nY[3] = nY[2];
-
- uint32 i;
-
- for (i = 0; i < 4; ++i)
- {
- nlassert (nX[i] >= 0);
- nlassert (nY[i] >= 0 );
- nlassert (nX[i] < nWidth);
- nlassert (nY[i] < nHeight);
- }
-
- // Decimal part of (x,y)
- x = x - (float)nX[0];
- y = y - (float)nY[0];
-
- switch (this->PixelFormat)
- {
- case RGBA:
- case DXTC1:
- case DXTC1Alpha:
- case DXTC3:
- case DXTC5:
- {
- CRGBAF finalVal;
- CRGBA val[4];
-
- if (this->PixelFormat == RGBA)
- {
- for (i = 0; i < 4; ++i)
- {
- val[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],
- rBitmap[(nX[i]+nY[i]*nWidth)*4+1],
- rBitmap[(nX[i]+nY[i]*nWidth)*4+2],
- rBitmap[(nX[i]+nY[i]*nWidth)*4+3]);
- }
- }
- else
- {
- // slower version : get from DXT
- for (i = 0; i < 4; ++i)
- {
- val[i] = getPixelColor(nX[i], nY[i]);
- }
- }
-
- finalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);
- finalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);
- finalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);
- finalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);
- finalVal /= 255.f;
-
- return finalVal;
- }
- break;
- case Alpha:
- case Luminance:
- {
-
- float finalVal;
- float val[4];
-
- for (i = 0; i < 4; ++i)
- val[i] = rBitmap[(nX[i]+nY[i]*nWidth)];
-
- finalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);
- finalVal /= 255.f;
-
- if (this->PixelFormat == Alpha)
- return CRGBAF (1.f, 1.f, 1.f, finalVal);
- else // Luminance
- return CRGBAF (finalVal, finalVal, finalVal, 1.f);
- }
- break;
- default: break;
- }
-
- return CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);
-}
-
-// wrap a value inside the given range (for positive value it is like a modulo)
-static inline uint32 wrap(sint32 value, uint32 range)
-{
- return value >= 0 ? (value % range) : range - 1 - (- value - 1) % range;
-}
-
-
-CRGBAF CBitmap::getColor(float x, float y, bool tileU, bool tileV) const
-{
- sint32 nWidth = getWidth(0);
- sint32 nHeight = getHeight(0);
- if (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);
-
- sint32 nX[4], nY[4];
-
- if (!tileU)
- {
- if (x < 0.0f) x = 0.0f;
- if (x > 1.0f) x = 1.0f;
- x *= nWidth-1;
- nX[0] = ((sint32)floor(x));
- nX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);
- nX[2] = nX[0];
- nX[3] = nX[1];
- uint32 i;
- for (i = 0; i < 4; ++i)
- {
- nlassert (nX[i] >= 0);
- nlassert (nX[i] < nWidth);
- }
- }
- else
- {
- x *= nWidth;
- nX[0] = wrap((sint32)floorf(x), nWidth);
- nX[1] = wrap(nX[0] + 1, nWidth);
- nX[2] = nX[0];
- nX[3] = nX[1];
- }
- //
- if (!tileV)
- {
- if (y < 0.0f) y = 0.0f;
- if (y > 1.0f) y = 1.0f;
- y *= nHeight-1;
- nY[0] = ((sint32)floor(y));
- nY[1] = nY[0];
- nY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);
- nY[3] = nY[2];
- uint32 i;
- for (i = 0; i < 4; ++i)
- {
- nlassert (nY[i] >= 0 );
- nlassert (nY[i] < nHeight);
- }
- }
- else
- {
- y *= nHeight;
- nY[0] = wrap((sint32)floorf(y), nHeight);
- nY[1] = nY[0];
- nY[2] = wrap(nY[0] + 1, nHeight);
- nY[3] = nY[2];
- }
- // Decimal part of (x,y)
- x = x - (float)nX[0];
- y = y - (float)nY[0];
- const CObjectVector &rBitmap = getPixels(0);
- switch (this->PixelFormat)
- {
- case RGBA:
- case DXTC1:
- case DXTC1Alpha:
- case DXTC3:
- case DXTC5:
- {
- CRGBAF finalVal;
- CRGBA val[4];
-
- if (this->PixelFormat == RGBA)
- {
- for (uint32 i = 0; i < 4; ++i)
- {
- val[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],
- rBitmap[(nX[i]+nY[i]*nWidth)*4+1],
- rBitmap[(nX[i]+nY[i]*nWidth)*4+2],
- rBitmap[(nX[i]+nY[i]*nWidth)*4+3]);
- }
- }
- else
- {
- // slower version : get from DXT
- for (uint32 i = 0; i < 4; ++i)
- {
- val[i] = getPixelColor(nX[i], nY[i]);
- }
- }
-
- finalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);
- finalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);
- finalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);
- finalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);
- finalVal /= 255.f;
-
- return finalVal;
- }
- break;
- case Alpha:
- case Luminance:
- {
-
- float finalVal;
- float val[4];
-
- for (uint32 i = 0; i < 4; ++i)
- val[i] = rBitmap[(nX[i]+nY[i]*nWidth)];
-
- finalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);
- finalVal /= 255.f;
-
- if (this->PixelFormat == Alpha)
- return CRGBAF (1.f, 1.f, 1.f, finalVal);
- else // Luminance
- return CRGBAF (finalVal, finalVal, finalVal, 1.f);
- }
- break;
- default: break;
- }
- return CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);
-}
-
-
-
-void CBitmap::loadSize(NLMISC::IStream &f, uint32 &retWidth, uint32 &retHeight)
-{
- retWidth= 0;
- retHeight= 0;
-
- nlassert(f.isReading());
-
- // testing if DDS
- uint32 fileType = 0;
- f.serial(fileType);
- if(fileType == DDS_HEADER)
- {
- // read entire DDS header.
- uint32 size = 0;
- f.serial(size); // size in Bytes of header(without "DDS")
- uint32 * _DDSSurfaceDesc = new uint32[size];
- _DDSSurfaceDesc[0]= size;
-
- for(uint i= 0; i= 0xd0 && blockMarker2 <= 0xd8)
- {
- // no content
- }
- else
- {
- // size of a block
- f.serial(blockSize);
- NLMISC_BSWAP16(blockSize);
-
- // frame marker (which contains image width and height)
- if (blockMarker2 >= 0xc0 && blockMarker2 <= 0xc3)
- {
- uint8 imagePrecision = 0; // sample precision
- uint32 imageSize = 0; // width and height
- f.serial(imagePrecision);
- f.serial(imageSize);
- NLMISC_BSWAP32(imageSize);
-
- retWidth = imageSize & 0xffff;
- retHeight = (imageSize & 0xffff0000) >> 16;
-
- break;
- }
-
- // skip the block
- f.seek(blockSize - 2, IStream::current);
- }
- }
- }
- catch(...)
- {
- eof = true;
- }
- }
- while(!eof);
- }
- // assuming it's TGA
- else
- {
- if(!f.seek (0, NLMISC::IStream::begin))
- {
- throw ESeekFailed();
- }
-
- // Reading header,
- // To make sure that the bitmap is TGA, we check imageType and imageDepth.
- uint8 lengthID;
- uint8 cMapType;
- uint8 imageType;
- uint16 tgaOrigin;
- uint16 length;
- uint8 depth;
- uint16 xOrg;
- uint16 yOrg;
- uint16 width;
- uint16 height;
- uint8 imageDepth;
- uint8 desc;
-
- f.serial(lengthID);
- f.serial(cMapType);
- f.serial(imageType);
- if(imageType!=2 && imageType!=3 && imageType!=10 && imageType!=11)
- {
- nlwarning("Invalid TGA format, type %u in not supported (must be 2,3,10 or 11)", imageType);
- return;
- }
- f.serial(tgaOrigin);
- f.serial(length);
- f.serial(depth);
- f.serial(xOrg);
- f.serial(yOrg);
- f.serial(width);
- f.serial(height);
- f.serial(imageDepth);
- if(imageDepth!=8 && imageDepth!=16 && imageDepth!=24 && imageDepth!=32)
- {
- nlwarning("Invalid TGA format, bit depth %u in not supported (must be 8,16,24 or 32)", imageDepth);
- return;
- }
- f.serial(desc);
-
- // Ok, we have width and height.
- retWidth= width;
- retHeight= height;
- }
-
- // reset stream.
- if(!f.seek (0, NLMISC::IStream::begin))
- {
- throw ESeekFailed();
- }
-}
-
-
-void CBitmap::loadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight)
-{
- retWidth= 0;
- retHeight= 0;
-
- CIFile f(path);
- if(f.open(path))
- loadSize(f, retWidth, retHeight);
-}
-
-// ***************************************************************************
-void CBitmap::flipHDXTCBlockColor(uint8 *bitColor, uint32 w)
-{
- // pack each line in a u32 (NB: the following works either in Little and Big Endian)
- uint32 bits= *(uint32*)bitColor;
-
- // swap in X for each line
- uint32 res;
- if(w!=2)
- {
- res = (bits & 0xC0C0C0C0) >> 6;
- res+= (bits & 0x30303030) >> 2;
- res+= (bits & 0x0C0C0C0C) << 2;
- res+= (bits & 0x03030303) << 6;
- }
- // special case where w==2
- else
- {
- res = (bits & 0x0C0C0C0C) >> 2;
- res+= (bits & 0x03030303) << 2;
- }
-
- // copy
- *((uint32*)bitColor)= res;
-}
-
-// ***************************************************************************
-void CBitmap::flipVDXTCBlockColor(uint8 *bitColor, uint32 h)
-{
- // swap just bytes (work either in Little and Big Endian)
- if(h!=2)
- {
- std::swap(bitColor[0], bitColor[3]);
- std::swap(bitColor[1], bitColor[2]);
- }
- // special case where h==2)
- else
- {
- // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
- std::swap(bitColor[0], bitColor[1]);
- }
-}
-
-// ***************************************************************************
-void CBitmap::flipHDXTCBlockAlpha3(uint8 *blockAlpha, uint32 w)
-{
-#ifdef NL_LITTLE_ENDIAN
- uint64 bits= *(uint64*)blockAlpha;
-#else
- uint64 bits= (uint64)blockAlpha[0] + ((uint64)blockAlpha[1]<<8) +
- ((uint64)blockAlpha[2]<<16) + ((uint64)blockAlpha[3]<<24) +
- ((uint64)blockAlpha[4]<<32) + ((uint64)blockAlpha[5]<<40) +
- ((uint64)blockAlpha[6]<<48) + ((uint64)blockAlpha[7]<<56);
-#endif
-
- // swap in X for each line
- uint64 res;
- if(w!=2)
- {
- res = (bits & INT64_CONSTANT(0xF000F000F000F000)) >> 12;
- res+= (bits & INT64_CONSTANT(0x0F000F000F000F00)) >> 4;
- res+= (bits & INT64_CONSTANT(0x00F000F000F000F0)) << 4;
- res+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 12;
- }
- // special case where w==2
- else
- {
- res = (bits & INT64_CONSTANT(0x00F000F000F000F0)) >> 4;
- res+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 4;
- }
-
- // copy
-#ifdef NL_LITTLE_ENDIAN
- *((uint64*)blockAlpha)= res;
-#else
- blockAlpha[0]= res & 255;
- blockAlpha[1]= (res>>8) & 255;
- blockAlpha[2]= (res>>16) & 255;
- blockAlpha[3]= (res>>24) & 255;
- blockAlpha[4]= (res>>32) & 255;
- blockAlpha[5]= (res>>40) & 255;
- blockAlpha[6]= (res>>48) & 255;
- blockAlpha[7]= (res>>56) & 255;
-#endif
-}
-
-// ***************************************************************************
-void CBitmap::flipVDXTCBlockAlpha3(uint8 *blockAlpha, uint32 h)
-{
- uint16 *wAlpha= (uint16*)blockAlpha;
-
- // swap just words (work either in Little and Big Endian)
- if(h!=2)
- {
- std::swap(wAlpha[0], wAlpha[3]);
- std::swap(wAlpha[1], wAlpha[2]);
- }
- // special case where h==2)
- else
- {
- // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
- std::swap(wAlpha[0], wAlpha[1]);
- }
-}
-
-// ***************************************************************************
-void CBitmap::flipHDXTCBlockAlpha5(uint8 *bitAlpha, uint32 w)
-{
- // pack into bits. Little Indian in all cases
- uint64 bits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +
- ((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +
- ((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);
-
- // swap in X for each line
- uint64 res;
- if(w!=2)
- {
- res = (bits & INT64_CONSTANT(0xE00E00E00E00)) >> 9;
- res+= (bits & INT64_CONSTANT(0x1C01C01C01C0)) >> 3;
- res+= (bits & INT64_CONSTANT(0x038038038038)) << 3;
- res+= (bits & INT64_CONSTANT(0x007007007007)) << 9;
- }
- // special case where w==2
- else
- {
- res = (bits & INT64_CONSTANT(0x038038038038)) >> 3;
- res+= (bits & INT64_CONSTANT(0x007007007007)) << 3;
- }
-
- // copy. Little Indian in all cases
- bitAlpha[0]= uint8(res & 255);
- bitAlpha[1]= uint8((res>>8) & 255);
- bitAlpha[2]= uint8((res>>16) & 255);
- bitAlpha[3]= uint8((res>>24) & 255);
- bitAlpha[4]= uint8((res>>32) & 255);
- bitAlpha[5]= uint8((res>>40) & 255);
-}
-
-// ***************************************************************************
-void CBitmap::flipVDXTCBlockAlpha5(uint8 *bitAlpha, uint32 h)
-{
- // pack into bits. Little Indian in all cases
- uint64 bits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +
- ((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +
- ((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);
-
- // swap in Y
- uint64 res;
- if(h!=2)
- {
- res = (bits & INT64_CONSTANT(0xFFF000000000)) >> 36;
- res+= (bits & INT64_CONSTANT(0x000FFF000000)) >> 12;
- res+= (bits & INT64_CONSTANT(0x000000FFF000)) << 12;
- res+= (bits & INT64_CONSTANT(0x000000000FFF)) << 36;
- }
- // special case where h==2
- else
- {
- res = (bits & INT64_CONSTANT(0x000000FFF000)) >> 12;
- res+= (bits & INT64_CONSTANT(0x000000000FFF)) << 12;
- }
-
- // copy. Little Indian in all cases
- bitAlpha[0]= uint8(res & 255);
- bitAlpha[1]= uint8((res>>8) & 255);
- bitAlpha[2]= uint8((res>>16) & 255);
- bitAlpha[3]= uint8((res>>24) & 255);
- bitAlpha[4]= uint8((res>>32) & 255);
- bitAlpha[5]= uint8((res>>40) & 255);
-}
-
-// ***************************************************************************
-void CBitmap::flipDXTCMipMap(bool vertical, uint mm, uint type)
-{
- nlassert(mm1)
- needRebuild = true;
- releaseMipMaps();
-
- for( i = 0; i < nHeight; ++i )
- for( j = 0; j < nWidth/2; ++j )
- {
- temp = pBitmap[i*nWidth+j];
- pBitmap[i*nWidth+j] = pBitmap[i*nWidth+nWidth-j-1];
- pBitmap[i*nWidth+nWidth-j-1] = temp;
- }
-
- // Rebuilding mipmaps
- if(needRebuild)
- {
- buildMipMaps();
- }
-}
-
-
-// ***************************************************************************
-void CBitmap::flipV()
-{
- if (PixelFormat != RGBA)
- {
- // try for DXTC
- flipDXTC(true);
-
- // then quit (whether it worked or not)
- return;
- }
-
- sint32 nWidth = getWidth(0);
- sint32 nHeight = getHeight(0);
- sint32 i, j;
- NLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];
- bool needRebuild = false;
- CRGBA temp;
-
- if(_MipMapCount>1)
- needRebuild = true;
- releaseMipMaps();
-
- for( j = 0; j < nHeight/2; ++j )
- for( i = 0; i < nWidth; ++i )
- {
- temp = pBitmap[j*nWidth+i];
- pBitmap[j*nWidth+i] = pBitmap[(nHeight-j-1)*nWidth+i];
- pBitmap[(nHeight-j-1)*nWidth+i] = temp;
- }
-
- // Rebuilding mipmaps
- if(needRebuild)
- {
- buildMipMaps();
- }
-}
-
-
-void CBitmap::rot90CW()
-{
- if (PixelFormat != RGBA)
- return;
- sint32 nWidth = getWidth(0);
- sint32 nHeight = getHeight(0);
- sint32 i, j;
- NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
- bool needRebuild = false;
-
- if(_MipMapCount>1)
- needRebuild = true;
- releaseMipMaps();
-
- CObjectVector pDestui;
- pDestui.resize(nWidth*nHeight*4);
- NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
-
- for( j = 0; j < nHeight; ++j )
- for( i = 0; i < nWidth; ++i )
- pDestRgba[j+i*nHeight] = pSrcRgba[i+(nHeight-1-j)*nWidth];
-
- uint32 nTemp = _Width;
- _Width = _Height;
- _Height = nTemp;
-
- NLMISC::contReset(_Data[0]); // free memory
- _Data[0] = pDestui;
- // Rebuilding mipmaps
- if(needRebuild)
- {
- buildMipMaps();
- }
-}
-
-void CBitmap::rot90CCW()
-{
- if (PixelFormat != RGBA)
- return;
- sint32 nWidth = getWidth(0);
- sint32 nHeight = getHeight(0);
- sint32 i, j;
- NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
- bool needRebuild = false;
-
- if(_MipMapCount>1)
- needRebuild = true;
- releaseMipMaps();
-
- CObjectVector pDestui;
- pDestui.resize(nWidth*nHeight*4);
- NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
-
- for( j = 0; j < nHeight; ++j )
- for( i = 0; i < nWidth; ++i )
- pDestRgba[j+i*nHeight] = pSrcRgba[nWidth-1-i+j*nWidth];
-
- uint32 nTemp = _Width;
- _Width = _Height;
- _Height = nTemp;
-
- NLMISC::contReset(_Data[0]); // free memory
- _Data[0] = pDestui;
- // Rebuilding mipmaps
- if(needRebuild)
- {
- buildMipMaps();
- }
-}
-
-//===========================================================================
-void CBitmap::blend(CBitmap &Bm0, CBitmap &Bm1, uint16 factor, bool inputBitmapIsMutable /*= false*/)
-{
- nlassert(factor <= 256);
-
- nlassert(Bm0._Width != 0 && Bm0._Height != 0
- && Bm1._Width != 0 && Bm1._Height != 0);
-
- nlassert(Bm0._Width == Bm1._Width); // the bitmap should have the same size
- nlassert(Bm0._Height == Bm1._Height);
-
- const CBitmap *nBm0, *nBm1; // pointer to the bitmap that is used for blending, or to a copy is a conversion wa required
-
- CBitmap cp0, cp1; // these bitmap are copies of Bm1 and Bm0 if a conversion was needed
-
- if (Bm0.PixelFormat != RGBA)
- {
- if (inputBitmapIsMutable)
- {
- Bm0.convertToRGBA();
- nBm0 = &Bm0;
- }
- else
- {
- cp0 = Bm0;
- cp0.convertToRGBA();
- nBm0 = &cp0;
- }
- }
- else
- {
- nBm0 = &Bm0;
- }
-
-
- if (Bm1.PixelFormat != RGBA)
- {
- if (inputBitmapIsMutable)
- {
- Bm1.convertToRGBA();
- nBm1 = &Bm1;
- }
- else
- {
- cp1 = Bm1;
- cp1.convertToRGBA();
- nBm1 = &cp1;
- }
- }
- else
- {
- nBm1 = &Bm1;
- }
-
- if (this != nBm0 && this != nBm1)
- {
- // if source is the same than the dets, don't resize because this clear the bitmap
- this->resize(Bm0._Width, Bm0._Height, RGBA);
- }
-
- uint numPix = _Width * _Height; // 4 component per pixels
-
-
- const uint8 *src0 = &(nBm0->_Data[0][0]);
- const uint8 *src1 = &(nBm1->_Data[0][0]);
- uint8 *dest = &(this->_Data[0][0]);
-
-
- #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)
- if (CSystemInfo::hasMMX())
- {
- // On a P4 2GHz, with a 256x256 texture, I got the following results :
- // without mmx : 5.2 ms
- // with mmx : 1.7 ms
- // I'm sure this can be further optimized..
-
- uint numPixLeft = numPix & 1; // process 2 pixels at once, so special case for odd number
- numPix = numPix & ~1;
- // do fast blend with mmx
- uint64 blendFactor0;
- uint64 blendFactor1;
- uint16 *bf0 = (uint16 *) &blendFactor0;
- uint16 *bf1 = (uint16 *) &blendFactor1;
- bf0[0] = bf0[1] = bf0[2] = bf0[3] = (1 << 6) * (factor);
- bf1[0] = bf1[1] = bf1[2] = bf1[3] = (1 << 6) * (256 - factor);
- __asm
- {
- mov esi, src0
- mov eax, src1
- mov edi, dest
- mov ebx, -8
- mov ecx, numPix
- shr ecx, 1 // process pixels 2 by 2
- movq mm1, blendFactor0
- movq mm0, blendFactor1
-
- myLoop:
- pxor mm6, mm6
- lea ebx, [ebx + 8] // points next location
- pxor mm7, mm7
- movq mm2, [esi + ebx]
- movq mm3, [eax + ebx]
- // do blend
- punpckhbw mm7, mm2 // mm7 contains src0 color 0 in high bytes
- punpckhbw mm6, mm3 // mm6 contains src1 color 0 in high bytes
- psrl mm7, 1
- pxor mm4, mm4 // mm4 = 0
- psrl mm6, 1
- pmulhw mm7, mm0 // src0 = src0 * blendFactor
- pxor mm5, mm5 // mm5 = 0
- pmulhw mm6, mm1 // src1 = src1 * (1 - blendfactor)
- punpcklbw mm4, mm2 // mm4 contains src0 color 1 in high bytes
- paddusw mm6, mm7 // mm6 = src0[0] blended with src1[0]
- psrl mm4, 1
- psrlw mm6, 5
- punpcklbw mm5, mm3 // mm4 contains src1 color 1 in high bytes
- psrl mm5, 1
- pmulhw mm4, mm0 // src0 = src0 * blendFactor
- pmulhw mm5, mm1 // src1 = src1 * (1 - blendfactor)
- paddusw mm4, mm5 // mm6 = src0[1] blended with src1[1]
- psrlw mm4, 5
- // pack result
- packuswb mm4, mm6
- dec ecx
- movq [edi + ebx], mm4 // store result
- jne myLoop
- emms
- }
- if (numPixLeft)
- {
- // case of odd number of pixels
- src0 += 4 * numPix;
- src1 += 4 * numPix;
- dest += 4 * numPix;
- uint blendFact = (uint) factor;
- uint invblendFact = 256 - blendFact;
- *dest = (uint8) (((blendFact * *src1) + (invblendFact * *src0)) >> 8);
- *(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);
- *(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);
- *(dest + 3) = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);
- }
- }
- else
- #endif //#ifdef NL_OS_WINDOWS
- {
- uint8 *endPix = dest + (numPix << 2);
- // no mmx version
- uint blendFact = (uint) factor;
- uint invblendFact = 256 - blendFact;
- do
- {
- /// blend 4 component at each pass
- *dest = (uint8) (((blendFact * *src1) + (invblendFact * *src0)) >> 8);
- *(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);
- *(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);
- *(dest + 3) = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);
-
- src0 = src0 + 4;
- src1 = src1 + 4;
- dest = dest + 4;
- }
- while (dest != endPix);
- }
-}
-
-
-
-//-----------------------------------------------
-CRGBA CBitmap::getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const
-{
- uint w = getWidth(numMipMap);
- uint h = getHeight(numMipMap);
- if (w == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
- const uint8 *pix = &getPixels(numMipMap)[(x + y * w) << 2];
- return CRGBA(pix[0], pix[1], pix[2], pix[3]);
-}
-
-//-----------------------------------------------
-CRGBA CBitmap::getDXTCColorFromBlock(const uint8 *block, sint x, sint y)
-{
- uint16 col0;
- uint16 col1;
- memcpy(&col0, block, sizeof(uint16));
- memcpy(&col1, block + 2, sizeof(uint16));
- uint colIndex = (block[4 + (y & 3)] >> ((x & 3) << 1)) & 3;
- CRGBA result, c0, c1;
- if (col0 > col1)
- {
- switch(colIndex)
- {
- case 0:
- uncompress(col0, result);
- break;
- case 1:
- uncompress(col1, result);
- break;
- case 2:
- uncompress(col0, c0);
- uncompress(col1, c1);
- result.blendFromui(c0, c1, 85);
- break;
- case 3:
- uncompress(col0, c0);
- uncompress(col1, c1);
- result.blendFromui(c0, c1, 171);
- break;
- default:
- ;
- }
- result.A = 255;
- }
- else
- {
- switch(colIndex)
- {
- case 0:
- uncompress(col0, result);
- result.A = 255;
- break;
- case 1:
- uncompress(col1, result);
- result.A = 255;
- break;
- case 2:
- uncompress(col0, c0);
- uncompress(col1, c1);
- result.blendFromui(c0, c1, 128);
- result.A = 255;
- break;
- case 3:
- result.set(0, 0, 0, 0);
- break;
- }
- }
- return result;
-}
-
-//-----------------------------------------------
-CRGBA CBitmap::getDXTC1Texel(sint x, sint y, uint32 numMipMap) const
-{
- uint w = getWidth(numMipMap);
- uint h = getHeight(numMipMap);
- if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
- uint numRowBlocks = std::max((w + 3) >> 2, 1u);
- const uint8 *pix = &getPixels(numMipMap)[0];
- const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 3) + ((x >> 2) << 3));
- return getDXTCColorFromBlock(block, x, y);
-}
-
-
-//-----------------------------------------------
-CRGBA CBitmap::getDXTC3Texel(sint x, sint y, uint32 numMipMap) const
-{
- uint w = getWidth(numMipMap);
- uint h = getHeight(numMipMap);
- if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
- uint numRowBlocks = std::max((w + 3) >> 2, 1u);
- const uint8 *pix = &getPixels(numMipMap)[0];
- const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));
- CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
- // get alpha part
- uint8 alphaByte = block[((y & 3) << 1) + ((x & 2) >> 1)];
- result.A = (x & 1) ? (alphaByte & 0xf0) : ((alphaByte & 0x0f) << 4);
- return result;
-}
-
-//-----------------------------------------------
-CRGBA CBitmap::getDXTC5Texel(sint x, sint y, uint32 numMipMap) const
-{
- uint w = getWidth(numMipMap);
- uint h = getHeight(numMipMap);
- if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
- uint numRowBlocks = std::max((w + 3) >> 2, 1u);
- const uint8 *pix = &getPixels(numMipMap)[0];
- const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));
- CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
- // get alpha part
- uint8 alpha0 = block[0];
- uint8 alpha1 = block[1];
-
- uint alphaIndex;
- uint tripletIndex = (x & 3) + ((y & 3) << 2);
- if (tripletIndex < 8)
- {
- alphaIndex = (((uint32 &) block[2]) >> (tripletIndex * 3)) & 7;
- }
- else
- {
- alphaIndex = (((uint32 &) block[5]) >> ((tripletIndex - 8) * 3)) & 7; // we can read a dword there because there are color datas following he alpha datas
- }
-
- if (alpha0 > alpha1)
- {
- switch (alphaIndex)
- {
- case 0: result.A = alpha0; break;
- case 1: result.A = alpha1; break;
- case 2: result.A = (uint8) ((6 * (uint) alpha0 + (uint) alpha1) / 7); break;
- case 3: result.A = (uint8) ((5 * (uint) alpha0 + 2 * (uint) alpha1) / 7); break;
- case 4: result.A = (uint8) ((4 * (uint) alpha0 + 3 * (uint) alpha1) / 7); break;
- case 5: result.A = (uint8) ((3 * (uint) alpha0 + 4 * (uint) alpha1) / 7); break;
- case 6: result.A = (uint8) ((2 * (uint) alpha0 + 5 * (uint) alpha1) / 7); break;
- case 7: result.A = (uint8) (((uint) alpha0 + (uint) 6 * alpha1) / 7); break;
- }
- }
- else
- {
- switch (alphaIndex)
- {
- case 0: result.A = alpha0; break;
- case 1: result.A = alpha1; break;
- case 2: result.A = (uint8) ((4 * (uint) alpha0 + (uint) alpha1) / 5); break;
- case 3: result.A = (uint8) ((3 * (uint) alpha0 + 2 * (uint) alpha1) / 5); break;
- case 4: result.A = (uint8) ((2 * (uint) alpha0 + 3 * (uint) alpha1) / 5); break;
- case 5: result.A = (uint8) (((uint) alpha0 + 4 * (uint) alpha1) / 5); break;
- case 6: result.A = 0; break;
- case 7: result.A = 255; break;
- }
- }
- return result;
-}
-
-
-//-----------------------------------------------
-CRGBA CBitmap::getPixelColor(sint x, sint y, uint32 numMipMap /*=0*/) const
-{
-
- switch (PixelFormat)
- {
- case RGBA:
- return getRGBAPixel(x, y, numMipMap);
- case DXTC1:
- case DXTC1Alpha:
- return getDXTC1Texel(x, y, numMipMap);
- case DXTC3:
- return getDXTC3Texel(x, y, numMipMap);
- case DXTC5:
- return getDXTC5Texel(x, y, numMipMap);
- default:
- nlstop;
- break;
- }
- return CRGBA::Black;
-}
-
-
-//-----------------------------------------------
-void CBitmap::swap(CBitmap &other)
-{
- std::swap(PixelFormat, other.PixelFormat);
- std::swap(_MipMapCount, other._MipMapCount);
- std::swap(_LoadGrayscaleAsAlpha, other._LoadGrayscaleAsAlpha);
- std::swap(_Width, other._Width);
- std::swap(_Height, other._Height);
- for(uint k = 0; k < MAX_MIPMAP; ++k)
- {
- _Data[k].swap(other._Data[k]);
- }
-}
-
-//-----------------------------------------------
-void CBitmap::unattachPixels(CObjectVector *mipmapDestArray, uint maxMipMapCount /*=MAX_MIPMAP*/)
-{
- if (!mipmapDestArray) return;
- uint k;
- for(k = 0; k < std::min((uint) _MipMapCount, maxMipMapCount); ++k)
- {
- mipmapDestArray[k].swap(_Data[k]);
- _Data[k].clear();
- }
- for(; k < _MipMapCount; ++k)
- {
- _Data[k].clear();
- }
- #ifdef NL_DEBUG
- // check that remaining mipmaps are empty
- for(; k < _MipMapCount; ++k)
- {
- nlassert(_Data[k].empty());
- }
- #endif
- _MipMapCount = 1;
- _Width = 0;
- _Height = 0;
- PixelFormat = RGBA;
- _LoadGrayscaleAsAlpha = true;
-}
-
-
-
-
-void CBitmap::getData(uint8*& extractData)
-{
-
- uint32 size=0;
- if(PixelFormat==RGBA)
- size=_Width*_Height*4;
- else if(PixelFormat==Alpha||PixelFormat==Luminance)
- size=_Width*_Height;
- else
- {
- nlstop;
- }
-
- for(uint32 pix=0;pix=0;i--)
- {
- buf[_Height-1-i]=&_Data[0][i*lineSize];
- }
-
- size=lineSize*_Height;
-
- for(uint32 line=0;line<_Height;line++)
- {
- for(uint32 pix=0;pix
+// Copyright (C) 2010 Winch Gate Property Limited
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+#include "stdmisc.h"
+
+#include "nel/misc/bitmap.h"
+#include "nel/misc/stream.h"
+#include "nel/misc/file.h"
+
+// Define this to force all bitmap white (debug)
+// #define NEL_ALL_BITMAP_WHITE
+
+
+using namespace std;
+
+
+namespace NLMISC
+{
+
+struct EDDSBadHeader : public NLMISC::EStream
+{
+ EDDSBadHeader() : EStream( "Bad or unrecognized DDS file header" ) {}
+};
+
+struct ESeekFailed : public NLMISC::EStream
+{
+ ESeekFailed() : EStream( "Seek failed" ) {}
+};
+
+struct EAllocationFailure : public Exception
+{
+ EAllocationFailure() : Exception( "Can't allocate memory" ) {}
+};
+
+void blendFromui(NLMISC::CRGBA &c0, NLMISC::CRGBA &c1, uint coef);
+uint32 blend(uint32 &n0, uint32 &n1, uint32 coef0);
+
+const uint32 CBitmap::bitPerPixels[ModeCount]=
+{
+ 32, // RGBA
+ 8, // Luminance
+ 8, // Alpha
+ 16, // AlphaLuminance
+ 4, // DXTC1
+ 4, // DXTC1Alpha
+ 8, // DXTC3
+ 8, // DXTC5
+ 16 // DsDt
+};
+
+const uint32 CBitmap::DXTC1HEADER = NL_MAKEFOURCC('D','X', 'T', '1');
+const uint32 CBitmap::DXTC3HEADER = NL_MAKEFOURCC('D','X', 'T', '3');
+const uint32 CBitmap::DXTC5HEADER = NL_MAKEFOURCC('D','X', 'T', '5');
+
+
+#ifdef NEL_ALL_BITMAP_WHITE
+// Make all the textures white
+void MakeWhite(CBitmap &bitmaps)
+{
+ for (uint i=0; i0) //AlphaBitDepth
+ {
+ PixelFormat = DXTC1Alpha;
+ }
+//#endif
+
+ if(PixelFormat!= DXTC1 && PixelFormat!= DXTC1Alpha && PixelFormat!= DXTC3 && PixelFormat!= DXTC5)
+ {
+ delete [] _DDSSurfaceDesc;
+ throw EDDSBadHeader();
+ }
+
+ // compute the min power of 2 between width and height
+ uint minSizeLevel= min(_Width, _Height);
+ minSizeLevel= getPowerOf2(minSizeLevel);
+
+ //------------- manage mipMapSkip
+ if(_MipMapCount>1 && mipMapSkip>0 && minSizeLevel>2)
+ {
+ // Keep at least the level where width and height are at least 4.
+ mipMapSkip= min(mipMapSkip, minSizeLevel-2);
+ // skip any mipmap
+ uint seekSize= 0;
+ while(mipMapSkip>0 && _MipMapCount>1)
+ {
+ // raise to next multiple of 4
+ uint32 wtmp= (_Width+3)&(~3);
+ uint32 htmp= (_Height+3)&(~3);
+ wtmp= max(wtmp, uint32(4));
+ htmp= max(htmp, uint32(4));
+
+ uint32 mipMapSz;
+ if(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)
+ mipMapSz = wtmp*htmp/2;
+ else
+ mipMapSz = wtmp*htmp;
+
+ // add to how many to skip
+ seekSize+= mipMapSz;
+
+ // Size of final bitmap is reduced.
+ _Width>>=1;
+ _Height>>=1;
+ _MipMapCount--;
+ mipMapSkip--;
+ }
+ // skip data in file
+ if(seekSize>0)
+ {
+ if(!f.seek(seekSize, IStream::current))
+ {
+ delete [] _DDSSurfaceDesc;
+ throw ESeekFailed();
+ }
+ }
+
+ }
+
+ //------------- preload all the mipmaps (one serialBuffer() is faster)
+ uint32 w = _Width;
+ uint32 h = _Height;
+ uint32 totalSize= 0;
+
+ uint8 m;
+ for(m= 0; m<_MipMapCount; m++)
+ {
+ // raise to next multiple of 4
+ uint32 wtmp= (w+3)&(~3);
+ uint32 htmp= (h+3)&(~3);
+ wtmp= max(wtmp, uint32(4));
+ htmp= max(htmp, uint32(4));
+
+ uint32 mipMapSz;
+ if(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)
+ mipMapSz = wtmp*htmp/2;
+ else
+ mipMapSz = wtmp*htmp;
+
+
+ _Data[m].resize(mipMapSz);
+ totalSize+= mipMapSz;
+
+ w = (w+1)/2;
+ h = (h+1)/2;
+ }
+
+ // Read all the data in one block.
+ vector pixData;
+ pixData.resize(totalSize);
+ f.serialBuffer(&(*pixData.begin()), totalSize);
+
+
+ //------------- reading mipmap levels from pixData
+
+ uint32 pixIndex= 0;
+
+ for(m= 0; m<_MipMapCount; m++)
+ {
+ uint32 mipMapSz= _Data[m].size();
+ memcpy(_Data[m].getPtr(), &(pixData[pixIndex]), mipMapSz);
+ pixIndex+= mipMapSz;
+ }
+
+ //------------- End
+
+ delete [] _DDSSurfaceDesc;
+
+ switch(PixelFormat)
+ {
+ case DXTC1 : return 24;
+ case DXTC1Alpha : return 32;
+ case DXTC3 : return 32;
+ case DXTC5 : return 32;
+ default : break;
+ }
+
+ return 0;
+}
+
+
+
+
+/*-------------------------------------------------------------------*\
+ convertToDXTC5
+\*-------------------------------------------------------------------*/
+bool CBitmap::convertToDXTC5()
+{
+ /* Yoyo: RGB encoding for DXTC1 and DXTC5/3 are actually different!!
+ DXTC3/5 don't rely on sign of color0>color1 to setup special encoding (ie use a special compression for Black)
+ Since this can arise if the src is DXTC1 , we can't simply compress it into DXTC5 without doing a
+ heavy compression...
+ (the inverse is false: DXTC5 to DXTC1 is possible, with maybe swap color0/color1 and bits).
+ */
+
+ return false;
+
+/* uint32 i,j;
+
+ if(PixelFormat!=DXTC1) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(2*_Data[m].size());
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i+=8)
+ {
+ //64 bits alpha
+ for(j=0; j<8; j++)
+ {
+ dataTmp[dstId++]= 255;
+ }
+
+ //64 bits RGB
+ for(j=0; j<8; j++)
+ {
+ dataTmp[dstId++]= _Data[m][i+j];
+ }
+ }
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = DXTC5;
+ return true;
+*/
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ luminanceToRGBA()
+\*-------------------------------------------------------------------*/
+bool CBitmap::luminanceToRGBA()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()*4);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i++)
+ {
+ dataTmp[dstId++]= _Data[m][i];
+ dataTmp[dstId++]= _Data[m][i];
+ dataTmp[dstId++]= _Data[m][i];
+ dataTmp[dstId++]= 255;
+ }
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = RGBA;
+ return true;
+}
+
+/*-------------------------------------------------------------------*\
+ alphaToRGBA()
+\*-------------------------------------------------------------------*/
+bool CBitmap::alphaToRGBA()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()*4);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i++)
+ {
+ dataTmp[dstId++]= 255;
+ dataTmp[dstId++]= 255;
+ dataTmp[dstId++]= 255;
+ dataTmp[dstId++]= _Data[m][i];
+ }
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = RGBA;
+ return true;
+}
+
+
+/*-------------------------------------------------------------------*\
+ alphaLuminanceToRGBA()
+\*-------------------------------------------------------------------*/
+bool CBitmap::alphaLuminanceToRGBA()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()*2);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i+=2)
+ {
+ dataTmp[dstId++]= _Data[m][i];
+ dataTmp[dstId++]= _Data[m][i];
+ dataTmp[dstId++]= _Data[m][i];
+ dataTmp[dstId++]= _Data[m][i+1];
+ }
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = RGBA;
+ return true;
+}
+
+
+
+
+/*-------------------------------------------------------------------*\
+ rgbaToAlphaLuminance
+\*-------------------------------------------------------------------*/
+bool CBitmap::rgbaToAlphaLuminance()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()/2);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i+=4)
+ {
+ dataTmp[dstId++]= (_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255;
+ dataTmp[dstId++]= _Data[m][i+3];
+ }
+ NLMISC::contReset(_Data[m]);
+ _Data[m].resize(0);
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = AlphaLuminance;
+ return true;
+}
+
+
+/*-------------------------------------------------------------------*\
+ luminanceToAlphaLuminance
+\*-------------------------------------------------------------------*/
+bool CBitmap::luminanceToAlphaLuminance()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()*2);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i++)
+ {
+ dataTmp[dstId++]= _Data[m][i];
+ dataTmp[dstId++]= 255;
+ }
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = AlphaLuminance;
+ return true;
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ alphaToAlphaLuminance
+\*-------------------------------------------------------------------*/
+bool CBitmap::alphaToAlphaLuminance()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()*2);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i++)
+ {
+ dataTmp[dstId++]= 0;
+ dataTmp[dstId++]= _Data[m][i];
+ }
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = AlphaLuminance;
+ return true;
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ rgbaToLuminance
+\*-------------------------------------------------------------------*/
+bool CBitmap::rgbaToLuminance()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()/4);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i+=4)
+ {
+ dataTmp[dstId++]= (_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255;
+ }
+ NLMISC::contReset(_Data[m]);
+ _Data[m].resize(0);
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = Luminance;
+ return true;
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ alphaToLuminance
+\*-------------------------------------------------------------------*/
+bool CBitmap::alphaToLuminance()
+{
+ if(_Width*_Height == 0) return false;
+
+ PixelFormat = Luminance;
+ return true;
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ alphaLuminanceToLuminance
+\*-------------------------------------------------------------------*/
+bool CBitmap::alphaLuminanceToLuminance()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()/2);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i+=2)
+ {
+ dataTmp[dstId++]= 0;
+ dataTmp[dstId++]= 0;
+ dataTmp[dstId++]= 0;
+ dataTmp[dstId++]= _Data[m][i];
+ }
+ NLMISC::contReset(_Data[m]);
+ _Data[m].resize(0);
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = Luminance;
+ return true;
+}
+
+
+/*-------------------------------------------------------------------*\
+ rgbaToAlpha
+\*-------------------------------------------------------------------*/
+bool CBitmap::rgbaToAlpha()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()/4);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i+=4)
+ {
+ dataTmp[dstId++]= _Data[m][i+3];
+ }
+ NLMISC::contReset(_Data[m]);
+ _Data[m].resize(0);
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = Alpha;
+ return true;
+}
+
+
+/*-------------------------------------------------------------------*\
+ luminanceToAlpha
+\*-------------------------------------------------------------------*/
+bool CBitmap::luminanceToAlpha()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size());
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i++)
+ {
+ dataTmp[dstId++]= _Data[m][i];
+ }
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = Alpha;
+ return true;
+}
+
+
+/*-------------------------------------------------------------------*\
+ alphaLuminanceToAlpha
+\*-------------------------------------------------------------------*/
+bool CBitmap::alphaLuminanceToAlpha()
+{
+ uint32 i;
+
+ if(_Width*_Height == 0) return false;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ CObjectVector dataTmp;
+ dataTmp.resize(_Data[m].size()/2);
+ uint dstId= 0;
+
+ for(i=0; i<_Data[m].size(); i+=2)
+ {
+ dataTmp[dstId++]= _Data[m][i+1];
+ }
+ NLMISC::contReset(_Data[m]);
+ _Data[m].resize(0);
+ _Data[m] = dataTmp;
+ }
+ PixelFormat = Alpha;
+ return true;
+}
+
+
+/*-------------------------------------------------------------------*\
+ convertToLuminance
+\*-------------------------------------------------------------------*/
+bool CBitmap::convertToLuminance()
+{
+ switch(PixelFormat)
+ {
+ case RGBA :
+ return rgbaToLuminance();
+ break;
+
+ case Luminance :
+ return true;
+ break;
+
+ case Alpha :
+ return alphaToLuminance();
+ break;
+
+ case AlphaLuminance :
+ return alphaLuminanceToLuminance();
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ convertToAlpha
+\*-------------------------------------------------------------------*/
+bool CBitmap::convertToAlpha()
+{
+ switch(PixelFormat)
+ {
+ case RGBA :
+ return rgbaToAlpha();
+ break;
+
+ case Luminance :
+ return luminanceToAlpha();
+ break;
+
+ case Alpha :
+ return true;
+ break;
+
+ case AlphaLuminance :
+ return alphaLuminanceToAlpha();
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ convertToAlphaLuminance
+\*-------------------------------------------------------------------*/
+bool CBitmap::convertToAlphaLuminance()
+{
+ switch(PixelFormat)
+ {
+ case RGBA :
+ return rgbaToAlphaLuminance();
+ break;
+
+ case Luminance :
+ return luminanceToAlphaLuminance();
+ break;
+
+ case Alpha :
+ return alphaToAlphaLuminance();
+ break;
+
+ case AlphaLuminance :
+ return true;
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+/*-------------------------------------------------------------------*\
+ convertToRGBA
+\*-------------------------------------------------------------------*/
+bool CBitmap::convertToRGBA()
+{
+ switch(PixelFormat)
+ {
+ case DXTC1 :
+ return decompressDXT1(false);
+ break;
+
+ case DXTC1Alpha :
+ return decompressDXT1(true);
+ break;
+
+ case DXTC3 :
+ return decompressDXT3();
+ break;
+
+ case DXTC5 :
+ return decompressDXT5();
+ break;
+
+ case Luminance :
+ return luminanceToRGBA();
+ break;
+
+ case Alpha :
+ return alphaToRGBA();
+ break;
+
+ case AlphaLuminance :
+ return alphaLuminanceToRGBA();
+ break;
+ case RGBA:
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+
+/*-------------------------------------------------------------------*\
+ convertToType
+\*-------------------------------------------------------------------*/
+bool CBitmap::convertToType(CBitmap::TType type)
+{
+ if(PixelFormat==type) return true;
+
+ switch(type)
+ {
+ case RGBA :
+ return convertToRGBA();
+ break;
+
+ case DXTC5 :
+ return convertToDXTC5();
+ break;
+
+ case Luminance :
+ return convertToLuminance();
+ break;
+
+ case Alpha :
+ return convertToAlpha();
+ break;
+
+ case AlphaLuminance :
+ return convertToAlphaLuminance();
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
+
+
+/*-------------------------------------------------------------------*\
+ decompressDXT1
+\*-------------------------------------------------------------------*/
+bool CBitmap::decompressDXT1(bool alpha)
+{
+ uint32 i,j,k;
+ NLMISC::CRGBA c[4];
+ CObjectVector dataTmp[MAX_MIPMAP];
+
+ uint32 width= _Width;
+ uint32 height= _Height;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ uint32 wtmp, htmp;
+ if(width<4)
+ wtmp = 4;
+ else
+ wtmp = width;
+ if(height < 4)
+ htmp = 4;
+ else
+ htmp = height;
+ uint32 mipMapSz = wtmp*htmp*4;
+ dataTmp[m].resize(mipMapSz);
+ if(dataTmp[m].size()color1)
+ {
+ c[2].blendFromui(c[0],c[1],85);
+ if(alpha) c[2].A= 255;
+
+ c[3].blendFromui(c[0],c[1],171);
+ if(alpha) c[3].A= 255;
+ }
+ else
+ {
+ c[2].blendFromui(c[0],c[1],128);
+ if(alpha) c[2].A= 255;
+
+ c[3].set(0,0,0,0);
+ }
+
+ // computing the 16 RGBA of the block
+
+ uint32 blockNum= i/8; //(64 bits)
+ // * 4 (rows) * _Width (columns) + 4pix*4rgba*
+ uint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);
+ for(j=0; j<4; j++)
+ {
+ for(k=0; k<4; k++)
+ {
+ dataTmp[m][pixelsCount + j*wtmp*4 + 4*k]= c[bits&3].R;
+ dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+1]= c[bits&3].G;
+ dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+2]= c[bits&3].B;
+ dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+3]= c[bits&3].A;
+ bits>>=2;
+ }
+ }
+ }
+
+ // Copy result into the mipmap level.
+ if(wtmp==width && htmp==height)
+ {
+ // For mipmaps level >4 pixels.
+ _Data[m]= dataTmp[m];
+ }
+ else
+ {
+ // For last mipmaps, level <4 pixels.
+ _Data[m].resize(width*height*4);
+ CRGBA *src= (CRGBA*)&dataTmp[m][0];
+ CRGBA *dst= (CRGBA*)&_Data[m][0];
+ uint x,y;
+ for(y=0;y dataTmp[MAX_MIPMAP];
+
+ uint32 width= _Width;
+ uint32 height= _Height;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ uint32 wtmp, htmp;
+ if(width<4)
+ wtmp = 4;
+ else
+ wtmp = width;
+ if(height < 4)
+ htmp = 4;
+ else
+ htmp = height;
+ uint32 mipMapSz = wtmp*htmp*4;
+ dataTmp[m].resize(mipMapSz);
+ if(dataTmp[m].size()>=4;
+ }
+
+
+ uint16 color0;
+ uint16 color1;
+ uint32 bits;
+ memcpy(&color0,&_Data[m][i+8],2);
+ memcpy(&color1,&_Data[m][i+10],2);
+ memcpy(&bits,&_Data[m][i+12],4);
+
+ uncompress(color0,c[0]);
+ uncompress(color1,c[1]);
+
+ // ignore color0>color1 for DXT3 and DXT5.
+ c[2].blendFromui(c[0],c[1],85);
+ c[3].blendFromui(c[0],c[1],171);
+
+ // computing the 16 RGBA of the block
+
+ uint32 blockNum= i/16; //(128 bits)
+ // * 4 (rows) * wtmp (columns) + 4pix*4rgba*
+ uint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);
+ for(j=0; j<4; j++)
+ {
+ for(k=0; k<4; k++)
+ {
+ dataTmp[m][pixelsCount + j*wtmp*4 + 4*k]= c[bits&3].R;
+ dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+1]= c[bits&3].G;
+ dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+2]= c[bits&3].B;
+ dataTmp[m][pixelsCount + j*wtmp*4 + 4*k+3]= alpha[4*j+k];
+ bits>>=2;
+ }
+ }
+ }
+
+ // Copy result into the mipmap level.
+ if(wtmp==width && htmp==height)
+ {
+ // For mipmaps level >4 pixels.
+ _Data[m]= dataTmp[m];
+ }
+ else
+ {
+ // For last mipmaps, level <4 pixels.
+ _Data[m].resize(width*height*4);
+ CRGBA *src= (CRGBA*)&dataTmp[m][0];
+ CRGBA *dst= (CRGBA*)&_Data[m][0];
+ uint x,y;
+ for(y=0;y dataTmp[MAX_MIPMAP];
+
+ uint32 width= _Width;
+ uint32 height= _Height;
+
+ for(uint8 m= 0; m<_MipMapCount; m++)
+ {
+ uint32 wtmp, htmp;
+ if(width<4)
+ wtmp = 4;
+ else
+ wtmp = width;
+ if(height < 4)
+ htmp = 4;
+ else
+ htmp = height;
+ uint32 mipMapSz = wtmp*htmp*4;
+ dataTmp[m].resize(mipMapSz);
+ if(dataTmp[m].size()>= 16;
+
+ uint32 alpha[8];
+ alpha[0]= _Data[m][i+0];
+ alpha[1]= _Data[m][i+1];
+
+ if(alpha[0]>alpha[1])
+ {
+ alpha[2]= blend(alpha[0], alpha[1], 219);
+ alpha[3]= blend(alpha[0], alpha[1], 183);
+ alpha[4]= blend(alpha[0], alpha[1], 146);
+ alpha[5]= blend(alpha[0], alpha[1], 110);
+ alpha[6]= blend(alpha[0], alpha[1], 73);
+ alpha[7]= blend(alpha[0], alpha[1], 37);
+ }
+ else
+ {
+ alpha[2]= blend(alpha[0], alpha[1], 204);
+ alpha[3]= blend(alpha[0], alpha[1], 154);
+ alpha[4]= blend(alpha[0], alpha[1], 102);
+ alpha[5]= blend(alpha[0], alpha[1], 51);
+ alpha[6]= 0;
+ alpha[7]= 255;
+ }
+
+ uint8 codeAlpha[16];
+ for(j=0; j<16; j++)
+ {
+ codeAlpha[j] = (uint8)(bitsAlpha & 7);
+ bitsAlpha>>=3;
+ }
+
+
+ uint16 color0;
+ uint16 color1;
+ uint32 bits;
+ memcpy(&color0,&_Data[m][i+8],2);
+ memcpy(&color1,&_Data[m][i+10],2);
+ memcpy(&bits,&_Data[m][i+12],4);
+
+ uncompress(color0,c[0]);
+ uncompress(color1,c[1]);
+
+ // ignore color0>color1 for DXT3 and DXT5.
+ c[2].blendFromui(c[0],c[1],85);
+ c[3].blendFromui(c[0],c[1],171);
+
+ // computing the 16 RGBA of the block
+
+ uint32 blockNum= i/16; //(128 bits)
+
+ // * 4 (rows) * wtmp (columns) + 4pix*
+ uint32 pixelsCount= (blockNum/wBlockCount)*wtmp*4 + 4*(blockNum%wBlockCount);
+ // *sizeof(RGBA)
+ pixelsCount*=4;
+ for(j=0; j<4; j++)
+ {
+ for(k=0; k<4; k++)
+ {
+ dataTmp[m][pixelsCount + (j*wtmp+k)*4 +0]= c[bits&3].R;
+ dataTmp[m][pixelsCount + (j*wtmp+k)*4 +1]= c[bits&3].G;
+ dataTmp[m][pixelsCount + (j*wtmp+k)*4 +2]= c[bits&3].B;
+ dataTmp[m][pixelsCount + (j*wtmp+k)*4 +3]= (uint8) alpha[codeAlpha[4*j+k]];
+ bits>>=2;
+ }
+ }
+
+ }
+
+ // Copy result into the mipmap level.
+ if(wtmp==width && htmp==height)
+ {
+ // For mipmaps level >4 pixels.
+ _Data[m]= dataTmp[m];
+ }
+ else
+ {
+ // For last mipmaps, level <4 pixels.
+ _Data[m].resize(width*height*4);
+ CRGBA *src= (CRGBA*)&dataTmp[m][0];
+ CRGBA *dst= (CRGBA*)&_Data[m][0];
+ uint x,y;
+ for(y=0;y>8);
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ uncompress
+\*-------------------------------------------------------------------*/
+inline void CBitmap::uncompress(uint16 color, NLMISC::CRGBA &r)
+{
+ r.A= 0;
+ r.R= ((color>>11)&31) << 3; r.R+= r.R>>5;
+ r.G= ((color>>5)&63) << 2; r.G+= r.G>>6;
+ r.B= ((color)&31) << 3; r.B+= r.B>>5;
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ getWidth
+\*-------------------------------------------------------------------*/
+uint32 CBitmap::getWidth(uint32 mipMap) const
+{
+ if(mipMap==0) return _Width;
+
+ uint32 w = _Width;
+ uint32 h = _Height;
+ uint32 m = 0;
+
+ do
+ {
+ m++;
+ w = (w+1)/2;
+ h = (h+1)/2;
+ if(m==mipMap) return w;
+ }
+ while(w!=1 || h!=1);
+
+ return 0;
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ getHeight
+\*-------------------------------------------------------------------*/
+uint32 CBitmap::getHeight(uint32 mipMap) const
+{
+ if(mipMap==0) return _Height;
+
+ uint32 w = _Width;
+ uint32 h = _Height;
+ uint32 m = 0;
+
+ do
+ {
+ m++;
+ w = (w+1)/2;
+ h = (h+1)/2;
+ if(m==mipMap) return h;
+ }
+ while(w!=1 || h!=1);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------*\
+ getSize
+\*-------------------------------------------------------------------*/
+uint32 CBitmap::getSize(uint32 numMipMap) const
+{
+ return getHeight(numMipMap)*getWidth(numMipMap);
+}
+
+
+
+/*-------------------------------------------------------------------*\
+ buildMipMaps
+\*-------------------------------------------------------------------*/
+void CBitmap::buildMipMaps()
+{
+ uint32 i,j;
+
+ if(PixelFormat!=RGBA) return;
+ if(_MipMapCount!=1) return;
+ if(!NLMISC::isPowerOf2(_Width)) return;
+ if(!NLMISC::isPowerOf2(_Height)) return;
+
+ uint32 w = _Width;
+ uint32 h = _Height;
+
+ while(w>1 || h>1)
+ {
+ uint32 precw = w;
+ uint32 prech = h;
+ w = (w+1)/2;
+ h = (h+1)/2;
+ uint32 mulw= precw/w;
+ uint32 mulh= prech/h;
+
+ _Data[_MipMapCount].resize(w*h*4);
+
+ NLMISC::CRGBA *pRgba = (NLMISC::CRGBA*)&_Data[_MipMapCount][0];
+ NLMISC::CRGBA *pRgbaPrev = (NLMISC::CRGBA*)&_Data[_MipMapCount-1][0];
+ for(i=0; i1 || h>1)
+ {
+ w = (w+1)/2;
+ h = (h+1)/2;
+ ++mipMapCount;
+ }
+ return mipMapCount;
+}
+
+/*-------------------------------------------------------------------*\
+ releaseMipMaps
+\*-------------------------------------------------------------------*/
+void CBitmap::releaseMipMaps()
+{
+ if(_MipMapCount<=1) return;
+
+ _MipMapCount=1;
+ for(sint i=1;i1)
+ needRebuild = true;
+ releaseMipMaps();
+ //logResample("Resample: 20");
+
+ if(nNewWidth==0 || nNewHeight==0)
+ {
+ _Width = _Height = 0;
+ //logResample("Resample: 25");
+ return;
+ }
+
+ //logResample("Resample: 30");
+ CObjectVector pDestui;
+ pDestui.resize(nNewWidth*nNewHeight*4);
+ //logResample("Resample: 40");
+ NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
+ //logResample("Resample: 50");
+
+ resamplePicture32 ((NLMISC::CRGBA*)&_Data[0][0], pDestRgba, _Width, _Height, nNewWidth, nNewHeight);
+ //logResample("Resample: 60");
+
+ NLMISC::contReset(_Data[0]); // free memory
+ //logResample("Resample: 70");
+
+ _Data[0] = pDestui;
+ //logResample("Resample: 80");
+ _Width= nNewWidth;
+ _Height= nNewHeight;
+
+ // Rebuilding mipmaps
+ //logResample("Resample: 90");
+ if(needRebuild)
+ {
+ buildMipMaps();
+ //logResample("Resample: 95");
+ }
+ //logResample("Resample: 100");
+}
+
+
+/*-------------------------------------------------------------------*\
+ resize
+\*-------------------------------------------------------------------*/
+void CBitmap::resize (sint32 nNewWidth, sint32 nNewHeight, TType newType, bool resetTo0)
+{
+ // Deleting mipmaps
+ releaseMipMaps();
+
+ // Change type of bitmap ?
+ if (newType!=DonTKnow)
+ PixelFormat=newType;
+
+ _Width = nNewWidth;
+ _Height = nNewHeight;
+
+ // resize the level 0 only.
+ resizeMipMap(0, nNewWidth, nNewHeight, resetTo0);
+}
+
+
+/*-------------------------------------------------------------------*\
+ resizeMipMap
+\*-------------------------------------------------------------------*/
+void CBitmap::resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight, bool resetTo0)
+{
+ nlassert(numMipMap=nSrcWidth);
+ bool bYMag=(nDestHeight>=nSrcHeight);
+ bool bXEq=(nDestWidth==nSrcWidth);
+ bool bYEq=(nDestHeight==nSrcHeight);
+ std::vector pIterm (nDestWidth*nSrcHeight);
+
+ if (bXMag)
+ {
+ float fXdelta=(float)(nSrcWidth)/(float)(nDestWidth);
+ NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
+ sint32 nY;
+ for (nY=0; nY=0.f);
+ NLMISC::CRGBAF vColor;
+ if (fVirgule>=0.5f)
+ {
+ if (fX<(float)(nSrcWidth-1))
+ {
+ NLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);
+ NLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)+1]);
+ vColor=vColor1*(1.5f-fVirgule)+vColor2*(fVirgule-0.5f);
+ }
+ else
+ vColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
+ }
+ else
+ {
+ if (fX>=1.f)
+ {
+ NLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);
+ NLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)-1]);
+ vColor=vColor1*(0.5f+fVirgule)+vColor2*(0.5f-fVirgule);
+ }
+ else
+ vColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
+ }
+ *(pItermPtr++)=vColor;
+ fX+=fXdelta;
+ }
+ pSrc+=nSrcWidth;
+ }
+ }
+ else if (bXEq)
+ {
+ NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
+ for (sint32 nY=0; nY1.f);
+ NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
+ sint32 nY;
+ for (nY=0; nYfFinal)
+ fNext=fFinal;
+ vColor+=((float)(fNext-fX))*NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
+ fX=fNext;
+ }
+ fX = fFinal; // ensure fX == fFinal
+ vColor/=(float)fXdelta;
+ *(pItermPtr++)=vColor;
+ }
+ pSrc+=nSrcWidth;
+ }
+ }
+
+ if (bYMag)
+ {
+ double fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);
+ sint32 nX;
+ for (nX=0; nX=0.f);
+ NLMISC::CRGBAF vColor;
+ if (fVirgule>=0.5f)
+ {
+ if (fY<(double)(nSrcHeight-1))
+ {
+ NLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
+ NLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))+1)*nDestWidth+nX];
+ vColor=vColor1*(1.5f-(float)fVirgule)+vColor2*((float)fVirgule-0.5f);
+ }
+ else
+ vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
+ }
+ else
+ {
+ if (fY>=1.f)
+ {
+ NLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
+ NLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))-1)*nDestWidth+nX];
+ vColor=vColor1*(0.5f+(float)fVirgule)+vColor2*(0.5f-(float)fVirgule);
+ }
+ else
+ vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
+ }
+ pDest[nX+nY*nDestWidth]=vColor;
+ fY+=fYdelta;
+ }
+ }
+ }
+ else if (bYEq)
+ {
+ for (sint32 nX=0; nX1.f);
+ sint32 nX;
+ for (nX=0; nXfFinal)
+ fNext=fFinal;
+ vColor+=((float)(fNext-fY))*pIterm[((sint32)floor(fY))*nDestWidth+nX];
+ fY=fNext;
+ }
+ vColor/=(float)fYdelta;
+ pDest[nX+nY*nDestWidth]=vColor;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*\
+ resamplePicture32Fast
+\*-------------------------------------------------------------------*/
+void CBitmap::resamplePicture32Fast (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest,
+ sint32 nSrcWidth, sint32 nSrcHeight,
+ sint32 nDestWidth, sint32 nDestHeight)
+{
+ // the image is divided by two : 1 pixel in dest = 4 pixels in src
+ // the resulting pixel in dest is an average of the four pixels in src
+
+ nlassert(nSrcWidth % 2 == 0);
+ nlassert(nSrcHeight % 2 == 0);
+ nlassert(nSrcWidth / 2 == nDestWidth);
+ nlassert(nSrcHeight / 2 == nDestHeight);
+
+ sint32 x, y, twoX, twoSrcWidthByY;
+
+ for (y=0 ; y= 26)
+ {
+ f.seek (-26, f.end);
+ f.serial(extAreaOffset);
+ f.serial(devDirectoryOffset);
+ for(i=0; i<16; i++)
+ {
+ f.serial(signature[i]);
+ }
+ if(strncmp(signature,"TRUEVISION-XFILE",16)==0)
+ newTgaFormat = true;
+ }
+
+
+
+ // Reading TGA file header
+ f.seek (0, f.begin);
+
+ f.serial(lengthID);
+ f.serial(cMapType);
+ f.serial(imageType);
+ f.serial(origin);
+ f.serial(length);
+ f.serial(depth);
+ f.serial(xOrg);
+ f.serial(yOrg);
+ f.serial(width);
+ f.serial(height);
+ f.serial(imageDepth);
+ f.serial(desc);
+
+ if(cMapType!=0)
+ {
+ nlinfo("readTga : color-map not supported");
+ }
+
+ if(lengthID>0)
+ {
+ uint8 dummy;
+ for(i=0; i>10;
+ uint _g = (toto>>5)&0x1f;
+ uint _b = toto&0x1f;
+ _Data[0][(height-y-1)*width*4 + 4*i] = uint8((_r<<3) | (_r>>2));
+ _Data[0][(height-y-1)*width*4 + 4*i + 1] = uint8((_g<<3) | (_g>>2));
+ _Data[0][(height-y-1)*width*4 + 4*i + 2] = uint8((_b<<3) | (_b>>2));
+ _Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;
+ }
+ else
+ {
+ _Data[0][(height-y-1)*width*4 + 4*i] = scanline[k++];
+ _Data[0][(height-y-1)*width*4 + 4*i + 1] = scanline[k++];
+ _Data[0][(height-y-1)*width*4 + 4*i + 2] = scanline[k++];
+ if(imageDepth==32)
+ _Data[0][(height-y-1)*width*4 + 4*i + 3] = scanline[k++];
+ else
+ _Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;
+ }
+ }
+ else
+ {
+ if(imageDepth==16)
+ {
+ uint16 toto = (uint16)scanline[k++];
+ toto |= scanline[k++]<<8;
+ int _r = toto>>10;
+ int _g = toto&(0x3e0)>>5;
+ int _b = toto&0x1f;
+ _Data[0][y*width*4 + 4*i] = uint8((_r<<3) | (_r>>2));
+ _Data[0][y*width*4 + 4*i + 1] = uint8((_g<<3) | (_g>>2));
+ _Data[0][y*width*4 + 4*i + 2] = uint8((_b<<3) | (_b>>2));
+ _Data[0][y*width*4 + 4*i + 3] = 255;
+ }
+ else
+ {
+ _Data[0][y*width*4 + 4*i] = scanline[k++];
+ _Data[0][y*width*4 + 4*i + 1] = scanline[k++];
+ _Data[0][y*width*4 + 4*i + 2] = scanline[k++];
+ if(imageDepth==32)
+ _Data[0][y*width*4 + 4*i + 3] = scanline[k++];
+ else
+ _Data[0][y*width*4 + 4*i + 3] = 255;
+ }
+ }
+ }
+ }
+
+ PixelFormat = RGBA;
+ delete []scanline;
+ };
+ break;
+
+ // Uncompressed Grayscale bitmap
+ case 3:
+ {
+ _Data[0].resize(_Width*_Height);
+ uint8 upSideDown = ((desc & (1 << 5))==0);
+ slsize = _Width;
+
+ scanline = new uint8[slsize];
+ if(!scanline)
+ {
+ throw EAllocationFailure();
+ }
+
+ for(y=0; y<_Height;y++)
+ {
+ // Serial buffer: more efficient way to load.
+ f.serialBuffer (scanline, slsize);
+
+ k=0;
+ for(i=0; i 0) // packet RLE
+ {
+ for(i=0; i 0) // packet RLE
+ {
+ f.serial(pixel[0]);
+ for (i=0; i < (packet & 0x7F) + 1; i++)
+ {
+ _Data[0][dstId++]= pixel[0];
+ }
+ }
+ else // packet Raw
+ {
+ for(i=0; i<((packet & 0x7F) + 1); i++)
+ {
+ f.serial(pixel[0]);
+ _Data[0][dstId++]= pixel[0];
+ }
+ }
+ readSize += (packet & 0x7F) + 1;
+ }
+ PixelFormat = _LoadGrayscaleAsAlpha?Alpha:Luminance;
+ };
+ break;
+
+ default:
+ return 0;
+ }
+
+ _MipMapCount = 1;
+ return(imageDepth);
+
+}
+
+/*-------------------------------------------------------------------*\
+ writeTGA
+\*-------------------------------------------------------------------*/
+bool CBitmap::writeTGA( NLMISC::IStream &f, uint32 d, bool upsideDown)
+{
+ if(f.isReading()) return false;
+ if (d==0)
+ {
+ switch (PixelFormat)
+ {
+ case RGBA:
+ d = 32;
+ break;
+ case Luminance:
+ d = 8;
+ break;
+ case Alpha:
+ d = 8;
+ break;
+ default:
+ ;
+ }
+ }
+ if(d!=24 && d!=32 && d!=16 && d!=8) return false;
+ if ((PixelFormat != RGBA)&&(PixelFormat != Alpha)&&(PixelFormat != Luminance)) return false;
+ if ((PixelFormat == Alpha) && (d != 8)) return false;
+ if ((PixelFormat == Luminance) && (d != 8)) return false;
+
+ sint32 i,j,x,y;
+ uint8 * scanline;
+ uint8 r,g,b,a;
+
+ uint8 lengthID = 0;
+ uint8 cMapType = 0;
+ uint8 imageType = 2;
+ uint16 origin = 0;
+ uint16 length = 0;
+ uint8 depth = 0;
+ uint16 xOrg = 0;
+ uint16 yOrg = 0;
+ uint16 width = (uint16)_Width;
+ uint16 height = (uint16)_Height;
+ uint8 imageDepth = (uint8)d;
+ uint8 desc = 0;
+ if (upsideDown)
+ desc |= 1<<5;
+
+ if ((PixelFormat == Alpha) || (PixelFormat == Luminance))
+ imageType = 3; // Uncompressed grayscale
+
+ f.serial(lengthID);
+ f.serial(cMapType);
+ f.serial(imageType);
+ f.serial(origin);
+ f.serial(length);
+ f.serial(depth);
+ f.serial(xOrg);
+ f.serial(yOrg);
+ f.serial(width);
+ f.serial(height);
+ f.serial(imageDepth);
+ f.serial(desc);
+
+ if ((PixelFormat == Alpha)||(PixelFormat == Luminance))
+ scanline = new uint8[width];
+ else
+ scanline = new uint8[width*4];
+ if(!scanline)
+ {
+ throw EAllocationFailure();
+ }
+
+ for(y=0; y<(sint32)height; y++)
+ {
+
+ uint32 k=0;
+ if (PixelFormat == Alpha)
+ {
+ for(i=0; i>3;
+ int gg = g >>3;
+ int bb = b >>3;
+ uint16 c16 = uint16((rr<<10) | (gg<<5) | bb);
+ scanline[x*2+0] = c16&0xff;
+ scanline[x*2+1] = c16>>8;
+ }
+ }
+ if(d==24)
+ {
+ for(x=0; x<(sint32)width; x++)
+ {
+ r = scanline[x*3+0];
+ g = scanline[x*3+1];
+ b = scanline[x*3+2];
+ scanline[x*3+0] = b;
+ scanline[x*3+1] = g;
+ scanline[x*3+2] = r;
+ }
+ }
+ if(d==32)
+ {
+ for(x=0; x<(sint32)width; x++)
+ {
+ r = scanline[x*4+0];
+ g = scanline[x*4+1];
+ b = scanline[x*4+2];
+ a= scanline[x*4+3];
+ scanline[x*4+0] = b;
+ scanline[x*4+1] = g;
+ scanline[x*4+2] = r;
+ scanline[x*4+3] = a;
+ }
+ }
+
+ int finaleSize=width*d/8;
+ for(i=0; i
+void rotateCCW (const T* src, T* dst, uint srcWidth, uint srcHeight)
+{
+ for (uint y=0; y
+void rotateCCW (const vector& src, vector& dst, uint srcWidth, uint srcHeight)
+{
+ for (uint y=0; y copy=_Data[0];
+
+ switch (PixelFormat)
+ {
+ case RGBA:
+ NLMISC::rotateCCW ((uint32*)&(_Data[0][0]), (uint32*)&(copy[0]), _Width, _Height);
+ break;
+ case Luminance:
+ case Alpha:
+ NLMISC::rotateCCW (&_Data[0][0], ©[0], _Width, _Height);
+ break;
+ case AlphaLuminance:
+ NLMISC::rotateCCW ((uint16*)&(_Data[0][0]), (uint16*)&(copy[0]), _Width, _Height);;
+ break;
+ default: break;
+ }
+
+ uint32 tmp=_Width;
+ _Width=_Height;
+ _Height=tmp;
+ _Data[0]=copy;
+}
+
+void CBitmap::blit(const CBitmap &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint destX, sint destY)
+{
+ nlassert(PixelFormat == RGBA);
+ nlassert(src.PixelFormat == RGBA);
+ // clip x
+ if (srcX < 0)
+ {
+ srcWidth += srcX;
+ if (srcWidth <= 0) return;
+ destX -= srcX;
+ srcX = 0;
+ }
+ if (srcX + srcWidth > (sint) src.getWidth())
+ {
+ srcWidth = src.getWidth() - srcX;
+ if (srcWidth <= 0) return;
+ }
+ if (destX < 0)
+ {
+ srcWidth += destX;
+ if (srcWidth <= 0) return;
+ srcX -= destX;
+ destX = 0;
+ }
+ if (destX + srcWidth > (sint) getWidth())
+ {
+ srcWidth = getWidth() - destX;
+ if (srcWidth <= 0) return;
+ }
+ // clip y
+ if (srcY < 0)
+ {
+ srcHeight += srcY;
+ if (srcHeight <= 0) return;
+ destY -= srcY;
+ srcY = 0;
+ }
+ if (srcY + srcHeight > (sint) src.getHeight())
+ {
+ srcHeight = src.getHeight() - srcY;
+ if (srcHeight <= 0) return;
+ }
+ if (destY < 0)
+ {
+ srcHeight += destY;
+ if (srcHeight <= 0) return;
+ srcY -= destY;
+ destY = 0;
+ }
+ if (destY + srcHeight > (sint) getHeight())
+ {
+ srcHeight = getHeight() - destY;
+ if (srcHeight <= 0) return;
+ }
+ uint32 *srcPixels = (uint32 *) &src.getPixels()[0];
+ uint32 *srcPtr = &(srcPixels[srcX + srcY * src.getWidth()]);
+ uint32 *srcEndPtr = srcPtr + srcHeight * src.getWidth();
+ uint32 *destPixels = (uint32 *) &getPixels()[0];
+ uint32 *destPtr = &(destPixels[destX + destY * getWidth()]);
+ while (srcPtr != srcEndPtr)
+ {
+ memcpy(destPtr, srcPtr, sizeof(uint32) * srcWidth);
+ srcPtr += src.getWidth();
+ destPtr += getWidth();
+ }
+
+}
+
+
+bool CBitmap::blit(const CBitmap *src, sint32 x, sint32 y)
+{
+
+ nlassert(this->PixelFormat == src->PixelFormat);
+ if (this->PixelFormat != src->PixelFormat)
+ {
+ return false;
+ }
+
+
+ // check for dxtc use
+
+ const bool useDXTC = PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha || PixelFormat == DXTC3 || PixelFormat == DXTC5;
+
+ // number of bits for a 4x4 pix block
+ const uint dxtcNumBits = PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha ? 64 : 128;
+
+
+ if (useDXTC)
+ {
+ // blit pos must be multiple of 4
+
+ nlassert(! (x & 3 || y & 3) );
+ if (x & 3 || y & 3) return false;
+
+ }
+
+ nlassert(PixelFormat != DonTKnow);
+
+ // the width to copy
+ sint width = src->_Width;
+ // the height to copy
+ sint height = src->_Height;
+
+ uint destStartX, destStartY;
+ uint srcStartX, srcStartY;
+
+
+ // clip against left
+ if (x < 0)
+ {
+ width += x;
+ if (width <= 0) return true;
+ destStartX = 0;
+ srcStartX = -x;
+ }
+ else
+ {
+ destStartX = x;
+ srcStartX = 0;
+ }
+
+ // clip against top
+ if (y < 0)
+ {
+ height += y;
+ if (height <= 0) return true;
+ srcStartY = -y;
+ destStartY = 0;
+ }
+ else
+ {
+ destStartY = y;
+ srcStartY = 0;
+ }
+
+ // clip against right
+ if ((destStartX + width - 1) >= _Width)
+ {
+ width = _Width - destStartX;
+ if (width <= 0) return true;
+ }
+
+ // clip against bottom
+ if ((destStartY + height - 1) >= _Height)
+ {
+ height = _Height - destStartY;
+ if (width <= 0) return true;
+ }
+
+
+ // divide all distance by 4 when using DXTC
+ if (useDXTC)
+ {
+ destStartX >>= 2;
+ destStartY >>= 2;
+ srcStartX >>= 2;
+ srcStartY >>= 2;
+ width >>= 2;
+ height >>= 2;
+ }
+
+
+ // bytes per pixs is for either one pixel or 16 (a 4x4 block in DXTC)
+ const uint bytePerPixs = ( useDXTC ? dxtcNumBits : bitPerPixels[PixelFormat] ) >> 3 /* divide by 8 to get the number of bytes */;
+
+
+ const uint destRealWidth = useDXTC ? (_Width >> 2) : _Width;
+ const uint srcRealWidth = useDXTC ? (src->_Width >> 2) : src->_Width;
+
+
+ // size to go to the next line in the destination
+ const uint destStride = destRealWidth * bytePerPixs;
+
+ // size to go to the next line in the source
+ const uint srcStride = srcRealWidth * bytePerPixs;
+
+ // length in bytes of a line to copy
+ const uint lineLength = width * bytePerPixs;
+
+
+ uint8 *destPos = &(_Data[0][0]) + destStride * destStartY + bytePerPixs * destStartX;
+ const uint8 *srcPos = &(src->_Data[0][0]) + srcStride * srcStartY + bytePerPixs * srcStartX;
+
+ // copy each hline
+ for (sint k = 0; k < height; ++k)
+ {
+ ::memcpy(destPos, srcPos, lineLength);
+ destPos += destStride;
+ srcPos += srcStride;
+ }
+
+
+ return true;
+}
+
+// Private :
+float CBitmap::getColorInterp (float x, float y, float colorInXY00, float colorInXY10, float colorInXY01, float colorInXY11) const
+{
+ float res = colorInXY00*(1.0f-x)*(1.0f-y) +
+ colorInXY10*( x)*(1.0f-y) +
+ colorInXY01*(1.0f-x)*( y) +
+ colorInXY11*( x)*( y);
+ clamp (res, 0.0f, 255.0f);
+ return res;
+}
+
+// Public:
+CRGBAF CBitmap::getColor (float x, float y) const
+{
+ if (x < 0.0f) x = 0.0f;
+ if (x > 1.0f) x = 1.0f;
+ if (y < 0.0f) y = 0.0f;
+ if (y > 1.0f) y = 1.0f;
+
+ sint32 nWidth = getWidth(0);
+ sint32 nHeight = getHeight(0);
+
+ if (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);
+
+ const CObjectVector &rBitmap = getPixels(0);
+ sint32 nX[4], nY[4];
+
+ x *= nWidth-1;
+ y *= nHeight-1;
+
+ // Integer part of (x,y)
+ //nX[0] = ((sint32)floor(x-0.5f));
+ //nY[0] = ((sint32)floor(y-0.5f));
+ nX[0] = ((sint32)floor(x));
+ nY[0] = ((sint32)floor(y));
+
+ nX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);
+ nY[1] = nY[0];
+
+ nX[2] = nX[0];
+ nY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);
+
+ nX[3] = nX[1];
+ nY[3] = nY[2];
+
+ uint32 i;
+
+ for (i = 0; i < 4; ++i)
+ {
+ nlassert (nX[i] >= 0);
+ nlassert (nY[i] >= 0 );
+ nlassert (nX[i] < nWidth);
+ nlassert (nY[i] < nHeight);
+ }
+
+ // Decimal part of (x,y)
+ x = x - (float)nX[0];
+ y = y - (float)nY[0];
+
+ switch (this->PixelFormat)
+ {
+ case RGBA:
+ case DXTC1:
+ case DXTC1Alpha:
+ case DXTC3:
+ case DXTC5:
+ {
+ CRGBAF finalVal;
+ CRGBA val[4];
+
+ if (this->PixelFormat == RGBA)
+ {
+ for (i = 0; i < 4; ++i)
+ {
+ val[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],
+ rBitmap[(nX[i]+nY[i]*nWidth)*4+1],
+ rBitmap[(nX[i]+nY[i]*nWidth)*4+2],
+ rBitmap[(nX[i]+nY[i]*nWidth)*4+3]);
+ }
+ }
+ else
+ {
+ // slower version : get from DXT
+ for (i = 0; i < 4; ++i)
+ {
+ val[i] = getPixelColor(nX[i], nY[i]);
+ }
+ }
+
+ finalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);
+ finalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);
+ finalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);
+ finalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);
+ finalVal /= 255.f;
+
+ return finalVal;
+ }
+ break;
+ case Alpha:
+ case Luminance:
+ {
+
+ float finalVal;
+ float val[4];
+
+ for (i = 0; i < 4; ++i)
+ val[i] = rBitmap[(nX[i]+nY[i]*nWidth)];
+
+ finalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);
+ finalVal /= 255.f;
+
+ if (this->PixelFormat == Alpha)
+ return CRGBAF (1.f, 1.f, 1.f, finalVal);
+ else // Luminance
+ return CRGBAF (finalVal, finalVal, finalVal, 1.f);
+ }
+ break;
+ default: break;
+ }
+
+ return CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+// wrap a value inside the given range (for positive value it is like a modulo)
+static inline uint32 wrap(sint32 value, uint32 range)
+{
+ return value >= 0 ? (value % range) : range - 1 - (- value - 1) % range;
+}
+
+
+CRGBAF CBitmap::getColor(float x, float y, bool tileU, bool tileV) const
+{
+ sint32 nWidth = getWidth(0);
+ sint32 nHeight = getHeight(0);
+ if (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);
+
+ sint32 nX[4], nY[4];
+
+ if (!tileU)
+ {
+ if (x < 0.0f) x = 0.0f;
+ if (x > 1.0f) x = 1.0f;
+ x *= nWidth-1;
+ nX[0] = ((sint32)floor(x));
+ nX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);
+ nX[2] = nX[0];
+ nX[3] = nX[1];
+ uint32 i;
+ for (i = 0; i < 4; ++i)
+ {
+ nlassert (nX[i] >= 0);
+ nlassert (nX[i] < nWidth);
+ }
+ }
+ else
+ {
+ x *= nWidth;
+ nX[0] = wrap((sint32)floorf(x), nWidth);
+ nX[1] = wrap(nX[0] + 1, nWidth);
+ nX[2] = nX[0];
+ nX[3] = nX[1];
+ }
+ //
+ if (!tileV)
+ {
+ if (y < 0.0f) y = 0.0f;
+ if (y > 1.0f) y = 1.0f;
+ y *= nHeight-1;
+ nY[0] = ((sint32)floor(y));
+ nY[1] = nY[0];
+ nY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);
+ nY[3] = nY[2];
+ uint32 i;
+ for (i = 0; i < 4; ++i)
+ {
+ nlassert (nY[i] >= 0 );
+ nlassert (nY[i] < nHeight);
+ }
+ }
+ else
+ {
+ y *= nHeight;
+ nY[0] = wrap((sint32)floorf(y), nHeight);
+ nY[1] = nY[0];
+ nY[2] = wrap(nY[0] + 1, nHeight);
+ nY[3] = nY[2];
+ }
+ // Decimal part of (x,y)
+ x = x - (float)nX[0];
+ y = y - (float)nY[0];
+ const CObjectVector &rBitmap = getPixels(0);
+ switch (this->PixelFormat)
+ {
+ case RGBA:
+ case DXTC1:
+ case DXTC1Alpha:
+ case DXTC3:
+ case DXTC5:
+ {
+ CRGBAF finalVal;
+ CRGBA val[4];
+
+ if (this->PixelFormat == RGBA)
+ {
+ for (uint32 i = 0; i < 4; ++i)
+ {
+ val[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],
+ rBitmap[(nX[i]+nY[i]*nWidth)*4+1],
+ rBitmap[(nX[i]+nY[i]*nWidth)*4+2],
+ rBitmap[(nX[i]+nY[i]*nWidth)*4+3]);
+ }
+ }
+ else
+ {
+ // slower version : get from DXT
+ for (uint32 i = 0; i < 4; ++i)
+ {
+ val[i] = getPixelColor(nX[i], nY[i]);
+ }
+ }
+
+ finalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);
+ finalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);
+ finalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);
+ finalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);
+ finalVal /= 255.f;
+
+ return finalVal;
+ }
+ break;
+ case Alpha:
+ case Luminance:
+ {
+
+ float finalVal;
+ float val[4];
+
+ for (uint32 i = 0; i < 4; ++i)
+ val[i] = rBitmap[(nX[i]+nY[i]*nWidth)];
+
+ finalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);
+ finalVal /= 255.f;
+
+ if (this->PixelFormat == Alpha)
+ return CRGBAF (1.f, 1.f, 1.f, finalVal);
+ else // Luminance
+ return CRGBAF (finalVal, finalVal, finalVal, 1.f);
+ }
+ break;
+ default: break;
+ }
+ return CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+
+
+void CBitmap::loadSize(NLMISC::IStream &f, uint32 &retWidth, uint32 &retHeight)
+{
+ retWidth= 0;
+ retHeight= 0;
+
+ nlassert(f.isReading());
+
+ // testing if DDS
+ uint32 fileType = 0;
+ f.serial(fileType);
+ if(fileType == DDS_HEADER)
+ {
+ // read entire DDS header.
+ uint32 size = 0;
+ f.serial(size); // size in Bytes of header(without "DDS")
+ uint32 * _DDSSurfaceDesc = new uint32[size];
+ _DDSSurfaceDesc[0]= size;
+
+ for(uint i= 0; i= 0xd0 && blockMarker2 <= 0xd8)
+ {
+ // no content
+ }
+ else
+ {
+ // size of a block
+ f.serial(blockSize);
+ NLMISC_BSWAP16(blockSize);
+
+ // frame marker (which contains image width and height)
+ if (blockMarker2 >= 0xc0 && blockMarker2 <= 0xc3)
+ {
+ uint8 imagePrecision = 0; // sample precision
+ uint32 imageSize = 0; // width and height
+ f.serial(imagePrecision);
+ f.serial(imageSize);
+ NLMISC_BSWAP32(imageSize);
+
+ retWidth = imageSize & 0xffff;
+ retHeight = (imageSize & 0xffff0000) >> 16;
+
+ break;
+ }
+
+ // skip the block
+ f.seek(blockSize - 2, IStream::current);
+ }
+ }
+ }
+ catch(...)
+ {
+ eof = true;
+ }
+ }
+ while(!eof);
+ }
+ // assuming it's TGA
+ else
+ {
+ if(!f.seek (0, NLMISC::IStream::begin))
+ {
+ throw ESeekFailed();
+ }
+
+ // Reading header,
+ // To make sure that the bitmap is TGA, we check imageType and imageDepth.
+ uint8 lengthID;
+ uint8 cMapType;
+ uint8 imageType;
+ uint16 tgaOrigin;
+ uint16 length;
+ uint8 depth;
+ uint16 xOrg;
+ uint16 yOrg;
+ uint16 width;
+ uint16 height;
+ uint8 imageDepth;
+ uint8 desc;
+
+ f.serial(lengthID);
+ f.serial(cMapType);
+ f.serial(imageType);
+ if(imageType!=2 && imageType!=3 && imageType!=10 && imageType!=11)
+ {
+ nlwarning("Invalid TGA format, type %u in not supported (must be 2,3,10 or 11)", imageType);
+ return;
+ }
+ f.serial(tgaOrigin);
+ f.serial(length);
+ f.serial(depth);
+ f.serial(xOrg);
+ f.serial(yOrg);
+ f.serial(width);
+ f.serial(height);
+ f.serial(imageDepth);
+ if(imageDepth!=8 && imageDepth!=16 && imageDepth!=24 && imageDepth!=32)
+ {
+ nlwarning("Invalid TGA format, bit depth %u in not supported (must be 8,16,24 or 32)", imageDepth);
+ return;
+ }
+ f.serial(desc);
+
+ // Ok, we have width and height.
+ retWidth= width;
+ retHeight= height;
+ }
+
+ // reset stream.
+ if(!f.seek (0, NLMISC::IStream::begin))
+ {
+ throw ESeekFailed();
+ }
+}
+
+
+void CBitmap::loadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight)
+{
+ retWidth= 0;
+ retHeight= 0;
+
+ CIFile f(path);
+ if(f.open(path))
+ loadSize(f, retWidth, retHeight);
+}
+
+// ***************************************************************************
+void CBitmap::flipHDXTCBlockColor(uint8 *bitColor, uint32 w)
+{
+ // pack each line in a u32 (NB: the following works either in Little and Big Endian)
+ uint32 bits= *(uint32*)bitColor;
+
+ // swap in X for each line
+ uint32 res;
+ if(w!=2)
+ {
+ res = (bits & 0xC0C0C0C0) >> 6;
+ res+= (bits & 0x30303030) >> 2;
+ res+= (bits & 0x0C0C0C0C) << 2;
+ res+= (bits & 0x03030303) << 6;
+ }
+ // special case where w==2
+ else
+ {
+ res = (bits & 0x0C0C0C0C) >> 2;
+ res+= (bits & 0x03030303) << 2;
+ }
+
+ // copy
+ *((uint32*)bitColor)= res;
+}
+
+// ***************************************************************************
+void CBitmap::flipVDXTCBlockColor(uint8 *bitColor, uint32 h)
+{
+ // swap just bytes (work either in Little and Big Endian)
+ if(h!=2)
+ {
+ std::swap(bitColor[0], bitColor[3]);
+ std::swap(bitColor[1], bitColor[2]);
+ }
+ // special case where h==2)
+ else
+ {
+ // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
+ std::swap(bitColor[0], bitColor[1]);
+ }
+}
+
+// ***************************************************************************
+void CBitmap::flipHDXTCBlockAlpha3(uint8 *blockAlpha, uint32 w)
+{
+#ifdef NL_LITTLE_ENDIAN
+ uint64 bits= *(uint64*)blockAlpha;
+#else
+ uint64 bits= (uint64)blockAlpha[0] + ((uint64)blockAlpha[1]<<8) +
+ ((uint64)blockAlpha[2]<<16) + ((uint64)blockAlpha[3]<<24) +
+ ((uint64)blockAlpha[4]<<32) + ((uint64)blockAlpha[5]<<40) +
+ ((uint64)blockAlpha[6]<<48) + ((uint64)blockAlpha[7]<<56);
+#endif
+
+ // swap in X for each line
+ uint64 res;
+ if(w!=2)
+ {
+ res = (bits & INT64_CONSTANT(0xF000F000F000F000)) >> 12;
+ res+= (bits & INT64_CONSTANT(0x0F000F000F000F00)) >> 4;
+ res+= (bits & INT64_CONSTANT(0x00F000F000F000F0)) << 4;
+ res+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 12;
+ }
+ // special case where w==2
+ else
+ {
+ res = (bits & INT64_CONSTANT(0x00F000F000F000F0)) >> 4;
+ res+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 4;
+ }
+
+ // copy
+#ifdef NL_LITTLE_ENDIAN
+ *((uint64*)blockAlpha)= res;
+#else
+ blockAlpha[0]= res & 255;
+ blockAlpha[1]= (res>>8) & 255;
+ blockAlpha[2]= (res>>16) & 255;
+ blockAlpha[3]= (res>>24) & 255;
+ blockAlpha[4]= (res>>32) & 255;
+ blockAlpha[5]= (res>>40) & 255;
+ blockAlpha[6]= (res>>48) & 255;
+ blockAlpha[7]= (res>>56) & 255;
+#endif
+}
+
+// ***************************************************************************
+void CBitmap::flipVDXTCBlockAlpha3(uint8 *blockAlpha, uint32 h)
+{
+ uint16 *wAlpha= (uint16*)blockAlpha;
+
+ // swap just words (work either in Little and Big Endian)
+ if(h!=2)
+ {
+ std::swap(wAlpha[0], wAlpha[3]);
+ std::swap(wAlpha[1], wAlpha[2]);
+ }
+ // special case where h==2)
+ else
+ {
+ // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
+ std::swap(wAlpha[0], wAlpha[1]);
+ }
+}
+
+// ***************************************************************************
+void CBitmap::flipHDXTCBlockAlpha5(uint8 *bitAlpha, uint32 w)
+{
+ // pack into bits. Little Indian in all cases
+ uint64 bits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +
+ ((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +
+ ((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);
+
+ // swap in X for each line
+ uint64 res;
+ if(w!=2)
+ {
+ res = (bits & INT64_CONSTANT(0xE00E00E00E00)) >> 9;
+ res+= (bits & INT64_CONSTANT(0x1C01C01C01C0)) >> 3;
+ res+= (bits & INT64_CONSTANT(0x038038038038)) << 3;
+ res+= (bits & INT64_CONSTANT(0x007007007007)) << 9;
+ }
+ // special case where w==2
+ else
+ {
+ res = (bits & INT64_CONSTANT(0x038038038038)) >> 3;
+ res+= (bits & INT64_CONSTANT(0x007007007007)) << 3;
+ }
+
+ // copy. Little Indian in all cases
+ bitAlpha[0]= uint8(res & 255);
+ bitAlpha[1]= uint8((res>>8) & 255);
+ bitAlpha[2]= uint8((res>>16) & 255);
+ bitAlpha[3]= uint8((res>>24) & 255);
+ bitAlpha[4]= uint8((res>>32) & 255);
+ bitAlpha[5]= uint8((res>>40) & 255);
+}
+
+// ***************************************************************************
+void CBitmap::flipVDXTCBlockAlpha5(uint8 *bitAlpha, uint32 h)
+{
+ // pack into bits. Little Indian in all cases
+ uint64 bits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +
+ ((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +
+ ((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);
+
+ // swap in Y
+ uint64 res;
+ if(h!=2)
+ {
+ res = (bits & INT64_CONSTANT(0xFFF000000000)) >> 36;
+ res+= (bits & INT64_CONSTANT(0x000FFF000000)) >> 12;
+ res+= (bits & INT64_CONSTANT(0x000000FFF000)) << 12;
+ res+= (bits & INT64_CONSTANT(0x000000000FFF)) << 36;
+ }
+ // special case where h==2
+ else
+ {
+ res = (bits & INT64_CONSTANT(0x000000FFF000)) >> 12;
+ res+= (bits & INT64_CONSTANT(0x000000000FFF)) << 12;
+ }
+
+ // copy. Little Indian in all cases
+ bitAlpha[0]= uint8(res & 255);
+ bitAlpha[1]= uint8((res>>8) & 255);
+ bitAlpha[2]= uint8((res>>16) & 255);
+ bitAlpha[3]= uint8((res>>24) & 255);
+ bitAlpha[4]= uint8((res>>32) & 255);
+ bitAlpha[5]= uint8((res>>40) & 255);
+}
+
+// ***************************************************************************
+void CBitmap::flipDXTCMipMap(bool vertical, uint mm, uint type)
+{
+ nlassert(mm1)
+ needRebuild = true;
+ releaseMipMaps();
+
+ for( i = 0; i < nHeight; ++i )
+ for( j = 0; j < nWidth/2; ++j )
+ {
+ temp = pBitmap[i*nWidth+j];
+ pBitmap[i*nWidth+j] = pBitmap[i*nWidth+nWidth-j-1];
+ pBitmap[i*nWidth+nWidth-j-1] = temp;
+ }
+
+ // Rebuilding mipmaps
+ if(needRebuild)
+ {
+ buildMipMaps();
+ }
+}
+
+
+// ***************************************************************************
+void CBitmap::flipV()
+{
+ if (PixelFormat != RGBA)
+ {
+ // try for DXTC
+ flipDXTC(true);
+
+ // then quit (whether it worked or not)
+ return;
+ }
+
+ sint32 nWidth = getWidth(0);
+ sint32 nHeight = getHeight(0);
+ sint32 i, j;
+ NLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];
+ bool needRebuild = false;
+ CRGBA temp;
+
+ if(_MipMapCount>1)
+ needRebuild = true;
+ releaseMipMaps();
+
+ for( j = 0; j < nHeight/2; ++j )
+ for( i = 0; i < nWidth; ++i )
+ {
+ temp = pBitmap[j*nWidth+i];
+ pBitmap[j*nWidth+i] = pBitmap[(nHeight-j-1)*nWidth+i];
+ pBitmap[(nHeight-j-1)*nWidth+i] = temp;
+ }
+
+ // Rebuilding mipmaps
+ if(needRebuild)
+ {
+ buildMipMaps();
+ }
+}
+
+
+void CBitmap::rot90CW()
+{
+ if (PixelFormat != RGBA)
+ return;
+ sint32 nWidth = getWidth(0);
+ sint32 nHeight = getHeight(0);
+ sint32 i, j;
+ NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
+ bool needRebuild = false;
+
+ if(_MipMapCount>1)
+ needRebuild = true;
+ releaseMipMaps();
+
+ CObjectVector pDestui;
+ pDestui.resize(nWidth*nHeight*4);
+ NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
+
+ for( j = 0; j < nHeight; ++j )
+ for( i = 0; i < nWidth; ++i )
+ pDestRgba[j+i*nHeight] = pSrcRgba[i+(nHeight-1-j)*nWidth];
+
+ uint32 nTemp = _Width;
+ _Width = _Height;
+ _Height = nTemp;
+
+ NLMISC::contReset(_Data[0]); // free memory
+ _Data[0] = pDestui;
+ // Rebuilding mipmaps
+ if(needRebuild)
+ {
+ buildMipMaps();
+ }
+}
+
+void CBitmap::rot90CCW()
+{
+ if (PixelFormat != RGBA)
+ return;
+ sint32 nWidth = getWidth(0);
+ sint32 nHeight = getHeight(0);
+ sint32 i, j;
+ NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
+ bool needRebuild = false;
+
+ if(_MipMapCount>1)
+ needRebuild = true;
+ releaseMipMaps();
+
+ CObjectVector pDestui;
+ pDestui.resize(nWidth*nHeight*4);
+ NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
+
+ for( j = 0; j < nHeight; ++j )
+ for( i = 0; i < nWidth; ++i )
+ pDestRgba[j+i*nHeight] = pSrcRgba[nWidth-1-i+j*nWidth];
+
+ uint32 nTemp = _Width;
+ _Width = _Height;
+ _Height = nTemp;
+
+ NLMISC::contReset(_Data[0]); // free memory
+ _Data[0] = pDestui;
+ // Rebuilding mipmaps
+ if(needRebuild)
+ {
+ buildMipMaps();
+ }
+}
+
+//===========================================================================
+void CBitmap::blend(CBitmap &Bm0, CBitmap &Bm1, uint16 factor, bool inputBitmapIsMutable /*= false*/)
+{
+ nlassert(factor <= 256);
+
+ nlassert(Bm0._Width != 0 && Bm0._Height != 0
+ && Bm1._Width != 0 && Bm1._Height != 0);
+
+ nlassert(Bm0._Width == Bm1._Width); // the bitmap should have the same size
+ nlassert(Bm0._Height == Bm1._Height);
+
+ const CBitmap *nBm0, *nBm1; // pointer to the bitmap that is used for blending, or to a copy is a conversion wa required
+
+ CBitmap cp0, cp1; // these bitmap are copies of Bm1 and Bm0 if a conversion was needed
+
+ if (Bm0.PixelFormat != RGBA)
+ {
+ if (inputBitmapIsMutable)
+ {
+ Bm0.convertToRGBA();
+ nBm0 = &Bm0;
+ }
+ else
+ {
+ cp0 = Bm0;
+ cp0.convertToRGBA();
+ nBm0 = &cp0;
+ }
+ }
+ else
+ {
+ nBm0 = &Bm0;
+ }
+
+
+ if (Bm1.PixelFormat != RGBA)
+ {
+ if (inputBitmapIsMutable)
+ {
+ Bm1.convertToRGBA();
+ nBm1 = &Bm1;
+ }
+ else
+ {
+ cp1 = Bm1;
+ cp1.convertToRGBA();
+ nBm1 = &cp1;
+ }
+ }
+ else
+ {
+ nBm1 = &Bm1;
+ }
+
+ if (this != nBm0 && this != nBm1)
+ {
+ // if source is the same than the dets, don't resize because this clear the bitmap
+ this->resize(Bm0._Width, Bm0._Height, RGBA);
+ }
+
+ uint numPix = _Width * _Height; // 4 component per pixels
+
+
+ const uint8 *src0 = &(nBm0->_Data[0][0]);
+ const uint8 *src1 = &(nBm1->_Data[0][0]);
+ uint8 *dest = &(this->_Data[0][0]);
+
+
+ #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)
+ if (CSystemInfo::hasMMX())
+ {
+ // On a P4 2GHz, with a 256x256 texture, I got the following results :
+ // without mmx : 5.2 ms
+ // with mmx : 1.7 ms
+ // I'm sure this can be further optimized..
+
+ uint numPixLeft = numPix & 1; // process 2 pixels at once, so special case for odd number
+ numPix = numPix & ~1;
+ // do fast blend with mmx
+ uint64 blendFactor0;
+ uint64 blendFactor1;
+ uint16 *bf0 = (uint16 *) &blendFactor0;
+ uint16 *bf1 = (uint16 *) &blendFactor1;
+ bf0[0] = bf0[1] = bf0[2] = bf0[3] = (1 << 6) * (factor);
+ bf1[0] = bf1[1] = bf1[2] = bf1[3] = (1 << 6) * (256 - factor);
+ __asm
+ {
+ mov esi, src0
+ mov eax, src1
+ mov edi, dest
+ mov ebx, -8
+ mov ecx, numPix
+ shr ecx, 1 // process pixels 2 by 2
+ movq mm1, blendFactor0
+ movq mm0, blendFactor1
+
+ myLoop:
+ pxor mm6, mm6
+ lea ebx, [ebx + 8] // points next location
+ pxor mm7, mm7
+ movq mm2, [esi + ebx]
+ movq mm3, [eax + ebx]
+ // do blend
+ punpckhbw mm7, mm2 // mm7 contains src0 color 0 in high bytes
+ punpckhbw mm6, mm3 // mm6 contains src1 color 0 in high bytes
+ psrl mm7, 1
+ pxor mm4, mm4 // mm4 = 0
+ psrl mm6, 1
+ pmulhw mm7, mm0 // src0 = src0 * blendFactor
+ pxor mm5, mm5 // mm5 = 0
+ pmulhw mm6, mm1 // src1 = src1 * (1 - blendfactor)
+ punpcklbw mm4, mm2 // mm4 contains src0 color 1 in high bytes
+ paddusw mm6, mm7 // mm6 = src0[0] blended with src1[0]
+ psrl mm4, 1
+ psrlw mm6, 5
+ punpcklbw mm5, mm3 // mm4 contains src1 color 1 in high bytes
+ psrl mm5, 1
+ pmulhw mm4, mm0 // src0 = src0 * blendFactor
+ pmulhw mm5, mm1 // src1 = src1 * (1 - blendfactor)
+ paddusw mm4, mm5 // mm6 = src0[1] blended with src1[1]
+ psrlw mm4, 5
+ // pack result
+ packuswb mm4, mm6
+ dec ecx
+ movq [edi + ebx], mm4 // store result
+ jne myLoop
+ emms
+ }
+ if (numPixLeft)
+ {
+ // case of odd number of pixels
+ src0 += 4 * numPix;
+ src1 += 4 * numPix;
+ dest += 4 * numPix;
+ uint blendFact = (uint) factor;
+ uint invblendFact = 256 - blendFact;
+ *dest = (uint8) (((blendFact * *src1) + (invblendFact * *src0)) >> 8);
+ *(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);
+ *(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);
+ *(dest + 3) = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);
+ }
+ }
+ else
+ #endif //#ifdef NL_OS_WINDOWS
+ {
+ uint8 *endPix = dest + (numPix << 2);
+ // no mmx version
+ uint blendFact = (uint) factor;
+ uint invblendFact = 256 - blendFact;
+ do
+ {
+ /// blend 4 component at each pass
+ *dest = (uint8) (((blendFact * *src1) + (invblendFact * *src0)) >> 8);
+ *(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);
+ *(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);
+ *(dest + 3) = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);
+
+ src0 = src0 + 4;
+ src1 = src1 + 4;
+ dest = dest + 4;
+ }
+ while (dest != endPix);
+ }
+}
+
+
+
+//-----------------------------------------------
+CRGBA CBitmap::getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const
+{
+ uint w = getWidth(numMipMap);
+ uint h = getHeight(numMipMap);
+ if (w == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
+ const uint8 *pix = &getPixels(numMipMap)[(x + y * w) << 2];
+ return CRGBA(pix[0], pix[1], pix[2], pix[3]);
+}
+
+//-----------------------------------------------
+CRGBA CBitmap::getDXTCColorFromBlock(const uint8 *block, sint x, sint y)
+{
+ uint16 col0;
+ uint16 col1;
+ memcpy(&col0, block, sizeof(uint16));
+ memcpy(&col1, block + 2, sizeof(uint16));
+ uint colIndex = (block[4 + (y & 3)] >> ((x & 3) << 1)) & 3;
+ CRGBA result, c0, c1;
+ if (col0 > col1)
+ {
+ switch(colIndex)
+ {
+ case 0:
+ uncompress(col0, result);
+ break;
+ case 1:
+ uncompress(col1, result);
+ break;
+ case 2:
+ uncompress(col0, c0);
+ uncompress(col1, c1);
+ result.blendFromui(c0, c1, 85);
+ break;
+ case 3:
+ uncompress(col0, c0);
+ uncompress(col1, c1);
+ result.blendFromui(c0, c1, 171);
+ break;
+ default:
+ ;
+ }
+ result.A = 255;
+ }
+ else
+ {
+ switch(colIndex)
+ {
+ case 0:
+ uncompress(col0, result);
+ result.A = 255;
+ break;
+ case 1:
+ uncompress(col1, result);
+ result.A = 255;
+ break;
+ case 2:
+ uncompress(col0, c0);
+ uncompress(col1, c1);
+ result.blendFromui(c0, c1, 128);
+ result.A = 255;
+ break;
+ case 3:
+ result.set(0, 0, 0, 0);
+ break;
+ }
+ }
+ return result;
+}
+
+//-----------------------------------------------
+CRGBA CBitmap::getDXTC1Texel(sint x, sint y, uint32 numMipMap) const
+{
+ uint w = getWidth(numMipMap);
+ uint h = getHeight(numMipMap);
+ if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
+ uint numRowBlocks = std::max((w + 3) >> 2, 1u);
+ const uint8 *pix = &getPixels(numMipMap)[0];
+ const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 3) + ((x >> 2) << 3));
+ return getDXTCColorFromBlock(block, x, y);
+}
+
+
+//-----------------------------------------------
+CRGBA CBitmap::getDXTC3Texel(sint x, sint y, uint32 numMipMap) const
+{
+ uint w = getWidth(numMipMap);
+ uint h = getHeight(numMipMap);
+ if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
+ uint numRowBlocks = std::max((w + 3) >> 2, 1u);
+ const uint8 *pix = &getPixels(numMipMap)[0];
+ const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));
+ CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
+ // get alpha part
+ uint8 alphaByte = block[((y & 3) << 1) + ((x & 2) >> 1)];
+ result.A = (x & 1) ? (alphaByte & 0xf0) : ((alphaByte & 0x0f) << 4);
+ return result;
+}
+
+//-----------------------------------------------
+CRGBA CBitmap::getDXTC5Texel(sint x, sint y, uint32 numMipMap) const
+{
+ uint w = getWidth(numMipMap);
+ uint h = getHeight(numMipMap);
+ if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
+ uint numRowBlocks = std::max((w + 3) >> 2, 1u);
+ const uint8 *pix = &getPixels(numMipMap)[0];
+ const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));
+ CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
+ // get alpha part
+ uint8 alpha0 = block[0];
+ uint8 alpha1 = block[1];
+
+ uint alphaIndex;
+ uint tripletIndex = (x & 3) + ((y & 3) << 2);
+ if (tripletIndex < 8)
+ {
+ alphaIndex = (((uint32 &) block[2]) >> (tripletIndex * 3)) & 7;
+ }
+ else
+ {
+ alphaIndex = (((uint32 &) block[5]) >> ((tripletIndex - 8) * 3)) & 7; // we can read a dword there because there are color datas following he alpha datas
+ }
+
+ if (alpha0 > alpha1)
+ {
+ switch (alphaIndex)
+ {
+ case 0: result.A = alpha0; break;
+ case 1: result.A = alpha1; break;
+ case 2: result.A = (uint8) ((6 * (uint) alpha0 + (uint) alpha1) / 7); break;
+ case 3: result.A = (uint8) ((5 * (uint) alpha0 + 2 * (uint) alpha1) / 7); break;
+ case 4: result.A = (uint8) ((4 * (uint) alpha0 + 3 * (uint) alpha1) / 7); break;
+ case 5: result.A = (uint8) ((3 * (uint) alpha0 + 4 * (uint) alpha1) / 7); break;
+ case 6: result.A = (uint8) ((2 * (uint) alpha0 + 5 * (uint) alpha1) / 7); break;
+ case 7: result.A = (uint8) (((uint) alpha0 + (uint) 6 * alpha1) / 7); break;
+ }
+ }
+ else
+ {
+ switch (alphaIndex)
+ {
+ case 0: result.A = alpha0; break;
+ case 1: result.A = alpha1; break;
+ case 2: result.A = (uint8) ((4 * (uint) alpha0 + (uint) alpha1) / 5); break;
+ case 3: result.A = (uint8) ((3 * (uint) alpha0 + 2 * (uint) alpha1) / 5); break;
+ case 4: result.A = (uint8) ((2 * (uint) alpha0 + 3 * (uint) alpha1) / 5); break;
+ case 5: result.A = (uint8) (((uint) alpha0 + 4 * (uint) alpha1) / 5); break;
+ case 6: result.A = 0; break;
+ case 7: result.A = 255; break;
+ }
+ }
+ return result;
+}
+
+
+//-----------------------------------------------
+CRGBA CBitmap::getPixelColor(sint x, sint y, uint32 numMipMap /*=0*/) const
+{
+
+ switch (PixelFormat)
+ {
+ case RGBA:
+ return getRGBAPixel(x, y, numMipMap);
+ case DXTC1:
+ case DXTC1Alpha:
+ return getDXTC1Texel(x, y, numMipMap);
+ case DXTC3:
+ return getDXTC3Texel(x, y, numMipMap);
+ case DXTC5:
+ return getDXTC5Texel(x, y, numMipMap);
+ default:
+ nlstop;
+ break;
+ }
+ return CRGBA::Black;
+}
+
+
+//-----------------------------------------------
+void CBitmap::swap(CBitmap &other)
+{
+ std::swap(PixelFormat, other.PixelFormat);
+ std::swap(_MipMapCount, other._MipMapCount);
+ std::swap(_LoadGrayscaleAsAlpha, other._LoadGrayscaleAsAlpha);
+ std::swap(_Width, other._Width);
+ std::swap(_Height, other._Height);
+ for(uint k = 0; k < MAX_MIPMAP; ++k)
+ {
+ _Data[k].swap(other._Data[k]);
+ }
+}
+
+//-----------------------------------------------
+void CBitmap::unattachPixels(CObjectVector *mipmapDestArray, uint maxMipMapCount /*=MAX_MIPMAP*/)
+{
+ if (!mipmapDestArray) return;
+ uint k;
+ for(k = 0; k < std::min((uint) _MipMapCount, maxMipMapCount); ++k)
+ {
+ mipmapDestArray[k].swap(_Data[k]);
+ _Data[k].clear();
+ }
+ for(; k < _MipMapCount; ++k)
+ {
+ _Data[k].clear();
+ }
+ #ifdef NL_DEBUG
+ // check that remaining mipmaps are empty
+ for(; k < _MipMapCount; ++k)
+ {
+ nlassert(_Data[k].empty());
+ }
+ #endif
+ _MipMapCount = 1;
+ _Width = 0;
+ _Height = 0;
+ PixelFormat = RGBA;
+ _LoadGrayscaleAsAlpha = true;
+}
+
+
+
+
+void CBitmap::getData(uint8*& extractData)
+{
+
+ uint32 size=0;
+ if(PixelFormat==RGBA)
+ size=_Width*_Height*4;
+ else if(PixelFormat==Alpha||PixelFormat==Luminance)
+ size=_Width*_Height;
+ else
+ {
+ nlstop;
+ }
+
+ for(uint32 pix=0;pix=0;i--)
+ {
+ buf[_Height-1-i]=&_Data[0][i*lineSize];
+ }
+
+ size=lineSize*_Height;
+
+ for(uint32 line=0;line<_Height;line++)
+ {
+ for(uint32 pix=0;pix