Show bonus/malus timer text if available
[ryzomcore.git] / nel / src / misc / bitmap.cpp
blob33c0cec43d9cd9c64b65db15a6fb87756f057807
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2016-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdmisc.h"
22 #include "nel/misc/bitmap.h"
23 #include "nel/misc/stream.h"
24 #include "nel/misc/file.h"
25 #include "nel/misc/system_info.h"
27 // Define this to force all bitmap white (debug)
28 // #define NEL_ALL_BITMAP_WHITE
31 using namespace std;
33 #ifdef DEBUG_NEW
34 #define new DEBUG_NEW
35 #endif
37 namespace NLMISC
40 struct EDDSBadHeader : public NLMISC::EStream
42 EDDSBadHeader() : EStream( "Bad or unrecognized DDS file header" ) {}
45 struct ESeekFailed : public NLMISC::EStream
47 ESeekFailed() : EStream( "Seek failed" ) {}
50 struct EAllocationFailure : public Exception
52 EAllocationFailure() : Exception( "Can't allocate memory" ) {}
55 void blendFromui(NLMISC::CRGBA &c0, NLMISC::CRGBA &c1, uint coef);
56 uint32 blend(uint32 &n0, uint32 &n1, uint32 coef0);
58 const uint32 CBitmap::bitPerPixels[ModeCount]=
60 32, // RGBA
61 8, // Luminance
62 8, // Alpha
63 16, // AlphaLuminance
64 4, // DXTC1
65 4, // DXTC1Alpha
66 8, // DXTC3
67 8, // DXTC5
68 16 // DsDt
71 const uint32 CBitmap::DXTC1HEADER = NL_MAKEFOURCC('D', 'X', 'T', '1');
72 const uint32 CBitmap::DXTC3HEADER = NL_MAKEFOURCC('D', 'X', 'T', '3');
73 const uint32 CBitmap::DXTC5HEADER = NL_MAKEFOURCC('D', 'X', 'T', '5');
76 #ifdef NEL_ALL_BITMAP_WHITE
77 // Make all the textures white
78 void MakeWhite(CBitmap &bitmaps)
80 for (uint i=0; i<bitmaps.getMipMapCount (); i++)
82 uint size = bitmaps.getPixels (i).size ();
83 bitmaps.getPixels (i).resize (0);
84 bitmaps.getPixels (i).resize (size);
85 bitmaps.getPixels (i).fill (0xff);
88 #endif // NEL_ALL_BITMAP_WHITE
90 CBitmap::CBitmap()
92 _MipMapCount = 1;
93 _Width = 0;
94 _Height = 0;
95 PixelFormat = RGBA;
96 _LoadGrayscaleAsAlpha = true;
99 CBitmap::~CBitmap()
104 /*-------------------------------------------------------------------*\
105 load
106 \*-------------------------------------------------------------------*/
107 uint8 CBitmap::load(NLMISC::IStream &f, uint mipMapSkip)
109 /* ***********************************************
110 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
111 * It can be loaded/called through CAsyncFileManager for instance
112 * ***********************************************/
114 nlassert(f.isReading());
116 // testing if DDS
117 uint32 fileType = 0;;
118 f.serial(fileType);
119 if(fileType == DDS_HEADER)
121 #ifdef NEL_ALL_BITMAP_WHITE
122 uint8 result = readDDS(f, mipMapSkip);
123 MakeWhite (*this);
124 return result;
125 #else // NEL_ALL_BITMAP_WHITE
126 return readDDS(f, mipMapSkip);
127 #endif // NEL_ALL_BITMAP_WHITE
130 if (fileType == PNG_HEADER)
132 #ifdef NEL_ALL_BITMAP_WHITE
133 uint8 result = readPNG(f);
134 MakeWhite (*this);
135 return result;
136 #else // NEL_ALL_BITMAP_WHITE
137 return readPNG(f);
138 #endif // NEL_ALL_BITMAP_WHITE
141 #ifdef USE_JPEG
142 // only compare fist word
143 if (memcmp(&fileType, &JPG_HEADER, 2) == 0)
145 #ifdef NEL_ALL_BITMAP_WHITE
146 uint8 result = readJPG(f);
147 MakeWhite (*this);
148 return result;
149 #else // NEL_ALL_BITMAP_WHITE
150 return readJPG(f);
151 #endif // NEL_ALL_BITMAP_WHITE
153 #endif // USE_JPEG
155 #ifdef USE_GIF
156 if (fileType == GIF_HEADER)
158 #ifdef NEL_ALL_BITMAP_WHITE
159 uint8 result = readGIF(f);
160 MakeWhite (*this);
161 return result;
162 #else // NEL_ALL_BITMAP_WHITE
163 return readGIF(f);
164 #endif // NEL_ALL_BITMAP_WHITE
166 #endif // USE_GIF
168 // assuming it's TGA
169 NLMISC::IStream::TSeekOrigin origin= f.begin;
170 if(!f.seek (0, origin))
172 throw ESeekFailed();
175 // Reading header,
176 // To make sure that the bitmap is TGA, we check imageType and imageDepth.
177 uint8 lengthID;
178 uint8 cMapType;
179 uint8 imageType;
180 uint16 tgaOrigin;
181 uint16 length;
182 uint8 depth;
183 uint16 xOrg;
184 uint16 yOrg;
185 uint16 width;
186 uint16 height;
187 uint8 imageDepth;
188 uint8 desc;
190 f.serial(lengthID);
191 f.serial(cMapType);
192 f.serial(imageType);
193 if(imageType!=2 && imageType!=3 && imageType!=10 && imageType!=11) return 0;
194 f.serial(tgaOrigin);
195 f.serial(length);
196 f.serial(depth);
197 f.serial(xOrg);
198 f.serial(yOrg);
199 f.serial(width);
200 f.serial(height);
201 f.serial(imageDepth);
202 if(imageDepth!=8 && imageDepth!=16 && imageDepth!=24 && imageDepth!=32) return 0;
203 f.serial(desc);
205 if(!f.seek (0, origin))
207 throw ESeekFailed();
209 #ifdef NEL_ALL_BITMAP_WHITE
210 uint8 result = readTGA(f);
211 MakeWhite (*this);
212 return result;
213 #else // NEL_ALL_BITMAP_WHITE
214 return readTGA(f);
215 #endif // NEL_ALL_BITMAP_WHITE
219 /*-------------------------------------------------------------------*\
220 makeDummy
221 \*-------------------------------------------------------------------*/
222 void CBitmap::makeDummy()
224 static const uint8 bitmap[1024]= {
225 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
226 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
227 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
228 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
229 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
230 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
231 0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
232 0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
233 0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,
234 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
235 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
236 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
237 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
238 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
239 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
240 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
241 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
242 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
243 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
244 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
245 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
246 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
247 0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
248 0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
249 0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,
250 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
251 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
252 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
253 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
254 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
255 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
256 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
259 makeDummyFromBitField(bitmap);
263 /*-------------------------------------------------------------------*\
264 makeDummy
265 \*-------------------------------------------------------------------*/
266 void CBitmap::makeNonPowerOf2Dummy()
268 static const uint8 bitmap[1024]= {
269 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
270 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
271 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,
272 0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,
273 0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,
274 0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,
275 0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
276 0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
277 0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,
278 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,
279 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
280 0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,
281 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,
282 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,
283 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
284 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
285 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
286 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
287 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,
288 0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,
289 0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,
290 0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,
291 0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
292 0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
293 0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,
294 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,
295 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
296 0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,
297 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,
298 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,
299 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
300 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
303 makeDummyFromBitField(bitmap);
307 /*-------------------------------------------------------------------*\
308 makeDummyFromBitField
309 \*-------------------------------------------------------------------*/
310 void CBitmap::makeDummyFromBitField(const uint8 bitmap[1024])
312 PixelFormat = RGBA;
313 _MipMapCount = 1;
314 _Width= 32;
315 _Height= 32;
316 _Data[0].resize(_Width*_Height*sizeof(NLMISC::CRGBA));
317 for(sint m=1;m<MAX_MIPMAP;m++)
318 _Data[m].clear();
319 NLMISC::CRGBA *pix= (NLMISC::CRGBA*)(_Data[0].getPtr());
321 for(sint i=0;i<(sint)(_Width*_Height);i++)
323 if(bitmap[i])
324 pix[i].set(255,255,255,255);
325 else
326 pix[i].set(0x80,0x80,0x80,0x40);
330 /*-------------------------------------------------------------------*\
331 makeOpaque
332 \*-------------------------------------------------------------------*/
333 void CBitmap::makeOpaque()
335 if (_Width*_Height == 0) return;
337 uint pixelSize;
339 switch(PixelFormat)
341 case RGBA: pixelSize = 4; break;
342 case AlphaLuminance: pixelSize = 2; break;
343 case Alpha: pixelSize = 1; break;
344 default: return;
347 for(uint8 m = 0; m < _MipMapCount; ++m)
349 // get a pointer on original data
350 uint8 *data = _Data[m].getPtr();
352 // special case for only alpha values
353 if (pixelSize == 1)
355 memset(data, 255, _Data[m].size());
357 else
359 // end of data
360 uint8 *endData = data + _Data[m].size();
362 // first alpha
363 data += pixelSize - 1;
365 // replace all alpha values by 255
366 while(data < endData)
368 *data = 255;
369 data += pixelSize;
376 /*-------------------------------------------------------------------*\
377 makeTransparentPixelsBlack
378 \*-------------------------------------------------------------------*/
379 void CBitmap::makeTransparentPixelsBlack()
381 if (_Width*_Height == 0) return;
383 uint pixelSize;
385 switch (PixelFormat)
387 case RGBA: pixelSize = 4; break;
388 case AlphaLuminance: pixelSize = 2; break;
389 default: return;
392 uint colorsSize = pixelSize - 1;
394 for (uint8 m = 0; m < _MipMapCount; ++m)
396 // get a pointer on original data
397 uint8 *data = _Data[m].getPtr();
399 // end of data
400 uint8 *endData = data + _Data[m].size();
402 // first alpha
403 data += pixelSize - 1;
405 // replace all alpha values by 255
406 while (data < endData)
408 // fully transparent pixel
409 if (*data == 0)
411 // make colors black
412 memset(data - colorsSize, 0, colorsSize);
415 data += pixelSize;
421 /*-------------------------------------------------------------------*\
422 isAlphaUniform
423 \*-------------------------------------------------------------------*/
424 bool CBitmap::isAlphaUniform(uint8 *alpha) const
426 uint32 size = _Data[0].size();
428 if (size == 0) return false;
430 uint pixelSize;
432 switch(PixelFormat)
434 // formats with alpha channel
435 case RGBA:
436 pixelSize = 4;
437 break;
439 case AlphaLuminance:
440 pixelSize = 2;
441 break;
443 case Alpha:
444 pixelSize = 1;
445 break;
447 // formats without alpha channel
448 case Luminance:
449 if (alpha) *alpha = 255;
450 return true;
452 default:
453 return false;
456 // get a pointer on original data
457 uint8 *data = (uint8*)_Data[0].getPtr();
458 uint8 *endData = data + size;
460 // first alpha
461 data += pixelSize - 1;
463 // first alpha value
464 uint8 value = *data;
466 // check if all alphas have the same value
467 while(data < endData && *data == value) data += pixelSize;
469 // texture can be converted if all alphas are 0 or 255
470 if (data >= endData)
472 // return the uniform value
473 if (alpha) *alpha = value;
474 return true;
477 return false;
481 /*-------------------------------------------------------------------*\
482 isGrayscale
483 \*-------------------------------------------------------------------*/
484 bool CBitmap::isGrayscale() const
486 // all grayscale formats or, al least, without color information
487 switch(PixelFormat)
489 case Luminance:
490 case AlphaLuminance:
491 case Alpha:
492 return true;
494 case RGBA:
495 break;
497 default:
498 // DXTC formats won't be managed at the moment
499 return false;
502 uint32 size = _Data[0].size();
503 if (size == 0) return false;
505 // get a pointer on original data
506 uint32 *data = (uint32*)_Data[0].getPtr();
507 uint32 *endData = (uint32*)((uint8*)data + size);
509 NLMISC::CRGBA *color = NULL;
511 // check if all alphas have the same value
512 while(data < endData)
514 color = (NLMISC::CRGBA*)data;
516 if (!color->isGray()) return false;
518 ++data;
521 return true;
527 /*-------------------------------------------------------------------*\
528 readDDS
529 \*-------------------------------------------------------------------*/
530 uint8 CBitmap::readDDS(NLMISC::IStream &f, uint mipMapSkip)
532 /* ***********************************************
533 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
534 * It can be loaded/called through CAsyncFileManager for instance
535 * ***********************************************/
537 //------------------ Reading Header ------------------------
539 //-------------- reading entire header
541 uint32 size = 0;
542 f.serial(size); // size in Bytes of header(without "DDS")
543 uint32 * _DDSSurfaceDesc = new uint32[size];
544 _DDSSurfaceDesc[0]= size;
546 #ifdef NL_LITTLE_ENDIAN
547 f.serialBuffer((uint8*)(_DDSSurfaceDesc+1), size-4);
548 #else
549 for(uint i= 0; i<size/4 - 1; i++)
551 f.serial(_DDSSurfaceDesc[i+1]);
553 #endif
555 // flags determines which members of the header structure contain valid data
556 uint32 flags = _DDSSurfaceDesc[1];
558 //verify if file have linearsize set
559 if(!(flags & DDSD_LINEARSIZE))
561 nlwarning("A DDS doesn't have the flag DDSD_LINEARSIZE");
562 //delete [] _DDSSurfaceDesc;
563 //throw EDDSBadHeader();
566 //-------------- extracting and testing useful info
568 _Height = _DDSSurfaceDesc[2];
569 _Width = _DDSSurfaceDesc[3];
570 _MipMapCount= (uint8) _DDSSurfaceDesc[6];
571 // If no mipmap.
572 if(_MipMapCount==0)
573 _MipMapCount=1;
575 switch (_DDSSurfaceDesc[20])
577 case DXTC1HEADER:
578 PixelFormat=DXTC1;
579 break;
580 case DXTC3HEADER:
581 PixelFormat=DXTC3;
582 break;
583 case DXTC5HEADER:
584 PixelFormat=DXTC5;
585 break;
588 flags = _DDSSurfaceDesc[19]; //PixelFormat flags
590 /* ace: I changed this code because it's not a way to detect if DXTC1 has a alpha channel or not
591 There's no easy way to detect if the DXTC1 has an alpha channel or not, so, for now, we'll suppose
592 that all DXTC1 has alpha channel per default.
594 "There is no flag unfortunately, you need to read each block of DXT1 data, check if one of the colors
595 contains alpha, and check if that color is used in the data.
596 It's not that hard to write, but it IS a pain that it's the only way that I've found to check for alpha."
597 http://www.gamedev.net/community/forums/topic.asp?topic_id=177475
599 UPDATE: worst... on linux/opengl, it generates random alpha values
600 if we use alpha dxtc1 by default. So I only to that for windows
601 and leave the old test on linux
603 kervala: some used textures don't have an alpha channel and they are
604 (very) bad rendered with this fix so we have to deactivate it the for moment
607 if(PixelFormat==DXTC1 && _DDSSurfaceDesc[21]>0) //AlphaBitDepth
609 PixelFormat = DXTC1Alpha;
612 if(PixelFormat!= DXTC1 && PixelFormat!= DXTC1Alpha && PixelFormat!= DXTC3 && PixelFormat!= DXTC5)
614 delete [] _DDSSurfaceDesc;
615 throw EDDSBadHeader();
618 // compute the min power of 2 between width and height
619 uint minSizeLevel= min(_Width, _Height);
620 minSizeLevel= getPowerOf2(minSizeLevel);
622 //------------- manage mipMapSkip
623 if(_MipMapCount>1 && mipMapSkip>0 && minSizeLevel>2)
625 // Keep at least the level where width and height are at least 4.
626 mipMapSkip= min(mipMapSkip, minSizeLevel-2);
627 // skip any mipmap
628 uint seekSize= 0;
629 while(mipMapSkip>0 && _MipMapCount>1)
631 // raise to next multiple of 4
632 uint32 wtmp= (_Width+3)&(~3);
633 uint32 htmp= (_Height+3)&(~3);
634 wtmp= max(wtmp, uint32(4));
635 htmp= max(htmp, uint32(4));
637 uint32 mipMapSz;
638 if(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)
639 mipMapSz = wtmp*htmp/2;
640 else
641 mipMapSz = wtmp*htmp;
643 // add to how many to skip
644 seekSize+= mipMapSz;
646 // Size of final bitmap is reduced.
647 _Width>>=1;
648 _Height>>=1;
649 _MipMapCount--;
650 mipMapSkip--;
652 // skip data in file
653 if(seekSize>0)
655 if(!f.seek(seekSize, IStream::current))
657 delete [] _DDSSurfaceDesc;
658 throw ESeekFailed();
664 //------------- preload all the mipmaps (one serialBuffer() is faster)
665 uint32 w = _Width;
666 uint32 h = _Height;
667 uint32 totalSize= 0;
669 uint8 m;
670 for(m= 0; m<_MipMapCount; m++)
672 // raise to next multiple of 4
673 uint32 wtmp= (w+3)&(~3);
674 uint32 htmp= (h+3)&(~3);
675 wtmp= max(wtmp, uint32(4));
676 htmp= max(htmp, uint32(4));
678 uint32 mipMapSz;
679 if(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)
680 mipMapSz = wtmp*htmp/2;
681 else
682 mipMapSz = wtmp*htmp;
685 _Data[m].resize(mipMapSz);
686 totalSize+= mipMapSz;
688 w = (w+1)/2;
689 h = (h+1)/2;
692 // Read all the data in one block.
693 vector<uint8> pixData;
694 pixData.resize(totalSize);
695 f.serialBuffer(&(*pixData.begin()), totalSize);
698 //------------- reading mipmap levels from pixData
700 uint32 pixIndex= 0;
702 for(m= 0; m<_MipMapCount; m++)
704 uint32 mipMapSz= _Data[m].size();
705 memcpy(_Data[m].getPtr(), &(pixData[pixIndex]), mipMapSz);
706 pixIndex+= mipMapSz;
709 //------------- End
711 delete [] _DDSSurfaceDesc;
713 switch(PixelFormat)
715 case DXTC1 : return 24;
716 case DXTC1Alpha : return 32;
717 case DXTC3 : return 32;
718 case DXTC5 : return 32;
719 default : break;
722 return 0;
728 /*-------------------------------------------------------------------*\
729 convertToDXTC5
730 \*-------------------------------------------------------------------*/
731 bool CBitmap::convertToDXTC5()
733 /* Yoyo: RGB encoding for DXTC1 and DXTC5/3 are actually different!!
734 DXTC3/5 don't rely on sign of color0>color1 to setup special encoding (ie use a special compression for Black)
735 Since this can arise if the src is DXTC1 , we can't simply compress it into DXTC5 without doing a
736 heavy compression...
737 (the inverse is false: DXTC5 to DXTC1 is possible, with maybe swap color0/color1 and bits).
740 return false;
742 /* uint32 i,j;
744 if(PixelFormat!=DXTC1) return false;
746 for(uint8 m= 0; m<_MipMapCount; m++)
748 CObjectVector<uint8> dataTmp;
749 dataTmp.resize(2*_Data[m].size());
750 uint dstId= 0;
752 for(i=0; i<_Data[m].size(); i+=8)
754 //64 bits alpha
755 for(j=0; j<8; j++)
757 dataTmp[dstId++]= 255;
760 //64 bits RGB
761 for(j=0; j<8; j++)
763 dataTmp[dstId++]= _Data[m][i+j];
766 _Data[m] = dataTmp;
768 PixelFormat = DXTC5;
769 return true;
775 /*-------------------------------------------------------------------*\
776 luminanceToRGBA()
777 \*-------------------------------------------------------------------*/
778 bool CBitmap::luminanceToRGBA()
780 uint32 i;
782 if(_Width*_Height == 0) return false;
784 for(uint8 m= 0; m<_MipMapCount; m++)
786 CObjectVector<uint8> dataTmp;
787 dataTmp.resize(_Data[m].size()*4);
788 uint dstId= 0;
790 for(i=0; i<_Data[m].size(); i++)
792 dataTmp[dstId++]= _Data[m][i];
793 dataTmp[dstId++]= _Data[m][i];
794 dataTmp[dstId++]= _Data[m][i];
795 dataTmp[dstId++]= 255;
797 _Data[m] = dataTmp;
799 PixelFormat = RGBA;
800 return true;
803 /*-------------------------------------------------------------------*\
804 alphaToRGBA()
805 \*-------------------------------------------------------------------*/
806 bool CBitmap::alphaToRGBA()
808 uint32 i;
810 if(_Width*_Height == 0) return false;
812 for(uint8 m= 0; m<_MipMapCount; m++)
814 CObjectVector<uint8> dataTmp;
815 dataTmp.resize(_Data[m].size()*4);
816 uint dstId= 0;
818 for(i=0; i<_Data[m].size(); i++)
820 dataTmp[dstId++]= 255;
821 dataTmp[dstId++]= 255;
822 dataTmp[dstId++]= 255;
823 dataTmp[dstId++]= _Data[m][i];
825 _Data[m] = dataTmp;
827 PixelFormat = RGBA;
828 return true;
832 /*-------------------------------------------------------------------*\
833 alphaLuminanceToRGBA()
834 \*-------------------------------------------------------------------*/
835 bool CBitmap::alphaLuminanceToRGBA()
837 uint32 i;
839 if(_Width*_Height == 0) return false;
841 for(uint8 m= 0; m<_MipMapCount; m++)
843 CObjectVector<uint8> dataTmp;
844 dataTmp.resize(_Data[m].size()*2);
845 uint dstId= 0;
847 for(i=0; i<_Data[m].size(); i+=2)
849 dataTmp[dstId++]= _Data[m][i];
850 dataTmp[dstId++]= _Data[m][i];
851 dataTmp[dstId++]= _Data[m][i];
852 dataTmp[dstId++]= _Data[m][i+1];
854 _Data[m] = dataTmp;
856 PixelFormat = RGBA;
857 return true;
863 /*-------------------------------------------------------------------*\
864 rgbaToAlphaLuminance
865 \*-------------------------------------------------------------------*/
866 bool CBitmap::rgbaToAlphaLuminance()
868 uint32 i;
870 if(_Width*_Height == 0) return false;
872 for(uint8 m= 0; m<_MipMapCount; m++)
874 CObjectVector<uint8> dataTmp;
875 dataTmp.resize(_Data[m].size()/2);
876 uint dstId= 0;
878 for(i=0; i<_Data[m].size(); i+=4)
880 dataTmp[dstId++]= (_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255;
881 dataTmp[dstId++]= _Data[m][i+3];
883 NLMISC::contReset(_Data[m]);
884 _Data[m].resize(0);
885 _Data[m] = dataTmp;
887 PixelFormat = AlphaLuminance;
888 return true;
892 /*-------------------------------------------------------------------*\
893 luminanceToAlphaLuminance
894 \*-------------------------------------------------------------------*/
895 bool CBitmap::luminanceToAlphaLuminance()
897 uint32 i;
899 if(_Width*_Height == 0) return false;
901 for(uint8 m= 0; m<_MipMapCount; m++)
903 CObjectVector<uint8> dataTmp;
904 dataTmp.resize(_Data[m].size()*2);
905 uint dstId= 0;
907 for(i=0; i<_Data[m].size(); i++)
909 dataTmp[dstId++]= _Data[m][i];
910 dataTmp[dstId++]= 255;
912 _Data[m] = dataTmp;
914 PixelFormat = AlphaLuminance;
915 return true;
920 /*-------------------------------------------------------------------*\
921 alphaToAlphaLuminance
922 \*-------------------------------------------------------------------*/
923 bool CBitmap::alphaToAlphaLuminance()
925 uint32 i;
927 if(_Width*_Height == 0) return false;
929 for(uint8 m= 0; m<_MipMapCount; m++)
931 CObjectVector<uint8> dataTmp;
932 dataTmp.resize(_Data[m].size()*2);
933 uint dstId= 0;
935 for(i=0; i<_Data[m].size(); i++)
937 dataTmp[dstId++]= 0;
938 dataTmp[dstId++]= _Data[m][i];
940 _Data[m] = dataTmp;
942 PixelFormat = AlphaLuminance;
943 return true;
948 /*-------------------------------------------------------------------*\
949 rgbaToLuminance
950 \*-------------------------------------------------------------------*/
951 bool CBitmap::rgbaToLuminance()
953 uint32 i;
955 if(_Width*_Height == 0) return false;
957 for(uint8 m= 0; m<_MipMapCount; m++)
959 CObjectVector<uint8> dataTmp;
960 dataTmp.resize(_Data[m].size()/4);
961 uint dstId= 0;
963 for(i=0; i<_Data[m].size(); i+=4)
965 dataTmp[dstId++]= (_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255;
967 NLMISC::contReset(_Data[m]);
968 _Data[m].resize(0);
969 _Data[m] = dataTmp;
971 PixelFormat = Luminance;
972 return true;
977 /*-------------------------------------------------------------------*\
978 alphaToLuminance
979 \*-------------------------------------------------------------------*/
980 bool CBitmap::alphaToLuminance()
982 if(_Width*_Height == 0) return false;
984 PixelFormat = Luminance;
985 return true;
990 /*-------------------------------------------------------------------*\
991 alphaLuminanceToLuminance
992 \*-------------------------------------------------------------------*/
993 bool CBitmap::alphaLuminanceToLuminance()
995 if (_Width*_Height == 0) return false;
997 for(uint8 m = 0; m<_MipMapCount; ++m)
999 CObjectVector<uint8> dataTmp;
1000 dataTmp.resize(_Data[m].size()/2);
1001 uint dstId= 0;
1003 for(uint32 i=0; i<_Data[m].size(); i+=2)
1005 dataTmp[dstId++]= _Data[m][i];
1008 NLMISC::contReset(_Data[m]);
1010 _Data[m].resize(0);
1011 _Data[m] = dataTmp;
1014 PixelFormat = Luminance;
1016 return true;
1020 /*-------------------------------------------------------------------*\
1021 rgbaToAlpha
1022 \*-------------------------------------------------------------------*/
1023 bool CBitmap::rgbaToAlpha()
1025 uint32 i;
1027 if(_Width*_Height == 0) return false;
1029 for(uint8 m= 0; m<_MipMapCount; m++)
1031 CObjectVector<uint8> dataTmp;
1032 dataTmp.resize(_Data[m].size()/4);
1033 uint dstId= 0;
1035 for(i=0; i<_Data[m].size(); i+=4)
1037 dataTmp[dstId++]= _Data[m][i+3];
1039 NLMISC::contReset(_Data[m]);
1040 _Data[m].resize(0);
1041 _Data[m] = dataTmp;
1043 PixelFormat = Alpha;
1044 return true;
1048 /*-------------------------------------------------------------------*\
1049 luminanceToAlpha
1050 \*-------------------------------------------------------------------*/
1051 bool CBitmap::luminanceToAlpha()
1053 uint32 i;
1055 if(_Width*_Height == 0) return false;
1057 for(uint8 m= 0; m<_MipMapCount; m++)
1059 CObjectVector<uint8> dataTmp;
1060 dataTmp.resize(_Data[m].size());
1061 uint dstId= 0;
1063 for(i=0; i<_Data[m].size(); i++)
1065 dataTmp[dstId++]= _Data[m][i];
1067 _Data[m] = dataTmp;
1069 PixelFormat = Alpha;
1070 return true;
1074 /*-------------------------------------------------------------------*\
1075 alphaLuminanceToAlpha
1076 \*-------------------------------------------------------------------*/
1077 bool CBitmap::alphaLuminanceToAlpha()
1079 uint32 i;
1081 if(_Width*_Height == 0) return false;
1083 for(uint8 m= 0; m<_MipMapCount; m++)
1085 CObjectVector<uint8> dataTmp;
1086 dataTmp.resize(_Data[m].size()/2);
1087 uint dstId= 0;
1089 for(i=0; i<_Data[m].size(); i+=2)
1091 dataTmp[dstId++]= _Data[m][i+1];
1093 NLMISC::contReset(_Data[m]);
1094 _Data[m].resize(0);
1095 _Data[m] = dataTmp;
1097 PixelFormat = Alpha;
1098 return true;
1102 /*-------------------------------------------------------------------*\
1103 convertToLuminance
1104 \*-------------------------------------------------------------------*/
1105 bool CBitmap::convertToLuminance()
1107 switch(PixelFormat)
1109 case RGBA :
1110 return rgbaToLuminance();
1111 break;
1113 case Luminance :
1114 return true;
1115 break;
1117 case Alpha :
1118 return alphaToLuminance();
1119 break;
1121 case AlphaLuminance :
1122 return alphaLuminanceToLuminance();
1123 break;
1125 default:
1126 break;
1128 return false;
1133 /*-------------------------------------------------------------------*\
1134 convertToAlpha
1135 \*-------------------------------------------------------------------*/
1136 bool CBitmap::convertToAlpha()
1138 switch(PixelFormat)
1140 case RGBA :
1141 return rgbaToAlpha();
1142 break;
1144 case Luminance :
1145 return luminanceToAlpha();
1146 break;
1148 case Alpha :
1149 return true;
1150 break;
1152 case AlphaLuminance :
1153 return alphaLuminanceToAlpha();
1154 break;
1156 default:
1157 break;
1159 return false;
1164 /*-------------------------------------------------------------------*\
1165 convertToAlphaLuminance
1166 \*-------------------------------------------------------------------*/
1167 bool CBitmap::convertToAlphaLuminance()
1169 switch(PixelFormat)
1171 case RGBA :
1172 return rgbaToAlphaLuminance();
1173 break;
1175 case Luminance :
1176 return luminanceToAlphaLuminance();
1177 break;
1179 case Alpha :
1180 return alphaToAlphaLuminance();
1181 break;
1183 case AlphaLuminance :
1184 return true;
1185 break;
1187 default:
1188 break;
1190 return false;
1194 /*-------------------------------------------------------------------*\
1195 convertToRGBA
1196 \*-------------------------------------------------------------------*/
1197 bool CBitmap::convertToRGBA()
1199 switch(PixelFormat)
1201 case DXTC1 :
1202 return decompressDXT1(false);
1203 break;
1205 case DXTC1Alpha :
1206 return decompressDXT1(true);
1207 break;
1209 case DXTC3 :
1210 return decompressDXT3();
1211 break;
1213 case DXTC5 :
1214 return decompressDXT5();
1215 break;
1217 case Luminance :
1218 return luminanceToRGBA();
1219 break;
1221 case Alpha :
1222 return alphaToRGBA();
1223 break;
1225 case AlphaLuminance :
1226 return alphaLuminanceToRGBA();
1227 break;
1228 case RGBA:
1229 return true;
1230 break;
1231 default:
1232 break;
1234 return false;
1238 /*-------------------------------------------------------------------*\
1239 convertToType
1240 \*-------------------------------------------------------------------*/
1241 bool CBitmap::convertToType(CBitmap::TType type)
1243 if(PixelFormat==type) return true;
1245 switch(type)
1247 case RGBA :
1248 return convertToRGBA();
1249 break;
1251 case DXTC5 :
1252 return convertToDXTC5();
1253 break;
1255 case Luminance :
1256 return convertToLuminance();
1257 break;
1259 case Alpha :
1260 return convertToAlpha();
1261 break;
1263 case AlphaLuminance :
1264 return convertToAlphaLuminance();
1265 break;
1267 default:
1268 break;
1271 return false;
1277 /*-------------------------------------------------------------------*\
1278 decompressDXT1
1279 \*-------------------------------------------------------------------*/
1280 bool CBitmap::decompressDXT1(bool alpha)
1282 uint32 i,j,k;
1283 NLMISC::CRGBA c[4];
1284 CObjectVector<uint8> dataTmp[MAX_MIPMAP];
1286 uint32 width= _Width;
1287 uint32 height= _Height;
1289 for(uint8 m= 0; m<_MipMapCount; m++)
1291 uint32 wtmp, htmp;
1292 if(width<4)
1293 wtmp = 4;
1294 else
1295 wtmp = width;
1296 if(height < 4)
1297 htmp = 4;
1298 else
1299 htmp = height;
1300 uint32 mipMapSz = wtmp*htmp*4;
1301 dataTmp[m].resize(mipMapSz);
1302 if(dataTmp[m].size()<mipMapSz)
1304 throw EAllocationFailure();
1306 uint32 wBlockCount= wtmp/4;
1310 for(i=0; i < _Data[m].size(); i+=8)
1312 uint16 color0;
1313 uint16 color1;
1314 uint32 bits;
1315 memcpy(&color0,&_Data[m][i],2);
1316 memcpy(&color1,&_Data[m][i+2],2);
1317 memcpy(&bits,&_Data[m][i+4],4);
1319 uncompress(color0,c[0]);
1320 uncompress(color1,c[1]);
1322 if (alpha)
1324 c[0].A= 0;
1325 c[1].A= 0;
1326 c[2].A= 0;
1327 c[3].A= 0;
1329 else
1331 c[0].A= 255;
1332 c[1].A= 255;
1333 c[2].A= 255;
1334 c[3].A= 255;
1337 if(color0>color1)
1339 c[2].blendFromui(c[0],c[1],85);
1340 if(alpha) c[2].A= 255;
1342 c[3].blendFromui(c[0],c[1],171);
1343 if(alpha) c[3].A= 255;
1345 else
1347 c[2].blendFromui(c[0],c[1],128);
1348 if(alpha) c[2].A= 255;
1350 c[3].set(0,0,0,0);
1353 // computing the 16 RGBA of the block
1355 uint32 blockNum= i/8; //(64 bits)
1356 // <previous blocks in above lines> * 4 (rows) * _Width (columns) + 4pix*4rgba*<same line previous blocks>
1357 uint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);
1358 for(j=0; j<4; j++)
1360 for(k=0; k<4; k++)
1362 uint32 index = pixelsCount + (j*wtmp+k)*4;
1363 // incase input image does not have proper width/height
1364 if (index+3 > mipMapSz) break;
1366 dataTmp[m][index+0]= c[bits&3].R;
1367 dataTmp[m][index+1]= c[bits&3].G;
1368 dataTmp[m][index+2]= c[bits&3].B;
1369 dataTmp[m][index+3]= c[bits&3].A;
1370 bits>>=2;
1375 // Copy result into the mipmap level.
1376 if(wtmp==width && htmp==height)
1378 // For mipmaps level >4 pixels.
1379 _Data[m]= dataTmp[m];
1381 else
1383 // For last mipmaps, level <4 pixels.
1384 _Data[m].resize(width*height*4);
1385 CRGBA *src= (CRGBA*)&dataTmp[m][0];
1386 CRGBA *dst= (CRGBA*)&_Data[m][0];
1387 uint x,y;
1388 for(y=0;y<height;y++)
1390 for(x=0;x<width;x++)
1391 dst[y*width+x]= src[y*wtmp+x];
1395 // Next mipmap size.
1396 width = (width+1)/2;
1397 height = (height+1)/2;
1399 PixelFormat = RGBA;
1400 return true;
1406 /*-------------------------------------------------------------------*\
1407 decompressDXT3
1408 \*-------------------------------------------------------------------*/
1409 bool CBitmap::decompressDXT3()
1411 uint32 i,j,k;
1412 NLMISC::CRGBA c[4];
1413 CObjectVector<uint8> dataTmp[MAX_MIPMAP];
1415 uint32 width= _Width;
1416 uint32 height= _Height;
1418 for(uint8 m= 0; m<_MipMapCount; m++)
1420 uint32 wtmp, htmp;
1421 if(width<4)
1422 wtmp = 4;
1423 else
1424 wtmp = width;
1425 if(height < 4)
1426 htmp = 4;
1427 else
1428 htmp = height;
1429 uint32 mipMapSz = wtmp*htmp*4;
1430 dataTmp[m].resize(mipMapSz);
1431 if(dataTmp[m].size()<mipMapSz)
1433 throw EAllocationFailure();
1435 uint32 wBlockCount= wtmp/4;
1438 for(i=0; i < _Data[m].size(); i+=16)
1440 uint8 alpha[16];
1441 uint64 alphatmp;
1442 memcpy(&alphatmp,&_Data[m][i],8);
1444 for(j=0; j<16; j++)
1446 uint8 a= (uint8)(alphatmp&15);
1447 // expand to 0-255.
1448 alpha[j]= a+(a<<4);
1449 alphatmp>>=4;
1453 uint16 color0;
1454 uint16 color1;
1455 uint32 bits;
1456 memcpy(&color0,&_Data[m][i+8],2);
1457 memcpy(&color1,&_Data[m][i+10],2);
1458 memcpy(&bits,&_Data[m][i+12],4);
1460 uncompress(color0,c[0]);
1461 uncompress(color1,c[1]);
1463 // ignore color0>color1 for DXT3 and DXT5.
1464 c[2].blendFromui(c[0],c[1],85);
1465 c[3].blendFromui(c[0],c[1],171);
1467 // computing the 16 RGBA of the block
1469 uint32 blockNum= i/16; //(128 bits)
1470 // <previous blocks in above lines> * 4 (rows) * wtmp (columns) + 4pix*4rgba*<same line previous blocks>
1471 uint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);
1472 for(j=0; j<4; j++)
1474 for(k=0; k<4; k++)
1476 uint32 index = pixelsCount + (j*wtmp+k)*4;
1477 // incase input image does not have proper width/height
1478 if (index+3 > mipMapSz) break;
1480 dataTmp[m][index+0]= c[bits&3].R;
1481 dataTmp[m][index+1]= c[bits&3].G;
1482 dataTmp[m][index+2]= c[bits&3].B;
1483 dataTmp[m][index+3]= alpha[4*j+k];
1484 bits>>=2;
1489 // Copy result into the mipmap level.
1490 if(wtmp==width && htmp==height)
1492 // For mipmaps level >4 pixels.
1493 _Data[m]= dataTmp[m];
1495 else
1497 // For last mipmaps, level <4 pixels.
1498 _Data[m].resize(width*height*4);
1499 CRGBA *src= (CRGBA*)&dataTmp[m][0];
1500 CRGBA *dst= (CRGBA*)&_Data[m][0];
1501 uint x,y;
1502 for(y=0;y<height;y++)
1504 for(x=0;x<width;x++)
1505 dst[y*width+x]= src[y*wtmp+x];
1509 // Next mipmap size.
1510 width = (width+1)/2;
1511 height = (height+1)/2;
1513 PixelFormat = RGBA;
1514 return true;
1520 /*-------------------------------------------------------------------*\
1521 decompressDXT5
1522 \*-------------------------------------------------------------------*/
1523 bool CBitmap::decompressDXT5()
1525 uint32 i,j,k;
1526 NLMISC::CRGBA c[4];
1527 CObjectVector<uint8> dataTmp[MAX_MIPMAP];
1529 uint32 width= _Width;
1530 uint32 height= _Height;
1532 for(uint8 m= 0; m<_MipMapCount; m++)
1534 uint32 wtmp, htmp;
1535 if(width<4)
1536 wtmp = 4;
1537 else
1538 wtmp = width;
1539 if(height < 4)
1540 htmp = 4;
1541 else
1542 htmp = height;
1543 uint32 mipMapSz = wtmp*htmp*4;
1544 dataTmp[m].resize(mipMapSz);
1545 if(dataTmp[m].size()<mipMapSz)
1547 throw EAllocationFailure();
1549 uint32 wBlockCount= wtmp/4;
1553 for(i=0; i < _Data[m].size(); i+=16)
1555 uint64 bitsAlpha;
1556 memcpy(&bitsAlpha,&_Data[m][i],8);
1557 bitsAlpha>>= 16;
1559 uint32 alpha[8];
1560 alpha[0]= _Data[m][i+0];
1561 alpha[1]= _Data[m][i+1];
1563 if(alpha[0]>alpha[1])
1565 alpha[2]= blend(alpha[0], alpha[1], 219);
1566 alpha[3]= blend(alpha[0], alpha[1], 183);
1567 alpha[4]= blend(alpha[0], alpha[1], 146);
1568 alpha[5]= blend(alpha[0], alpha[1], 110);
1569 alpha[6]= blend(alpha[0], alpha[1], 73);
1570 alpha[7]= blend(alpha[0], alpha[1], 37);
1572 else
1574 alpha[2]= blend(alpha[0], alpha[1], 204);
1575 alpha[3]= blend(alpha[0], alpha[1], 154);
1576 alpha[4]= blend(alpha[0], alpha[1], 102);
1577 alpha[5]= blend(alpha[0], alpha[1], 51);
1578 alpha[6]= 0;
1579 alpha[7]= 255;
1582 uint8 codeAlpha[16];
1583 for(j=0; j<16; j++)
1585 codeAlpha[j] = (uint8)(bitsAlpha & 7);
1586 bitsAlpha>>=3;
1590 uint16 color0;
1591 uint16 color1;
1592 uint32 bits;
1593 memcpy(&color0,&_Data[m][i+8],2);
1594 memcpy(&color1,&_Data[m][i+10],2);
1595 memcpy(&bits,&_Data[m][i+12],4);
1597 uncompress(color0,c[0]);
1598 uncompress(color1,c[1]);
1600 // ignore color0>color1 for DXT3 and DXT5.
1601 c[2].blendFromui(c[0],c[1],85);
1602 c[3].blendFromui(c[0],c[1],171);
1604 // computing the 16 RGBA of the block
1606 uint32 blockNum= i/16; //(128 bits)
1608 // <previous blocks in above lines> * 4 (rows) * wtmp (columns) + 4pix*<same line previous blocks>
1609 uint32 pixelsCount= (blockNum/wBlockCount)*wtmp*4 + 4*(blockNum%wBlockCount);
1610 // *sizeof(RGBA)
1611 pixelsCount*=4;
1612 for(j=0; j<4; j++)
1614 for(k=0; k<4; k++)
1616 uint32 index = pixelsCount + (j*wtmp+k)*4;
1617 // incase input image does not have proper width/height
1618 if (index+3 > mipMapSz) break;
1620 dataTmp[m][index+0]= c[bits&3].R;
1621 dataTmp[m][index+1]= c[bits&3].G;
1622 dataTmp[m][index+2]= c[bits&3].B;
1623 dataTmp[m][index+3]= (uint8) alpha[codeAlpha[4*j+k]];
1624 bits>>=2;
1630 // Copy result into the mipmap level.
1631 if(wtmp==width && htmp==height)
1633 // For mipmaps level >4 pixels.
1634 _Data[m]= dataTmp[m];
1636 else
1638 // For last mipmaps, level <4 pixels.
1639 _Data[m].resize(width*height*4);
1640 CRGBA *src= (CRGBA*)&dataTmp[m][0];
1641 CRGBA *dst= (CRGBA*)&_Data[m][0];
1642 uint x,y;
1643 for(y=0;y<height;y++)
1645 for(x=0;x<width;x++)
1646 dst[y*width+x]= src[y*wtmp+x];
1650 // Next mipmap size.
1651 width = (width+1)/2;
1652 height = (height+1)/2;
1654 PixelFormat = RGBA;
1655 return true;
1662 /*-------------------------------------------------------------------*\
1663 blend
1664 \*-------------------------------------------------------------------*/
1665 uint32 CBitmap::blend(uint32 &n0, uint32 &n1, uint32 coef0)
1667 int a0 = coef0;
1668 int a1 = 256-a0;
1669 return ((n0*a0 + n1*a1) >>8);
1674 /*-------------------------------------------------------------------*\
1675 uncompress
1676 \*-------------------------------------------------------------------*/
1677 inline void CBitmap::uncompress(uint16 color, NLMISC::CRGBA &r)
1679 r.A= 0;
1680 r.R= ((color>>11)&31) << 3; r.R+= r.R>>5;
1681 r.G= ((color>>5)&63) << 2; r.G+= r.G>>6;
1682 r.B= ((color)&31) << 3; r.B+= r.B>>5;
1687 /*-------------------------------------------------------------------*\
1688 getWidth
1689 \*-------------------------------------------------------------------*/
1690 uint32 CBitmap::getWidth(uint32 mipMap) const
1692 if(mipMap==0) return _Width;
1694 uint32 w = _Width;
1695 uint32 h = _Height;
1696 uint32 m = 0;
1700 m++;
1701 w = (w+1)/2;
1702 h = (h+1)/2;
1703 if(m==mipMap) return w;
1705 while(w!=1 || h!=1);
1707 return 0;
1712 /*-------------------------------------------------------------------*\
1713 getHeight
1714 \*-------------------------------------------------------------------*/
1715 uint32 CBitmap::getHeight(uint32 mipMap) const
1717 if(mipMap==0) return _Height;
1719 uint32 w = _Width;
1720 uint32 h = _Height;
1721 uint32 m = 0;
1725 m++;
1726 w = (w+1)/2;
1727 h = (h+1)/2;
1728 if(m==mipMap) return h;
1730 while(w!=1 || h!=1);
1732 return 0;
1736 /*-------------------------------------------------------------------*\
1737 getSize
1738 \*-------------------------------------------------------------------*/
1739 uint32 CBitmap::getSize(uint32 numMipMap) const
1741 return getHeight(numMipMap)*getWidth(numMipMap);
1746 /*-------------------------------------------------------------------*\
1747 buildMipMaps
1748 \*-------------------------------------------------------------------*/
1749 void CBitmap::buildMipMaps()
1751 uint32 i,j;
1753 if(PixelFormat!=RGBA) return;
1754 if(_MipMapCount!=1) return;
1755 if(!NLMISC::isPowerOf2(_Width)) return;
1756 if(!NLMISC::isPowerOf2(_Height)) return;
1758 uint32 w = _Width;
1759 uint32 h = _Height;
1761 while(w>1 || h>1)
1763 uint32 precw = w;
1764 uint32 prech = h;
1765 w = (w+1)/2;
1766 h = (h+1)/2;
1767 uint32 mulw= precw/w;
1768 uint32 mulh= prech/h;
1770 _Data[_MipMapCount].resize(w*h*4);
1772 NLMISC::CRGBA *pRgba = (NLMISC::CRGBA*)&_Data[_MipMapCount][0];
1773 NLMISC::CRGBA *pRgbaPrev = (NLMISC::CRGBA*)&_Data[_MipMapCount-1][0];
1774 for(i=0; i<h; i++)
1776 sint i0= mulh*i;
1777 sint i1= mulh*i+1;
1778 if(mulh==1)
1779 i1=i0;
1780 i0*=precw;
1781 i1*=precw;
1782 for(j=0; j<w; j++)
1784 sint j0= mulw*j;
1785 sint j1= mulw*j+1;
1786 if(mulw==1)
1787 j1=j0;
1788 CRGBA &c0= pRgbaPrev[i0+j0];
1789 CRGBA &c1= pRgbaPrev[i0+j1];
1790 CRGBA &c2= pRgbaPrev[i1+j0];
1791 CRGBA &c3= pRgbaPrev[i1+j1];
1792 pRgba[i*w + j].R = (c0.R +
1793 c1.R +
1794 c2.R +
1795 c3.R + 2 ) /4;
1796 pRgba[i*w + j].G = (c0.G +
1797 c1.G +
1798 c2.G +
1799 c3.G + 2 ) /4;
1800 pRgba[i*w + j].B = (c0.B +
1801 c1.B +
1802 c2.B +
1803 c3.B + 2 ) /4;
1804 pRgba[i*w + j].A = (c0.A +
1805 c1.A +
1806 c2.A +
1807 c3.A + 2 ) /4;
1811 _MipMapCount++;
1815 /*-------------------------------------------------------------------*\
1816 computeNeededMipMapCount
1817 \*-------------------------------------------------------------------*/
1818 uint32 CBitmap::computeNeededMipMapCount() const
1820 if(_MipMapCount == 0) return 0;
1821 if(!NLMISC::isPowerOf2(_Width)) return 1;
1822 if(!NLMISC::isPowerOf2(_Height)) return 1;
1824 uint32 mipMapCount = 1;
1825 uint32 w = _Width;
1826 uint32 h = _Height;
1828 while(w>1 || h>1)
1830 w = (w+1)/2;
1831 h = (h+1)/2;
1832 ++mipMapCount;
1834 return mipMapCount;
1837 /*-------------------------------------------------------------------*\
1838 releaseMipMaps
1839 \*-------------------------------------------------------------------*/
1840 void CBitmap::releaseMipMaps()
1842 if(_MipMapCount<=1) return;
1844 _MipMapCount=1;
1845 for(sint i=1;i<MAX_MIPMAP;i++)
1847 NLMISC::contReset(_Data[i]);
1851 /*-------------------------------------------------------------------*\
1852 resample
1853 \*-------------------------------------------------------------------*/
1854 void CBitmap::resample(sint32 nNewWidth, sint32 nNewHeight)
1856 nlassert(PixelFormat == RGBA || PixelFormat == Luminance || PixelFormat == AlphaLuminance);
1857 bool needRebuild = false;
1859 // Deleting mipmaps
1860 //logResample("Resample: 10");
1861 if(_MipMapCount>1)
1862 needRebuild = true;
1863 releaseMipMaps();
1864 //logResample("Resample: 20");
1866 if(nNewWidth==0 || nNewHeight==0)
1868 _Width = _Height = 0;
1869 //logResample("Resample: 25");
1870 return;
1873 //logResample("Resample: 30");
1874 CObjectVector<uint8> pDestui;
1876 if (PixelFormat == RGBA)
1878 pDestui.resize(nNewWidth*nNewHeight*4);
1879 //logResample("Resample: 40");
1880 NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
1881 //logResample("Resample: 50");
1883 resamplePicture32 ((NLMISC::CRGBA*)&_Data[0][0], pDestRgba, _Width, _Height, nNewWidth, nNewHeight);
1884 //logResample("Resample: 60");
1886 else if (PixelFormat == Luminance)
1888 pDestui.resize(nNewWidth*nNewHeight);
1889 //logResample("Resample: 40");
1890 uint8 *pDestGray = &pDestui[0];
1891 //logResample("Resample: 50");
1893 resamplePicture8 (&_Data[0][0], pDestGray, _Width, _Height, nNewWidth, nNewHeight);
1894 //logResample("Resample: 60");
1896 else if (PixelFormat == AlphaLuminance)
1898 pDestui.resize(nNewWidth*nNewHeight*2);
1900 uint16 *pSrc = (uint16*)&_Data[0][0];
1901 uint16 *pDest = (uint16*)&pDestui[0];
1903 size_t srcSize = _Width*_Width;
1904 uint8 *pSrcGray = new uint8[srcSize];
1905 uint8 *pSrcAlpha = new uint8[srcSize];
1907 // set iterators
1908 uint16 *i = (uint16*)pSrc;
1909 uint16 *iEnd = (uint16*)i + srcSize;
1910 uint8 *iGray = pSrcGray;
1911 uint8 *iAlpha = pSrcAlpha;
1913 // copy alpha and gray in distinct arrays
1914 while (i < iEnd)
1916 *(iGray++) = (*i) & 0xff;
1917 *(iAlpha++) = ((*i) >> 8) & 0xff;
1918 ++i;
1921 size_t destSize = nNewWidth*nNewHeight;
1923 // resample gray values array
1924 uint8 *pDestGray = new uint8[destSize];
1925 resamplePicture8(pSrcGray, pDestGray, _Width, _Height, nNewWidth, nNewHeight);
1926 delete[] pSrcGray;
1928 // resample alpha values array
1929 uint8 *pDestAlpha = new uint8[destSize];
1930 resamplePicture8(pSrcAlpha, pDestAlpha, _Width, _Height, nNewWidth, nNewHeight);
1931 delete[] pSrcAlpha;
1933 // set iterators
1934 i = (uint16*)pDest;
1935 iEnd = (uint16*)i + destSize;
1936 iGray = pDestGray;
1937 iAlpha = pDestAlpha;
1939 // merge alpha and gray in destination array
1940 while (i < iEnd)
1942 *(i++) = *(iGray++) | (*(iAlpha++) << 8);
1945 delete[] pDestGray;
1946 delete[] pDestAlpha;
1949 NLMISC::contReset(_Data[0]); // free memory
1950 //logResample("Resample: 70");
1952 _Data[0] = pDestui;
1953 //logResample("Resample: 80");
1954 _Width= nNewWidth;
1955 _Height= nNewHeight;
1957 // Rebuilding mipmaps
1958 //logResample("Resample: 90");
1959 if(needRebuild)
1961 buildMipMaps();
1962 //logResample("Resample: 95");
1964 //logResample("Resample: 100");
1968 /*-------------------------------------------------------------------*\
1969 resize
1970 \*-------------------------------------------------------------------*/
1971 void CBitmap::resize (sint32 nNewWidth, sint32 nNewHeight, TType newType, bool resetTo0)
1973 // Deleting mipmaps
1974 releaseMipMaps();
1976 // Change type of bitmap ?
1977 if (newType!=DonTKnow)
1978 PixelFormat=newType;
1980 _Width = nNewWidth;
1981 _Height = nNewHeight;
1983 // resize the level 0 only.
1984 resizeMipMap(0, nNewWidth, nNewHeight, resetTo0);
1988 /*-------------------------------------------------------------------*\
1989 resizeMipMap
1990 \*-------------------------------------------------------------------*/
1991 void CBitmap::resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight, bool resetTo0)
1993 nlassert(numMipMap<MAX_MIPMAP);
1995 // free memory
1996 NLMISC::contReset(_Data[numMipMap]);
1998 // DXTC compressed??
1999 //bool isDXTC= PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha || PixelFormat==DXTC3 || PixelFormat==DXTC5;
2000 // if yes, must round up width and height to 4, for allocation
2001 nNewWidth= 4*((nNewWidth+3)/4);
2002 nNewHeight= 4*((nNewHeight+3)/4);
2004 // resize the buffer
2005 _Data[numMipMap].resize (((uint32)(nNewWidth*nNewHeight)*bitPerPixels[PixelFormat])/8);
2007 // Fill 0?
2008 if( resetTo0 )
2009 _Data[numMipMap].fill(0);
2013 /*-------------------------------------------------------------------*\
2014 reset
2015 \*-------------------------------------------------------------------*/
2016 void CBitmap::setMipMapCount(uint32 mmc)
2018 _MipMapCount= uint8(mmc);
2022 /*-------------------------------------------------------------------*\
2023 reset
2024 \*-------------------------------------------------------------------*/
2025 void CBitmap::reset(TType type)
2027 for(uint i=0; i<_MipMapCount; i++)
2029 NLMISC::contReset(_Data[i]);
2030 _Data[i].resize(0);
2032 _Width = _Height = 0;
2033 _MipMapCount= 1;
2035 // Change pixel format
2036 PixelFormat=type;
2041 /*-------------------------------------------------------------------*\
2042 resamplePicture32
2043 \*-------------------------------------------------------------------*/
2044 void CBitmap::resamplePicture32 (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest,
2045 sint32 nSrcWidth, sint32 nSrcHeight,
2046 sint32 nDestWidth, sint32 nDestHeight)
2048 //logResample("RP32: 0 pSrc=%p pDest=%p, Src=%d x %d Dest=%d x %d", pSrc, pDest, nSrcWidth, nSrcHeight, nDestWidth, nDestHeight);
2049 if ((nSrcWidth<=0)||(nSrcHeight<=0)||(nDestWidth<=0)||(nDestHeight<=0))
2050 return;
2052 // If we're reducing it by 2, call the fast resample
2053 if (((nSrcHeight / 2) == nDestHeight) && ((nSrcHeight % 2) == 0) &&
2054 ((nSrcWidth / 2) == nDestWidth) && ((nSrcWidth % 2) == 0))
2056 resamplePicture32Fast(pSrc, pDest, nSrcWidth, nSrcHeight, nDestWidth, nDestHeight);
2057 return;
2060 bool bXMag=(nDestWidth>=nSrcWidth);
2061 bool bYMag=(nDestHeight>=nSrcHeight);
2062 bool bXEq=(nDestWidth==nSrcWidth);
2063 bool bYEq=(nDestHeight==nSrcHeight);
2064 std::vector<NLMISC::CRGBAF> pIterm (nDestWidth*nSrcHeight);
2066 if (bXMag)
2068 float fXdelta=(float)(nSrcWidth)/(float)(nDestWidth);
2069 NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
2070 sint32 nY;
2071 for (nY=0; nY<nSrcHeight; nY++)
2073 const NLMISC::CRGBA *pSrcLine=pSrc;
2074 float fX=0.f;
2075 sint32 nX;
2076 for (nX=0; nX<nDestWidth; nX++)
2078 float fVirgule=fX-(float)floor(fX);
2079 nlassert (fVirgule>=0.f);
2080 NLMISC::CRGBAF vColor;
2081 if (fVirgule>=0.5f)
2083 if (fX<(float)(nSrcWidth-1))
2085 NLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);
2086 NLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)+1]);
2087 vColor=vColor1*(1.5f-fVirgule)+vColor2*(fVirgule-0.5f);
2089 else
2090 vColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
2092 else
2094 if (fX>=1.f)
2096 NLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);
2097 NLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)-1]);
2098 vColor=vColor1*(0.5f+fVirgule)+vColor2*(0.5f-fVirgule);
2100 else
2101 vColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
2103 *(pItermPtr++)=vColor;
2104 fX+=fXdelta;
2106 pSrc+=nSrcWidth;
2109 else if (bXEq)
2111 NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
2112 for (sint32 nY=0; nY<nSrcHeight; nY++)
2114 const NLMISC::CRGBA *pSrcLine=pSrc;
2115 sint32 nX;
2116 for (nX=0; nX<nDestWidth; nX++)
2117 *(pItermPtr++)=NLMISC::CRGBAF (pSrcLine[nX]);
2118 pSrc+=nSrcWidth;
2121 else
2123 double fXdelta=(double)(nSrcWidth)/(double)(nDestWidth);
2124 nlassert (fXdelta>1.f);
2125 NLMISC::CRGBAF *pItermPtr=&*pIterm.begin();
2126 sint32 nY;
2127 for (nY=0; nY<nSrcHeight; nY++)
2129 const NLMISC::CRGBA *pSrcLine=pSrc;
2130 double fX=0.f;
2131 sint32 nX;
2132 for (nX=0; nX<nDestWidth; nX++)
2134 NLMISC::CRGBAF vColor (0.f, 0.f, 0.f, 0.f);
2135 double fFinal=fX+fXdelta;
2136 while ((fX<fFinal)&&((sint32)fX!=nSrcWidth))
2138 double fNext=(double)floor (fX)+1.f;
2139 if (fNext>fFinal)
2140 fNext=fFinal;
2141 vColor+=((float)(fNext-fX))*NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);
2142 fX=fNext;
2144 fX = fFinal; // ensure fX == fFinal
2145 vColor/=(float)fXdelta;
2146 *(pItermPtr++)=vColor;
2148 pSrc+=nSrcWidth;
2152 if (bYMag)
2154 double fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);
2155 sint32 nX;
2156 for (nX=0; nX<nDestWidth; nX++)
2158 double fY=0.f;
2159 sint32 nY;
2160 for (nY=0; nY<nDestHeight; nY++)
2162 double fVirgule=fY-(double)floor(fY);
2163 nlassert (fVirgule>=0.f);
2164 NLMISC::CRGBAF vColor;
2165 if (fVirgule>=0.5f)
2167 if (fY<(double)(nSrcHeight-1))
2169 NLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
2170 NLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))+1)*nDestWidth+nX];
2171 vColor=vColor1*(1.5f-(float)fVirgule)+vColor2*((float)fVirgule-0.5f);
2173 else
2174 vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
2176 else
2178 if (fY>=1.f)
2180 NLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
2181 NLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))-1)*nDestWidth+nX];
2182 vColor=vColor1*(0.5f+(float)fVirgule)+vColor2*(0.5f-(float)fVirgule);
2184 else
2185 vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
2187 pDest[nX+nY*nDestWidth]=vColor;
2188 fY+=fYdelta;
2192 else if (bYEq)
2194 for (sint32 nX=0; nX<nDestWidth; nX++)
2196 sint32 nY;
2197 for (nY=0; nY<nDestHeight; nY++)
2199 pDest[nX+nY*nDestWidth]=pIterm[nY*nDestWidth+nX];
2203 else
2205 double fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);
2206 nlassert (fYdelta>1.f);
2207 sint32 nX;
2208 for (nX=0; nX<nDestWidth; nX++)
2210 double fY=0.f;
2211 sint32 nY;
2212 for (nY=0; nY<nDestHeight; nY++)
2214 NLMISC::CRGBAF vColor (0.f, 0.f, 0.f, 0.f);
2215 double fFinal=fY+fYdelta;
2216 while ((fY<fFinal)&&((sint32)fY!=nSrcHeight))
2218 double fNext=(double)floor (fY)+1.f;
2219 if (fNext>fFinal)
2220 fNext=fFinal;
2221 vColor+=((float)(fNext-fY))*pIterm[((sint32)floor(fY))*nDestWidth+nX];
2222 fY=fNext;
2224 vColor/=(float)fYdelta;
2225 pDest[nX+nY*nDestWidth]=vColor;
2231 /*-------------------------------------------------------------------*\
2232 resamplePicture32Fast
2233 \*-------------------------------------------------------------------*/
2234 void CBitmap::resamplePicture32Fast (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest,
2235 sint32 nSrcWidth, sint32 nSrcHeight,
2236 sint32 nDestWidth, sint32 nDestHeight)
2238 // the image is divided by two : 1 pixel in dest = 4 pixels in src
2239 // the resulting pixel in dest is an average of the four pixels in src
2241 nlassert(nSrcWidth % 2 == 0);
2242 nlassert(nSrcHeight % 2 == 0);
2243 nlassert(nSrcWidth / 2 == nDestWidth);
2244 nlassert(nSrcHeight / 2 == nDestHeight);
2246 sint32 x, y, twoX, twoSrcWidthByY;
2248 for (y=0 ; y<nDestHeight ; y++)
2250 twoSrcWidthByY = 2*nSrcWidth*y;
2251 for (x=0 ; x<nDestWidth ; x++)
2253 twoX = 2*x;
2254 pDest[x+y*nDestWidth].avg4( pSrc[twoX + twoSrcWidthByY ],
2255 pSrc[twoX + twoSrcWidthByY + nSrcWidth ],
2256 pSrc[twoX+1 + twoSrcWidthByY ],
2257 pSrc[twoX+1 + twoSrcWidthByY + nSrcWidth ]);
2263 /*-------------------------------------------------------------------*\
2264 resamplePicture8
2265 \*-------------------------------------------------------------------*/
2266 void CBitmap::resamplePicture8 (const uint8 *pSrc, uint8 *pDest,
2267 sint32 nSrcWidth, sint32 nSrcHeight,
2268 sint32 nDestWidth, sint32 nDestHeight)
2270 //logResample("RP8: 0 pSrc=%p pDest=%p, Src=%d x %d Dest=%d x %d", pSrc, pDest, nSrcWidth, nSrcHeight, nDestWidth, nDestHeight);
2271 if ((nSrcWidth<=0)||(nSrcHeight<=0)||(nDestWidth<=0)||(nDestHeight<=0))
2272 return;
2274 // If we're reducing it by 2, call the fast resample
2275 if (((nSrcHeight / 2) == nDestHeight) && ((nSrcHeight % 2) == 0) &&
2276 ((nSrcWidth / 2) == nDestWidth) && ((nSrcWidth % 2) == 0))
2278 resamplePicture8Fast(pSrc, pDest, nSrcWidth, nSrcHeight, nDestWidth, nDestHeight);
2279 return;
2282 bool bXMag=(nDestWidth>=nSrcWidth);
2283 bool bYMag=(nDestHeight>=nSrcHeight);
2284 bool bXEq=(nDestWidth==nSrcWidth);
2285 bool bYEq=(nDestHeight==nSrcHeight);
2286 std::vector<float> pIterm (nDestWidth*nSrcHeight);
2288 if (bXMag)
2290 float fXdelta=(float)(nSrcWidth)/(float)(nDestWidth);
2291 float *pItermPtr=&*pIterm.begin();
2292 sint32 nY;
2293 for (nY=0; nY<nSrcHeight; nY++)
2295 const uint8 *pSrcLine=pSrc;
2296 float fX=0.f;
2297 sint32 nX;
2298 for (nX=0; nX<nDestWidth; nX++)
2300 float fVirgule=fX-(float)floor(fX);
2301 nlassert (fVirgule>=0.f);
2302 float vColor;
2303 if (fVirgule>=0.5f)
2305 if (fX<(float)(nSrcWidth-1))
2307 float vColor1 (pSrcLine[(sint32)floor(fX)]);
2308 float vColor2 (pSrcLine[(sint32)floor(fX)+1]);
2309 vColor=vColor1*(1.5f-fVirgule)+vColor2*(fVirgule-0.5f);
2311 else
2312 vColor = float(pSrcLine[(sint32)floor(fX)]);
2314 else
2316 if (fX>=1.f)
2318 float vColor1 (pSrcLine[(sint32)floor(fX)]);
2319 float vColor2 (pSrcLine[(sint32)floor(fX)-1]);
2320 vColor = vColor1*(0.5f+fVirgule)+vColor2*(0.5f-fVirgule);
2322 else
2323 vColor = float (pSrcLine[(sint32)floor(fX)]);
2325 *(pItermPtr++)=vColor;
2326 fX+=fXdelta;
2328 pSrc+=nSrcWidth;
2331 else if (bXEq)
2333 float *pItermPtr=&*pIterm.begin();
2334 for (sint32 nY=0; nY<nSrcHeight; nY++)
2336 const uint8 *pSrcLine=pSrc;
2337 sint32 nX;
2338 for (nX=0; nX<nDestWidth; nX++)
2339 *(pItermPtr++) = float (pSrcLine[nX]);
2340 pSrc+=nSrcWidth;
2343 else
2345 double fXdelta=(double)(nSrcWidth)/(double)(nDestWidth);
2346 nlassert (fXdelta>1.f);
2347 float *pItermPtr=&*pIterm.begin();
2348 sint32 nY;
2349 for (nY=0; nY<nSrcHeight; nY++)
2351 const uint8 *pSrcLine=pSrc;
2352 double fX=0.f;
2353 sint32 nX;
2354 for (nX=0; nX<nDestWidth; nX++)
2356 float vColor = 0.f;
2357 double fFinal=fX+fXdelta;
2358 while ((fX<fFinal)&&((sint32)fX!=nSrcWidth))
2360 double fNext=(double)floor (fX)+1.f;
2361 if (fNext>fFinal)
2362 fNext=fFinal;
2363 vColor+=((float)(fNext-fX))* float (pSrcLine[(sint32)floor(fX)]);
2364 fX=fNext;
2366 fX = fFinal; // ensure fX == fFinal
2367 vColor/=(float)fXdelta;
2368 *(pItermPtr++)=vColor;
2370 pSrc+=nSrcWidth;
2374 if (bYMag)
2376 double fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);
2377 sint32 nX;
2378 for (nX=0; nX<nDestWidth; nX++)
2380 double fY=0.f;
2381 sint32 nY;
2382 for (nY=0; nY<nDestHeight; nY++)
2384 double fVirgule=fY-(double)floor(fY);
2385 nlassert (fVirgule>=0.f);
2386 float vColor;
2387 if (fVirgule>=0.5f)
2389 if (fY<(double)(nSrcHeight-1))
2391 float vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
2392 float vColor2=pIterm[(((sint32)floor(fY))+1)*nDestWidth+nX];
2393 vColor=vColor1*(1.5f-(float)fVirgule)+vColor2*((float)fVirgule-0.5f);
2395 else
2396 vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
2398 else
2400 if (fY>=1.f)
2402 float vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];
2403 float vColor2=pIterm[(((sint32)floor(fY))-1)*nDestWidth+nX];
2404 vColor=vColor1*(0.5f+(float)fVirgule)+vColor2*(0.5f-(float)fVirgule);
2406 else
2407 vColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];
2409 pDest[nX+nY*nDestWidth]=vColor;
2410 fY+=fYdelta;
2414 else if (bYEq)
2416 for (sint32 nX=0; nX<nDestWidth; nX++)
2418 sint32 nY;
2419 for (nY=0; nY<nDestHeight; nY++)
2421 pDest[nX+nY*nDestWidth]=pIterm[nY*nDestWidth+nX];
2425 else
2427 double fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);
2428 nlassert (fYdelta>1.f);
2429 sint32 nX;
2430 for (nX=0; nX<nDestWidth; nX++)
2432 double fY=0.f;
2433 sint32 nY;
2434 for (nY=0; nY<nDestHeight; nY++)
2436 float vColor = 0.f;
2437 double fFinal=fY+fYdelta;
2438 while ((fY<fFinal)&&((sint32)fY!=nSrcHeight))
2440 double fNext=(double)floor (fY)+1.f;
2441 if (fNext>fFinal)
2442 fNext=fFinal;
2443 vColor+=((float)(fNext-fY))*pIterm[((sint32)floor(fY))*nDestWidth+nX];
2444 fY=fNext;
2446 vColor/=(float)fYdelta;
2447 pDest[nX+nY*nDestWidth]=vColor;
2454 /*-------------------------------------------------------------------*\
2455 resamplePicture8Fast
2456 \*-------------------------------------------------------------------*/
2457 void CBitmap::resamplePicture8Fast (const uint8 *pSrc, uint8 *pDest,
2458 sint32 nSrcWidth, sint32 nSrcHeight,
2459 sint32 nDestWidth, sint32 nDestHeight)
2461 // the image is divided by two : 1 pixel in dest = 4 pixels in src
2462 // the resulting pixel in dest is an average of the four pixels in src
2464 nlassert(nSrcWidth % 2 == 0);
2465 nlassert(nSrcHeight % 2 == 0);
2466 nlassert(nSrcWidth / 2 == nDestWidth);
2467 nlassert(nSrcHeight / 2 == nDestHeight);
2469 sint32 x, y, twoX, twoSrcWidthByY;
2471 for (y=0 ; y<nDestHeight ; y++)
2473 twoSrcWidthByY = 2*nSrcWidth*y;
2474 for (x=0 ; x<nDestWidth ; x++)
2476 twoX = 2*x;
2477 pDest[x+y*nDestWidth] = (
2478 (uint)pSrc[twoX + twoSrcWidthByY ]+
2479 (uint)pSrc[twoX + twoSrcWidthByY + nSrcWidth ]+
2480 (uint)pSrc[twoX+1 + twoSrcWidthByY ]+
2481 (uint)pSrc[twoX+1 + twoSrcWidthByY + nSrcWidth ]+1)>>2;
2488 /*-------------------------------------------------------------------*\
2489 readTGA
2490 \*-------------------------------------------------------------------*/
2491 uint8 CBitmap::readTGA( NLMISC::IStream &f)
2493 /* ***********************************************
2494 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
2495 * It can be loaded/called through CAsyncFileManager for instance
2496 * ***********************************************/
2498 if(!f.isReading()) return 0;
2500 uint32 x,y;
2501 sint32 slsize;
2502 uint8 *scanline;
2503 uint8 r,g,b;
2504 sint32 i,j,k;
2506 // TGA file header fields
2507 uint8 lengthID;
2508 uint8 cMapType;
2509 uint8 imageType;
2510 uint16 origin;
2511 uint16 length;
2512 uint8 depth;
2513 uint16 xOrg;
2514 uint16 yOrg;
2515 uint16 width;
2516 uint16 height;
2517 uint8 imageDepth;
2518 uint8 desc;
2521 // Determining whether file is in Original or New TGA format
2523 uint32 extAreaOffset;
2524 uint32 devDirectoryOffset;
2525 char signature[16];
2527 f.seek (0, f.end);
2528 if (f.getPos() >= 26)
2530 f.seek (-26, f.end);
2531 f.serial(extAreaOffset);
2532 f.serial(devDirectoryOffset);
2533 for(i=0; i<16; i++)
2535 f.serial(signature[i]);
2541 // Reading TGA file header
2542 f.seek (0, f.begin);
2544 f.serial(lengthID);
2545 f.serial(cMapType);
2546 f.serial(imageType);
2547 f.serial(origin);
2548 f.serial(length);
2549 f.serial(depth);
2550 f.serial(xOrg);
2551 f.serial(yOrg);
2552 f.serial(width);
2553 f.serial(height);
2554 f.serial(imageDepth);
2555 f.serial(desc);
2557 if(cMapType!=0)
2559 nlinfo("readTga : color-map not supported");
2562 if(lengthID>0)
2564 uint8 dummy;
2565 for(i=0; i<lengthID; i++)
2566 f.serial(dummy);
2571 // Reading TGA image data
2573 _Width = width;
2574 _Height = height;
2576 switch(imageType)
2578 // Uncompressed RGB or RGBA
2579 case 2:
2581 _Data[0].resize(_Width*_Height*4);
2582 uint8 upSideDown = ((desc & (1 << 5))==0);
2583 slsize = _Width * imageDepth / 8;
2585 scanline = new uint8[slsize];
2586 if(!scanline)
2588 throw EAllocationFailure();
2591 for(y=0; y<_Height;y++)
2593 // Serial buffer: more efficient way to load.
2594 f.serialBuffer (scanline, slsize);
2596 if(imageDepth==24 || imageDepth==32)
2598 sint32 mult = 3;
2599 if(imageDepth==16)
2601 mult = 2;
2603 if(imageDepth==32)
2605 mult = 4;
2607 if(imageDepth!=16)
2609 for(x=0; x<_Width; x++)
2611 // RGB(A)
2612 r = scanline[x*mult+0];
2613 g = scanline[x*mult+1];
2614 b = scanline[x*mult+2];
2615 // Switching to BGR(A)
2616 scanline[x*mult+0] = b;
2617 scanline[x*mult+1] = g;
2618 scanline[x*mult+2] = r;
2623 k=0;
2624 for(i=0; i<width; i++)
2626 if(upSideDown)
2628 if(imageDepth==16)
2630 uint16 toto = (uint16)scanline[k++];
2631 toto |= scanline[k++]<<8;
2632 uint _r = toto>>10;
2633 uint _g = (toto>>5)&0x1f;
2634 uint _b = toto&0x1f;
2635 _Data[0][(height-y-1)*width*4 + 4*i] = uint8((_r<<3) | (_r>>2));
2636 _Data[0][(height-y-1)*width*4 + 4*i + 1] = uint8((_g<<3) | (_g>>2));
2637 _Data[0][(height-y-1)*width*4 + 4*i + 2] = uint8((_b<<3) | (_b>>2));
2638 _Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;
2640 else
2642 _Data[0][(height-y-1)*width*4 + 4*i] = scanline[k++];
2643 _Data[0][(height-y-1)*width*4 + 4*i + 1] = scanline[k++];
2644 _Data[0][(height-y-1)*width*4 + 4*i + 2] = scanline[k++];
2645 if(imageDepth==32)
2646 _Data[0][(height-y-1)*width*4 + 4*i + 3] = scanline[k++];
2647 else
2648 _Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;
2651 else
2653 if(imageDepth==16)
2655 uint16 toto = (uint16)scanline[k++];
2656 toto |= scanline[k++]<<8;
2657 int _r = toto>>10;
2658 int _g = toto&(0x3e0)>>5;
2659 int _b = toto&0x1f;
2660 _Data[0][y*width*4 + 4*i] = uint8((_r<<3) | (_r>>2));
2661 _Data[0][y*width*4 + 4*i + 1] = uint8((_g<<3) | (_g>>2));
2662 _Data[0][y*width*4 + 4*i + 2] = uint8((_b<<3) | (_b>>2));
2663 _Data[0][y*width*4 + 4*i + 3] = 255;
2665 else
2667 _Data[0][y*width*4 + 4*i] = scanline[k++];
2668 _Data[0][y*width*4 + 4*i + 1] = scanline[k++];
2669 _Data[0][y*width*4 + 4*i + 2] = scanline[k++];
2670 if(imageDepth==32)
2671 _Data[0][y*width*4 + 4*i + 3] = scanline[k++];
2672 else
2673 _Data[0][y*width*4 + 4*i + 3] = 255;
2679 PixelFormat = RGBA;
2680 delete []scanline;
2682 break;
2684 // Uncompressed Grayscale bitmap
2685 case 3:
2687 _Data[0].resize(_Width*_Height);
2688 uint8 upSideDown = ((desc & (1 << 5))==0);
2689 slsize = _Width;
2691 scanline = new uint8[slsize];
2692 if(!scanline)
2694 throw EAllocationFailure();
2697 for(y=0; y<_Height;y++)
2699 // Serial buffer: more efficient way to load.
2700 f.serialBuffer (scanline, slsize);
2702 k=0;
2703 for(i=0; i<width; i++)
2705 if(upSideDown)
2706 _Data[0][(height-y-1)*width + i] = scanline[k++];
2707 else
2708 _Data[0][y*width + i] = scanline[k++];
2712 PixelFormat = _LoadGrayscaleAsAlpha?Alpha:Luminance;
2713 delete []scanline;
2715 break;
2717 // Compressed RGB or RGBA
2718 case 10:
2720 uint8 packet;
2721 uint8 pixel[4] = {0};
2722 uint32 imageSize = width*height;
2723 uint32 readSize = 0;
2724 uint8 upSideDown = ((desc & (1 << 5))==0);
2725 _Data[0].resize(_Width*_Height*4);
2726 uint dstId= 0;
2728 while(readSize < imageSize)
2730 f.serial(packet);
2731 if((packet & 0x80) > 0) // packet RLE
2733 for(i=0; i<imageDepth/8; i++)
2735 f.serial(pixel[i]);
2737 for (i=0; i < (packet & 0x7F) + 1; i++)
2739 _Data[0][dstId++]= pixel[2];
2740 _Data[0][dstId++]= pixel[1];
2741 _Data[0][dstId++]= pixel[0];
2742 _Data[0][dstId++]= pixel[3];
2745 else // packet Raw
2747 for(i=0; i<((packet & 0x7F) + 1); i++)
2749 for(j=0; j<imageDepth/8; j++)
2751 f.serial(pixel[j]);
2753 _Data[0][dstId++]= pixel[2];
2754 _Data[0][dstId++]= pixel[1];
2755 _Data[0][dstId++]= pixel[0];
2756 _Data[0][dstId++]= pixel[3];
2759 readSize += (packet & 0x7F) + 1;
2761 PixelFormat = RGBA;
2763 if (upSideDown) flipV();
2765 break;
2767 // Compressed Grayscale bitmap (not tested)
2768 case 11:
2770 uint8 packet;
2771 uint8 pixel[4];
2772 uint32 imageSize = width*height;
2773 uint32 readSize = 0;
2774 _Data[0].resize(_Width*_Height);
2775 uint dstId= 0;
2777 while(readSize < imageSize)
2779 f.serial(packet);
2780 if((packet & 0x80) > 0) // packet RLE
2782 f.serial(pixel[0]);
2783 for (i=0; i < (packet & 0x7F) + 1; i++)
2785 _Data[0][dstId++]= pixel[0];
2788 else // packet Raw
2790 for(i=0; i<((packet & 0x7F) + 1); i++)
2792 f.serial(pixel[0]);
2793 _Data[0][dstId++]= pixel[0];
2796 readSize += (packet & 0x7F) + 1;
2798 PixelFormat = _LoadGrayscaleAsAlpha?Alpha:Luminance;
2800 break;
2802 default:
2803 return 0;
2806 _MipMapCount = 1;
2807 return(imageDepth);
2811 /*-------------------------------------------------------------------*\
2812 writeTGA
2813 \*-------------------------------------------------------------------*/
2814 bool CBitmap::writeTGA( NLMISC::IStream &f, uint32 d, bool upsideDown)
2816 if(f.isReading()) return false;
2817 if (d==0)
2819 switch (PixelFormat)
2821 case RGBA:
2822 d = 32;
2823 break;
2824 case Luminance:
2825 d = 8;
2826 break;
2827 case Alpha:
2828 d = 8;
2829 break;
2830 default:
2834 if(d!=24 && d!=32 && d!=16 && d!=8) return false;
2835 if ((PixelFormat != RGBA)&&(PixelFormat != Alpha)&&(PixelFormat != Luminance)) return false;
2836 if ((PixelFormat == Alpha) && (d != 8)) return false;
2837 if ((PixelFormat == Luminance) && (d != 8)) return false;
2839 sint32 i,j,x,y;
2840 uint8 * scanline;
2841 uint8 r,g,b,a;
2843 uint8 lengthID = 0;
2844 uint8 cMapType = 0;
2845 uint8 imageType = 2;
2846 uint16 origin = 0;
2847 uint16 length = 0;
2848 uint8 depth = 0;
2849 uint16 xOrg = 0;
2850 uint16 yOrg = 0;
2851 uint16 width = (uint16)_Width;
2852 uint16 height = (uint16)_Height;
2853 uint8 imageDepth = (uint8)d;
2854 uint8 desc = 0;
2855 if (upsideDown)
2856 desc |= 1<<5;
2858 if ((PixelFormat == Alpha) || (PixelFormat == Luminance))
2859 imageType = 3; // Uncompressed grayscale
2861 f.serial(lengthID);
2862 f.serial(cMapType);
2863 f.serial(imageType);
2864 f.serial(origin);
2865 f.serial(length);
2866 f.serial(depth);
2867 f.serial(xOrg);
2868 f.serial(yOrg);
2869 f.serial(width);
2870 f.serial(height);
2871 f.serial(imageDepth);
2872 f.serial(desc);
2874 if ((PixelFormat == Alpha)||(PixelFormat == Luminance))
2875 scanline = new uint8[width];
2876 else
2877 scanline = new uint8[width*4];
2878 if(!scanline)
2880 throw EAllocationFailure();
2883 for(y=0; y<(sint32)height; y++)
2885 uint32 k=0;
2886 if (PixelFormat == Alpha)
2888 for(i=0; i<width; ++i) // Alpha
2890 scanline[k++] = _Data[0][(height-y-1)*width + i];
2893 else if (PixelFormat == Luminance)
2895 for(i=0; i<width; ++i) // Luminance
2897 scanline[k++] = _Data[0][(height-y-1)*width + i];
2900 else
2902 for(i=0; i<width*4; i+=4) // 4:RGBA
2904 if(d==16)
2906 for(j=0; j<(sint32)4; j++)
2908 scanline[k++] = _Data[0][(height-y-1)*width*4 + i + j];
2911 else
2913 for(j=0; j<(sint32)d/8; j++)
2915 scanline[k++] = _Data[0][(height-y-1)*width*4 + i + j];
2921 if(d==16)
2923 for(x=0; x<(sint32)width; x++)
2925 r = scanline[x*4+0];
2926 g = scanline[x*4+1];
2927 b = scanline[x*4+2];
2928 int rr = r >>3;
2929 int gg = g >>3;
2930 int bb = b >>3;
2931 uint16 c16 = uint16((rr<<10) | (gg<<5) | bb);
2932 scanline[x*2+0] = c16&0xff;
2933 scanline[x*2+1] = c16>>8;
2936 if(d==24)
2938 for(x=0; x<(sint32)width; x++)
2940 r = scanline[x*3+0];
2941 g = scanline[x*3+1];
2942 b = scanline[x*3+2];
2943 scanline[x*3+0] = b;
2944 scanline[x*3+1] = g;
2945 scanline[x*3+2] = r;
2948 if(d==32)
2950 for(x=0; x<(sint32)width; x++)
2952 r = scanline[x*4+0];
2953 g = scanline[x*4+1];
2954 b = scanline[x*4+2];
2955 a= scanline[x*4+3];
2956 scanline[x*4+0] = b;
2957 scanline[x*4+1] = g;
2958 scanline[x*4+2] = r;
2959 scanline[x*4+3] = a;
2963 int finaleSize=width*d/8;
2964 for(i=0; i<finaleSize; i++)
2966 f.serial(scanline[i]);
2969 delete []scanline;
2970 return true;
2974 template<class T>
2975 void rotateCCW (const T* src, T* dst, uint srcWidth, uint srcHeight)
2977 for (uint y=0; y<srcHeight; y++)
2978 for (uint x=0; x<srcWidth; x++)
2980 uint dstX=y;
2981 uint dstY=srcWidth-x-1;
2982 dst[dstX+dstY*srcHeight]=src[x+y*srcWidth];
2986 /*template<class T>
2987 void rotateCCW (const vector<T>& src, vector<T>& dst, uint srcWidth, uint srcHeight)
2989 for (uint y=0; y<srcHeight; y++)
2990 for (uint x=0; x<srcWidth; x++)
2992 uint dstX=y;
2993 uint dstY=srcWidth-x;
2994 dst[dstX+dstY*srcHeight]=src[x+y*srcWidth];
2998 void CBitmap::rotateCCW()
3000 // Copy the array
3001 CObjectVector<uint8> copy=_Data[0];
3003 switch (PixelFormat)
3005 case RGBA:
3006 NLMISC::rotateCCW ((uint32*)&(_Data[0][0]), (uint32*)&(copy[0]), _Width, _Height);
3007 break;
3008 case Luminance:
3009 case Alpha:
3010 NLMISC::rotateCCW (&_Data[0][0], &copy[0], _Width, _Height);
3011 break;
3012 case AlphaLuminance:
3013 NLMISC::rotateCCW ((uint16*)&(_Data[0][0]), (uint16*)&(copy[0]), _Width, _Height);;
3014 break;
3015 default: break;
3018 uint32 tmp=_Width;
3019 _Width=_Height;
3020 _Height=tmp;
3021 _Data[0]=copy;
3024 void CBitmap::blit(const CBitmap &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint destX, sint destY)
3026 nlassert(PixelFormat == RGBA);
3027 nlassert(src.PixelFormat == RGBA);
3028 // clip x
3029 if (srcX < 0)
3031 srcWidth += srcX;
3032 if (srcWidth <= 0) return;
3033 destX -= srcX;
3034 srcX = 0;
3036 if (srcX + srcWidth > (sint) src.getWidth())
3038 srcWidth = src.getWidth() - srcX;
3039 if (srcWidth <= 0) return;
3041 if (destX < 0)
3043 srcWidth += destX;
3044 if (srcWidth <= 0) return;
3045 srcX -= destX;
3046 destX = 0;
3048 if (destX + srcWidth > (sint) getWidth())
3050 srcWidth = getWidth() - destX;
3051 if (srcWidth <= 0) return;
3053 // clip y
3054 if (srcY < 0)
3056 srcHeight += srcY;
3057 if (srcHeight <= 0) return;
3058 destY -= srcY;
3059 srcY = 0;
3061 if (srcY + srcHeight > (sint) src.getHeight())
3063 srcHeight = src.getHeight() - srcY;
3064 if (srcHeight <= 0) return;
3066 if (destY < 0)
3068 srcHeight += destY;
3069 if (srcHeight <= 0) return;
3070 srcY -= destY;
3071 destY = 0;
3073 if (destY + srcHeight > (sint) getHeight())
3075 srcHeight = getHeight() - destY;
3076 if (srcHeight <= 0) return;
3078 uint32 *srcPixels = (uint32 *) &src.getPixels()[0];
3079 uint32 *srcPtr = &(srcPixels[srcX + srcY * src.getWidth()]);
3080 uint32 *srcEndPtr = srcPtr + srcHeight * src.getWidth();
3081 uint32 *destPixels = (uint32 *) &getPixels()[0];
3082 uint32 *destPtr = &(destPixels[destX + destY * getWidth()]);
3083 while (srcPtr != srcEndPtr)
3085 memcpy(destPtr, srcPtr, sizeof(uint32) * srcWidth);
3086 srcPtr += src.getWidth();
3087 destPtr += getWidth();
3093 bool CBitmap::blit(const CBitmap *src, sint32 x, sint32 y)
3096 nlassert(this->PixelFormat == src->PixelFormat);
3097 if (this->PixelFormat != src->PixelFormat)
3099 return false;
3103 // check for dxtc use
3105 const bool useDXTC = PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha || PixelFormat == DXTC3 || PixelFormat == DXTC5;
3107 // number of bits for a 4x4 pix block
3108 const uint dxtcNumBits = PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha ? 64 : 128;
3111 if (useDXTC)
3113 // blit pos must be multiple of 4
3115 nlassert(! (x & 3 || y & 3) );
3116 if (x & 3 || y & 3) return false;
3120 nlassert(PixelFormat != DonTKnow);
3122 // the width to copy
3123 sint width = src->_Width;
3124 // the height to copy
3125 sint height = src->_Height;
3127 uint destStartX, destStartY;
3128 uint srcStartX, srcStartY;
3131 // clip against left
3132 if (x < 0)
3134 width += x;
3135 if (width <= 0) return true;
3136 destStartX = 0;
3137 srcStartX = -x;
3139 else
3141 destStartX = x;
3142 srcStartX = 0;
3145 // clip against top
3146 if (y < 0)
3148 height += y;
3149 if (height <= 0) return true;
3150 srcStartY = -y;
3151 destStartY = 0;
3153 else
3155 destStartY = y;
3156 srcStartY = 0;
3159 // clip against right
3160 if ((destStartX + width - 1) >= _Width)
3162 width = _Width - destStartX;
3163 if (width <= 0) return true;
3166 // clip against bottom
3167 if ((destStartY + height - 1) >= _Height)
3169 height = _Height - destStartY;
3170 if (width <= 0) return true;
3174 // divide all distance by 4 when using DXTC
3175 if (useDXTC)
3177 destStartX >>= 2;
3178 destStartY >>= 2;
3179 srcStartX >>= 2;
3180 srcStartY >>= 2;
3181 width >>= 2;
3182 height >>= 2;
3186 // bytes per pixs is for either one pixel or 16 (a 4x4 block in DXTC)
3187 const uint bytePerPixs = ( useDXTC ? dxtcNumBits : bitPerPixels[PixelFormat] ) >> 3 /* divide by 8 to get the number of bytes */;
3190 const uint destRealWidth = useDXTC ? (_Width >> 2) : _Width;
3191 const uint srcRealWidth = useDXTC ? (src->_Width >> 2) : src->_Width;
3194 // size to go to the next line in the destination
3195 const uint destStride = destRealWidth * bytePerPixs;
3197 // size to go to the next line in the source
3198 const uint srcStride = srcRealWidth * bytePerPixs;
3200 // length in bytes of a line to copy
3201 const uint lineLength = width * bytePerPixs;
3204 uint8 *destPos = &(_Data[0][0]) + destStride * destStartY + bytePerPixs * destStartX;
3205 const uint8 *srcPos = &(src->_Data[0][0]) + srcStride * srcStartY + bytePerPixs * srcStartX;
3207 // copy each hline
3208 for (sint k = 0; k < height; ++k)
3210 ::memcpy(destPos, srcPos, lineLength);
3211 destPos += destStride;
3212 srcPos += srcStride;
3216 return true;
3219 // Private :
3220 float CBitmap::getColorInterp (float x, float y, float colorInXY00, float colorInXY10, float colorInXY01, float colorInXY11) const
3222 if (colorInXY00 == colorInXY10
3223 && colorInXY00 == colorInXY01
3224 && colorInXY00 == colorInXY11)
3225 return colorInXY00; // Fix rounding error for alpha 255...
3227 float res = colorInXY00*(1.0f-x)*(1.0f-y) +
3228 colorInXY10*( x)*(1.0f-y) +
3229 colorInXY01*(1.0f-x)*( y) +
3230 colorInXY11*( x)*( y);
3231 clamp(res, 0.0f, 255.0f);
3233 return res;
3236 // Public:
3237 CRGBAF CBitmap::getColor (float x, float y) const
3239 if (x < 0.0f) x = 0.0f;
3240 if (x > 1.0f) x = 1.0f;
3241 if (y < 0.0f) y = 0.0f;
3242 if (y > 1.0f) y = 1.0f;
3244 sint32 nWidth = getWidth(0);
3245 sint32 nHeight = getHeight(0);
3247 if (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);
3249 const CObjectVector<uint8> &rBitmap = getPixels(0);
3250 sint32 nX[4], nY[4];
3252 x *= nWidth-1;
3253 y *= nHeight-1;
3255 // Integer part of (x,y)
3256 //nX[0] = ((sint32)floor(x-0.5f));
3257 //nY[0] = ((sint32)floor(y-0.5f));
3258 nX[0] = ((sint32)floor(x));
3259 nY[0] = ((sint32)floor(y));
3261 nX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);
3262 nY[1] = nY[0];
3264 nX[2] = nX[0];
3265 nY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);
3267 nX[3] = nX[1];
3268 nY[3] = nY[2];
3270 uint32 i;
3272 for (i = 0; i < 4; ++i)
3274 nlassert (nX[i] >= 0);
3275 nlassert (nY[i] >= 0 );
3276 nlassert (nX[i] < nWidth);
3277 nlassert (nY[i] < nHeight);
3280 // Decimal part of (x,y)
3281 x = x - (float)nX[0];
3282 y = y - (float)nY[0];
3284 switch (this->PixelFormat)
3286 case RGBA:
3287 case DXTC1:
3288 case DXTC1Alpha:
3289 case DXTC3:
3290 case DXTC5:
3292 CRGBAF finalVal;
3293 CRGBA val[4];
3295 if (this->PixelFormat == RGBA)
3297 for (i = 0; i < 4; ++i)
3299 val[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],
3300 rBitmap[(nX[i]+nY[i]*nWidth)*4+1],
3301 rBitmap[(nX[i]+nY[i]*nWidth)*4+2],
3302 rBitmap[(nX[i]+nY[i]*nWidth)*4+3]);
3305 else
3307 // slower version : get from DXT
3308 for (i = 0; i < 4; ++i)
3310 val[i] = getPixelColor(nX[i], nY[i]);
3314 finalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);
3315 finalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);
3316 finalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);
3317 finalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);
3318 finalVal /= 255.f;
3320 return finalVal;
3322 break;
3323 case Alpha:
3324 case Luminance:
3327 float finalVal;
3328 float val[4];
3330 for (i = 0; i < 4; ++i)
3331 val[i] = rBitmap[(nX[i]+nY[i]*nWidth)];
3333 finalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);
3334 finalVal /= 255.f;
3336 if (this->PixelFormat == Alpha)
3337 return CRGBAF (1.f, 1.f, 1.f, finalVal);
3338 else // Luminance
3339 return CRGBAF (finalVal, finalVal, finalVal, 1.f);
3341 break;
3342 default: break;
3345 return CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);
3348 // wrap a value inside the given range (for positive value it is like a modulo)
3349 static inline uint32 wrap(sint32 value, uint32 range)
3351 return value >= 0 ? (value % range) : range - 1 - (- value - 1) % range;
3355 CRGBAF CBitmap::getColor(float x, float y, bool tileU, bool tileV) const
3357 sint32 nWidth = getWidth(0);
3358 sint32 nHeight = getHeight(0);
3359 if (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);
3361 sint32 nX[4], nY[4];
3363 if (!tileU)
3365 if (x < 0.0f) x = 0.0f;
3366 if (x > 1.0f) x = 1.0f;
3367 x *= nWidth-1;
3368 nX[0] = ((sint32)floor(x));
3369 nX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);
3370 nX[2] = nX[0];
3371 nX[3] = nX[1];
3372 uint32 i;
3373 for (i = 0; i < 4; ++i)
3375 nlassert (nX[i] >= 0);
3376 nlassert (nX[i] < nWidth);
3379 else
3381 x *= nWidth;
3382 nX[0] = wrap((sint32)floorf(x), nWidth);
3383 nX[1] = wrap(nX[0] + 1, nWidth);
3384 nX[2] = nX[0];
3385 nX[3] = nX[1];
3388 if (!tileV)
3390 if (y < 0.0f) y = 0.0f;
3391 if (y > 1.0f) y = 1.0f;
3392 y *= nHeight-1;
3393 nY[0] = ((sint32)floor(y));
3394 nY[1] = nY[0];
3395 nY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);
3396 nY[3] = nY[2];
3397 uint32 i;
3398 for (i = 0; i < 4; ++i)
3400 nlassert (nY[i] >= 0 );
3401 nlassert (nY[i] < nHeight);
3404 else
3406 y *= nHeight;
3407 nY[0] = wrap((sint32)floorf(y), nHeight);
3408 nY[1] = nY[0];
3409 nY[2] = wrap(nY[0] + 1, nHeight);
3410 nY[3] = nY[2];
3412 // Decimal part of (x,y)
3413 x = x - (float)nX[0];
3414 y = y - (float)nY[0];
3415 const CObjectVector<uint8> &rBitmap = getPixels(0);
3416 switch (this->PixelFormat)
3418 case RGBA:
3419 case DXTC1:
3420 case DXTC1Alpha:
3421 case DXTC3:
3422 case DXTC5:
3424 CRGBAF finalVal;
3425 CRGBA val[4];
3427 if (this->PixelFormat == RGBA)
3429 for (uint32 i = 0; i < 4; ++i)
3431 val[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],
3432 rBitmap[(nX[i]+nY[i]*nWidth)*4+1],
3433 rBitmap[(nX[i]+nY[i]*nWidth)*4+2],
3434 rBitmap[(nX[i]+nY[i]*nWidth)*4+3]);
3437 else
3439 // slower version : get from DXT
3440 for (uint32 i = 0; i < 4; ++i)
3442 val[i] = getPixelColor(nX[i], nY[i]);
3446 finalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);
3447 finalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);
3448 finalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);
3449 finalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);
3450 finalVal /= 255.f;
3452 return finalVal;
3454 break;
3455 case Alpha:
3456 case Luminance:
3459 float finalVal;
3460 float val[4];
3462 for (uint32 i = 0; i < 4; ++i)
3463 val[i] = rBitmap[(nX[i]+nY[i]*nWidth)];
3465 finalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);
3466 finalVal /= 255.f;
3468 if (this->PixelFormat == Alpha)
3469 return CRGBAF (1.f, 1.f, 1.f, finalVal);
3470 else // Luminance
3471 return CRGBAF (finalVal, finalVal, finalVal, 1.f);
3473 break;
3474 default: break;
3476 return CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);
3481 void CBitmap::loadSize(NLMISC::IStream &f, uint32 &retWidth, uint32 &retHeight)
3483 retWidth= 0;
3484 retHeight= 0;
3486 nlassert(f.isReading());
3488 // testing if DDS
3489 uint32 fileType = 0;
3490 f.serial(fileType);
3491 if(fileType == DDS_HEADER)
3493 // read entire DDS header.
3494 uint32 size = 0;
3495 f.serial(size); // size in Bytes of header(without "DDS")
3496 uint32 * _DDSSurfaceDesc = new uint32[size];
3497 _DDSSurfaceDesc[0]= size;
3499 for(uint i= 0; i<size/4 - 1; i++)
3501 f.serial(_DDSSurfaceDesc[i+1]);
3504 // flags determines which members of the header structure contain valid data
3505 uint32 flags = _DDSSurfaceDesc[1];
3507 //verify if file have linearsize set
3508 if(!(flags & DDSD_LINEARSIZE))
3510 nlwarning("A DDS doesn't have the flag DDSD_LINEARSIZE");
3511 //delete [] _DDSSurfaceDesc;
3512 //throw EDDSBadHeader();
3515 //-------------- extracting and testing useful info
3516 retHeight = _DDSSurfaceDesc[2];
3517 retWidth = _DDSSurfaceDesc[3];
3519 delete [] _DDSSurfaceDesc;
3521 else if(fileType == PNG_HEADER)
3523 // check second part of header
3524 f.serialCheck(0x0a1a0a0d);
3526 uint32 chunkLength = 0;
3527 uint32 chunkName = 0;
3528 bool eof = false;
3534 // length of chunk data
3535 f.serial(chunkLength);
3536 NLMISC_BSWAP32(chunkLength);
3538 // name of chunk
3539 f.serial(chunkName);
3541 // size of image is a part of IHDR chunk
3542 if (chunkName == NL_MAKEFOURCC('I', 'H', 'D', 'R'))
3544 uint32 val;
3545 f.serial(val);
3546 NLMISC_BSWAP32(val);
3547 retWidth = val;
3549 f.serial(val);
3550 NLMISC_BSWAP32(val);
3551 retHeight = val;
3553 break;
3555 // end of file chunk
3556 else if (chunkName == NL_MAKEFOURCC('I', 'E', 'N', 'D'))
3558 break;
3561 // skip data of this chunk and CRC32
3562 f.seek(chunkLength+4, IStream::current);
3564 catch(...)
3566 eof = true;
3569 while(!eof);
3571 else if(fileType == JPG_HEADER)
3573 uint8 blockMarker1 = 0;
3574 uint8 blockMarker2 = 0;
3575 uint16 blockSize = 0;
3576 bool eof = false;
3582 // marker of a block
3583 f.serial(blockMarker1);
3585 if (blockMarker1 == 0xff)
3587 // marker of a block
3588 f.serial(blockMarker2);
3590 // 0xff00 is only found in image data
3591 if (blockMarker2 == 0x00)
3593 // image data 0xff
3595 // 0xffda is image data
3596 else if (blockMarker2 == 0xda)
3598 // next data is image data which must end with 0xffd9
3600 // 0xffd9 is the end of an image
3601 else if (blockMarker2 == 0xd9)
3603 // real end of file
3604 break;
3606 else if (blockMarker2 == 0xdd || blockMarker2 == 0xdc)
3608 f.seek(4, IStream::current);
3610 else if (blockMarker2 == 0xdf)
3612 f.seek(3, IStream::current);
3614 else if (blockMarker2 >= 0xd0 && blockMarker2 <= 0xd8)
3616 // no content
3618 else
3620 // size of a block
3621 f.serial(blockSize);
3622 NLMISC_BSWAP16(blockSize);
3624 // frame marker (which contains image width and height)
3625 if (blockMarker2 >= 0xc0 && blockMarker2 <= 0xc3)
3627 uint8 imagePrecision = 0; // sample precision
3628 uint32 imageSize = 0; // width and height
3629 f.serial(imagePrecision);
3630 f.serial(imageSize);
3631 NLMISC_BSWAP32(imageSize);
3633 retWidth = imageSize & 0xffff;
3634 retHeight = (imageSize & 0xffff0000) >> 16;
3636 break;
3639 // skip the block
3640 f.seek(blockSize - 2, IStream::current);
3644 catch(...)
3646 eof = true;
3649 while(!eof);
3651 else if(fileType == GIF_HEADER)
3653 // check second part of header ("7a" or "9a" in 'GIF89a')
3654 uint16 s;
3655 f.serial(s);
3656 if (s != 0x6137 && s != 0x6139)
3658 nlwarning("Invalid GIF header, expected GIF87a or GIF89a");
3659 return;
3662 uint16 lsWidth;
3663 uint16 lsHeight;
3664 f.serial(lsWidth);
3665 f.serial(lsHeight);
3667 retWidth = lsWidth;
3668 retHeight = lsHeight;
3670 // assuming it's TGA
3671 else
3673 if(!f.seek (0, NLMISC::IStream::begin))
3675 throw ESeekFailed();
3678 // Reading header,
3679 // To make sure that the bitmap is TGA, we check imageType and imageDepth.
3680 uint8 lengthID;
3681 uint8 cMapType;
3682 uint8 imageType;
3683 uint16 tgaOrigin;
3684 uint16 length;
3685 uint8 depth;
3686 uint16 xOrg;
3687 uint16 yOrg;
3688 uint16 width;
3689 uint16 height;
3690 uint8 imageDepth;
3691 uint8 desc;
3693 f.serial(lengthID);
3694 f.serial(cMapType);
3695 f.serial(imageType);
3696 if(imageType!=2 && imageType!=3 && imageType!=10 && imageType!=11)
3698 nlwarning("Invalid TGA format, type %u in not supported (must be 2, 3, 10 or 11)", imageType);
3699 return;
3701 f.serial(tgaOrigin);
3702 f.serial(length);
3703 f.serial(depth);
3704 f.serial(xOrg);
3705 f.serial(yOrg);
3706 f.serial(width);
3707 f.serial(height);
3708 f.serial(imageDepth);
3709 if(imageDepth!=8 && imageDepth!=16 && imageDepth!=24 && imageDepth!=32)
3711 nlwarning("Invalid TGA format, bit depth %u in not supported (must be 8,16,24 or 32)", imageDepth);
3712 return;
3714 f.serial(desc);
3716 // Ok, we have width and height.
3717 retWidth= width;
3718 retHeight= height;
3721 // reset stream.
3722 if(!f.seek (0, NLMISC::IStream::begin))
3724 throw ESeekFailed();
3729 void CBitmap::loadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight)
3731 retWidth= 0;
3732 retHeight= 0;
3734 CIFile f(path);
3735 if(f.open(path))
3736 loadSize(f, retWidth, retHeight);
3739 // ***************************************************************************
3740 void CBitmap::flipHDXTCBlockColor(uint8 *bitColor, uint32 w)
3742 // pack each line in a u32 (NB: the following works either in Little and Big Endian)
3743 uint32 bits= *(uint32*)bitColor;
3745 // swap in X for each line
3746 uint32 res;
3747 if(w!=2)
3749 res = (bits & 0xC0C0C0C0) >> 6;
3750 res+= (bits & 0x30303030) >> 2;
3751 res+= (bits & 0x0C0C0C0C) << 2;
3752 res+= (bits & 0x03030303) << 6;
3754 // special case where w==2
3755 else
3757 res = (bits & 0x0C0C0C0C) >> 2;
3758 res+= (bits & 0x03030303) << 2;
3761 // copy
3762 *((uint32*)bitColor)= res;
3765 // ***************************************************************************
3766 void CBitmap::flipVDXTCBlockColor(uint8 *bitColor, uint32 h)
3768 // swap just bytes (work either in Little and Big Endian)
3769 if(h!=2)
3771 std::swap(bitColor[0], bitColor[3]);
3772 std::swap(bitColor[1], bitColor[2]);
3774 // special case where h==2)
3775 else
3777 // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
3778 std::swap(bitColor[0], bitColor[1]);
3782 // ***************************************************************************
3783 void CBitmap::flipHDXTCBlockAlpha3(uint8 *blockAlpha, uint32 w)
3785 #ifdef NL_LITTLE_ENDIAN
3786 uint64 bits= *(uint64*)blockAlpha;
3787 #else
3788 uint64 bits= (uint64)blockAlpha[0] + ((uint64)blockAlpha[1]<<8) +
3789 ((uint64)blockAlpha[2]<<16) + ((uint64)blockAlpha[3]<<24) +
3790 ((uint64)blockAlpha[4]<<32) + ((uint64)blockAlpha[5]<<40) +
3791 ((uint64)blockAlpha[6]<<48) + ((uint64)blockAlpha[7]<<56);
3792 #endif
3794 // swap in X for each line
3795 uint64 res;
3796 if(w!=2)
3798 res = (bits & INT64_CONSTANT(0xF000F000F000F000)) >> 12;
3799 res+= (bits & INT64_CONSTANT(0x0F000F000F000F00)) >> 4;
3800 res+= (bits & INT64_CONSTANT(0x00F000F000F000F0)) << 4;
3801 res+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 12;
3803 // special case where w==2
3804 else
3806 res = (bits & INT64_CONSTANT(0x00F000F000F000F0)) >> 4;
3807 res+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 4;
3810 // copy
3811 #ifdef NL_LITTLE_ENDIAN
3812 *((uint64*)blockAlpha)= res;
3813 #else
3814 blockAlpha[0]= res & 255;
3815 blockAlpha[1]= (res>>8) & 255;
3816 blockAlpha[2]= (res>>16) & 255;
3817 blockAlpha[3]= (res>>24) & 255;
3818 blockAlpha[4]= (res>>32) & 255;
3819 blockAlpha[5]= (res>>40) & 255;
3820 blockAlpha[6]= (res>>48) & 255;
3821 blockAlpha[7]= (res>>56) & 255;
3822 #endif
3825 // ***************************************************************************
3826 void CBitmap::flipVDXTCBlockAlpha3(uint8 *blockAlpha, uint32 h)
3828 uint16 *wAlpha= (uint16*)blockAlpha;
3830 // swap just words (work either in Little and Big Endian)
3831 if(h!=2)
3833 std::swap(wAlpha[0], wAlpha[3]);
3834 std::swap(wAlpha[1], wAlpha[2]);
3836 // special case where h==2)
3837 else
3839 // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
3840 std::swap(wAlpha[0], wAlpha[1]);
3844 // ***************************************************************************
3845 void CBitmap::flipHDXTCBlockAlpha5(uint8 *bitAlpha, uint32 w)
3847 // pack into bits. Little Indian in all cases
3848 uint64 bits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +
3849 ((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +
3850 ((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);
3852 // swap in X for each line
3853 uint64 res;
3854 if(w!=2)
3856 res = (bits & INT64_CONSTANT(0xE00E00E00E00)) >> 9;
3857 res+= (bits & INT64_CONSTANT(0x1C01C01C01C0)) >> 3;
3858 res+= (bits & INT64_CONSTANT(0x038038038038)) << 3;
3859 res+= (bits & INT64_CONSTANT(0x007007007007)) << 9;
3861 // special case where w==2
3862 else
3864 res = (bits & INT64_CONSTANT(0x038038038038)) >> 3;
3865 res+= (bits & INT64_CONSTANT(0x007007007007)) << 3;
3868 // copy. Little Indian in all cases
3869 bitAlpha[0]= uint8(res & 255);
3870 bitAlpha[1]= uint8((res>>8) & 255);
3871 bitAlpha[2]= uint8((res>>16) & 255);
3872 bitAlpha[3]= uint8((res>>24) & 255);
3873 bitAlpha[4]= uint8((res>>32) & 255);
3874 bitAlpha[5]= uint8((res>>40) & 255);
3877 // ***************************************************************************
3878 void CBitmap::flipVDXTCBlockAlpha5(uint8 *bitAlpha, uint32 h)
3880 // pack into bits. Little Indian in all cases
3881 uint64 bits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +
3882 ((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +
3883 ((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);
3885 // swap in Y
3886 uint64 res;
3887 if(h!=2)
3889 res = (bits & INT64_CONSTANT(0xFFF000000000)) >> 36;
3890 res+= (bits & INT64_CONSTANT(0x000FFF000000)) >> 12;
3891 res+= (bits & INT64_CONSTANT(0x000000FFF000)) << 12;
3892 res+= (bits & INT64_CONSTANT(0x000000000FFF)) << 36;
3894 // special case where h==2
3895 else
3897 res = (bits & INT64_CONSTANT(0x000000FFF000)) >> 12;
3898 res+= (bits & INT64_CONSTANT(0x000000000FFF)) << 12;
3901 // copy. Little Indian in all cases
3902 bitAlpha[0]= uint8(res & 255);
3903 bitAlpha[1]= uint8((res>>8) & 255);
3904 bitAlpha[2]= uint8((res>>16) & 255);
3905 bitAlpha[3]= uint8((res>>24) & 255);
3906 bitAlpha[4]= uint8((res>>32) & 255);
3907 bitAlpha[5]= uint8((res>>40) & 255);
3910 // ***************************************************************************
3911 void CBitmap::flipDXTCMipMap(bool vertical, uint mm, uint type)
3913 nlassert(mm<MAX_MIPMAP);
3914 // size of a DXTC block. 64 bits (2 U32) for DXTC1, else 128 bits (4*U32)
3915 uint blockSizeU32= type==1? 2 : 4;
3916 // get size in block
3917 sint32 width = getWidth(mm);
3918 sint32 height = getHeight(mm);
3919 if(width==0 || height==0)
3920 return;
3921 uint32 wBlock= (width+3)/4;
3922 uint32 hBlock= (height+3)/4;
3923 // get data ptr and check size.
3924 uint32 *data= (uint32*)(&_Data[mm][0]);
3925 nlassert(_Data[mm].size()==wBlock*hBlock*blockSizeU32*4);
3927 // get the offset (in bytes) to the start of color pixels bits
3928 uint32 offsetColorBits= type==1? 4 : 12;
3930 // abort if swap is nonsense
3931 if(vertical && height==1)
3932 return;
3933 if(!vertical && width==1)
3934 return;
3936 // *** First reverse Blocks
3937 if(vertical)
3939 // reverse vertical
3940 for(uint yBlock=0;yBlock<hBlock/2;yBlock++)
3942 uint32 *src0= data + (yBlock*wBlock)*blockSizeU32;
3943 uint32 *src1= data + ((hBlock-yBlock-1)*wBlock)*blockSizeU32;
3944 for(uint xBlock=0;xBlock<wBlock;xBlock++, src0+=blockSizeU32, src1+=blockSizeU32)
3946 uint32 *block0= src0;
3947 uint32 *block1= src1;
3948 // swap the blocks
3949 for(uint i=0;i<blockSizeU32;i++, block0++, block1++)
3951 std::swap(*block0, *block1);
3956 else
3958 // reverse horizontal
3959 for(uint yBlock=0;yBlock<hBlock;yBlock++)
3961 uint32 *src0= data + (yBlock*wBlock)*blockSizeU32;
3962 uint32 *src1= data + (yBlock*wBlock + wBlock-1)*blockSizeU32;
3963 for(uint xBlock=0;xBlock<wBlock/2;xBlock++, src0+=blockSizeU32, src1-=blockSizeU32)
3965 uint32 *block0= src0;
3966 uint32 *block1= src1;
3967 // swap the blocks
3968 for(uint i=0;i<blockSizeU32;i++, block0++, block1++)
3970 std::swap(*block0, *block1);
3976 // *** Then reverse Bits
3977 for(uint yBlock=0;yBlock<hBlock;yBlock++)
3979 uint32 *src= data + (yBlock*wBlock)*blockSizeU32;
3980 for(uint xBlock=0;xBlock<wBlock;xBlock++, src+=blockSizeU32)
3982 uint8 *block= (uint8*)src;
3984 // flip color bits
3985 if(vertical) flipVDXTCBlockColor(block+offsetColorBits, height);
3986 else flipHDXTCBlockColor(block+offsetColorBits, width);
3988 // flip alpha bits if any
3989 if(type==3)
3991 // point to the alpha part (16*4 bits)
3992 if(vertical) flipVDXTCBlockAlpha3(block, height);
3993 else flipHDXTCBlockAlpha3(block, width);
3995 else if(type==5)
3997 // point to the bit alpha part (16*3 bits)
3998 if(vertical) flipVDXTCBlockAlpha5(block+2, height);
3999 else flipHDXTCBlockAlpha5(block+2, width);
4007 // ***************************************************************************
4008 void CBitmap::flipDXTC(bool vertical)
4010 // get type
4011 uint type;
4012 if(PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha )
4013 type=1;
4014 else if(PixelFormat == DXTC3)
4015 type=3;
4016 else if(PixelFormat == DXTC5)
4017 type=5;
4018 else
4019 return;
4021 // correct width/height?
4022 sint32 nWidth = getWidth(0);
4023 sint32 nHeight = getHeight(0);
4024 if(!isPowerOf2(nWidth) || !isPowerOf2(nHeight))
4025 return;
4027 // flip all mipmaps
4028 for(uint mm=0;mm<_MipMapCount;mm++)
4030 flipDXTCMipMap(vertical, mm, type);
4035 // ***************************************************************************
4036 void CBitmap::flipH()
4038 if (PixelFormat != RGBA)
4040 // try for DXTC
4041 flipDXTC(false);
4043 // then quit (whether it worked or not)
4044 return;
4047 sint32 nWidth = getWidth(0);
4048 sint32 nHeight = getHeight(0);
4049 sint32 i, j;
4050 NLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];
4051 bool needRebuild = false;
4052 CRGBA temp;
4054 if(_MipMapCount>1)
4055 needRebuild = true;
4056 releaseMipMaps();
4058 for( i = 0; i < nHeight; ++i )
4059 for( j = 0; j < nWidth/2; ++j )
4061 temp = pBitmap[i*nWidth+j];
4062 pBitmap[i*nWidth+j] = pBitmap[i*nWidth+nWidth-j-1];
4063 pBitmap[i*nWidth+nWidth-j-1] = temp;
4066 // Rebuilding mipmaps
4067 if(needRebuild)
4069 buildMipMaps();
4074 // ***************************************************************************
4075 void CBitmap::flipV()
4077 if (PixelFormat != RGBA)
4079 // try for DXTC
4080 flipDXTC(true);
4082 // then quit (whether it worked or not)
4083 return;
4086 sint32 nWidth = getWidth(0);
4087 sint32 nHeight = getHeight(0);
4088 sint32 i, j;
4089 NLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];
4090 bool needRebuild = false;
4091 CRGBA temp;
4093 if(_MipMapCount>1)
4094 needRebuild = true;
4095 releaseMipMaps();
4097 for( j = 0; j < nHeight/2; ++j )
4098 for( i = 0; i < nWidth; ++i )
4100 temp = pBitmap[j*nWidth+i];
4101 pBitmap[j*nWidth+i] = pBitmap[(nHeight-j-1)*nWidth+i];
4102 pBitmap[(nHeight-j-1)*nWidth+i] = temp;
4105 // Rebuilding mipmaps
4106 if(needRebuild)
4108 buildMipMaps();
4113 void CBitmap::rot90CW()
4115 if (PixelFormat != RGBA)
4116 return;
4117 sint32 nWidth = getWidth(0);
4118 sint32 nHeight = getHeight(0);
4119 sint32 i, j;
4120 NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
4121 bool needRebuild = false;
4123 if(_MipMapCount>1)
4124 needRebuild = true;
4125 releaseMipMaps();
4127 CObjectVector<uint8> pDestui;
4128 pDestui.resize(nWidth*nHeight*4);
4129 NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
4131 for( j = 0; j < nHeight; ++j )
4132 for( i = 0; i < nWidth; ++i )
4133 pDestRgba[j+i*nHeight] = pSrcRgba[i+(nHeight-1-j)*nWidth];
4135 uint32 nTemp = _Width;
4136 _Width = _Height;
4137 _Height = nTemp;
4139 NLMISC::contReset(_Data[0]); // free memory
4140 _Data[0] = pDestui;
4141 // Rebuilding mipmaps
4142 if(needRebuild)
4144 buildMipMaps();
4148 void CBitmap::rot90CCW()
4150 if (PixelFormat != RGBA)
4151 return;
4152 sint32 nWidth = getWidth(0);
4153 sint32 nHeight = getHeight(0);
4154 sint32 i, j;
4155 NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
4156 bool needRebuild = false;
4158 if(_MipMapCount>1)
4159 needRebuild = true;
4160 releaseMipMaps();
4162 CObjectVector<uint8> pDestui;
4163 pDestui.resize(nWidth*nHeight*4);
4164 NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
4166 for( j = 0; j < nHeight; ++j )
4167 for( i = 0; i < nWidth; ++i )
4168 pDestRgba[j+i*nHeight] = pSrcRgba[nWidth-1-i+j*nWidth];
4170 uint32 nTemp = _Width;
4171 _Width = _Height;
4172 _Height = nTemp;
4174 NLMISC::contReset(_Data[0]); // free memory
4175 _Data[0] = pDestui;
4176 // Rebuilding mipmaps
4177 if(needRebuild)
4179 buildMipMaps();
4183 //===========================================================================
4184 void CBitmap::blend(CBitmap &Bm0, CBitmap &Bm1, uint16 factor, bool inputBitmapIsMutable /*= false*/)
4186 nlassert(factor <= 256);
4188 nlassert(Bm0._Width != 0 && Bm0._Height != 0
4189 && Bm1._Width != 0 && Bm1._Height != 0);
4191 nlassert(Bm0._Width == Bm1._Width); // the bitmap should have the same size
4192 nlassert(Bm0._Height == Bm1._Height);
4194 const CBitmap *nBm0, *nBm1; // pointer to the bitmap that is used for blending, or to a copy is a conversion wa required
4196 CBitmap cp0, cp1; // these bitmap are copies of Bm1 and Bm0 if a conversion was needed
4198 if (Bm0.PixelFormat != RGBA)
4200 if (inputBitmapIsMutable)
4202 Bm0.convertToRGBA();
4203 nBm0 = &Bm0;
4205 else
4207 cp0 = Bm0;
4208 cp0.convertToRGBA();
4209 nBm0 = &cp0;
4212 else
4214 nBm0 = &Bm0;
4218 if (Bm1.PixelFormat != RGBA)
4220 if (inputBitmapIsMutable)
4222 Bm1.convertToRGBA();
4223 nBm1 = &Bm1;
4225 else
4227 cp1 = Bm1;
4228 cp1.convertToRGBA();
4229 nBm1 = &cp1;
4232 else
4234 nBm1 = &Bm1;
4237 if (this != nBm0 && this != nBm1)
4239 // if source is the same than the dets, don't resize because this clear the bitmap
4240 this->resize(Bm0._Width, Bm0._Height, RGBA);
4243 uint numPix = _Width * _Height; // 4 component per pixels
4246 const uint8 *src0 = &(nBm0->_Data[0][0]);
4247 const uint8 *src1 = &(nBm1->_Data[0][0]);
4248 uint8 *dest = &(this->_Data[0][0]);
4251 #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)
4252 if (CSystemInfo::hasMMX())
4254 // On a P4 2GHz, with a 256x256 texture, I got the following results :
4255 // without mmx : 5.2 ms
4256 // with mmx : 1.7 ms
4257 // I'm sure this can be further optimized..
4259 uint numPixLeft = numPix & 1; // process 2 pixels at once, so special case for odd number
4260 numPix = numPix & ~1;
4261 // do fast blend with mmx
4262 uint64 blendFactor0;
4263 uint64 blendFactor1;
4264 uint16 *bf0 = (uint16 *) &blendFactor0;
4265 uint16 *bf1 = (uint16 *) &blendFactor1;
4266 bf0[0] = bf0[1] = bf0[2] = bf0[3] = (1 << 6) * (factor);
4267 bf1[0] = bf1[1] = bf1[2] = bf1[3] = (1 << 6) * (256 - factor);
4268 __asm
4270 mov esi, src0
4271 mov eax, src1
4272 mov edi, dest
4273 mov ebx, -8
4274 mov ecx, numPix
4275 shr ecx, 1 // process pixels 2 by 2
4276 movq mm1, blendFactor0
4277 movq mm0, blendFactor1
4279 myLoop:
4280 pxor mm6, mm6
4281 lea ebx, [ebx + 8] // points next location
4282 pxor mm7, mm7
4283 movq mm2, [esi + ebx]
4284 movq mm3, [eax + ebx]
4285 // do blend
4286 punpckhbw mm7, mm2 // mm7 contains src0 color 0 in high bytes
4287 punpckhbw mm6, mm3 // mm6 contains src1 color 0 in high bytes
4288 psrl mm7, 1
4289 pxor mm4, mm4 // mm4 = 0
4290 psrl mm6, 1
4291 pmulhw mm7, mm0 // src0 = src0 * blendFactor
4292 pxor mm5, mm5 // mm5 = 0
4293 pmulhw mm6, mm1 // src1 = src1 * (1 - blendfactor)
4294 punpcklbw mm4, mm2 // mm4 contains src0 color 1 in high bytes
4295 paddusw mm6, mm7 // mm6 = src0[0] blended with src1[0]
4296 psrl mm4, 1
4297 psrlw mm6, 5
4298 punpcklbw mm5, mm3 // mm4 contains src1 color 1 in high bytes
4299 psrl mm5, 1
4300 pmulhw mm4, mm0 // src0 = src0 * blendFactor
4301 pmulhw mm5, mm1 // src1 = src1 * (1 - blendfactor)
4302 paddusw mm4, mm5 // mm6 = src0[1] blended with src1[1]
4303 psrlw mm4, 5
4304 // pack result
4305 packuswb mm4, mm6
4306 dec ecx
4307 movq [edi + ebx], mm4 // store result
4308 jne myLoop
4309 emms
4311 if (numPixLeft)
4313 // case of odd number of pixels
4314 src0 += 4 * numPix;
4315 src1 += 4 * numPix;
4316 dest += 4 * numPix;
4317 uint blendFact = (uint) factor;
4318 uint invblendFact = 256 - blendFact;
4319 *dest = (uint8) (((blendFact * *src1) + (invblendFact * *src0)) >> 8);
4320 *(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);
4321 *(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);
4322 *(dest + 3) = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);
4325 else
4326 #endif //#ifdef NL_OS_WINDOWS
4328 uint8 *endPix = dest + ((ptrdiff_t)numPix << 2);
4329 // no mmx version
4330 uint blendFact = (uint) factor;
4331 uint invblendFact = 256 - blendFact;
4334 /// blend 4 component at each pass
4335 *dest = (uint8) (((blendFact * *src1) + (invblendFact * *src0)) >> 8);
4336 *(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);
4337 *(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);
4338 *(dest + 3) = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);
4340 src0 = src0 + 4;
4341 src1 = src1 + 4;
4342 dest = dest + 4;
4344 while (dest != endPix);
4350 //-----------------------------------------------
4351 CRGBA CBitmap::getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const
4353 uint w = getWidth(numMipMap);
4354 uint h = getHeight(numMipMap);
4355 if (w == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
4356 const uint8 *pix = &getPixels(numMipMap)[(x + y * w) << 2];
4357 return CRGBA(pix[0], pix[1], pix[2], pix[3]);
4360 //-----------------------------------------------
4361 CRGBA CBitmap::getDXTCColorFromBlock(const uint8 *block, sint x, sint y)
4363 uint16 col0;
4364 uint16 col1;
4365 memcpy(&col0, block, sizeof(uint16));
4366 memcpy(&col1, block + 2, sizeof(uint16));
4367 uint colIndex = (block[4 + (y & 3)] >> ((x & 3) << 1)) & 3;
4368 CRGBA result, c0, c1;
4369 if (col0 > col1)
4371 switch(colIndex)
4373 case 0:
4374 uncompress(col0, result);
4375 break;
4376 case 1:
4377 uncompress(col1, result);
4378 break;
4379 case 2:
4380 uncompress(col0, c0);
4381 uncompress(col1, c1);
4382 result.blendFromui(c0, c1, 85);
4383 break;
4384 case 3:
4385 uncompress(col0, c0);
4386 uncompress(col1, c1);
4387 result.blendFromui(c0, c1, 171);
4388 break;
4389 default:
4392 result.A = 255;
4394 else
4396 switch(colIndex)
4398 case 0:
4399 uncompress(col0, result);
4400 result.A = 255;
4401 break;
4402 case 1:
4403 uncompress(col1, result);
4404 result.A = 255;
4405 break;
4406 case 2:
4407 uncompress(col0, c0);
4408 uncompress(col1, c1);
4409 result.blendFromui(c0, c1, 128);
4410 result.A = 255;
4411 break;
4412 case 3:
4413 result.set(0, 0, 0, 0);
4414 break;
4417 return result;
4420 //-----------------------------------------------
4421 CRGBA CBitmap::getDXTC1Texel(sint x, sint y, uint32 numMipMap) const
4423 uint w = getWidth(numMipMap);
4424 uint h = getHeight(numMipMap);
4425 if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
4426 uint numRowBlocks = std::max((w + 3) >> 2, 1u);
4427 const uint8 *pix = &getPixels(numMipMap)[0];
4428 const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 3) + ((x >> 2) << 3));
4429 return getDXTCColorFromBlock(block, x, y);
4433 //-----------------------------------------------
4434 CRGBA CBitmap::getDXTC3Texel(sint x, sint y, uint32 numMipMap) const
4436 uint w = getWidth(numMipMap);
4437 uint h = getHeight(numMipMap);
4438 if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
4439 uint numRowBlocks = std::max((w + 3) >> 2, 1u);
4440 const uint8 *pix = &getPixels(numMipMap)[0];
4441 const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));
4442 CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
4443 // get alpha part
4444 uint8 alphaByte = block[((y & 3) << 1) + ((x & 2) >> 1)];
4445 result.A = (x & 1) ? (alphaByte & 0xf0) : ((alphaByte & 0x0f) << 4);
4446 return result;
4449 //-----------------------------------------------
4450 CRGBA CBitmap::getDXTC5Texel(sint x, sint y, uint32 numMipMap) const
4452 uint w = getWidth(numMipMap);
4453 uint h = getHeight(numMipMap);
4454 if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
4455 uint numRowBlocks = std::max((w + 3) >> 2, 1u);
4456 const uint8 *pix = &getPixels(numMipMap)[0];
4457 const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));
4458 CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
4459 // get alpha part
4460 uint8 alpha0 = block[0];
4461 uint8 alpha1 = block[1];
4463 uint alphaIndex;
4464 uint tripletIndex = (x & 3) + ((y & 3) << 2);
4465 if (tripletIndex < 8)
4467 alphaIndex = (((uint32 &) block[2]) >> (tripletIndex * 3)) & 7;
4469 else
4471 alphaIndex = (((uint32 &) block[5]) >> ((tripletIndex - 8) * 3)) & 7; // we can read a dword there because there are color datas following he alpha datas
4474 if (alpha0 > alpha1)
4476 switch (alphaIndex)
4478 case 0: result.A = alpha0; break;
4479 case 1: result.A = alpha1; break;
4480 case 2: result.A = (uint8) ((6 * (uint) alpha0 + (uint) alpha1) / 7); break;
4481 case 3: result.A = (uint8) ((5 * (uint) alpha0 + 2 * (uint) alpha1) / 7); break;
4482 case 4: result.A = (uint8) ((4 * (uint) alpha0 + 3 * (uint) alpha1) / 7); break;
4483 case 5: result.A = (uint8) ((3 * (uint) alpha0 + 4 * (uint) alpha1) / 7); break;
4484 case 6: result.A = (uint8) ((2 * (uint) alpha0 + 5 * (uint) alpha1) / 7); break;
4485 case 7: result.A = (uint8) (((uint) alpha0 + (uint) 6 * alpha1) / 7); break;
4488 else
4490 switch (alphaIndex)
4492 case 0: result.A = alpha0; break;
4493 case 1: result.A = alpha1; break;
4494 case 2: result.A = (uint8) ((4 * (uint) alpha0 + (uint) alpha1) / 5); break;
4495 case 3: result.A = (uint8) ((3 * (uint) alpha0 + 2 * (uint) alpha1) / 5); break;
4496 case 4: result.A = (uint8) ((2 * (uint) alpha0 + 3 * (uint) alpha1) / 5); break;
4497 case 5: result.A = (uint8) (((uint) alpha0 + 4 * (uint) alpha1) / 5); break;
4498 case 6: result.A = 0; break;
4499 case 7: result.A = 255; break;
4502 return result;
4506 //-----------------------------------------------
4507 CRGBA CBitmap::getPixelColor(sint x, sint y, uint32 numMipMap /*=0*/) const
4510 switch (PixelFormat)
4512 case RGBA:
4513 return getRGBAPixel(x, y, numMipMap);
4514 case DXTC1:
4515 case DXTC1Alpha:
4516 return getDXTC1Texel(x, y, numMipMap);
4517 case DXTC3:
4518 return getDXTC3Texel(x, y, numMipMap);
4519 case DXTC5:
4520 return getDXTC5Texel(x, y, numMipMap);
4521 default:
4522 nlstop;
4523 break;
4525 return CRGBA::Black;
4528 //-----------------------------------------------
4529 void CBitmap::setPixelColor(sint x, sint y, CRGBA c, uint32 numMipMap)
4531 nlassert(PixelFormat == RGBA);
4533 uint w = getWidth(numMipMap);
4534 uint h = getHeight(numMipMap);
4536 if (w == 0 || x < 0 || y < 0 || x >= (sint)w || y >= (sint)h) return;
4538 uint8 *pix = &getPixels(numMipMap)[(x + y * w) << 2];
4540 memcpy(pix, &c, sizeof(CRGBA));
4543 //-----------------------------------------------
4544 void CBitmap::swap(CBitmap &other)
4546 std::swap(PixelFormat, other.PixelFormat);
4547 std::swap(_MipMapCount, other._MipMapCount);
4548 std::swap(_LoadGrayscaleAsAlpha, other._LoadGrayscaleAsAlpha);
4549 std::swap(_Width, other._Width);
4550 std::swap(_Height, other._Height);
4551 for(uint k = 0; k < MAX_MIPMAP; ++k)
4553 _Data[k].swap(other._Data[k]);
4557 //-----------------------------------------------
4558 void CBitmap::unattachPixels(CObjectVector<uint8> *mipmapDestArray, uint maxMipMapCount /*=MAX_MIPMAP*/)
4560 if (!mipmapDestArray) return;
4561 uint k;
4562 for(k = 0; k < std::min((uint) _MipMapCount, maxMipMapCount); ++k)
4564 mipmapDestArray[k].swap(_Data[k]);
4565 _Data[k].clear();
4567 for(; k < _MipMapCount; ++k)
4569 _Data[k].clear();
4571 #ifdef NL_DEBUG
4572 // check that remaining mipmaps are empty
4573 for(; k < _MipMapCount; ++k)
4575 nlassert(_Data[k].empty());
4577 #endif
4578 _MipMapCount = 1;
4579 _Width = 0;
4580 _Height = 0;
4581 PixelFormat = RGBA;
4582 _LoadGrayscaleAsAlpha = true;
4588 void CBitmap::getData(uint8*& extractData)
4591 uint32 size=0;
4592 if(PixelFormat==RGBA)
4593 size=_Width*_Height*4;
4594 else if(PixelFormat==Alpha||PixelFormat==Luminance)
4595 size=_Width*_Height;
4596 else
4598 nlstop;
4601 for(uint32 pix=0;pix<size;pix++)
4602 extractData[pix]=_Data[0][pix];
4606 void CBitmap::getDibData(uint8*& extractData)
4609 uint32 lineSize=0,size;
4610 uint8** buf;
4611 buf=new uint8*[_Height];
4612 if(PixelFormat==RGBA)
4614 lineSize=_Width*4;
4618 else if(PixelFormat==Alpha||PixelFormat==Luminance)
4620 lineSize=_Width;
4622 else
4624 nlstop;
4627 for(sint32 i=_Height-1;i>=0;i--)
4629 buf[_Height-1-i]=&_Data[0][i*lineSize];
4632 size=lineSize*_Height;
4634 for(uint32 line=0;line<_Height;line++)
4636 for(uint32 pix=0;pix<lineSize;pix++)
4637 extractData[line*lineSize+pix]=_Data[0][size-(line+1)*lineSize+pix];
4639 delete []buf;
4643 } // NLMISC