Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / misc / bitmap.cpp
blobcaf29494926586443909988999f6b3c8f174c587
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2021 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 bool isValid = true;
3273 for (i = 0; i < 4; ++i)
3275 if (nX[i] < 0 || nY[i] < 0 || nX[i] >= nWidth || nY[i] >= nHeight)
3276 isValid = false;
3279 if (isValid)
3281 // Decimal part of (x,y)
3282 x = x - (float)nX[0];
3283 y = y - (float)nY[0];
3285 switch (this->PixelFormat)
3287 case RGBA:
3288 case DXTC1:
3289 case DXTC1Alpha:
3290 case DXTC3:
3291 case DXTC5:
3293 CRGBAF finalVal;
3294 CRGBA val[4];
3296 if (this->PixelFormat == RGBA)
3298 for (i = 0; i < 4; ++i)
3300 val[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],
3301 rBitmap[(nX[i]+nY[i]*nWidth)*4+1],
3302 rBitmap[(nX[i]+nY[i]*nWidth)*4+2],
3303 rBitmap[(nX[i]+nY[i]*nWidth)*4+3]);
3306 else
3308 // slower version : get from DXT
3309 for (i = 0; i < 4; ++i)
3311 val[i] = getPixelColor(nX[i], nY[i]);
3315 finalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);
3316 finalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);
3317 finalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);
3318 finalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);
3319 finalVal /= 255.f;
3321 return finalVal;
3323 break;
3324 case Alpha:
3325 case Luminance:
3328 float finalVal;
3329 float val[4];
3331 for (i = 0; i < 4; ++i)
3332 val[i] = rBitmap[(nX[i]+nY[i]*nWidth)];
3334 finalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);
3335 finalVal /= 255.f;
3337 if (this->PixelFormat == Alpha)
3338 return CRGBAF (1.f, 1.f, 1.f, finalVal);
3339 else // Luminance
3340 return CRGBAF (finalVal, finalVal, finalVal, 1.f);
3342 break;
3343 default: break;
3347 return CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);
3350 // wrap a value inside the given range (for positive value it is like a modulo)
3351 static inline uint32 wrap(sint32 value, uint32 range)
3353 return value >= 0 ? (value % range) : range - 1 - (- value - 1) % range;
3357 CRGBAF CBitmap::getColor(float x, float y, bool tileU, bool tileV) const
3359 sint32 nWidth = getWidth(0);
3360 sint32 nHeight = getHeight(0);
3361 if (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);
3363 sint32 nX[4], nY[4];
3365 if (!tileU)
3367 if (x < 0.0f) x = 0.0f;
3368 if (x > 1.0f) x = 1.0f;
3369 x *= nWidth-1;
3370 nX[0] = ((sint32)floor(x));
3371 nX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);
3372 nX[2] = nX[0];
3373 nX[3] = nX[1];
3374 uint32 i;
3375 for (i = 0; i < 4; ++i)
3377 nlassert (nX[i] >= 0);
3378 nlassert (nX[i] < nWidth);
3381 else
3383 x *= nWidth;
3384 nX[0] = wrap((sint32)floorf(x), nWidth);
3385 nX[1] = wrap(nX[0] + 1, nWidth);
3386 nX[2] = nX[0];
3387 nX[3] = nX[1];
3390 if (!tileV)
3392 if (y < 0.0f) y = 0.0f;
3393 if (y > 1.0f) y = 1.0f;
3394 y *= nHeight-1;
3395 nY[0] = ((sint32)floor(y));
3396 nY[1] = nY[0];
3397 nY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);
3398 nY[3] = nY[2];
3399 uint32 i;
3400 for (i = 0; i < 4; ++i)
3402 nlassert (nY[i] >= 0 );
3403 nlassert (nY[i] < nHeight);
3406 else
3408 y *= nHeight;
3409 nY[0] = wrap((sint32)floorf(y), nHeight);
3410 nY[1] = nY[0];
3411 nY[2] = wrap(nY[0] + 1, nHeight);
3412 nY[3] = nY[2];
3414 // Decimal part of (x,y)
3415 x = x - (float)nX[0];
3416 y = y - (float)nY[0];
3417 const CObjectVector<uint8> &rBitmap = getPixels(0);
3418 switch (this->PixelFormat)
3420 case RGBA:
3421 case DXTC1:
3422 case DXTC1Alpha:
3423 case DXTC3:
3424 case DXTC5:
3426 CRGBAF finalVal;
3427 CRGBA val[4];
3429 if (this->PixelFormat == RGBA)
3431 for (uint32 i = 0; i < 4; ++i)
3433 val[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],
3434 rBitmap[(nX[i]+nY[i]*nWidth)*4+1],
3435 rBitmap[(nX[i]+nY[i]*nWidth)*4+2],
3436 rBitmap[(nX[i]+nY[i]*nWidth)*4+3]);
3439 else
3441 // slower version : get from DXT
3442 for (uint32 i = 0; i < 4; ++i)
3444 val[i] = getPixelColor(nX[i], nY[i]);
3448 finalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);
3449 finalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);
3450 finalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);
3451 finalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);
3452 finalVal /= 255.f;
3454 return finalVal;
3456 break;
3457 case Alpha:
3458 case Luminance:
3461 float finalVal;
3462 float val[4];
3464 for (uint32 i = 0; i < 4; ++i)
3465 val[i] = rBitmap[(nX[i]+nY[i]*nWidth)];
3467 finalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);
3468 finalVal /= 255.f;
3470 if (this->PixelFormat == Alpha)
3471 return CRGBAF (1.f, 1.f, 1.f, finalVal);
3472 else // Luminance
3473 return CRGBAF (finalVal, finalVal, finalVal, 1.f);
3475 break;
3476 default: break;
3478 return CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);
3483 void CBitmap::loadSize(NLMISC::IStream &f, uint32 &retWidth, uint32 &retHeight)
3485 retWidth= 0;
3486 retHeight= 0;
3488 nlassert(f.isReading());
3490 // testing if DDS
3491 uint32 fileType = 0;
3492 f.serial(fileType);
3493 if(fileType == DDS_HEADER)
3495 // read entire DDS header.
3496 uint32 size = 0;
3497 f.serial(size); // size in Bytes of header(without "DDS")
3498 uint32 * _DDSSurfaceDesc = new uint32[size];
3499 _DDSSurfaceDesc[0]= size;
3501 for(uint i= 0; i<size/4 - 1; i++)
3503 f.serial(_DDSSurfaceDesc[i+1]);
3506 // flags determines which members of the header structure contain valid data
3507 uint32 flags = _DDSSurfaceDesc[1];
3509 //verify if file have linearsize set
3510 if(!(flags & DDSD_LINEARSIZE))
3512 nlwarning("A DDS doesn't have the flag DDSD_LINEARSIZE");
3513 //delete [] _DDSSurfaceDesc;
3514 //throw EDDSBadHeader();
3517 //-------------- extracting and testing useful info
3518 retHeight = _DDSSurfaceDesc[2];
3519 retWidth = _DDSSurfaceDesc[3];
3521 delete [] _DDSSurfaceDesc;
3523 else if(fileType == PNG_HEADER)
3525 // check second part of header
3526 f.serialCheck(0x0a1a0a0d);
3528 uint32 chunkLength = 0;
3529 uint32 chunkName = 0;
3530 bool eof = false;
3536 // length of chunk data
3537 f.serial(chunkLength);
3538 NLMISC_BSWAP32(chunkLength);
3540 // name of chunk
3541 f.serial(chunkName);
3543 // size of image is a part of IHDR chunk
3544 if (chunkName == NL_MAKEFOURCC('I', 'H', 'D', 'R'))
3546 uint32 val;
3547 f.serial(val);
3548 NLMISC_BSWAP32(val);
3549 retWidth = val;
3551 f.serial(val);
3552 NLMISC_BSWAP32(val);
3553 retHeight = val;
3555 break;
3557 // end of file chunk
3558 else if (chunkName == NL_MAKEFOURCC('I', 'E', 'N', 'D'))
3560 break;
3563 // skip data of this chunk and CRC32
3564 f.seek(chunkLength+4, IStream::current);
3566 catch(...)
3568 eof = true;
3571 while(!eof);
3573 else if(memcmp(&fileType, &JPG_HEADER, 2) == 0)
3575 uint8 blockMarker1 = 0;
3576 uint8 blockMarker2 = 0;
3577 uint16 blockSize = 0;
3578 bool eof = false;
3584 // marker of a block
3585 f.serial(blockMarker1);
3587 if (blockMarker1 == 0xff)
3589 // marker of a block
3590 f.serial(blockMarker2);
3592 // 0xff00 is only found in image data
3593 if (blockMarker2 == 0x00)
3595 // image data 0xff
3597 // 0xffda is image data
3598 else if (blockMarker2 == 0xda)
3600 // next data is image data which must end with 0xffd9
3602 // 0xffd9 is the end of an image
3603 else if (blockMarker2 == 0xd9)
3605 // real end of file
3606 break;
3608 else if (blockMarker2 == 0xdd || blockMarker2 == 0xdc)
3610 f.seek(4, IStream::current);
3612 else if (blockMarker2 == 0xdf)
3614 f.seek(3, IStream::current);
3616 else if (blockMarker2 >= 0xd0 && blockMarker2 <= 0xd8)
3618 // no content
3620 else
3622 // size of a block
3623 f.serial(blockSize);
3624 NLMISC_BSWAP16(blockSize);
3626 // frame marker (which contains image width and height)
3627 if (blockMarker2 >= 0xc0 && blockMarker2 <= 0xc3)
3629 uint8 imagePrecision = 0; // sample precision
3630 uint32 imageSize = 0; // width and height
3631 f.serial(imagePrecision);
3632 f.serial(imageSize);
3633 NLMISC_BSWAP32(imageSize);
3635 retWidth = imageSize & 0xffff;
3636 retHeight = (imageSize & 0xffff0000) >> 16;
3638 break;
3641 // skip the block
3642 f.seek(blockSize - 2, IStream::current);
3646 catch(...)
3648 eof = true;
3651 while(!eof);
3653 else if(fileType == GIF_HEADER)
3655 // check second part of header ("7a" or "9a" in 'GIF89a')
3656 uint16 s;
3657 f.serial(s);
3658 if (s != 0x6137 && s != 0x6139)
3660 nlwarning("Invalid GIF header, expected GIF87a or GIF89a");
3661 return;
3664 uint16 lsWidth;
3665 uint16 lsHeight;
3666 f.serial(lsWidth);
3667 f.serial(lsHeight);
3669 retWidth = lsWidth;
3670 retHeight = lsHeight;
3672 // assuming it's TGA
3673 else
3675 if(!f.seek (0, NLMISC::IStream::begin))
3677 throw ESeekFailed();
3680 // Reading header,
3681 // To make sure that the bitmap is TGA, we check imageType and imageDepth.
3682 uint8 lengthID;
3683 uint8 cMapType;
3684 uint8 imageType;
3685 uint16 tgaOrigin;
3686 uint16 length;
3687 uint8 depth;
3688 uint16 xOrg;
3689 uint16 yOrg;
3690 uint16 width;
3691 uint16 height;
3692 uint8 imageDepth;
3693 uint8 desc;
3695 f.serial(lengthID);
3696 f.serial(cMapType);
3697 f.serial(imageType);
3698 if(imageType!=2 && imageType!=3 && imageType!=10 && imageType!=11)
3700 nlwarning("Invalid TGA format, type %u in not supported (must be 2, 3, 10 or 11)", imageType);
3701 return;
3703 f.serial(tgaOrigin);
3704 f.serial(length);
3705 f.serial(depth);
3706 f.serial(xOrg);
3707 f.serial(yOrg);
3708 f.serial(width);
3709 f.serial(height);
3710 f.serial(imageDepth);
3711 if(imageDepth!=8 && imageDepth!=16 && imageDepth!=24 && imageDepth!=32)
3713 nlwarning("Invalid TGA format, bit depth %u in not supported (must be 8,16,24 or 32)", imageDepth);
3714 return;
3716 f.serial(desc);
3718 // Ok, we have width and height.
3719 retWidth= width;
3720 retHeight= height;
3723 // reset stream.
3724 if(!f.seek (0, NLMISC::IStream::begin))
3726 throw ESeekFailed();
3731 void CBitmap::loadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight)
3733 retWidth= 0;
3734 retHeight= 0;
3736 CIFile f(path);
3737 if(f.open(path))
3738 loadSize(f, retWidth, retHeight);
3741 // ***************************************************************************
3742 void CBitmap::flipHDXTCBlockColor(uint8 *bitColor, uint32 w)
3744 // pack each line in a u32 (NB: the following works either in Little and Big Endian)
3745 uint32 bits= *(uint32*)bitColor;
3747 // swap in X for each line
3748 uint32 res;
3749 if(w!=2)
3751 res = (bits & 0xC0C0C0C0) >> 6;
3752 res+= (bits & 0x30303030) >> 2;
3753 res+= (bits & 0x0C0C0C0C) << 2;
3754 res+= (bits & 0x03030303) << 6;
3756 // special case where w==2
3757 else
3759 res = (bits & 0x0C0C0C0C) >> 2;
3760 res+= (bits & 0x03030303) << 2;
3763 // copy
3764 *((uint32*)bitColor)= res;
3767 // ***************************************************************************
3768 void CBitmap::flipVDXTCBlockColor(uint8 *bitColor, uint32 h)
3770 // swap just bytes (work either in Little and Big Endian)
3771 if(h!=2)
3773 std::swap(bitColor[0], bitColor[3]);
3774 std::swap(bitColor[1], bitColor[2]);
3776 // special case where h==2)
3777 else
3779 // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
3780 std::swap(bitColor[0], bitColor[1]);
3784 // ***************************************************************************
3785 void CBitmap::flipHDXTCBlockAlpha3(uint8 *blockAlpha, uint32 w)
3787 #ifdef NL_LITTLE_ENDIAN
3788 uint64 bits= *(uint64*)blockAlpha;
3789 #else
3790 uint64 bits= (uint64)blockAlpha[0] + ((uint64)blockAlpha[1]<<8) +
3791 ((uint64)blockAlpha[2]<<16) + ((uint64)blockAlpha[3]<<24) +
3792 ((uint64)blockAlpha[4]<<32) + ((uint64)blockAlpha[5]<<40) +
3793 ((uint64)blockAlpha[6]<<48) + ((uint64)blockAlpha[7]<<56);
3794 #endif
3796 // swap in X for each line
3797 uint64 res;
3798 if(w!=2)
3800 res = (bits & INT64_CONSTANT(0xF000F000F000F000)) >> 12;
3801 res+= (bits & INT64_CONSTANT(0x0F000F000F000F00)) >> 4;
3802 res+= (bits & INT64_CONSTANT(0x00F000F000F000F0)) << 4;
3803 res+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 12;
3805 // special case where w==2
3806 else
3808 res = (bits & INT64_CONSTANT(0x00F000F000F000F0)) >> 4;
3809 res+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 4;
3812 // copy
3813 #ifdef NL_LITTLE_ENDIAN
3814 *((uint64*)blockAlpha)= res;
3815 #else
3816 blockAlpha[0]= res & 255;
3817 blockAlpha[1]= (res>>8) & 255;
3818 blockAlpha[2]= (res>>16) & 255;
3819 blockAlpha[3]= (res>>24) & 255;
3820 blockAlpha[4]= (res>>32) & 255;
3821 blockAlpha[5]= (res>>40) & 255;
3822 blockAlpha[6]= (res>>48) & 255;
3823 blockAlpha[7]= (res>>56) & 255;
3824 #endif
3827 // ***************************************************************************
3828 void CBitmap::flipVDXTCBlockAlpha3(uint8 *blockAlpha, uint32 h)
3830 uint16 *wAlpha= (uint16*)blockAlpha;
3832 // swap just words (work either in Little and Big Endian)
3833 if(h!=2)
3835 std::swap(wAlpha[0], wAlpha[3]);
3836 std::swap(wAlpha[1], wAlpha[2]);
3838 // special case where h==2)
3839 else
3841 // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
3842 std::swap(wAlpha[0], wAlpha[1]);
3846 // ***************************************************************************
3847 void CBitmap::flipHDXTCBlockAlpha5(uint8 *bitAlpha, uint32 w)
3849 // pack into bits. Little Indian in all cases
3850 uint64 bits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +
3851 ((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +
3852 ((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);
3854 // swap in X for each line
3855 uint64 res;
3856 if(w!=2)
3858 res = (bits & INT64_CONSTANT(0xE00E00E00E00)) >> 9;
3859 res+= (bits & INT64_CONSTANT(0x1C01C01C01C0)) >> 3;
3860 res+= (bits & INT64_CONSTANT(0x038038038038)) << 3;
3861 res+= (bits & INT64_CONSTANT(0x007007007007)) << 9;
3863 // special case where w==2
3864 else
3866 res = (bits & INT64_CONSTANT(0x038038038038)) >> 3;
3867 res+= (bits & INT64_CONSTANT(0x007007007007)) << 3;
3870 // copy. Little Indian in all cases
3871 bitAlpha[0]= uint8(res & 255);
3872 bitAlpha[1]= uint8((res>>8) & 255);
3873 bitAlpha[2]= uint8((res>>16) & 255);
3874 bitAlpha[3]= uint8((res>>24) & 255);
3875 bitAlpha[4]= uint8((res>>32) & 255);
3876 bitAlpha[5]= uint8((res>>40) & 255);
3879 // ***************************************************************************
3880 void CBitmap::flipVDXTCBlockAlpha5(uint8 *bitAlpha, uint32 h)
3882 // pack into bits. Little Indian in all cases
3883 uint64 bits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +
3884 ((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +
3885 ((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);
3887 // swap in Y
3888 uint64 res;
3889 if(h!=2)
3891 res = (bits & INT64_CONSTANT(0xFFF000000000)) >> 36;
3892 res+= (bits & INT64_CONSTANT(0x000FFF000000)) >> 12;
3893 res+= (bits & INT64_CONSTANT(0x000000FFF000)) << 12;
3894 res+= (bits & INT64_CONSTANT(0x000000000FFF)) << 36;
3896 // special case where h==2
3897 else
3899 res = (bits & INT64_CONSTANT(0x000000FFF000)) >> 12;
3900 res+= (bits & INT64_CONSTANT(0x000000000FFF)) << 12;
3903 // copy. Little Indian in all cases
3904 bitAlpha[0]= uint8(res & 255);
3905 bitAlpha[1]= uint8((res>>8) & 255);
3906 bitAlpha[2]= uint8((res>>16) & 255);
3907 bitAlpha[3]= uint8((res>>24) & 255);
3908 bitAlpha[4]= uint8((res>>32) & 255);
3909 bitAlpha[5]= uint8((res>>40) & 255);
3912 // ***************************************************************************
3913 void CBitmap::flipDXTCMipMap(bool vertical, uint mm, uint type)
3915 nlassert(mm<MAX_MIPMAP);
3916 // size of a DXTC block. 64 bits (2 U32) for DXTC1, else 128 bits (4*U32)
3917 uint blockSizeU32= type==1? 2 : 4;
3918 // get size in block
3919 sint32 width = getWidth(mm);
3920 sint32 height = getHeight(mm);
3921 if(width==0 || height==0)
3922 return;
3923 uint32 wBlock= (width+3)/4;
3924 uint32 hBlock= (height+3)/4;
3925 // get data ptr and check size.
3926 uint32 *data= (uint32*)(&_Data[mm][0]);
3927 nlassert(_Data[mm].size()==wBlock*hBlock*blockSizeU32*4);
3929 // get the offset (in bytes) to the start of color pixels bits
3930 uint32 offsetColorBits= type==1? 4 : 12;
3932 // abort if swap is nonsense
3933 if(vertical && height==1)
3934 return;
3935 if(!vertical && width==1)
3936 return;
3938 // *** First reverse Blocks
3939 if(vertical)
3941 // reverse vertical
3942 for(uint yBlock=0;yBlock<hBlock/2;yBlock++)
3944 uint32 *src0= data + (yBlock*wBlock)*blockSizeU32;
3945 uint32 *src1= data + ((hBlock-yBlock-1)*wBlock)*blockSizeU32;
3946 for(uint xBlock=0;xBlock<wBlock;xBlock++, src0+=blockSizeU32, src1+=blockSizeU32)
3948 uint32 *block0= src0;
3949 uint32 *block1= src1;
3950 // swap the blocks
3951 for(uint i=0;i<blockSizeU32;i++, block0++, block1++)
3953 std::swap(*block0, *block1);
3958 else
3960 // reverse horizontal
3961 for(uint yBlock=0;yBlock<hBlock;yBlock++)
3963 uint32 *src0= data + (yBlock*wBlock)*blockSizeU32;
3964 uint32 *src1= data + (yBlock*wBlock + wBlock-1)*blockSizeU32;
3965 for(uint xBlock=0;xBlock<wBlock/2;xBlock++, src0+=blockSizeU32, src1-=blockSizeU32)
3967 uint32 *block0= src0;
3968 uint32 *block1= src1;
3969 // swap the blocks
3970 for(uint i=0;i<blockSizeU32;i++, block0++, block1++)
3972 std::swap(*block0, *block1);
3978 // *** Then reverse Bits
3979 for(uint yBlock=0;yBlock<hBlock;yBlock++)
3981 uint32 *src= data + (yBlock*wBlock)*blockSizeU32;
3982 for(uint xBlock=0;xBlock<wBlock;xBlock++, src+=blockSizeU32)
3984 uint8 *block= (uint8*)src;
3986 // flip color bits
3987 if(vertical) flipVDXTCBlockColor(block+offsetColorBits, height);
3988 else flipHDXTCBlockColor(block+offsetColorBits, width);
3990 // flip alpha bits if any
3991 if(type==3)
3993 // point to the alpha part (16*4 bits)
3994 if(vertical) flipVDXTCBlockAlpha3(block, height);
3995 else flipHDXTCBlockAlpha3(block, width);
3997 else if(type==5)
3999 // point to the bit alpha part (16*3 bits)
4000 if(vertical) flipVDXTCBlockAlpha5(block+2, height);
4001 else flipHDXTCBlockAlpha5(block+2, width);
4009 // ***************************************************************************
4010 void CBitmap::flipDXTC(bool vertical)
4012 // get type
4013 uint type;
4014 if(PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha )
4015 type=1;
4016 else if(PixelFormat == DXTC3)
4017 type=3;
4018 else if(PixelFormat == DXTC5)
4019 type=5;
4020 else
4021 return;
4023 // correct width/height?
4024 sint32 nWidth = getWidth(0);
4025 sint32 nHeight = getHeight(0);
4026 if(!isPowerOf2(nWidth) || !isPowerOf2(nHeight))
4027 return;
4029 // flip all mipmaps
4030 for(uint mm=0;mm<_MipMapCount;mm++)
4032 flipDXTCMipMap(vertical, mm, type);
4037 // ***************************************************************************
4038 void CBitmap::flipH()
4040 if (PixelFormat != RGBA)
4042 // try for DXTC
4043 flipDXTC(false);
4045 // then quit (whether it worked or not)
4046 return;
4049 sint32 nWidth = getWidth(0);
4050 sint32 nHeight = getHeight(0);
4051 sint32 i, j;
4052 NLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];
4053 bool needRebuild = false;
4054 CRGBA temp;
4056 if(_MipMapCount>1)
4057 needRebuild = true;
4058 releaseMipMaps();
4060 for( i = 0; i < nHeight; ++i )
4061 for( j = 0; j < nWidth/2; ++j )
4063 temp = pBitmap[i*nWidth+j];
4064 pBitmap[i*nWidth+j] = pBitmap[i*nWidth+nWidth-j-1];
4065 pBitmap[i*nWidth+nWidth-j-1] = temp;
4068 // Rebuilding mipmaps
4069 if(needRebuild)
4071 buildMipMaps();
4076 // ***************************************************************************
4077 void CBitmap::flipV()
4079 if (PixelFormat != RGBA)
4081 // try for DXTC
4082 flipDXTC(true);
4084 // then quit (whether it worked or not)
4085 return;
4088 sint32 nWidth = getWidth(0);
4089 sint32 nHeight = getHeight(0);
4090 sint32 i, j;
4091 NLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];
4092 bool needRebuild = false;
4093 CRGBA temp;
4095 if(_MipMapCount>1)
4096 needRebuild = true;
4097 releaseMipMaps();
4099 for( j = 0; j < nHeight/2; ++j )
4100 for( i = 0; i < nWidth; ++i )
4102 temp = pBitmap[j*nWidth+i];
4103 pBitmap[j*nWidth+i] = pBitmap[(nHeight-j-1)*nWidth+i];
4104 pBitmap[(nHeight-j-1)*nWidth+i] = temp;
4107 // Rebuilding mipmaps
4108 if(needRebuild)
4110 buildMipMaps();
4115 void CBitmap::rot90CW()
4117 if (PixelFormat != RGBA)
4118 return;
4119 sint32 nWidth = getWidth(0);
4120 sint32 nHeight = getHeight(0);
4121 sint32 i, j;
4122 NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
4123 bool needRebuild = false;
4125 if(_MipMapCount>1)
4126 needRebuild = true;
4127 releaseMipMaps();
4129 CObjectVector<uint8> pDestui;
4130 pDestui.resize(nWidth*nHeight*4);
4131 NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
4133 for( j = 0; j < nHeight; ++j )
4134 for( i = 0; i < nWidth; ++i )
4135 pDestRgba[j+i*nHeight] = pSrcRgba[i+(nHeight-1-j)*nWidth];
4137 uint32 nTemp = _Width;
4138 _Width = _Height;
4139 _Height = nTemp;
4141 NLMISC::contReset(_Data[0]); // free memory
4142 _Data[0] = pDestui;
4143 // Rebuilding mipmaps
4144 if(needRebuild)
4146 buildMipMaps();
4150 void CBitmap::rot90CCW()
4152 if (PixelFormat != RGBA)
4153 return;
4154 sint32 nWidth = getWidth(0);
4155 sint32 nHeight = getHeight(0);
4156 sint32 i, j;
4157 NLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];
4158 bool needRebuild = false;
4160 if(_MipMapCount>1)
4161 needRebuild = true;
4162 releaseMipMaps();
4164 CObjectVector<uint8> pDestui;
4165 pDestui.resize(nWidth*nHeight*4);
4166 NLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];
4168 for( j = 0; j < nHeight; ++j )
4169 for( i = 0; i < nWidth; ++i )
4170 pDestRgba[j+i*nHeight] = pSrcRgba[nWidth-1-i+j*nWidth];
4172 uint32 nTemp = _Width;
4173 _Width = _Height;
4174 _Height = nTemp;
4176 NLMISC::contReset(_Data[0]); // free memory
4177 _Data[0] = pDestui;
4178 // Rebuilding mipmaps
4179 if(needRebuild)
4181 buildMipMaps();
4185 //===========================================================================
4186 void CBitmap::blend(CBitmap &Bm0, CBitmap &Bm1, uint16 factor, bool inputBitmapIsMutable /*= false*/)
4188 nlassert(factor <= 256);
4190 nlassert(Bm0._Width != 0 && Bm0._Height != 0
4191 && Bm1._Width != 0 && Bm1._Height != 0);
4193 nlassert(Bm0._Width == Bm1._Width); // the bitmap should have the same size
4194 nlassert(Bm0._Height == Bm1._Height);
4196 const CBitmap *nBm0, *nBm1; // pointer to the bitmap that is used for blending, or to a copy is a conversion wa required
4198 CBitmap cp0, cp1; // these bitmap are copies of Bm1 and Bm0 if a conversion was needed
4200 if (Bm0.PixelFormat != RGBA)
4202 if (inputBitmapIsMutable)
4204 Bm0.convertToRGBA();
4205 nBm0 = &Bm0;
4207 else
4209 cp0 = Bm0;
4210 cp0.convertToRGBA();
4211 nBm0 = &cp0;
4214 else
4216 nBm0 = &Bm0;
4220 if (Bm1.PixelFormat != RGBA)
4222 if (inputBitmapIsMutable)
4224 Bm1.convertToRGBA();
4225 nBm1 = &Bm1;
4227 else
4229 cp1 = Bm1;
4230 cp1.convertToRGBA();
4231 nBm1 = &cp1;
4234 else
4236 nBm1 = &Bm1;
4239 if (this != nBm0 && this != nBm1)
4241 // if source is the same than the dets, don't resize because this clear the bitmap
4242 this->resize(Bm0._Width, Bm0._Height, RGBA);
4245 uint numPix = _Width * _Height; // 4 component per pixels
4248 const uint8 *src0 = &(nBm0->_Data[0][0]);
4249 const uint8 *src1 = &(nBm1->_Data[0][0]);
4250 uint8 *dest = &(this->_Data[0][0]);
4253 #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)
4254 if (CSystemInfo::hasMMX())
4256 // On a P4 2GHz, with a 256x256 texture, I got the following results :
4257 // without mmx : 5.2 ms
4258 // with mmx : 1.7 ms
4259 // I'm sure this can be further optimized..
4261 uint numPixLeft = numPix & 1; // process 2 pixels at once, so special case for odd number
4262 numPix = numPix & ~1;
4263 // do fast blend with mmx
4264 uint64 blendFactor0;
4265 uint64 blendFactor1;
4266 uint16 *bf0 = (uint16 *) &blendFactor0;
4267 uint16 *bf1 = (uint16 *) &blendFactor1;
4268 bf0[0] = bf0[1] = bf0[2] = bf0[3] = (1 << 6) * (factor);
4269 bf1[0] = bf1[1] = bf1[2] = bf1[3] = (1 << 6) * (256 - factor);
4270 __asm
4272 mov esi, src0
4273 mov eax, src1
4274 mov edi, dest
4275 mov ebx, -8
4276 mov ecx, numPix
4277 shr ecx, 1 // process pixels 2 by 2
4278 movq mm1, blendFactor0
4279 movq mm0, blendFactor1
4281 myLoop:
4282 pxor mm6, mm6
4283 lea ebx, [ebx + 8] // points next location
4284 pxor mm7, mm7
4285 movq mm2, [esi + ebx]
4286 movq mm3, [eax + ebx]
4287 // do blend
4288 punpckhbw mm7, mm2 // mm7 contains src0 color 0 in high bytes
4289 punpckhbw mm6, mm3 // mm6 contains src1 color 0 in high bytes
4290 psrl mm7, 1
4291 pxor mm4, mm4 // mm4 = 0
4292 psrl mm6, 1
4293 pmulhw mm7, mm0 // src0 = src0 * blendFactor
4294 pxor mm5, mm5 // mm5 = 0
4295 pmulhw mm6, mm1 // src1 = src1 * (1 - blendfactor)
4296 punpcklbw mm4, mm2 // mm4 contains src0 color 1 in high bytes
4297 paddusw mm6, mm7 // mm6 = src0[0] blended with src1[0]
4298 psrl mm4, 1
4299 psrlw mm6, 5
4300 punpcklbw mm5, mm3 // mm4 contains src1 color 1 in high bytes
4301 psrl mm5, 1
4302 pmulhw mm4, mm0 // src0 = src0 * blendFactor
4303 pmulhw mm5, mm1 // src1 = src1 * (1 - blendfactor)
4304 paddusw mm4, mm5 // mm6 = src0[1] blended with src1[1]
4305 psrlw mm4, 5
4306 // pack result
4307 packuswb mm4, mm6
4308 dec ecx
4309 movq [edi + ebx], mm4 // store result
4310 jne myLoop
4311 emms
4313 if (numPixLeft)
4315 // case of odd number of pixels
4316 src0 += 4 * numPix;
4317 src1 += 4 * numPix;
4318 dest += 4 * numPix;
4319 uint blendFact = (uint) factor;
4320 uint invblendFact = 256 - blendFact;
4321 *dest = (uint8) (((blendFact * *src1) + (invblendFact * *src0)) >> 8);
4322 *(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);
4323 *(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);
4324 *(dest + 3) = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);
4327 else
4328 #endif //#ifdef NL_OS_WINDOWS
4330 uint8 *endPix = dest + ((ptrdiff_t)numPix << 2);
4331 // no mmx version
4332 uint blendFact = (uint) factor;
4333 uint invblendFact = 256 - blendFact;
4336 /// blend 4 component at each pass
4337 *dest = (uint8) (((blendFact * *src1) + (invblendFact * *src0)) >> 8);
4338 *(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);
4339 *(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);
4340 *(dest + 3) = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);
4342 src0 = src0 + 4;
4343 src1 = src1 + 4;
4344 dest = dest + 4;
4346 while (dest != endPix);
4352 //-----------------------------------------------
4353 CRGBA CBitmap::getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const
4355 uint w = getWidth(numMipMap);
4356 uint h = getHeight(numMipMap);
4357 if (w == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
4358 const uint8 *pix = &getPixels(numMipMap)[(x + y * w) << 2];
4359 return CRGBA(pix[0], pix[1], pix[2], pix[3]);
4362 //-----------------------------------------------
4363 CRGBA CBitmap::getDXTCColorFromBlock(const uint8 *block, sint x, sint y)
4365 uint16 col0;
4366 uint16 col1;
4367 memcpy(&col0, block, sizeof(uint16));
4368 memcpy(&col1, block + 2, sizeof(uint16));
4369 uint colIndex = (block[4 + (y & 3)] >> ((x & 3) << 1)) & 3;
4370 CRGBA result, c0, c1;
4371 if (col0 > col1)
4373 switch(colIndex)
4375 case 0:
4376 uncompress(col0, result);
4377 break;
4378 case 1:
4379 uncompress(col1, result);
4380 break;
4381 case 2:
4382 uncompress(col0, c0);
4383 uncompress(col1, c1);
4384 result.blendFromui(c0, c1, 85);
4385 break;
4386 case 3:
4387 uncompress(col0, c0);
4388 uncompress(col1, c1);
4389 result.blendFromui(c0, c1, 171);
4390 break;
4391 default:
4394 result.A = 255;
4396 else
4398 switch(colIndex)
4400 case 0:
4401 uncompress(col0, result);
4402 result.A = 255;
4403 break;
4404 case 1:
4405 uncompress(col1, result);
4406 result.A = 255;
4407 break;
4408 case 2:
4409 uncompress(col0, c0);
4410 uncompress(col1, c1);
4411 result.blendFromui(c0, c1, 128);
4412 result.A = 255;
4413 break;
4414 case 3:
4415 result.set(0, 0, 0, 0);
4416 break;
4419 return result;
4422 //-----------------------------------------------
4423 CRGBA CBitmap::getDXTC1Texel(sint x, sint y, uint32 numMipMap) const
4425 uint w = getWidth(numMipMap);
4426 uint h = getHeight(numMipMap);
4427 if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
4428 uint numRowBlocks = std::max((w + 3) >> 2, 1u);
4429 const uint8 *pix = &getPixels(numMipMap)[0];
4430 const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 3) + ((x >> 2) << 3));
4431 return getDXTCColorFromBlock(block, x, y);
4435 //-----------------------------------------------
4436 CRGBA CBitmap::getDXTC3Texel(sint x, sint y, uint32 numMipMap) const
4438 uint w = getWidth(numMipMap);
4439 uint h = getHeight(numMipMap);
4440 if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
4441 uint numRowBlocks = std::max((w + 3) >> 2, 1u);
4442 const uint8 *pix = &getPixels(numMipMap)[0];
4443 const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));
4444 CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
4445 // get alpha part
4446 uint8 alphaByte = block[((y & 3) << 1) + ((x & 2) >> 1)];
4447 result.A = (x & 1) ? (alphaByte & 0xf0) : ((alphaByte & 0x0f) << 4);
4448 return result;
4451 //-----------------------------------------------
4452 CRGBA CBitmap::getDXTC5Texel(sint x, sint y, uint32 numMipMap) const
4454 uint w = getWidth(numMipMap);
4455 uint h = getHeight(numMipMap);
4456 if (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases
4457 uint numRowBlocks = std::max((w + 3) >> 2, 1u);
4458 const uint8 *pix = &getPixels(numMipMap)[0];
4459 const uint8 *block = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));
4460 CRGBA result = getDXTCColorFromBlock(block + 8, x, y);
4461 // get alpha part
4462 uint8 alpha0 = block[0];
4463 uint8 alpha1 = block[1];
4465 uint alphaIndex;
4466 uint tripletIndex = (x & 3) + ((y & 3) << 2);
4467 if (tripletIndex < 8)
4469 alphaIndex = (((uint32 &) block[2]) >> (tripletIndex * 3)) & 7;
4471 else
4473 alphaIndex = (((uint32 &) block[5]) >> ((tripletIndex - 8) * 3)) & 7; // we can read a dword there because there are color datas following he alpha datas
4476 if (alpha0 > alpha1)
4478 switch (alphaIndex)
4480 case 0: result.A = alpha0; break;
4481 case 1: result.A = alpha1; break;
4482 case 2: result.A = (uint8) ((6 * (uint) alpha0 + (uint) alpha1) / 7); break;
4483 case 3: result.A = (uint8) ((5 * (uint) alpha0 + 2 * (uint) alpha1) / 7); break;
4484 case 4: result.A = (uint8) ((4 * (uint) alpha0 + 3 * (uint) alpha1) / 7); break;
4485 case 5: result.A = (uint8) ((3 * (uint) alpha0 + 4 * (uint) alpha1) / 7); break;
4486 case 6: result.A = (uint8) ((2 * (uint) alpha0 + 5 * (uint) alpha1) / 7); break;
4487 case 7: result.A = (uint8) (((uint) alpha0 + (uint) 6 * alpha1) / 7); break;
4490 else
4492 switch (alphaIndex)
4494 case 0: result.A = alpha0; break;
4495 case 1: result.A = alpha1; break;
4496 case 2: result.A = (uint8) ((4 * (uint) alpha0 + (uint) alpha1) / 5); break;
4497 case 3: result.A = (uint8) ((3 * (uint) alpha0 + 2 * (uint) alpha1) / 5); break;
4498 case 4: result.A = (uint8) ((2 * (uint) alpha0 + 3 * (uint) alpha1) / 5); break;
4499 case 5: result.A = (uint8) (((uint) alpha0 + 4 * (uint) alpha1) / 5); break;
4500 case 6: result.A = 0; break;
4501 case 7: result.A = 255; break;
4504 return result;
4508 //-----------------------------------------------
4509 CRGBA CBitmap::getPixelColor(sint x, sint y, uint32 numMipMap /*=0*/) const
4512 switch (PixelFormat)
4514 case RGBA:
4515 return getRGBAPixel(x, y, numMipMap);
4516 case DXTC1:
4517 case DXTC1Alpha:
4518 return getDXTC1Texel(x, y, numMipMap);
4519 case DXTC3:
4520 return getDXTC3Texel(x, y, numMipMap);
4521 case DXTC5:
4522 return getDXTC5Texel(x, y, numMipMap);
4523 default:
4524 nlstop;
4525 break;
4527 return CRGBA::Black;
4530 //-----------------------------------------------
4531 void CBitmap::setPixelColor(sint x, sint y, CRGBA c, uint32 numMipMap)
4533 nlassert(PixelFormat == RGBA);
4535 uint w = getWidth(numMipMap);
4536 uint h = getHeight(numMipMap);
4538 if (w == 0 || x < 0 || y < 0 || x >= (sint)w || y >= (sint)h) return;
4540 uint8 *pix = &getPixels(numMipMap)[(x + y * w) << 2];
4542 memcpy(pix, &c, sizeof(CRGBA));
4545 //-----------------------------------------------
4546 void CBitmap::swap(CBitmap &other)
4548 std::swap(PixelFormat, other.PixelFormat);
4549 std::swap(_MipMapCount, other._MipMapCount);
4550 std::swap(_LoadGrayscaleAsAlpha, other._LoadGrayscaleAsAlpha);
4551 std::swap(_Width, other._Width);
4552 std::swap(_Height, other._Height);
4553 for(uint k = 0; k < MAX_MIPMAP; ++k)
4555 _Data[k].swap(other._Data[k]);
4559 //-----------------------------------------------
4560 void CBitmap::unattachPixels(CObjectVector<uint8> *mipmapDestArray, uint maxMipMapCount /*=MAX_MIPMAP*/)
4562 if (!mipmapDestArray) return;
4563 uint k;
4564 for(k = 0; k < std::min((uint) _MipMapCount, maxMipMapCount); ++k)
4566 mipmapDestArray[k].swap(_Data[k]);
4567 _Data[k].clear();
4569 for(; k < _MipMapCount; ++k)
4571 _Data[k].clear();
4573 #ifdef NL_DEBUG
4574 // check that remaining mipmaps are empty
4575 for(; k < _MipMapCount; ++k)
4577 nlassert(_Data[k].empty());
4579 #endif
4580 _MipMapCount = 1;
4581 _Width = 0;
4582 _Height = 0;
4583 PixelFormat = RGBA;
4584 _LoadGrayscaleAsAlpha = true;
4590 void CBitmap::getData(uint8*& extractData)
4593 uint32 size=0;
4594 if(PixelFormat==RGBA)
4595 size=_Width*_Height*4;
4596 else if(PixelFormat==Alpha||PixelFormat==Luminance)
4597 size=_Width*_Height;
4598 else
4600 nlstop;
4603 for(uint32 pix=0;pix<size;pix++)
4604 extractData[pix]=_Data[0][pix];
4608 void CBitmap::getDibData(uint8*& extractData)
4611 uint32 lineSize=0,size;
4612 uint8** buf;
4613 buf=new uint8*[_Height];
4614 if(PixelFormat==RGBA)
4616 lineSize=_Width*4;
4620 else if(PixelFormat==Alpha||PixelFormat==Luminance)
4622 lineSize=_Width;
4624 else
4626 nlstop;
4629 for(sint32 i=_Height-1;i>=0;i--)
4631 buf[_Height-1-i]=&_Data[0][i*lineSize];
4634 size=lineSize*_Height;
4636 for(uint32 line=0;line<_Height;line++)
4638 for(uint32 pix=0;pix<lineSize;pix++)
4639 extractData[line*lineSize+pix]=_Data[0][size-(line+1)*lineSize+pix];
4641 delete []buf;
4645 } // NLMISC