1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2016-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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
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
]=
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
96 _LoadGrayscaleAsAlpha
= true;
104 /*-------------------------------------------------------------------*\
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());
117 uint32 fileType
= 0;;
119 if(fileType
== DDS_HEADER
)
121 #ifdef NEL_ALL_BITMAP_WHITE
122 uint8 result
= readDDS(f
, mipMapSkip
);
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
);
136 #else // NEL_ALL_BITMAP_WHITE
138 #endif // NEL_ALL_BITMAP_WHITE
142 // only compare fist word
143 if (memcmp(&fileType
, &JPG_HEADER
, 2) == 0)
145 #ifdef NEL_ALL_BITMAP_WHITE
146 uint8 result
= readJPG(f
);
149 #else // NEL_ALL_BITMAP_WHITE
151 #endif // NEL_ALL_BITMAP_WHITE
156 if (fileType
== GIF_HEADER
)
158 #ifdef NEL_ALL_BITMAP_WHITE
159 uint8 result
= readGIF(f
);
162 #else // NEL_ALL_BITMAP_WHITE
164 #endif // NEL_ALL_BITMAP_WHITE
169 NLMISC::IStream::TSeekOrigin origin
= f
.begin
;
170 if(!f
.seek (0, origin
))
176 // To make sure that the bitmap is TGA, we check imageType and imageDepth.
193 if(imageType
!=2 && imageType
!=3 && imageType
!=10 && imageType
!=11) return 0;
201 f
.serial(imageDepth
);
202 if(imageDepth
!=8 && imageDepth
!=16 && imageDepth
!=24 && imageDepth
!=32) return 0;
205 if(!f
.seek (0, origin
))
209 #ifdef NEL_ALL_BITMAP_WHITE
210 uint8 result
= readTGA(f
);
213 #else // NEL_ALL_BITMAP_WHITE
215 #endif // NEL_ALL_BITMAP_WHITE
219 /*-------------------------------------------------------------------*\
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 /*-------------------------------------------------------------------*\
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])
316 _Data
[0].resize(_Width
*_Height
*sizeof(NLMISC::CRGBA
));
317 for(sint m
=1;m
<MAX_MIPMAP
;m
++)
319 NLMISC::CRGBA
*pix
= (NLMISC::CRGBA
*)(_Data
[0].getPtr());
321 for(sint i
=0;i
<(sint
)(_Width
*_Height
);i
++)
324 pix
[i
].set(255,255,255,255);
326 pix
[i
].set(0x80,0x80,0x80,0x40);
330 /*-------------------------------------------------------------------*\
332 \*-------------------------------------------------------------------*/
333 void CBitmap::makeOpaque()
335 if (_Width
*_Height
== 0) return;
341 case RGBA
: pixelSize
= 4; break;
342 case AlphaLuminance
: pixelSize
= 2; break;
343 case Alpha
: pixelSize
= 1; break;
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
355 memset(data
, 255, _Data
[m
].size());
360 uint8
*endData
= data
+ _Data
[m
].size();
363 data
+= pixelSize
- 1;
365 // replace all alpha values by 255
366 while(data
< endData
)
376 /*-------------------------------------------------------------------*\
377 makeTransparentPixelsBlack
378 \*-------------------------------------------------------------------*/
379 void CBitmap::makeTransparentPixelsBlack()
381 if (_Width
*_Height
== 0) return;
387 case RGBA
: pixelSize
= 4; break;
388 case AlphaLuminance
: pixelSize
= 2; break;
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();
400 uint8
*endData
= data
+ _Data
[m
].size();
403 data
+= pixelSize
- 1;
405 // replace all alpha values by 255
406 while (data
< endData
)
408 // fully transparent pixel
412 memset(data
- colorsSize
, 0, colorsSize
);
421 /*-------------------------------------------------------------------*\
423 \*-------------------------------------------------------------------*/
424 bool CBitmap::isAlphaUniform(uint8
*alpha
) const
426 uint32 size
= _Data
[0].size();
428 if (size
== 0) return false;
434 // formats with alpha channel
447 // formats without alpha channel
449 if (alpha
) *alpha
= 255;
456 // get a pointer on original data
457 uint8
*data
= (uint8
*)_Data
[0].getPtr();
458 uint8
*endData
= data
+ size
;
461 data
+= pixelSize
- 1;
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
472 // return the uniform value
473 if (alpha
) *alpha
= value
;
481 /*-------------------------------------------------------------------*\
483 \*-------------------------------------------------------------------*/
484 bool CBitmap::isGrayscale() const
486 // all grayscale formats or, al least, without color information
498 // DXTC formats won't be managed at the moment
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;
527 /*-------------------------------------------------------------------*\
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
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);
549 for(uint i
= 0; i
<size
/4 - 1; i
++)
551 f
.serial(_DDSSurfaceDesc
[i
+1]);
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];
575 switch (_DDSSurfaceDesc
[20])
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);
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));
638 if(PixelFormat
==DXTC1
|| PixelFormat
==DXTC1Alpha
)
639 mipMapSz
= wtmp
*htmp
/2;
641 mipMapSz
= wtmp
*htmp
;
643 // add to how many to skip
646 // Size of final bitmap is reduced.
655 if(!f
.seek(seekSize
, IStream::current
))
657 delete [] _DDSSurfaceDesc
;
664 //------------- preload all the mipmaps (one serialBuffer() is faster)
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));
679 if(PixelFormat
==DXTC1
|| PixelFormat
==DXTC1Alpha
)
680 mipMapSz
= wtmp
*htmp
/2;
682 mipMapSz
= wtmp
*htmp
;
685 _Data
[m
].resize(mipMapSz
);
686 totalSize
+= mipMapSz
;
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
702 for(m
= 0; m
<_MipMapCount
; m
++)
704 uint32 mipMapSz
= _Data
[m
].size();
705 memcpy(_Data
[m
].getPtr(), &(pixData
[pixIndex
]), mipMapSz
);
711 delete [] _DDSSurfaceDesc
;
715 case DXTC1
: return 24;
716 case DXTC1Alpha
: return 32;
717 case DXTC3
: return 32;
718 case DXTC5
: return 32;
728 /*-------------------------------------------------------------------*\
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
737 (the inverse is false: DXTC5 to DXTC1 is possible, with maybe swap color0/color1 and bits).
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());
752 for(i=0; i<_Data[m].size(); i+=8)
757 dataTmp[dstId++]= 255;
763 dataTmp[dstId++]= _Data[m][i+j];
775 /*-------------------------------------------------------------------*\
777 \*-------------------------------------------------------------------*/
778 bool CBitmap::luminanceToRGBA()
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);
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;
803 /*-------------------------------------------------------------------*\
805 \*-------------------------------------------------------------------*/
806 bool CBitmap::alphaToRGBA()
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);
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
];
832 /*-------------------------------------------------------------------*\
833 alphaLuminanceToRGBA()
834 \*-------------------------------------------------------------------*/
835 bool CBitmap::alphaLuminanceToRGBA()
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);
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];
863 /*-------------------------------------------------------------------*\
865 \*-------------------------------------------------------------------*/
866 bool CBitmap::rgbaToAlphaLuminance()
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);
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
]);
887 PixelFormat
= AlphaLuminance
;
892 /*-------------------------------------------------------------------*\
893 luminanceToAlphaLuminance
894 \*-------------------------------------------------------------------*/
895 bool CBitmap::luminanceToAlphaLuminance()
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);
907 for(i
=0; i
<_Data
[m
].size(); i
++)
909 dataTmp
[dstId
++]= _Data
[m
][i
];
910 dataTmp
[dstId
++]= 255;
914 PixelFormat
= AlphaLuminance
;
920 /*-------------------------------------------------------------------*\
921 alphaToAlphaLuminance
922 \*-------------------------------------------------------------------*/
923 bool CBitmap::alphaToAlphaLuminance()
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);
935 for(i
=0; i
<_Data
[m
].size(); i
++)
938 dataTmp
[dstId
++]= _Data
[m
][i
];
942 PixelFormat
= AlphaLuminance
;
948 /*-------------------------------------------------------------------*\
950 \*-------------------------------------------------------------------*/
951 bool CBitmap::rgbaToLuminance()
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);
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
]);
971 PixelFormat
= Luminance
;
977 /*-------------------------------------------------------------------*\
979 \*-------------------------------------------------------------------*/
980 bool CBitmap::alphaToLuminance()
982 if(_Width
*_Height
== 0) return false;
984 PixelFormat
= Luminance
;
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);
1003 for(uint32 i
=0; i
<_Data
[m
].size(); i
+=2)
1005 dataTmp
[dstId
++]= _Data
[m
][i
];
1008 NLMISC::contReset(_Data
[m
]);
1014 PixelFormat
= Luminance
;
1020 /*-------------------------------------------------------------------*\
1022 \*-------------------------------------------------------------------*/
1023 bool CBitmap::rgbaToAlpha()
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);
1035 for(i
=0; i
<_Data
[m
].size(); i
+=4)
1037 dataTmp
[dstId
++]= _Data
[m
][i
+3];
1039 NLMISC::contReset(_Data
[m
]);
1043 PixelFormat
= Alpha
;
1048 /*-------------------------------------------------------------------*\
1050 \*-------------------------------------------------------------------*/
1051 bool CBitmap::luminanceToAlpha()
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());
1063 for(i
=0; i
<_Data
[m
].size(); i
++)
1065 dataTmp
[dstId
++]= _Data
[m
][i
];
1069 PixelFormat
= Alpha
;
1074 /*-------------------------------------------------------------------*\
1075 alphaLuminanceToAlpha
1076 \*-------------------------------------------------------------------*/
1077 bool CBitmap::alphaLuminanceToAlpha()
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);
1089 for(i
=0; i
<_Data
[m
].size(); i
+=2)
1091 dataTmp
[dstId
++]= _Data
[m
][i
+1];
1093 NLMISC::contReset(_Data
[m
]);
1097 PixelFormat
= Alpha
;
1102 /*-------------------------------------------------------------------*\
1104 \*-------------------------------------------------------------------*/
1105 bool CBitmap::convertToLuminance()
1110 return rgbaToLuminance();
1118 return alphaToLuminance();
1121 case AlphaLuminance
:
1122 return alphaLuminanceToLuminance();
1133 /*-------------------------------------------------------------------*\
1135 \*-------------------------------------------------------------------*/
1136 bool CBitmap::convertToAlpha()
1141 return rgbaToAlpha();
1145 return luminanceToAlpha();
1152 case AlphaLuminance
:
1153 return alphaLuminanceToAlpha();
1164 /*-------------------------------------------------------------------*\
1165 convertToAlphaLuminance
1166 \*-------------------------------------------------------------------*/
1167 bool CBitmap::convertToAlphaLuminance()
1172 return rgbaToAlphaLuminance();
1176 return luminanceToAlphaLuminance();
1180 return alphaToAlphaLuminance();
1183 case AlphaLuminance
:
1194 /*-------------------------------------------------------------------*\
1196 \*-------------------------------------------------------------------*/
1197 bool CBitmap::convertToRGBA()
1202 return decompressDXT1(false);
1206 return decompressDXT1(true);
1210 return decompressDXT3();
1214 return decompressDXT5();
1218 return luminanceToRGBA();
1222 return alphaToRGBA();
1225 case AlphaLuminance
:
1226 return alphaLuminanceToRGBA();
1238 /*-------------------------------------------------------------------*\
1240 \*-------------------------------------------------------------------*/
1241 bool CBitmap::convertToType(CBitmap::TType type
)
1243 if(PixelFormat
==type
) return true;
1248 return convertToRGBA();
1252 return convertToDXTC5();
1256 return convertToLuminance();
1260 return convertToAlpha();
1263 case AlphaLuminance
:
1264 return convertToAlphaLuminance();
1277 /*-------------------------------------------------------------------*\
1279 \*-------------------------------------------------------------------*/
1280 bool CBitmap::decompressDXT1(bool alpha
)
1284 CObjectVector
<uint8
> dataTmp
[MAX_MIPMAP
];
1286 uint32 width
= _Width
;
1287 uint32 height
= _Height
;
1289 for(uint8 m
= 0; m
<_MipMapCount
; m
++)
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)
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]);
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;
1347 c
[2].blendFromui(c
[0],c
[1],128);
1348 if(alpha
) c
[2].A
= 255;
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
);
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
;
1375 // Copy result into the mipmap level.
1376 if(wtmp
==width
&& htmp
==height
)
1378 // For mipmaps level >4 pixels.
1379 _Data
[m
]= dataTmp
[m
];
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];
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;
1406 /*-------------------------------------------------------------------*\
1408 \*-------------------------------------------------------------------*/
1409 bool CBitmap::decompressDXT3()
1413 CObjectVector
<uint8
> dataTmp
[MAX_MIPMAP
];
1415 uint32 width
= _Width
;
1416 uint32 height
= _Height
;
1418 for(uint8 m
= 0; m
<_MipMapCount
; m
++)
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)
1442 memcpy(&alphatmp
,&_Data
[m
][i
],8);
1446 uint8 a
= (uint8
)(alphatmp
&15);
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
);
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
];
1489 // Copy result into the mipmap level.
1490 if(wtmp
==width
&& htmp
==height
)
1492 // For mipmaps level >4 pixels.
1493 _Data
[m
]= dataTmp
[m
];
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];
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;
1520 /*-------------------------------------------------------------------*\
1522 \*-------------------------------------------------------------------*/
1523 bool CBitmap::decompressDXT5()
1527 CObjectVector
<uint8
> dataTmp
[MAX_MIPMAP
];
1529 uint32 width
= _Width
;
1530 uint32 height
= _Height
;
1532 for(uint8 m
= 0; m
<_MipMapCount
; m
++)
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)
1556 memcpy(&bitsAlpha
,&_Data
[m
][i
],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);
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);
1582 uint8 codeAlpha
[16];
1585 codeAlpha
[j
] = (uint8
)(bitsAlpha
& 7);
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
);
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
]];
1630 // Copy result into the mipmap level.
1631 if(wtmp
==width
&& htmp
==height
)
1633 // For mipmaps level >4 pixels.
1634 _Data
[m
]= dataTmp
[m
];
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];
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;
1662 /*-------------------------------------------------------------------*\
1664 \*-------------------------------------------------------------------*/
1665 uint32
CBitmap::blend(uint32
&n0
, uint32
&n1
, uint32 coef0
)
1669 return ((n0
*a0
+ n1
*a1
) >>8);
1674 /*-------------------------------------------------------------------*\
1676 \*-------------------------------------------------------------------*/
1677 inline void CBitmap::uncompress(uint16 color
, NLMISC::CRGBA
&r
)
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 /*-------------------------------------------------------------------*\
1689 \*-------------------------------------------------------------------*/
1690 uint32
CBitmap::getWidth(uint32 mipMap
) const
1692 if(mipMap
==0) return _Width
;
1703 if(m
==mipMap
) return w
;
1705 while(w
!=1 || h
!=1);
1712 /*-------------------------------------------------------------------*\
1714 \*-------------------------------------------------------------------*/
1715 uint32
CBitmap::getHeight(uint32 mipMap
) const
1717 if(mipMap
==0) return _Height
;
1728 if(m
==mipMap
) return h
;
1730 while(w
!=1 || h
!=1);
1736 /*-------------------------------------------------------------------*\
1738 \*-------------------------------------------------------------------*/
1739 uint32
CBitmap::getSize(uint32 numMipMap
) const
1741 return getHeight(numMipMap
)*getWidth(numMipMap
);
1746 /*-------------------------------------------------------------------*\
1748 \*-------------------------------------------------------------------*/
1749 void CBitmap::buildMipMaps()
1753 if(PixelFormat
!=RGBA
) return;
1754 if(_MipMapCount
!=1) return;
1755 if(!NLMISC::isPowerOf2(_Width
)) return;
1756 if(!NLMISC::isPowerOf2(_Height
)) return;
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];
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
+
1796 pRgba
[i
*w
+ j
].G
= (c0
.G
+
1800 pRgba
[i
*w
+ j
].B
= (c0
.B
+
1804 pRgba
[i
*w
+ j
].A
= (c0
.A
+
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;
1837 /*-------------------------------------------------------------------*\
1839 \*-------------------------------------------------------------------*/
1840 void CBitmap::releaseMipMaps()
1842 if(_MipMapCount
<=1) return;
1845 for(sint i
=1;i
<MAX_MIPMAP
;i
++)
1847 NLMISC::contReset(_Data
[i
]);
1851 /*-------------------------------------------------------------------*\
1853 \*-------------------------------------------------------------------*/
1854 void CBitmap::resample(sint32 nNewWidth
, sint32 nNewHeight
)
1856 nlassert(PixelFormat
== RGBA
|| PixelFormat
== Luminance
|| PixelFormat
== AlphaLuminance
);
1857 bool needRebuild
= false;
1860 //logResample("Resample: 10");
1864 //logResample("Resample: 20");
1866 if(nNewWidth
==0 || nNewHeight
==0)
1868 _Width
= _Height
= 0;
1869 //logResample("Resample: 25");
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
];
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
1916 *(iGray
++) = (*i
) & 0xff;
1917 *(iAlpha
++) = ((*i
) >> 8) & 0xff;
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
);
1928 // resample alpha values array
1929 uint8
*pDestAlpha
= new uint8
[destSize
];
1930 resamplePicture8(pSrcAlpha
, pDestAlpha
, _Width
, _Height
, nNewWidth
, nNewHeight
);
1935 iEnd
= (uint16
*)i
+ destSize
;
1937 iAlpha
= pDestAlpha
;
1939 // merge alpha and gray in destination array
1942 *(i
++) = *(iGray
++) | (*(iAlpha
++) << 8);
1946 delete[] pDestAlpha
;
1949 NLMISC::contReset(_Data
[0]); // free memory
1950 //logResample("Resample: 70");
1953 //logResample("Resample: 80");
1955 _Height
= nNewHeight
;
1957 // Rebuilding mipmaps
1958 //logResample("Resample: 90");
1962 //logResample("Resample: 95");
1964 //logResample("Resample: 100");
1968 /*-------------------------------------------------------------------*\
1970 \*-------------------------------------------------------------------*/
1971 void CBitmap::resize (sint32 nNewWidth
, sint32 nNewHeight
, TType newType
, bool resetTo0
)
1976 // Change type of bitmap ?
1977 if (newType
!=DonTKnow
)
1978 PixelFormat
=newType
;
1981 _Height
= nNewHeight
;
1983 // resize the level 0 only.
1984 resizeMipMap(0, nNewWidth
, nNewHeight
, resetTo0
);
1988 /*-------------------------------------------------------------------*\
1990 \*-------------------------------------------------------------------*/
1991 void CBitmap::resizeMipMap (uint32 numMipMap
, sint32 nNewWidth
, sint32 nNewHeight
, bool resetTo0
)
1993 nlassert(numMipMap
<MAX_MIPMAP
);
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);
2009 _Data
[numMipMap
].fill(0);
2013 /*-------------------------------------------------------------------*\
2015 \*-------------------------------------------------------------------*/
2016 void CBitmap::setMipMapCount(uint32 mmc
)
2018 _MipMapCount
= uint8(mmc
);
2022 /*-------------------------------------------------------------------*\
2024 \*-------------------------------------------------------------------*/
2025 void CBitmap::reset(TType type
)
2027 for(uint i
=0; i
<_MipMapCount
; i
++)
2029 NLMISC::contReset(_Data
[i
]);
2032 _Width
= _Height
= 0;
2035 // Change pixel format
2041 /*-------------------------------------------------------------------*\
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))
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
);
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
);
2068 float fXdelta
=(float)(nSrcWidth
)/(float)(nDestWidth
);
2069 NLMISC::CRGBAF
*pItermPtr
=&*pIterm
.begin();
2071 for (nY
=0; nY
<nSrcHeight
; nY
++)
2073 const NLMISC::CRGBA
*pSrcLine
=pSrc
;
2076 for (nX
=0; nX
<nDestWidth
; nX
++)
2078 float fVirgule
=fX
-(float)floor(fX
);
2079 nlassert (fVirgule
>=0.f
);
2080 NLMISC::CRGBAF vColor
;
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
);
2090 vColor
=NLMISC::CRGBAF (pSrcLine
[(sint32
)floor(fX
)]);
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
);
2101 vColor
=NLMISC::CRGBAF (pSrcLine
[(sint32
)floor(fX
)]);
2103 *(pItermPtr
++)=vColor
;
2111 NLMISC::CRGBAF
*pItermPtr
=&*pIterm
.begin();
2112 for (sint32 nY
=0; nY
<nSrcHeight
; nY
++)
2114 const NLMISC::CRGBA
*pSrcLine
=pSrc
;
2116 for (nX
=0; nX
<nDestWidth
; nX
++)
2117 *(pItermPtr
++)=NLMISC::CRGBAF (pSrcLine
[nX
]);
2123 double fXdelta
=(double)(nSrcWidth
)/(double)(nDestWidth
);
2124 nlassert (fXdelta
>1.f
);
2125 NLMISC::CRGBAF
*pItermPtr
=&*pIterm
.begin();
2127 for (nY
=0; nY
<nSrcHeight
; nY
++)
2129 const NLMISC::CRGBA
*pSrcLine
=pSrc
;
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
;
2141 vColor
+=((float)(fNext
-fX
))*NLMISC::CRGBAF (pSrcLine
[(sint32
)floor(fX
)]);
2144 fX
= fFinal
; // ensure fX == fFinal
2145 vColor
/=(float)fXdelta
;
2146 *(pItermPtr
++)=vColor
;
2154 double fYdelta
=(double)(nSrcHeight
)/(double)(nDestHeight
);
2156 for (nX
=0; nX
<nDestWidth
; nX
++)
2160 for (nY
=0; nY
<nDestHeight
; nY
++)
2162 double fVirgule
=fY
-(double)floor(fY
);
2163 nlassert (fVirgule
>=0.f
);
2164 NLMISC::CRGBAF vColor
;
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
);
2174 vColor
=pIterm
[((sint32
)floor(fY
))*nDestWidth
+nX
];
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
);
2185 vColor
=pIterm
[((sint32
)floor(fY
))*nDestWidth
+nX
];
2187 pDest
[nX
+nY
*nDestWidth
]=vColor
;
2194 for (sint32 nX
=0; nX
<nDestWidth
; nX
++)
2197 for (nY
=0; nY
<nDestHeight
; nY
++)
2199 pDest
[nX
+nY
*nDestWidth
]=pIterm
[nY
*nDestWidth
+nX
];
2205 double fYdelta
=(double)(nSrcHeight
)/(double)(nDestHeight
);
2206 nlassert (fYdelta
>1.f
);
2208 for (nX
=0; nX
<nDestWidth
; nX
++)
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
;
2221 vColor
+=((float)(fNext
-fY
))*pIterm
[((sint32
)floor(fY
))*nDestWidth
+nX
];
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
++)
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 /*-------------------------------------------------------------------*\
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))
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
);
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
);
2290 float fXdelta
=(float)(nSrcWidth
)/(float)(nDestWidth
);
2291 float *pItermPtr
=&*pIterm
.begin();
2293 for (nY
=0; nY
<nSrcHeight
; nY
++)
2295 const uint8
*pSrcLine
=pSrc
;
2298 for (nX
=0; nX
<nDestWidth
; nX
++)
2300 float fVirgule
=fX
-(float)floor(fX
);
2301 nlassert (fVirgule
>=0.f
);
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
);
2312 vColor
= float(pSrcLine
[(sint32
)floor(fX
)]);
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
);
2323 vColor
= float (pSrcLine
[(sint32
)floor(fX
)]);
2325 *(pItermPtr
++)=vColor
;
2333 float *pItermPtr
=&*pIterm
.begin();
2334 for (sint32 nY
=0; nY
<nSrcHeight
; nY
++)
2336 const uint8
*pSrcLine
=pSrc
;
2338 for (nX
=0; nX
<nDestWidth
; nX
++)
2339 *(pItermPtr
++) = float (pSrcLine
[nX
]);
2345 double fXdelta
=(double)(nSrcWidth
)/(double)(nDestWidth
);
2346 nlassert (fXdelta
>1.f
);
2347 float *pItermPtr
=&*pIterm
.begin();
2349 for (nY
=0; nY
<nSrcHeight
; nY
++)
2351 const uint8
*pSrcLine
=pSrc
;
2354 for (nX
=0; nX
<nDestWidth
; nX
++)
2357 double fFinal
=fX
+fXdelta
;
2358 while ((fX
<fFinal
)&&((sint32
)fX
!=nSrcWidth
))
2360 double fNext
=(double)floor (fX
)+1.f
;
2363 vColor
+=((float)(fNext
-fX
))* float (pSrcLine
[(sint32
)floor(fX
)]);
2366 fX
= fFinal
; // ensure fX == fFinal
2367 vColor
/=(float)fXdelta
;
2368 *(pItermPtr
++)=vColor
;
2376 double fYdelta
=(double)(nSrcHeight
)/(double)(nDestHeight
);
2378 for (nX
=0; nX
<nDestWidth
; nX
++)
2382 for (nY
=0; nY
<nDestHeight
; nY
++)
2384 double fVirgule
=fY
-(double)floor(fY
);
2385 nlassert (fVirgule
>=0.f
);
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
);
2396 vColor
=pIterm
[((sint32
)floor(fY
))*nDestWidth
+nX
];
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
);
2407 vColor
=pIterm
[((sint32
)floor(fY
))*nDestWidth
+nX
];
2409 pDest
[nX
+nY
*nDestWidth
]=vColor
;
2416 for (sint32 nX
=0; nX
<nDestWidth
; nX
++)
2419 for (nY
=0; nY
<nDestHeight
; nY
++)
2421 pDest
[nX
+nY
*nDestWidth
]=pIterm
[nY
*nDestWidth
+nX
];
2427 double fYdelta
=(double)(nSrcHeight
)/(double)(nDestHeight
);
2428 nlassert (fYdelta
>1.f
);
2430 for (nX
=0; nX
<nDestWidth
; nX
++)
2434 for (nY
=0; nY
<nDestHeight
; nY
++)
2437 double fFinal
=fY
+fYdelta
;
2438 while ((fY
<fFinal
)&&((sint32
)fY
!=nSrcHeight
))
2440 double fNext
=(double)floor (fY
)+1.f
;
2443 vColor
+=((float)(fNext
-fY
))*pIterm
[((sint32
)floor(fY
))*nDestWidth
+nX
];
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
++)
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 /*-------------------------------------------------------------------*\
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;
2506 // TGA file header fields
2521 // Determining whether file is in Original or New TGA format
2523 uint32 extAreaOffset
;
2524 uint32 devDirectoryOffset
;
2528 if (f
.getPos() >= 26)
2530 f
.seek (-26, f
.end
);
2531 f
.serial(extAreaOffset
);
2532 f
.serial(devDirectoryOffset
);
2535 f
.serial(signature
[i
]);
2541 // Reading TGA file header
2542 f
.seek (0, f
.begin
);
2546 f
.serial(imageType
);
2554 f
.serial(imageDepth
);
2559 nlinfo("readTga : color-map not supported");
2565 for(i
=0; i
<lengthID
; i
++)
2571 // Reading TGA image data
2578 // Uncompressed RGB or RGBA
2581 _Data
[0].resize(_Width
*_Height
*4);
2582 uint8 upSideDown
= ((desc
& (1 << 5))==0);
2583 slsize
= _Width
* imageDepth
/ 8;
2585 scanline
= new uint8
[slsize
];
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)
2609 for(x
=0; x
<_Width
; x
++)
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
;
2624 for(i
=0; i
<width
; i
++)
2630 uint16 toto
= (uint16
)scanline
[k
++];
2631 toto
|= scanline
[k
++]<<8;
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;
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
++];
2646 _Data
[0][(height
-y
-1)*width
*4 + 4*i
+ 3] = scanline
[k
++];
2648 _Data
[0][(height
-y
-1)*width
*4 + 4*i
+ 3] = 255;
2655 uint16 toto
= (uint16
)scanline
[k
++];
2656 toto
|= scanline
[k
++]<<8;
2658 int _g
= toto
&(0x3e0)>>5;
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;
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
++];
2671 _Data
[0][y
*width
*4 + 4*i
+ 3] = scanline
[k
++];
2673 _Data
[0][y
*width
*4 + 4*i
+ 3] = 255;
2684 // Uncompressed Grayscale bitmap
2687 _Data
[0].resize(_Width
*_Height
);
2688 uint8 upSideDown
= ((desc
& (1 << 5))==0);
2691 scanline
= new uint8
[slsize
];
2694 throw EAllocationFailure();
2697 for(y
=0; y
<_Height
;y
++)
2699 // Serial buffer: more efficient way to load.
2700 f
.serialBuffer (scanline
, slsize
);
2703 for(i
=0; i
<width
; i
++)
2706 _Data
[0][(height
-y
-1)*width
+ i
] = scanline
[k
++];
2708 _Data
[0][y
*width
+ i
] = scanline
[k
++];
2712 PixelFormat
= _LoadGrayscaleAsAlpha
?Alpha
:Luminance
;
2717 // Compressed RGB or RGBA
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);
2728 while(readSize
< imageSize
)
2731 if((packet
& 0x80) > 0) // packet RLE
2733 for(i
=0; i
<imageDepth
/8; 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];
2747 for(i
=0; i
<((packet
& 0x7F) + 1); i
++)
2749 for(j
=0; j
<imageDepth
/8; 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;
2763 if (upSideDown
) flipV();
2767 // Compressed Grayscale bitmap (not tested)
2772 uint32 imageSize
= width
*height
;
2773 uint32 readSize
= 0;
2774 _Data
[0].resize(_Width
*_Height
);
2777 while(readSize
< imageSize
)
2780 if((packet
& 0x80) > 0) // packet RLE
2783 for (i
=0; i
< (packet
& 0x7F) + 1; i
++)
2785 _Data
[0][dstId
++]= pixel
[0];
2790 for(i
=0; i
<((packet
& 0x7F) + 1); i
++)
2793 _Data
[0][dstId
++]= pixel
[0];
2796 readSize
+= (packet
& 0x7F) + 1;
2798 PixelFormat
= _LoadGrayscaleAsAlpha
?Alpha
:Luminance
;
2811 /*-------------------------------------------------------------------*\
2813 \*-------------------------------------------------------------------*/
2814 bool CBitmap::writeTGA( NLMISC::IStream
&f
, uint32 d
, bool upsideDown
)
2816 if(f
.isReading()) return false;
2819 switch (PixelFormat
)
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;
2845 uint8 imageType
= 2;
2851 uint16 width
= (uint16
)_Width
;
2852 uint16 height
= (uint16
)_Height
;
2853 uint8 imageDepth
= (uint8
)d
;
2858 if ((PixelFormat
== Alpha
) || (PixelFormat
== Luminance
))
2859 imageType
= 3; // Uncompressed grayscale
2863 f
.serial(imageType
);
2871 f
.serial(imageDepth
);
2874 if ((PixelFormat
== Alpha
)||(PixelFormat
== Luminance
))
2875 scanline
= new uint8
[width
];
2877 scanline
= new uint8
[width
*4];
2880 throw EAllocationFailure();
2883 for(y
=0; y
<(sint32
)height
; y
++)
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
];
2902 for(i
=0; i
<width
*4; i
+=4) // 4:RGBA
2906 for(j
=0; j
<(sint32
)4; j
++)
2908 scanline
[k
++] = _Data
[0][(height
-y
-1)*width
*4 + i
+ j
];
2913 for(j
=0; j
<(sint32
)d
/8; j
++)
2915 scanline
[k
++] = _Data
[0][(height
-y
-1)*width
*4 + i
+ j
];
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];
2931 uint16 c16
= uint16((rr
<<10) | (gg
<<5) | bb
);
2932 scanline
[x
*2+0] = c16
&0xff;
2933 scanline
[x
*2+1] = c16
>>8;
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
;
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];
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
]);
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
++)
2981 uint dstY
=srcWidth
-x
-1;
2982 dst
[dstX
+dstY
*srcHeight
]=src
[x
+y
*srcWidth
];
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++)
2993 uint dstY=srcWidth-x;
2994 dst[dstX+dstY*srcHeight]=src[x+y*srcWidth];
2998 void CBitmap::rotateCCW()
3001 CObjectVector
<uint8
> copy
=_Data
[0];
3003 switch (PixelFormat
)
3006 NLMISC::rotateCCW ((uint32
*)&(_Data
[0][0]), (uint32
*)&(copy
[0]), _Width
, _Height
);
3010 NLMISC::rotateCCW (&_Data
[0][0], ©
[0], _Width
, _Height
);
3012 case AlphaLuminance
:
3013 NLMISC::rotateCCW ((uint16
*)&(_Data
[0][0]), (uint16
*)&(copy
[0]), _Width
, _Height
);;
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
);
3032 if (srcWidth
<= 0) return;
3036 if (srcX
+ srcWidth
> (sint
) src
.getWidth())
3038 srcWidth
= src
.getWidth() - srcX
;
3039 if (srcWidth
<= 0) return;
3044 if (srcWidth
<= 0) return;
3048 if (destX
+ srcWidth
> (sint
) getWidth())
3050 srcWidth
= getWidth() - destX
;
3051 if (srcWidth
<= 0) return;
3057 if (srcHeight
<= 0) return;
3061 if (srcY
+ srcHeight
> (sint
) src
.getHeight())
3063 srcHeight
= src
.getHeight() - srcY
;
3064 if (srcHeight
<= 0) return;
3069 if (srcHeight
<= 0) return;
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
)
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;
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
3135 if (width
<= 0) return true;
3149 if (height
<= 0) return true;
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
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
;
3208 for (sint k
= 0; k
< height
; ++k
)
3210 ::memcpy(destPos
, srcPos
, lineLength
);
3211 destPos
+= destStride
;
3212 srcPos
+= srcStride
;
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
);
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];
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]);
3265 nY
[2] = (nY
[0] < (nHeight
-1) ? nY
[0]+1 : nY
[0]);
3272 for (i
= 0; i
< 4; ++i
)
3274 nlassert (nX
[i
] >= 0);
3275 nlassert (nY
[i
] >= 0 );
3276 nlassert (nX
[i
] < nWidth
);
3277 nlassert (nY
[i
] < nHeight
);
3280 // Decimal part of (x,y)
3281 x
= x
- (float)nX
[0];
3282 y
= y
- (float)nY
[0];
3284 switch (this->PixelFormat
)
3295 if (this->PixelFormat
== RGBA
)
3297 for (i
= 0; i
< 4; ++i
)
3299 val
[i
] = CRGBA (rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+0],
3300 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+1],
3301 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+2],
3302 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+3]);
3307 // slower version : get from DXT
3308 for (i
= 0; i
< 4; ++i
)
3310 val
[i
] = getPixelColor(nX
[i
], nY
[i
]);
3314 finalVal
.R
= getColorInterp (x
, y
, val
[0].R
, val
[1].R
, val
[2].R
, val
[3].R
);
3315 finalVal
.G
= getColorInterp (x
, y
, val
[0].G
, val
[1].G
, val
[2].G
, val
[3].G
);
3316 finalVal
.B
= getColorInterp (x
, y
, val
[0].B
, val
[1].B
, val
[2].B
, val
[3].B
);
3317 finalVal
.A
= getColorInterp (x
, y
, val
[0].A
, val
[1].A
, val
[2].A
, val
[3].A
);
3330 for (i
= 0; i
< 4; ++i
)
3331 val
[i
] = rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)];
3333 finalVal
= getColorInterp (x
, y
, val
[0], val
[1], val
[2], val
[3]);
3336 if (this->PixelFormat
== Alpha
)
3337 return CRGBAF (1.f
, 1.f
, 1.f
, finalVal
);
3339 return CRGBAF (finalVal
, finalVal
, finalVal
, 1.f
);
3345 return CRGBAF (0.0f
, 0.0f
, 0.0f
, 0.0f
);
3348 // wrap a value inside the given range (for positive value it is like a modulo)
3349 static inline uint32
wrap(sint32 value
, uint32 range
)
3351 return value
>= 0 ? (value
% range
) : range
- 1 - (- value
- 1) % range
;
3355 CRGBAF
CBitmap::getColor(float x
, float y
, bool tileU
, bool tileV
) const
3357 sint32 nWidth
= getWidth(0);
3358 sint32 nHeight
= getHeight(0);
3359 if (nWidth
== 0 || nHeight
== 0) return CRGBAF(0, 0, 0, 0);
3361 sint32 nX
[4], nY
[4];
3365 if (x
< 0.0f
) x
= 0.0f
;
3366 if (x
> 1.0f
) x
= 1.0f
;
3368 nX
[0] = ((sint32
)floor(x
));
3369 nX
[1] = (nX
[0] < (nWidth
-1) ? nX
[0]+1 : nX
[0]);
3373 for (i
= 0; i
< 4; ++i
)
3375 nlassert (nX
[i
] >= 0);
3376 nlassert (nX
[i
] < nWidth
);
3382 nX
[0] = wrap((sint32
)floorf(x
), nWidth
);
3383 nX
[1] = wrap(nX
[0] + 1, nWidth
);
3390 if (y
< 0.0f
) y
= 0.0f
;
3391 if (y
> 1.0f
) y
= 1.0f
;
3393 nY
[0] = ((sint32
)floor(y
));
3395 nY
[2] = (nY
[0] < (nHeight
-1) ? nY
[0]+1 : nY
[0]);
3398 for (i
= 0; i
< 4; ++i
)
3400 nlassert (nY
[i
] >= 0 );
3401 nlassert (nY
[i
] < nHeight
);
3407 nY
[0] = wrap((sint32
)floorf(y
), nHeight
);
3409 nY
[2] = wrap(nY
[0] + 1, nHeight
);
3412 // Decimal part of (x,y)
3413 x
= x
- (float)nX
[0];
3414 y
= y
- (float)nY
[0];
3415 const CObjectVector
<uint8
> &rBitmap
= getPixels(0);
3416 switch (this->PixelFormat
)
3427 if (this->PixelFormat
== RGBA
)
3429 for (uint32 i
= 0; i
< 4; ++i
)
3431 val
[i
] = CRGBA (rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+0],
3432 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+1],
3433 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+2],
3434 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+3]);
3439 // slower version : get from DXT
3440 for (uint32 i
= 0; i
< 4; ++i
)
3442 val
[i
] = getPixelColor(nX
[i
], nY
[i
]);
3446 finalVal
.R
= getColorInterp (x
, y
, val
[0].R
, val
[1].R
, val
[2].R
, val
[3].R
);
3447 finalVal
.G
= getColorInterp (x
, y
, val
[0].G
, val
[1].G
, val
[2].G
, val
[3].G
);
3448 finalVal
.B
= getColorInterp (x
, y
, val
[0].B
, val
[1].B
, val
[2].B
, val
[3].B
);
3449 finalVal
.A
= getColorInterp (x
, y
, val
[0].A
, val
[1].A
, val
[2].A
, val
[3].A
);
3462 for (uint32 i
= 0; i
< 4; ++i
)
3463 val
[i
] = rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)];
3465 finalVal
= getColorInterp (x
, y
, val
[0], val
[1], val
[2], val
[3]);
3468 if (this->PixelFormat
== Alpha
)
3469 return CRGBAF (1.f
, 1.f
, 1.f
, finalVal
);
3471 return CRGBAF (finalVal
, finalVal
, finalVal
, 1.f
);
3476 return CRGBAF (0.0f
, 0.0f
, 0.0f
, 0.0f
);
3481 void CBitmap::loadSize(NLMISC::IStream
&f
, uint32
&retWidth
, uint32
&retHeight
)
3486 nlassert(f
.isReading());
3489 uint32 fileType
= 0;
3491 if(fileType
== DDS_HEADER
)
3493 // read entire DDS header.
3495 f
.serial(size
); // size in Bytes of header(without "DDS")
3496 uint32
* _DDSSurfaceDesc
= new uint32
[size
];
3497 _DDSSurfaceDesc
[0]= size
;
3499 for(uint i
= 0; i
<size
/4 - 1; i
++)
3501 f
.serial(_DDSSurfaceDesc
[i
+1]);
3504 // flags determines which members of the header structure contain valid data
3505 uint32 flags
= _DDSSurfaceDesc
[1];
3507 //verify if file have linearsize set
3508 if(!(flags
& DDSD_LINEARSIZE
))
3510 nlwarning("A DDS doesn't have the flag DDSD_LINEARSIZE");
3511 //delete [] _DDSSurfaceDesc;
3512 //throw EDDSBadHeader();
3515 //-------------- extracting and testing useful info
3516 retHeight
= _DDSSurfaceDesc
[2];
3517 retWidth
= _DDSSurfaceDesc
[3];
3519 delete [] _DDSSurfaceDesc
;
3521 else if(fileType
== PNG_HEADER
)
3523 // check second part of header
3524 f
.serialCheck(0x0a1a0a0d);
3526 uint32 chunkLength
= 0;
3527 uint32 chunkName
= 0;
3534 // length of chunk data
3535 f
.serial(chunkLength
);
3536 NLMISC_BSWAP32(chunkLength
);
3539 f
.serial(chunkName
);
3541 // size of image is a part of IHDR chunk
3542 if (chunkName
== NL_MAKEFOURCC('I', 'H', 'D', 'R'))
3546 NLMISC_BSWAP32(val
);
3550 NLMISC_BSWAP32(val
);
3555 // end of file chunk
3556 else if (chunkName
== NL_MAKEFOURCC('I', 'E', 'N', 'D'))
3561 // skip data of this chunk and CRC32
3562 f
.seek(chunkLength
+4, IStream::current
);
3571 else if(fileType
== JPG_HEADER
)
3573 uint8 blockMarker1
= 0;
3574 uint8 blockMarker2
= 0;
3575 uint16 blockSize
= 0;
3582 // marker of a block
3583 f
.serial(blockMarker1
);
3585 if (blockMarker1
== 0xff)
3587 // marker of a block
3588 f
.serial(blockMarker2
);
3590 // 0xff00 is only found in image data
3591 if (blockMarker2
== 0x00)
3595 // 0xffda is image data
3596 else if (blockMarker2
== 0xda)
3598 // next data is image data which must end with 0xffd9
3600 // 0xffd9 is the end of an image
3601 else if (blockMarker2
== 0xd9)
3606 else if (blockMarker2
== 0xdd || blockMarker2
== 0xdc)
3608 f
.seek(4, IStream::current
);
3610 else if (blockMarker2
== 0xdf)
3612 f
.seek(3, IStream::current
);
3614 else if (blockMarker2
>= 0xd0 && blockMarker2
<= 0xd8)
3621 f
.serial(blockSize
);
3622 NLMISC_BSWAP16(blockSize
);
3624 // frame marker (which contains image width and height)
3625 if (blockMarker2
>= 0xc0 && blockMarker2
<= 0xc3)
3627 uint8 imagePrecision
= 0; // sample precision
3628 uint32 imageSize
= 0; // width and height
3629 f
.serial(imagePrecision
);
3630 f
.serial(imageSize
);
3631 NLMISC_BSWAP32(imageSize
);
3633 retWidth
= imageSize
& 0xffff;
3634 retHeight
= (imageSize
& 0xffff0000) >> 16;
3640 f
.seek(blockSize
- 2, IStream::current
);
3651 else if(fileType
== GIF_HEADER
)
3653 // check second part of header ("7a" or "9a" in 'GIF89a')
3656 if (s
!= 0x6137 && s
!= 0x6139)
3658 nlwarning("Invalid GIF header, expected GIF87a or GIF89a");
3668 retHeight
= lsHeight
;
3670 // assuming it's TGA
3673 if(!f
.seek (0, NLMISC::IStream::begin
))
3675 throw ESeekFailed();
3679 // To make sure that the bitmap is TGA, we check imageType and imageDepth.
3695 f
.serial(imageType
);
3696 if(imageType
!=2 && imageType
!=3 && imageType
!=10 && imageType
!=11)
3698 nlwarning("Invalid TGA format, type %u in not supported (must be 2, 3, 10 or 11)", imageType
);
3701 f
.serial(tgaOrigin
);
3708 f
.serial(imageDepth
);
3709 if(imageDepth
!=8 && imageDepth
!=16 && imageDepth
!=24 && imageDepth
!=32)
3711 nlwarning("Invalid TGA format, bit depth %u in not supported (must be 8,16,24 or 32)", imageDepth
);
3716 // Ok, we have width and height.
3722 if(!f
.seek (0, NLMISC::IStream::begin
))
3724 throw ESeekFailed();
3729 void CBitmap::loadSize(const std::string
&path
, uint32
&retWidth
, uint32
&retHeight
)
3736 loadSize(f
, retWidth
, retHeight
);
3739 // ***************************************************************************
3740 void CBitmap::flipHDXTCBlockColor(uint8
*bitColor
, uint32 w
)
3742 // pack each line in a u32 (NB: the following works either in Little and Big Endian)
3743 uint32 bits
= *(uint32
*)bitColor
;
3745 // swap in X for each line
3749 res
= (bits
& 0xC0C0C0C0) >> 6;
3750 res
+= (bits
& 0x30303030) >> 2;
3751 res
+= (bits
& 0x0C0C0C0C) << 2;
3752 res
+= (bits
& 0x03030303) << 6;
3754 // special case where w==2
3757 res
= (bits
& 0x0C0C0C0C) >> 2;
3758 res
+= (bits
& 0x03030303) << 2;
3762 *((uint32
*)bitColor
)= res
;
3765 // ***************************************************************************
3766 void CBitmap::flipVDXTCBlockColor(uint8
*bitColor
, uint32 h
)
3768 // swap just bytes (work either in Little and Big Endian)
3771 std::swap(bitColor
[0], bitColor
[3]);
3772 std::swap(bitColor
[1], bitColor
[2]);
3774 // special case where h==2)
3777 // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
3778 std::swap(bitColor
[0], bitColor
[1]);
3782 // ***************************************************************************
3783 void CBitmap::flipHDXTCBlockAlpha3(uint8
*blockAlpha
, uint32 w
)
3785 #ifdef NL_LITTLE_ENDIAN
3786 uint64 bits
= *(uint64
*)blockAlpha
;
3788 uint64 bits
= (uint64
)blockAlpha
[0] + ((uint64
)blockAlpha
[1]<<8) +
3789 ((uint64
)blockAlpha
[2]<<16) + ((uint64
)blockAlpha
[3]<<24) +
3790 ((uint64
)blockAlpha
[4]<<32) + ((uint64
)blockAlpha
[5]<<40) +
3791 ((uint64
)blockAlpha
[6]<<48) + ((uint64
)blockAlpha
[7]<<56);
3794 // swap in X for each line
3798 res
= (bits
& INT64_CONSTANT(0xF000F000F000F000)) >> 12;
3799 res
+= (bits
& INT64_CONSTANT(0x0F000F000F000F00)) >> 4;
3800 res
+= (bits
& INT64_CONSTANT(0x00F000F000F000F0)) << 4;
3801 res
+= (bits
& INT64_CONSTANT(0x000F000F000F000F)) << 12;
3803 // special case where w==2
3806 res
= (bits
& INT64_CONSTANT(0x00F000F000F000F0)) >> 4;
3807 res
+= (bits
& INT64_CONSTANT(0x000F000F000F000F)) << 4;
3811 #ifdef NL_LITTLE_ENDIAN
3812 *((uint64
*)blockAlpha
)= res
;
3814 blockAlpha
[0]= res
& 255;
3815 blockAlpha
[1]= (res
>>8) & 255;
3816 blockAlpha
[2]= (res
>>16) & 255;
3817 blockAlpha
[3]= (res
>>24) & 255;
3818 blockAlpha
[4]= (res
>>32) & 255;
3819 blockAlpha
[5]= (res
>>40) & 255;
3820 blockAlpha
[6]= (res
>>48) & 255;
3821 blockAlpha
[7]= (res
>>56) & 255;
3825 // ***************************************************************************
3826 void CBitmap::flipVDXTCBlockAlpha3(uint8
*blockAlpha
, uint32 h
)
3828 uint16
*wAlpha
= (uint16
*)blockAlpha
;
3830 // swap just words (work either in Little and Big Endian)
3833 std::swap(wAlpha
[0], wAlpha
[3]);
3834 std::swap(wAlpha
[1], wAlpha
[2]);
3836 // special case where h==2)
3839 // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
3840 std::swap(wAlpha
[0], wAlpha
[1]);
3844 // ***************************************************************************
3845 void CBitmap::flipHDXTCBlockAlpha5(uint8
*bitAlpha
, uint32 w
)
3847 // pack into bits. Little Indian in all cases
3848 uint64 bits
= (uint64
)bitAlpha
[0] + ((uint64
)bitAlpha
[1]<<8) +
3849 ((uint64
)bitAlpha
[2]<<16) + ((uint64
)bitAlpha
[3]<<24) +
3850 ((uint64
)bitAlpha
[4]<<32) + ((uint64
)bitAlpha
[5]<<40);
3852 // swap in X for each line
3856 res
= (bits
& INT64_CONSTANT(0xE00E00E00E00)) >> 9;
3857 res
+= (bits
& INT64_CONSTANT(0x1C01C01C01C0)) >> 3;
3858 res
+= (bits
& INT64_CONSTANT(0x038038038038)) << 3;
3859 res
+= (bits
& INT64_CONSTANT(0x007007007007)) << 9;
3861 // special case where w==2
3864 res
= (bits
& INT64_CONSTANT(0x038038038038)) >> 3;
3865 res
+= (bits
& INT64_CONSTANT(0x007007007007)) << 3;
3868 // copy. Little Indian in all cases
3869 bitAlpha
[0]= uint8(res
& 255);
3870 bitAlpha
[1]= uint8((res
>>8) & 255);
3871 bitAlpha
[2]= uint8((res
>>16) & 255);
3872 bitAlpha
[3]= uint8((res
>>24) & 255);
3873 bitAlpha
[4]= uint8((res
>>32) & 255);
3874 bitAlpha
[5]= uint8((res
>>40) & 255);
3877 // ***************************************************************************
3878 void CBitmap::flipVDXTCBlockAlpha5(uint8
*bitAlpha
, uint32 h
)
3880 // pack into bits. Little Indian in all cases
3881 uint64 bits
= (uint64
)bitAlpha
[0] + ((uint64
)bitAlpha
[1]<<8) +
3882 ((uint64
)bitAlpha
[2]<<16) + ((uint64
)bitAlpha
[3]<<24) +
3883 ((uint64
)bitAlpha
[4]<<32) + ((uint64
)bitAlpha
[5]<<40);
3889 res
= (bits
& INT64_CONSTANT(0xFFF000000000)) >> 36;
3890 res
+= (bits
& INT64_CONSTANT(0x000FFF000000)) >> 12;
3891 res
+= (bits
& INT64_CONSTANT(0x000000FFF000)) << 12;
3892 res
+= (bits
& INT64_CONSTANT(0x000000000FFF)) << 36;
3894 // special case where h==2
3897 res
= (bits
& INT64_CONSTANT(0x000000FFF000)) >> 12;
3898 res
+= (bits
& INT64_CONSTANT(0x000000000FFF)) << 12;
3901 // copy. Little Indian in all cases
3902 bitAlpha
[0]= uint8(res
& 255);
3903 bitAlpha
[1]= uint8((res
>>8) & 255);
3904 bitAlpha
[2]= uint8((res
>>16) & 255);
3905 bitAlpha
[3]= uint8((res
>>24) & 255);
3906 bitAlpha
[4]= uint8((res
>>32) & 255);
3907 bitAlpha
[5]= uint8((res
>>40) & 255);
3910 // ***************************************************************************
3911 void CBitmap::flipDXTCMipMap(bool vertical
, uint mm
, uint type
)
3913 nlassert(mm
<MAX_MIPMAP
);
3914 // size of a DXTC block. 64 bits (2 U32) for DXTC1, else 128 bits (4*U32)
3915 uint blockSizeU32
= type
==1? 2 : 4;
3916 // get size in block
3917 sint32 width
= getWidth(mm
);
3918 sint32 height
= getHeight(mm
);
3919 if(width
==0 || height
==0)
3921 uint32 wBlock
= (width
+3)/4;
3922 uint32 hBlock
= (height
+3)/4;
3923 // get data ptr and check size.
3924 uint32
*data
= (uint32
*)(&_Data
[mm
][0]);
3925 nlassert(_Data
[mm
].size()==wBlock
*hBlock
*blockSizeU32
*4);
3927 // get the offset (in bytes) to the start of color pixels bits
3928 uint32 offsetColorBits
= type
==1? 4 : 12;
3930 // abort if swap is nonsense
3931 if(vertical
&& height
==1)
3933 if(!vertical
&& width
==1)
3936 // *** First reverse Blocks
3940 for(uint yBlock
=0;yBlock
<hBlock
/2;yBlock
++)
3942 uint32
*src0
= data
+ (yBlock
*wBlock
)*blockSizeU32
;
3943 uint32
*src1
= data
+ ((hBlock
-yBlock
-1)*wBlock
)*blockSizeU32
;
3944 for(uint xBlock
=0;xBlock
<wBlock
;xBlock
++, src0
+=blockSizeU32
, src1
+=blockSizeU32
)
3946 uint32
*block0
= src0
;
3947 uint32
*block1
= src1
;
3949 for(uint i
=0;i
<blockSizeU32
;i
++, block0
++, block1
++)
3951 std::swap(*block0
, *block1
);
3958 // reverse horizontal
3959 for(uint yBlock
=0;yBlock
<hBlock
;yBlock
++)
3961 uint32
*src0
= data
+ (yBlock
*wBlock
)*blockSizeU32
;
3962 uint32
*src1
= data
+ (yBlock
*wBlock
+ wBlock
-1)*blockSizeU32
;
3963 for(uint xBlock
=0;xBlock
<wBlock
/2;xBlock
++, src0
+=blockSizeU32
, src1
-=blockSizeU32
)
3965 uint32
*block0
= src0
;
3966 uint32
*block1
= src1
;
3968 for(uint i
=0;i
<blockSizeU32
;i
++, block0
++, block1
++)
3970 std::swap(*block0
, *block1
);
3976 // *** Then reverse Bits
3977 for(uint yBlock
=0;yBlock
<hBlock
;yBlock
++)
3979 uint32
*src
= data
+ (yBlock
*wBlock
)*blockSizeU32
;
3980 for(uint xBlock
=0;xBlock
<wBlock
;xBlock
++, src
+=blockSizeU32
)
3982 uint8
*block
= (uint8
*)src
;
3985 if(vertical
) flipVDXTCBlockColor(block
+offsetColorBits
, height
);
3986 else flipHDXTCBlockColor(block
+offsetColorBits
, width
);
3988 // flip alpha bits if any
3991 // point to the alpha part (16*4 bits)
3992 if(vertical
) flipVDXTCBlockAlpha3(block
, height
);
3993 else flipHDXTCBlockAlpha3(block
, width
);
3997 // point to the bit alpha part (16*3 bits)
3998 if(vertical
) flipVDXTCBlockAlpha5(block
+2, height
);
3999 else flipHDXTCBlockAlpha5(block
+2, width
);
4007 // ***************************************************************************
4008 void CBitmap::flipDXTC(bool vertical
)
4012 if(PixelFormat
== DXTC1
|| PixelFormat
== DXTC1Alpha
)
4014 else if(PixelFormat
== DXTC3
)
4016 else if(PixelFormat
== DXTC5
)
4021 // correct width/height?
4022 sint32 nWidth
= getWidth(0);
4023 sint32 nHeight
= getHeight(0);
4024 if(!isPowerOf2(nWidth
) || !isPowerOf2(nHeight
))
4028 for(uint mm
=0;mm
<_MipMapCount
;mm
++)
4030 flipDXTCMipMap(vertical
, mm
, type
);
4035 // ***************************************************************************
4036 void CBitmap::flipH()
4038 if (PixelFormat
!= RGBA
)
4043 // then quit (whether it worked or not)
4047 sint32 nWidth
= getWidth(0);
4048 sint32 nHeight
= getHeight(0);
4050 NLMISC::CRGBA
*pBitmap
= (NLMISC::CRGBA
*)&_Data
[0][0];
4051 bool needRebuild
= false;
4058 for( i
= 0; i
< nHeight
; ++i
)
4059 for( j
= 0; j
< nWidth
/2; ++j
)
4061 temp
= pBitmap
[i
*nWidth
+j
];
4062 pBitmap
[i
*nWidth
+j
] = pBitmap
[i
*nWidth
+nWidth
-j
-1];
4063 pBitmap
[i
*nWidth
+nWidth
-j
-1] = temp
;
4066 // Rebuilding mipmaps
4074 // ***************************************************************************
4075 void CBitmap::flipV()
4077 if (PixelFormat
!= RGBA
)
4082 // then quit (whether it worked or not)
4086 sint32 nWidth
= getWidth(0);
4087 sint32 nHeight
= getHeight(0);
4089 NLMISC::CRGBA
*pBitmap
= (NLMISC::CRGBA
*)&_Data
[0][0];
4090 bool needRebuild
= false;
4097 for( j
= 0; j
< nHeight
/2; ++j
)
4098 for( i
= 0; i
< nWidth
; ++i
)
4100 temp
= pBitmap
[j
*nWidth
+i
];
4101 pBitmap
[j
*nWidth
+i
] = pBitmap
[(nHeight
-j
-1)*nWidth
+i
];
4102 pBitmap
[(nHeight
-j
-1)*nWidth
+i
] = temp
;
4105 // Rebuilding mipmaps
4113 void CBitmap::rot90CW()
4115 if (PixelFormat
!= RGBA
)
4117 sint32 nWidth
= getWidth(0);
4118 sint32 nHeight
= getHeight(0);
4120 NLMISC::CRGBA
*pSrcRgba
= (NLMISC::CRGBA
*)&_Data
[0][0];
4121 bool needRebuild
= false;
4127 CObjectVector
<uint8
> pDestui
;
4128 pDestui
.resize(nWidth
*nHeight
*4);
4129 NLMISC::CRGBA
*pDestRgba
= (NLMISC::CRGBA
*)&pDestui
[0];
4131 for( j
= 0; j
< nHeight
; ++j
)
4132 for( i
= 0; i
< nWidth
; ++i
)
4133 pDestRgba
[j
+i
*nHeight
] = pSrcRgba
[i
+(nHeight
-1-j
)*nWidth
];
4135 uint32 nTemp
= _Width
;
4139 NLMISC::contReset(_Data
[0]); // free memory
4141 // Rebuilding mipmaps
4148 void CBitmap::rot90CCW()
4150 if (PixelFormat
!= RGBA
)
4152 sint32 nWidth
= getWidth(0);
4153 sint32 nHeight
= getHeight(0);
4155 NLMISC::CRGBA
*pSrcRgba
= (NLMISC::CRGBA
*)&_Data
[0][0];
4156 bool needRebuild
= false;
4162 CObjectVector
<uint8
> pDestui
;
4163 pDestui
.resize(nWidth
*nHeight
*4);
4164 NLMISC::CRGBA
*pDestRgba
= (NLMISC::CRGBA
*)&pDestui
[0];
4166 for( j
= 0; j
< nHeight
; ++j
)
4167 for( i
= 0; i
< nWidth
; ++i
)
4168 pDestRgba
[j
+i
*nHeight
] = pSrcRgba
[nWidth
-1-i
+j
*nWidth
];
4170 uint32 nTemp
= _Width
;
4174 NLMISC::contReset(_Data
[0]); // free memory
4176 // Rebuilding mipmaps
4183 //===========================================================================
4184 void CBitmap::blend(CBitmap
&Bm0
, CBitmap
&Bm1
, uint16 factor
, bool inputBitmapIsMutable
/*= false*/)
4186 nlassert(factor
<= 256);
4188 nlassert(Bm0
._Width
!= 0 && Bm0
._Height
!= 0
4189 && Bm1
._Width
!= 0 && Bm1
._Height
!= 0);
4191 nlassert(Bm0
._Width
== Bm1
._Width
); // the bitmap should have the same size
4192 nlassert(Bm0
._Height
== Bm1
._Height
);
4194 const CBitmap
*nBm0
, *nBm1
; // pointer to the bitmap that is used for blending, or to a copy is a conversion wa required
4196 CBitmap cp0
, cp1
; // these bitmap are copies of Bm1 and Bm0 if a conversion was needed
4198 if (Bm0
.PixelFormat
!= RGBA
)
4200 if (inputBitmapIsMutable
)
4202 Bm0
.convertToRGBA();
4208 cp0
.convertToRGBA();
4218 if (Bm1
.PixelFormat
!= RGBA
)
4220 if (inputBitmapIsMutable
)
4222 Bm1
.convertToRGBA();
4228 cp1
.convertToRGBA();
4237 if (this != nBm0
&& this != nBm1
)
4239 // if source is the same than the dets, don't resize because this clear the bitmap
4240 this->resize(Bm0
._Width
, Bm0
._Height
, RGBA
);
4243 uint numPix
= _Width
* _Height
; // 4 component per pixels
4246 const uint8
*src0
= &(nBm0
->_Data
[0][0]);
4247 const uint8
*src1
= &(nBm1
->_Data
[0][0]);
4248 uint8
*dest
= &(this->_Data
[0][0]);
4251 #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)
4252 if (CSystemInfo::hasMMX())
4254 // On a P4 2GHz, with a 256x256 texture, I got the following results :
4255 // without mmx : 5.2 ms
4256 // with mmx : 1.7 ms
4257 // I'm sure this can be further optimized..
4259 uint numPixLeft
= numPix
& 1; // process 2 pixels at once, so special case for odd number
4260 numPix
= numPix
& ~1;
4261 // do fast blend with mmx
4262 uint64 blendFactor0
;
4263 uint64 blendFactor1
;
4264 uint16
*bf0
= (uint16
*) &blendFactor0
;
4265 uint16
*bf1
= (uint16
*) &blendFactor1
;
4266 bf0
[0] = bf0
[1] = bf0
[2] = bf0
[3] = (1 << 6) * (factor
);
4267 bf1
[0] = bf1
[1] = bf1
[2] = bf1
[3] = (1 << 6) * (256 - factor
);
4275 shr ecx
, 1 // process pixels 2 by 2
4276 movq mm1
, blendFactor0
4277 movq mm0
, blendFactor1
4281 lea ebx
, [ebx
+ 8] // points next location
4283 movq mm2
, [esi
+ ebx
]
4284 movq mm3
, [eax
+ ebx
]
4286 punpckhbw mm7
, mm2
// mm7 contains src0 color 0 in high bytes
4287 punpckhbw mm6
, mm3
// mm6 contains src1 color 0 in high bytes
4289 pxor mm4
, mm4
// mm4 = 0
4291 pmulhw mm7
, mm0
// src0 = src0 * blendFactor
4292 pxor mm5
, mm5
// mm5 = 0
4293 pmulhw mm6
, mm1
// src1 = src1 * (1 - blendfactor)
4294 punpcklbw mm4
, mm2
// mm4 contains src0 color 1 in high bytes
4295 paddusw mm6
, mm7
// mm6 = src0[0] blended with src1[0]
4298 punpcklbw mm5
, mm3
// mm4 contains src1 color 1 in high bytes
4300 pmulhw mm4
, mm0
// src0 = src0 * blendFactor
4301 pmulhw mm5
, mm1
// src1 = src1 * (1 - blendfactor)
4302 paddusw mm4
, mm5
// mm6 = src0[1] blended with src1[1]
4307 movq
[edi
+ ebx
], mm4
// store result
4313 // case of odd number of pixels
4317 uint blendFact
= (uint
) factor
;
4318 uint invblendFact
= 256 - blendFact
;
4319 *dest
= (uint8
) (((blendFact
* *src1
) + (invblendFact
* *src0
)) >> 8);
4320 *(dest
+ 1) = (uint8
) (((blendFact
* *(src1
+ 1)) + (invblendFact
* *(src0
+ 1))) >> 8);
4321 *(dest
+ 2) = (uint8
) (((blendFact
* *(src1
+ 2)) + (invblendFact
* *(src0
+ 2))) >> 8);
4322 *(dest
+ 3) = (uint8
) (((blendFact
* *(src1
+ 3)) + (invblendFact
* *(src0
+ 3))) >> 8);
4326 #endif //#ifdef NL_OS_WINDOWS
4328 uint8
*endPix
= dest
+ ((ptrdiff_t)numPix
<< 2);
4330 uint blendFact
= (uint
) factor
;
4331 uint invblendFact
= 256 - blendFact
;
4334 /// blend 4 component at each pass
4335 *dest
= (uint8
) (((blendFact
* *src1
) + (invblendFact
* *src0
)) >> 8);
4336 *(dest
+ 1) = (uint8
) (((blendFact
* *(src1
+ 1)) + (invblendFact
* *(src0
+ 1))) >> 8);
4337 *(dest
+ 2) = (uint8
) (((blendFact
* *(src1
+ 2)) + (invblendFact
* *(src0
+ 2))) >> 8);
4338 *(dest
+ 3) = (uint8
) (((blendFact
* *(src1
+ 3)) + (invblendFact
* *(src0
+ 3))) >> 8);
4344 while (dest
!= endPix
);
4350 //-----------------------------------------------
4351 CRGBA
CBitmap::getRGBAPixel(sint x
, sint y
, uint32 numMipMap
/*=0*/) const
4353 uint w
= getWidth(numMipMap
);
4354 uint h
= getHeight(numMipMap
);
4355 if (w
== 0 || (uint
) x
>= w
|| (uint
) y
>= h
) return CRGBA::Black
; // include negative cases
4356 const uint8
*pix
= &getPixels(numMipMap
)[(x
+ y
* w
) << 2];
4357 return CRGBA(pix
[0], pix
[1], pix
[2], pix
[3]);
4360 //-----------------------------------------------
4361 CRGBA
CBitmap::getDXTCColorFromBlock(const uint8
*block
, sint x
, sint y
)
4365 memcpy(&col0
, block
, sizeof(uint16
));
4366 memcpy(&col1
, block
+ 2, sizeof(uint16
));
4367 uint colIndex
= (block
[4 + (y
& 3)] >> ((x
& 3) << 1)) & 3;
4368 CRGBA result
, c0
, c1
;
4374 uncompress(col0
, result
);
4377 uncompress(col1
, result
);
4380 uncompress(col0
, c0
);
4381 uncompress(col1
, c1
);
4382 result
.blendFromui(c0
, c1
, 85);
4385 uncompress(col0
, c0
);
4386 uncompress(col1
, c1
);
4387 result
.blendFromui(c0
, c1
, 171);
4399 uncompress(col0
, result
);
4403 uncompress(col1
, result
);
4407 uncompress(col0
, c0
);
4408 uncompress(col1
, c1
);
4409 result
.blendFromui(c0
, c1
, 128);
4413 result
.set(0, 0, 0, 0);
4420 //-----------------------------------------------
4421 CRGBA
CBitmap::getDXTC1Texel(sint x
, sint y
, uint32 numMipMap
) const
4423 uint w
= getWidth(numMipMap
);
4424 uint h
= getHeight(numMipMap
);
4425 if (w
== 0 || h
== 0 || (uint
) x
>= w
|| (uint
) y
>= h
) return CRGBA::Black
; // include negative cases
4426 uint numRowBlocks
= std::max((w
+ 3) >> 2, 1u);
4427 const uint8
*pix
= &getPixels(numMipMap
)[0];
4428 const uint8
*block
= pix
+ ((y
>> 2) * (numRowBlocks
<< 3) + ((x
>> 2) << 3));
4429 return getDXTCColorFromBlock(block
, x
, y
);
4433 //-----------------------------------------------
4434 CRGBA
CBitmap::getDXTC3Texel(sint x
, sint y
, uint32 numMipMap
) const
4436 uint w
= getWidth(numMipMap
);
4437 uint h
= getHeight(numMipMap
);
4438 if (w
== 0 || h
== 0 || (uint
) x
>= w
|| (uint
) y
>= h
) return CRGBA::Black
; // include negative cases
4439 uint numRowBlocks
= std::max((w
+ 3) >> 2, 1u);
4440 const uint8
*pix
= &getPixels(numMipMap
)[0];
4441 const uint8
*block
= pix
+ ((y
>> 2) * (numRowBlocks
<< 4) + ((x
>> 2) << 4));
4442 CRGBA result
= getDXTCColorFromBlock(block
+ 8, x
, y
);
4444 uint8 alphaByte
= block
[((y
& 3) << 1) + ((x
& 2) >> 1)];
4445 result
.A
= (x
& 1) ? (alphaByte
& 0xf0) : ((alphaByte
& 0x0f) << 4);
4449 //-----------------------------------------------
4450 CRGBA
CBitmap::getDXTC5Texel(sint x
, sint y
, uint32 numMipMap
) const
4452 uint w
= getWidth(numMipMap
);
4453 uint h
= getHeight(numMipMap
);
4454 if (w
== 0 || h
== 0 || (uint
) x
>= w
|| (uint
) y
>= h
) return CRGBA::Black
; // include negative cases
4455 uint numRowBlocks
= std::max((w
+ 3) >> 2, 1u);
4456 const uint8
*pix
= &getPixels(numMipMap
)[0];
4457 const uint8
*block
= pix
+ ((y
>> 2) * (numRowBlocks
<< 4) + ((x
>> 2) << 4));
4458 CRGBA result
= getDXTCColorFromBlock(block
+ 8, x
, y
);
4460 uint8 alpha0
= block
[0];
4461 uint8 alpha1
= block
[1];
4464 uint tripletIndex
= (x
& 3) + ((y
& 3) << 2);
4465 if (tripletIndex
< 8)
4467 alphaIndex
= (((uint32
&) block
[2]) >> (tripletIndex
* 3)) & 7;
4471 alphaIndex
= (((uint32
&) block
[5]) >> ((tripletIndex
- 8) * 3)) & 7; // we can read a dword there because there are color datas following he alpha datas
4474 if (alpha0
> alpha1
)
4478 case 0: result
.A
= alpha0
; break;
4479 case 1: result
.A
= alpha1
; break;
4480 case 2: result
.A
= (uint8
) ((6 * (uint
) alpha0
+ (uint
) alpha1
) / 7); break;
4481 case 3: result
.A
= (uint8
) ((5 * (uint
) alpha0
+ 2 * (uint
) alpha1
) / 7); break;
4482 case 4: result
.A
= (uint8
) ((4 * (uint
) alpha0
+ 3 * (uint
) alpha1
) / 7); break;
4483 case 5: result
.A
= (uint8
) ((3 * (uint
) alpha0
+ 4 * (uint
) alpha1
) / 7); break;
4484 case 6: result
.A
= (uint8
) ((2 * (uint
) alpha0
+ 5 * (uint
) alpha1
) / 7); break;
4485 case 7: result
.A
= (uint8
) (((uint
) alpha0
+ (uint
) 6 * alpha1
) / 7); break;
4492 case 0: result
.A
= alpha0
; break;
4493 case 1: result
.A
= alpha1
; break;
4494 case 2: result
.A
= (uint8
) ((4 * (uint
) alpha0
+ (uint
) alpha1
) / 5); break;
4495 case 3: result
.A
= (uint8
) ((3 * (uint
) alpha0
+ 2 * (uint
) alpha1
) / 5); break;
4496 case 4: result
.A
= (uint8
) ((2 * (uint
) alpha0
+ 3 * (uint
) alpha1
) / 5); break;
4497 case 5: result
.A
= (uint8
) (((uint
) alpha0
+ 4 * (uint
) alpha1
) / 5); break;
4498 case 6: result
.A
= 0; break;
4499 case 7: result
.A
= 255; break;
4506 //-----------------------------------------------
4507 CRGBA
CBitmap::getPixelColor(sint x
, sint y
, uint32 numMipMap
/*=0*/) const
4510 switch (PixelFormat
)
4513 return getRGBAPixel(x
, y
, numMipMap
);
4516 return getDXTC1Texel(x
, y
, numMipMap
);
4518 return getDXTC3Texel(x
, y
, numMipMap
);
4520 return getDXTC5Texel(x
, y
, numMipMap
);
4525 return CRGBA::Black
;
4528 //-----------------------------------------------
4529 void CBitmap::setPixelColor(sint x
, sint y
, CRGBA c
, uint32 numMipMap
)
4531 nlassert(PixelFormat
== RGBA
);
4533 uint w
= getWidth(numMipMap
);
4534 uint h
= getHeight(numMipMap
);
4536 if (w
== 0 || x
< 0 || y
< 0 || x
>= (sint
)w
|| y
>= (sint
)h
) return;
4538 uint8
*pix
= &getPixels(numMipMap
)[(x
+ y
* w
) << 2];
4540 memcpy(pix
, &c
, sizeof(CRGBA
));
4543 //-----------------------------------------------
4544 void CBitmap::swap(CBitmap
&other
)
4546 std::swap(PixelFormat
, other
.PixelFormat
);
4547 std::swap(_MipMapCount
, other
._MipMapCount
);
4548 std::swap(_LoadGrayscaleAsAlpha
, other
._LoadGrayscaleAsAlpha
);
4549 std::swap(_Width
, other
._Width
);
4550 std::swap(_Height
, other
._Height
);
4551 for(uint k
= 0; k
< MAX_MIPMAP
; ++k
)
4553 _Data
[k
].swap(other
._Data
[k
]);
4557 //-----------------------------------------------
4558 void CBitmap::unattachPixels(CObjectVector
<uint8
> *mipmapDestArray
, uint maxMipMapCount
/*=MAX_MIPMAP*/)
4560 if (!mipmapDestArray
) return;
4562 for(k
= 0; k
< std::min((uint
) _MipMapCount
, maxMipMapCount
); ++k
)
4564 mipmapDestArray
[k
].swap(_Data
[k
]);
4567 for(; k
< _MipMapCount
; ++k
)
4572 // check that remaining mipmaps are empty
4573 for(; k
< _MipMapCount
; ++k
)
4575 nlassert(_Data
[k
].empty());
4582 _LoadGrayscaleAsAlpha
= true;
4588 void CBitmap::getData(uint8
*& extractData
)
4592 if(PixelFormat
==RGBA
)
4593 size
=_Width
*_Height
*4;
4594 else if(PixelFormat
==Alpha
||PixelFormat
==Luminance
)
4595 size
=_Width
*_Height
;
4601 for(uint32 pix
=0;pix
<size
;pix
++)
4602 extractData
[pix
]=_Data
[0][pix
];
4606 void CBitmap::getDibData(uint8
*& extractData
)
4609 uint32 lineSize
=0,size
;
4611 buf
=new uint8
*[_Height
];
4612 if(PixelFormat
==RGBA
)
4618 else if(PixelFormat
==Alpha
||PixelFormat
==Luminance
)
4627 for(sint32 i
=_Height
-1;i
>=0;i
--)
4629 buf
[_Height
-1-i
]=&_Data
[0][i
*lineSize
];
4632 size
=lineSize
*_Height
;
4634 for(uint32 line
=0;line
<_Height
;line
++)
4636 for(uint32 pix
=0;pix
<lineSize
;pix
++)
4637 extractData
[line
*lineSize
+pix
]=_Data
[0][size
-(line
+1)*lineSize
+pix
];