1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2021 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 bool isValid
= true;
3273 for (i
= 0; i
< 4; ++i
)
3275 if (nX
[i
] < 0 || nY
[i
] < 0 || nX
[i
] >= nWidth
|| nY
[i
] >= nHeight
)
3281 // Decimal part of (x,y)
3282 x
= x
- (float)nX
[0];
3283 y
= y
- (float)nY
[0];
3285 switch (this->PixelFormat
)
3296 if (this->PixelFormat
== RGBA
)
3298 for (i
= 0; i
< 4; ++i
)
3300 val
[i
] = CRGBA (rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+0],
3301 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+1],
3302 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+2],
3303 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+3]);
3308 // slower version : get from DXT
3309 for (i
= 0; i
< 4; ++i
)
3311 val
[i
] = getPixelColor(nX
[i
], nY
[i
]);
3315 finalVal
.R
= getColorInterp (x
, y
, val
[0].R
, val
[1].R
, val
[2].R
, val
[3].R
);
3316 finalVal
.G
= getColorInterp (x
, y
, val
[0].G
, val
[1].G
, val
[2].G
, val
[3].G
);
3317 finalVal
.B
= getColorInterp (x
, y
, val
[0].B
, val
[1].B
, val
[2].B
, val
[3].B
);
3318 finalVal
.A
= getColorInterp (x
, y
, val
[0].A
, val
[1].A
, val
[2].A
, val
[3].A
);
3331 for (i
= 0; i
< 4; ++i
)
3332 val
[i
] = rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)];
3334 finalVal
= getColorInterp (x
, y
, val
[0], val
[1], val
[2], val
[3]);
3337 if (this->PixelFormat
== Alpha
)
3338 return CRGBAF (1.f
, 1.f
, 1.f
, finalVal
);
3340 return CRGBAF (finalVal
, finalVal
, finalVal
, 1.f
);
3347 return CRGBAF (0.0f
, 0.0f
, 0.0f
, 0.0f
);
3350 // wrap a value inside the given range (for positive value it is like a modulo)
3351 static inline uint32
wrap(sint32 value
, uint32 range
)
3353 return value
>= 0 ? (value
% range
) : range
- 1 - (- value
- 1) % range
;
3357 CRGBAF
CBitmap::getColor(float x
, float y
, bool tileU
, bool tileV
) const
3359 sint32 nWidth
= getWidth(0);
3360 sint32 nHeight
= getHeight(0);
3361 if (nWidth
== 0 || nHeight
== 0) return CRGBAF(0, 0, 0, 0);
3363 sint32 nX
[4], nY
[4];
3367 if (x
< 0.0f
) x
= 0.0f
;
3368 if (x
> 1.0f
) x
= 1.0f
;
3370 nX
[0] = ((sint32
)floor(x
));
3371 nX
[1] = (nX
[0] < (nWidth
-1) ? nX
[0]+1 : nX
[0]);
3375 for (i
= 0; i
< 4; ++i
)
3377 nlassert (nX
[i
] >= 0);
3378 nlassert (nX
[i
] < nWidth
);
3384 nX
[0] = wrap((sint32
)floorf(x
), nWidth
);
3385 nX
[1] = wrap(nX
[0] + 1, nWidth
);
3392 if (y
< 0.0f
) y
= 0.0f
;
3393 if (y
> 1.0f
) y
= 1.0f
;
3395 nY
[0] = ((sint32
)floor(y
));
3397 nY
[2] = (nY
[0] < (nHeight
-1) ? nY
[0]+1 : nY
[0]);
3400 for (i
= 0; i
< 4; ++i
)
3402 nlassert (nY
[i
] >= 0 );
3403 nlassert (nY
[i
] < nHeight
);
3409 nY
[0] = wrap((sint32
)floorf(y
), nHeight
);
3411 nY
[2] = wrap(nY
[0] + 1, nHeight
);
3414 // Decimal part of (x,y)
3415 x
= x
- (float)nX
[0];
3416 y
= y
- (float)nY
[0];
3417 const CObjectVector
<uint8
> &rBitmap
= getPixels(0);
3418 switch (this->PixelFormat
)
3429 if (this->PixelFormat
== RGBA
)
3431 for (uint32 i
= 0; i
< 4; ++i
)
3433 val
[i
] = CRGBA (rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+0],
3434 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+1],
3435 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+2],
3436 rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)*4+3]);
3441 // slower version : get from DXT
3442 for (uint32 i
= 0; i
< 4; ++i
)
3444 val
[i
] = getPixelColor(nX
[i
], nY
[i
]);
3448 finalVal
.R
= getColorInterp (x
, y
, val
[0].R
, val
[1].R
, val
[2].R
, val
[3].R
);
3449 finalVal
.G
= getColorInterp (x
, y
, val
[0].G
, val
[1].G
, val
[2].G
, val
[3].G
);
3450 finalVal
.B
= getColorInterp (x
, y
, val
[0].B
, val
[1].B
, val
[2].B
, val
[3].B
);
3451 finalVal
.A
= getColorInterp (x
, y
, val
[0].A
, val
[1].A
, val
[2].A
, val
[3].A
);
3464 for (uint32 i
= 0; i
< 4; ++i
)
3465 val
[i
] = rBitmap
[(nX
[i
]+nY
[i
]*nWidth
)];
3467 finalVal
= getColorInterp (x
, y
, val
[0], val
[1], val
[2], val
[3]);
3470 if (this->PixelFormat
== Alpha
)
3471 return CRGBAF (1.f
, 1.f
, 1.f
, finalVal
);
3473 return CRGBAF (finalVal
, finalVal
, finalVal
, 1.f
);
3478 return CRGBAF (0.0f
, 0.0f
, 0.0f
, 0.0f
);
3483 void CBitmap::loadSize(NLMISC::IStream
&f
, uint32
&retWidth
, uint32
&retHeight
)
3488 nlassert(f
.isReading());
3491 uint32 fileType
= 0;
3493 if(fileType
== DDS_HEADER
)
3495 // read entire DDS header.
3497 f
.serial(size
); // size in Bytes of header(without "DDS")
3498 uint32
* _DDSSurfaceDesc
= new uint32
[size
];
3499 _DDSSurfaceDesc
[0]= size
;
3501 for(uint i
= 0; i
<size
/4 - 1; i
++)
3503 f
.serial(_DDSSurfaceDesc
[i
+1]);
3506 // flags determines which members of the header structure contain valid data
3507 uint32 flags
= _DDSSurfaceDesc
[1];
3509 //verify if file have linearsize set
3510 if(!(flags
& DDSD_LINEARSIZE
))
3512 nlwarning("A DDS doesn't have the flag DDSD_LINEARSIZE");
3513 //delete [] _DDSSurfaceDesc;
3514 //throw EDDSBadHeader();
3517 //-------------- extracting and testing useful info
3518 retHeight
= _DDSSurfaceDesc
[2];
3519 retWidth
= _DDSSurfaceDesc
[3];
3521 delete [] _DDSSurfaceDesc
;
3523 else if(fileType
== PNG_HEADER
)
3525 // check second part of header
3526 f
.serialCheck(0x0a1a0a0d);
3528 uint32 chunkLength
= 0;
3529 uint32 chunkName
= 0;
3536 // length of chunk data
3537 f
.serial(chunkLength
);
3538 NLMISC_BSWAP32(chunkLength
);
3541 f
.serial(chunkName
);
3543 // size of image is a part of IHDR chunk
3544 if (chunkName
== NL_MAKEFOURCC('I', 'H', 'D', 'R'))
3548 NLMISC_BSWAP32(val
);
3552 NLMISC_BSWAP32(val
);
3557 // end of file chunk
3558 else if (chunkName
== NL_MAKEFOURCC('I', 'E', 'N', 'D'))
3563 // skip data of this chunk and CRC32
3564 f
.seek(chunkLength
+4, IStream::current
);
3573 else if(memcmp(&fileType
, &JPG_HEADER
, 2) == 0)
3575 uint8 blockMarker1
= 0;
3576 uint8 blockMarker2
= 0;
3577 uint16 blockSize
= 0;
3584 // marker of a block
3585 f
.serial(blockMarker1
);
3587 if (blockMarker1
== 0xff)
3589 // marker of a block
3590 f
.serial(blockMarker2
);
3592 // 0xff00 is only found in image data
3593 if (blockMarker2
== 0x00)
3597 // 0xffda is image data
3598 else if (blockMarker2
== 0xda)
3600 // next data is image data which must end with 0xffd9
3602 // 0xffd9 is the end of an image
3603 else if (blockMarker2
== 0xd9)
3608 else if (blockMarker2
== 0xdd || blockMarker2
== 0xdc)
3610 f
.seek(4, IStream::current
);
3612 else if (blockMarker2
== 0xdf)
3614 f
.seek(3, IStream::current
);
3616 else if (blockMarker2
>= 0xd0 && blockMarker2
<= 0xd8)
3623 f
.serial(blockSize
);
3624 NLMISC_BSWAP16(blockSize
);
3626 // frame marker (which contains image width and height)
3627 if (blockMarker2
>= 0xc0 && blockMarker2
<= 0xc3)
3629 uint8 imagePrecision
= 0; // sample precision
3630 uint32 imageSize
= 0; // width and height
3631 f
.serial(imagePrecision
);
3632 f
.serial(imageSize
);
3633 NLMISC_BSWAP32(imageSize
);
3635 retWidth
= imageSize
& 0xffff;
3636 retHeight
= (imageSize
& 0xffff0000) >> 16;
3642 f
.seek(blockSize
- 2, IStream::current
);
3653 else if(fileType
== GIF_HEADER
)
3655 // check second part of header ("7a" or "9a" in 'GIF89a')
3658 if (s
!= 0x6137 && s
!= 0x6139)
3660 nlwarning("Invalid GIF header, expected GIF87a or GIF89a");
3670 retHeight
= lsHeight
;
3672 // assuming it's TGA
3675 if(!f
.seek (0, NLMISC::IStream::begin
))
3677 throw ESeekFailed();
3681 // To make sure that the bitmap is TGA, we check imageType and imageDepth.
3697 f
.serial(imageType
);
3698 if(imageType
!=2 && imageType
!=3 && imageType
!=10 && imageType
!=11)
3700 nlwarning("Invalid TGA format, type %u in not supported (must be 2, 3, 10 or 11)", imageType
);
3703 f
.serial(tgaOrigin
);
3710 f
.serial(imageDepth
);
3711 if(imageDepth
!=8 && imageDepth
!=16 && imageDepth
!=24 && imageDepth
!=32)
3713 nlwarning("Invalid TGA format, bit depth %u in not supported (must be 8,16,24 or 32)", imageDepth
);
3718 // Ok, we have width and height.
3724 if(!f
.seek (0, NLMISC::IStream::begin
))
3726 throw ESeekFailed();
3731 void CBitmap::loadSize(const std::string
&path
, uint32
&retWidth
, uint32
&retHeight
)
3738 loadSize(f
, retWidth
, retHeight
);
3741 // ***************************************************************************
3742 void CBitmap::flipHDXTCBlockColor(uint8
*bitColor
, uint32 w
)
3744 // pack each line in a u32 (NB: the following works either in Little and Big Endian)
3745 uint32 bits
= *(uint32
*)bitColor
;
3747 // swap in X for each line
3751 res
= (bits
& 0xC0C0C0C0) >> 6;
3752 res
+= (bits
& 0x30303030) >> 2;
3753 res
+= (bits
& 0x0C0C0C0C) << 2;
3754 res
+= (bits
& 0x03030303) << 6;
3756 // special case where w==2
3759 res
= (bits
& 0x0C0C0C0C) >> 2;
3760 res
+= (bits
& 0x03030303) << 2;
3764 *((uint32
*)bitColor
)= res
;
3767 // ***************************************************************************
3768 void CBitmap::flipVDXTCBlockColor(uint8
*bitColor
, uint32 h
)
3770 // swap just bytes (work either in Little and Big Endian)
3773 std::swap(bitColor
[0], bitColor
[3]);
3774 std::swap(bitColor
[1], bitColor
[2]);
3776 // special case where h==2)
3779 // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
3780 std::swap(bitColor
[0], bitColor
[1]);
3784 // ***************************************************************************
3785 void CBitmap::flipHDXTCBlockAlpha3(uint8
*blockAlpha
, uint32 w
)
3787 #ifdef NL_LITTLE_ENDIAN
3788 uint64 bits
= *(uint64
*)blockAlpha
;
3790 uint64 bits
= (uint64
)blockAlpha
[0] + ((uint64
)blockAlpha
[1]<<8) +
3791 ((uint64
)blockAlpha
[2]<<16) + ((uint64
)blockAlpha
[3]<<24) +
3792 ((uint64
)blockAlpha
[4]<<32) + ((uint64
)blockAlpha
[5]<<40) +
3793 ((uint64
)blockAlpha
[6]<<48) + ((uint64
)blockAlpha
[7]<<56);
3796 // swap in X for each line
3800 res
= (bits
& INT64_CONSTANT(0xF000F000F000F000)) >> 12;
3801 res
+= (bits
& INT64_CONSTANT(0x0F000F000F000F00)) >> 4;
3802 res
+= (bits
& INT64_CONSTANT(0x00F000F000F000F0)) << 4;
3803 res
+= (bits
& INT64_CONSTANT(0x000F000F000F000F)) << 12;
3805 // special case where w==2
3808 res
= (bits
& INT64_CONSTANT(0x00F000F000F000F0)) >> 4;
3809 res
+= (bits
& INT64_CONSTANT(0x000F000F000F000F)) << 4;
3813 #ifdef NL_LITTLE_ENDIAN
3814 *((uint64
*)blockAlpha
)= res
;
3816 blockAlpha
[0]= res
& 255;
3817 blockAlpha
[1]= (res
>>8) & 255;
3818 blockAlpha
[2]= (res
>>16) & 255;
3819 blockAlpha
[3]= (res
>>24) & 255;
3820 blockAlpha
[4]= (res
>>32) & 255;
3821 blockAlpha
[5]= (res
>>40) & 255;
3822 blockAlpha
[6]= (res
>>48) & 255;
3823 blockAlpha
[7]= (res
>>56) & 255;
3827 // ***************************************************************************
3828 void CBitmap::flipVDXTCBlockAlpha3(uint8
*blockAlpha
, uint32 h
)
3830 uint16
*wAlpha
= (uint16
*)blockAlpha
;
3832 // swap just words (work either in Little and Big Endian)
3835 std::swap(wAlpha
[0], wAlpha
[3]);
3836 std::swap(wAlpha
[1], wAlpha
[2]);
3838 // special case where h==2)
3841 // whatever Little or Big endian, the first byte is the first line, and the second byte is the second line
3842 std::swap(wAlpha
[0], wAlpha
[1]);
3846 // ***************************************************************************
3847 void CBitmap::flipHDXTCBlockAlpha5(uint8
*bitAlpha
, uint32 w
)
3849 // pack into bits. Little Indian in all cases
3850 uint64 bits
= (uint64
)bitAlpha
[0] + ((uint64
)bitAlpha
[1]<<8) +
3851 ((uint64
)bitAlpha
[2]<<16) + ((uint64
)bitAlpha
[3]<<24) +
3852 ((uint64
)bitAlpha
[4]<<32) + ((uint64
)bitAlpha
[5]<<40);
3854 // swap in X for each line
3858 res
= (bits
& INT64_CONSTANT(0xE00E00E00E00)) >> 9;
3859 res
+= (bits
& INT64_CONSTANT(0x1C01C01C01C0)) >> 3;
3860 res
+= (bits
& INT64_CONSTANT(0x038038038038)) << 3;
3861 res
+= (bits
& INT64_CONSTANT(0x007007007007)) << 9;
3863 // special case where w==2
3866 res
= (bits
& INT64_CONSTANT(0x038038038038)) >> 3;
3867 res
+= (bits
& INT64_CONSTANT(0x007007007007)) << 3;
3870 // copy. Little Indian in all cases
3871 bitAlpha
[0]= uint8(res
& 255);
3872 bitAlpha
[1]= uint8((res
>>8) & 255);
3873 bitAlpha
[2]= uint8((res
>>16) & 255);
3874 bitAlpha
[3]= uint8((res
>>24) & 255);
3875 bitAlpha
[4]= uint8((res
>>32) & 255);
3876 bitAlpha
[5]= uint8((res
>>40) & 255);
3879 // ***************************************************************************
3880 void CBitmap::flipVDXTCBlockAlpha5(uint8
*bitAlpha
, uint32 h
)
3882 // pack into bits. Little Indian in all cases
3883 uint64 bits
= (uint64
)bitAlpha
[0] + ((uint64
)bitAlpha
[1]<<8) +
3884 ((uint64
)bitAlpha
[2]<<16) + ((uint64
)bitAlpha
[3]<<24) +
3885 ((uint64
)bitAlpha
[4]<<32) + ((uint64
)bitAlpha
[5]<<40);
3891 res
= (bits
& INT64_CONSTANT(0xFFF000000000)) >> 36;
3892 res
+= (bits
& INT64_CONSTANT(0x000FFF000000)) >> 12;
3893 res
+= (bits
& INT64_CONSTANT(0x000000FFF000)) << 12;
3894 res
+= (bits
& INT64_CONSTANT(0x000000000FFF)) << 36;
3896 // special case where h==2
3899 res
= (bits
& INT64_CONSTANT(0x000000FFF000)) >> 12;
3900 res
+= (bits
& INT64_CONSTANT(0x000000000FFF)) << 12;
3903 // copy. Little Indian in all cases
3904 bitAlpha
[0]= uint8(res
& 255);
3905 bitAlpha
[1]= uint8((res
>>8) & 255);
3906 bitAlpha
[2]= uint8((res
>>16) & 255);
3907 bitAlpha
[3]= uint8((res
>>24) & 255);
3908 bitAlpha
[4]= uint8((res
>>32) & 255);
3909 bitAlpha
[5]= uint8((res
>>40) & 255);
3912 // ***************************************************************************
3913 void CBitmap::flipDXTCMipMap(bool vertical
, uint mm
, uint type
)
3915 nlassert(mm
<MAX_MIPMAP
);
3916 // size of a DXTC block. 64 bits (2 U32) for DXTC1, else 128 bits (4*U32)
3917 uint blockSizeU32
= type
==1? 2 : 4;
3918 // get size in block
3919 sint32 width
= getWidth(mm
);
3920 sint32 height
= getHeight(mm
);
3921 if(width
==0 || height
==0)
3923 uint32 wBlock
= (width
+3)/4;
3924 uint32 hBlock
= (height
+3)/4;
3925 // get data ptr and check size.
3926 uint32
*data
= (uint32
*)(&_Data
[mm
][0]);
3927 nlassert(_Data
[mm
].size()==wBlock
*hBlock
*blockSizeU32
*4);
3929 // get the offset (in bytes) to the start of color pixels bits
3930 uint32 offsetColorBits
= type
==1? 4 : 12;
3932 // abort if swap is nonsense
3933 if(vertical
&& height
==1)
3935 if(!vertical
&& width
==1)
3938 // *** First reverse Blocks
3942 for(uint yBlock
=0;yBlock
<hBlock
/2;yBlock
++)
3944 uint32
*src0
= data
+ (yBlock
*wBlock
)*blockSizeU32
;
3945 uint32
*src1
= data
+ ((hBlock
-yBlock
-1)*wBlock
)*blockSizeU32
;
3946 for(uint xBlock
=0;xBlock
<wBlock
;xBlock
++, src0
+=blockSizeU32
, src1
+=blockSizeU32
)
3948 uint32
*block0
= src0
;
3949 uint32
*block1
= src1
;
3951 for(uint i
=0;i
<blockSizeU32
;i
++, block0
++, block1
++)
3953 std::swap(*block0
, *block1
);
3960 // reverse horizontal
3961 for(uint yBlock
=0;yBlock
<hBlock
;yBlock
++)
3963 uint32
*src0
= data
+ (yBlock
*wBlock
)*blockSizeU32
;
3964 uint32
*src1
= data
+ (yBlock
*wBlock
+ wBlock
-1)*blockSizeU32
;
3965 for(uint xBlock
=0;xBlock
<wBlock
/2;xBlock
++, src0
+=blockSizeU32
, src1
-=blockSizeU32
)
3967 uint32
*block0
= src0
;
3968 uint32
*block1
= src1
;
3970 for(uint i
=0;i
<blockSizeU32
;i
++, block0
++, block1
++)
3972 std::swap(*block0
, *block1
);
3978 // *** Then reverse Bits
3979 for(uint yBlock
=0;yBlock
<hBlock
;yBlock
++)
3981 uint32
*src
= data
+ (yBlock
*wBlock
)*blockSizeU32
;
3982 for(uint xBlock
=0;xBlock
<wBlock
;xBlock
++, src
+=blockSizeU32
)
3984 uint8
*block
= (uint8
*)src
;
3987 if(vertical
) flipVDXTCBlockColor(block
+offsetColorBits
, height
);
3988 else flipHDXTCBlockColor(block
+offsetColorBits
, width
);
3990 // flip alpha bits if any
3993 // point to the alpha part (16*4 bits)
3994 if(vertical
) flipVDXTCBlockAlpha3(block
, height
);
3995 else flipHDXTCBlockAlpha3(block
, width
);
3999 // point to the bit alpha part (16*3 bits)
4000 if(vertical
) flipVDXTCBlockAlpha5(block
+2, height
);
4001 else flipHDXTCBlockAlpha5(block
+2, width
);
4009 // ***************************************************************************
4010 void CBitmap::flipDXTC(bool vertical
)
4014 if(PixelFormat
== DXTC1
|| PixelFormat
== DXTC1Alpha
)
4016 else if(PixelFormat
== DXTC3
)
4018 else if(PixelFormat
== DXTC5
)
4023 // correct width/height?
4024 sint32 nWidth
= getWidth(0);
4025 sint32 nHeight
= getHeight(0);
4026 if(!isPowerOf2(nWidth
) || !isPowerOf2(nHeight
))
4030 for(uint mm
=0;mm
<_MipMapCount
;mm
++)
4032 flipDXTCMipMap(vertical
, mm
, type
);
4037 // ***************************************************************************
4038 void CBitmap::flipH()
4040 if (PixelFormat
!= RGBA
)
4045 // then quit (whether it worked or not)
4049 sint32 nWidth
= getWidth(0);
4050 sint32 nHeight
= getHeight(0);
4052 NLMISC::CRGBA
*pBitmap
= (NLMISC::CRGBA
*)&_Data
[0][0];
4053 bool needRebuild
= false;
4060 for( i
= 0; i
< nHeight
; ++i
)
4061 for( j
= 0; j
< nWidth
/2; ++j
)
4063 temp
= pBitmap
[i
*nWidth
+j
];
4064 pBitmap
[i
*nWidth
+j
] = pBitmap
[i
*nWidth
+nWidth
-j
-1];
4065 pBitmap
[i
*nWidth
+nWidth
-j
-1] = temp
;
4068 // Rebuilding mipmaps
4076 // ***************************************************************************
4077 void CBitmap::flipV()
4079 if (PixelFormat
!= RGBA
)
4084 // then quit (whether it worked or not)
4088 sint32 nWidth
= getWidth(0);
4089 sint32 nHeight
= getHeight(0);
4091 NLMISC::CRGBA
*pBitmap
= (NLMISC::CRGBA
*)&_Data
[0][0];
4092 bool needRebuild
= false;
4099 for( j
= 0; j
< nHeight
/2; ++j
)
4100 for( i
= 0; i
< nWidth
; ++i
)
4102 temp
= pBitmap
[j
*nWidth
+i
];
4103 pBitmap
[j
*nWidth
+i
] = pBitmap
[(nHeight
-j
-1)*nWidth
+i
];
4104 pBitmap
[(nHeight
-j
-1)*nWidth
+i
] = temp
;
4107 // Rebuilding mipmaps
4115 void CBitmap::rot90CW()
4117 if (PixelFormat
!= RGBA
)
4119 sint32 nWidth
= getWidth(0);
4120 sint32 nHeight
= getHeight(0);
4122 NLMISC::CRGBA
*pSrcRgba
= (NLMISC::CRGBA
*)&_Data
[0][0];
4123 bool needRebuild
= false;
4129 CObjectVector
<uint8
> pDestui
;
4130 pDestui
.resize(nWidth
*nHeight
*4);
4131 NLMISC::CRGBA
*pDestRgba
= (NLMISC::CRGBA
*)&pDestui
[0];
4133 for( j
= 0; j
< nHeight
; ++j
)
4134 for( i
= 0; i
< nWidth
; ++i
)
4135 pDestRgba
[j
+i
*nHeight
] = pSrcRgba
[i
+(nHeight
-1-j
)*nWidth
];
4137 uint32 nTemp
= _Width
;
4141 NLMISC::contReset(_Data
[0]); // free memory
4143 // Rebuilding mipmaps
4150 void CBitmap::rot90CCW()
4152 if (PixelFormat
!= RGBA
)
4154 sint32 nWidth
= getWidth(0);
4155 sint32 nHeight
= getHeight(0);
4157 NLMISC::CRGBA
*pSrcRgba
= (NLMISC::CRGBA
*)&_Data
[0][0];
4158 bool needRebuild
= false;
4164 CObjectVector
<uint8
> pDestui
;
4165 pDestui
.resize(nWidth
*nHeight
*4);
4166 NLMISC::CRGBA
*pDestRgba
= (NLMISC::CRGBA
*)&pDestui
[0];
4168 for( j
= 0; j
< nHeight
; ++j
)
4169 for( i
= 0; i
< nWidth
; ++i
)
4170 pDestRgba
[j
+i
*nHeight
] = pSrcRgba
[nWidth
-1-i
+j
*nWidth
];
4172 uint32 nTemp
= _Width
;
4176 NLMISC::contReset(_Data
[0]); // free memory
4178 // Rebuilding mipmaps
4185 //===========================================================================
4186 void CBitmap::blend(CBitmap
&Bm0
, CBitmap
&Bm1
, uint16 factor
, bool inputBitmapIsMutable
/*= false*/)
4188 nlassert(factor
<= 256);
4190 nlassert(Bm0
._Width
!= 0 && Bm0
._Height
!= 0
4191 && Bm1
._Width
!= 0 && Bm1
._Height
!= 0);
4193 nlassert(Bm0
._Width
== Bm1
._Width
); // the bitmap should have the same size
4194 nlassert(Bm0
._Height
== Bm1
._Height
);
4196 const CBitmap
*nBm0
, *nBm1
; // pointer to the bitmap that is used for blending, or to a copy is a conversion wa required
4198 CBitmap cp0
, cp1
; // these bitmap are copies of Bm1 and Bm0 if a conversion was needed
4200 if (Bm0
.PixelFormat
!= RGBA
)
4202 if (inputBitmapIsMutable
)
4204 Bm0
.convertToRGBA();
4210 cp0
.convertToRGBA();
4220 if (Bm1
.PixelFormat
!= RGBA
)
4222 if (inputBitmapIsMutable
)
4224 Bm1
.convertToRGBA();
4230 cp1
.convertToRGBA();
4239 if (this != nBm0
&& this != nBm1
)
4241 // if source is the same than the dets, don't resize because this clear the bitmap
4242 this->resize(Bm0
._Width
, Bm0
._Height
, RGBA
);
4245 uint numPix
= _Width
* _Height
; // 4 component per pixels
4248 const uint8
*src0
= &(nBm0
->_Data
[0][0]);
4249 const uint8
*src1
= &(nBm1
->_Data
[0][0]);
4250 uint8
*dest
= &(this->_Data
[0][0]);
4253 #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)
4254 if (CSystemInfo::hasMMX())
4256 // On a P4 2GHz, with a 256x256 texture, I got the following results :
4257 // without mmx : 5.2 ms
4258 // with mmx : 1.7 ms
4259 // I'm sure this can be further optimized..
4261 uint numPixLeft
= numPix
& 1; // process 2 pixels at once, so special case for odd number
4262 numPix
= numPix
& ~1;
4263 // do fast blend with mmx
4264 uint64 blendFactor0
;
4265 uint64 blendFactor1
;
4266 uint16
*bf0
= (uint16
*) &blendFactor0
;
4267 uint16
*bf1
= (uint16
*) &blendFactor1
;
4268 bf0
[0] = bf0
[1] = bf0
[2] = bf0
[3] = (1 << 6) * (factor
);
4269 bf1
[0] = bf1
[1] = bf1
[2] = bf1
[3] = (1 << 6) * (256 - factor
);
4277 shr ecx
, 1 // process pixels 2 by 2
4278 movq mm1
, blendFactor0
4279 movq mm0
, blendFactor1
4283 lea ebx
, [ebx
+ 8] // points next location
4285 movq mm2
, [esi
+ ebx
]
4286 movq mm3
, [eax
+ ebx
]
4288 punpckhbw mm7
, mm2
// mm7 contains src0 color 0 in high bytes
4289 punpckhbw mm6
, mm3
// mm6 contains src1 color 0 in high bytes
4291 pxor mm4
, mm4
// mm4 = 0
4293 pmulhw mm7
, mm0
// src0 = src0 * blendFactor
4294 pxor mm5
, mm5
// mm5 = 0
4295 pmulhw mm6
, mm1
// src1 = src1 * (1 - blendfactor)
4296 punpcklbw mm4
, mm2
// mm4 contains src0 color 1 in high bytes
4297 paddusw mm6
, mm7
// mm6 = src0[0] blended with src1[0]
4300 punpcklbw mm5
, mm3
// mm4 contains src1 color 1 in high bytes
4302 pmulhw mm4
, mm0
// src0 = src0 * blendFactor
4303 pmulhw mm5
, mm1
// src1 = src1 * (1 - blendfactor)
4304 paddusw mm4
, mm5
// mm6 = src0[1] blended with src1[1]
4309 movq
[edi
+ ebx
], mm4
// store result
4315 // case of odd number of pixels
4319 uint blendFact
= (uint
) factor
;
4320 uint invblendFact
= 256 - blendFact
;
4321 *dest
= (uint8
) (((blendFact
* *src1
) + (invblendFact
* *src0
)) >> 8);
4322 *(dest
+ 1) = (uint8
) (((blendFact
* *(src1
+ 1)) + (invblendFact
* *(src0
+ 1))) >> 8);
4323 *(dest
+ 2) = (uint8
) (((blendFact
* *(src1
+ 2)) + (invblendFact
* *(src0
+ 2))) >> 8);
4324 *(dest
+ 3) = (uint8
) (((blendFact
* *(src1
+ 3)) + (invblendFact
* *(src0
+ 3))) >> 8);
4328 #endif //#ifdef NL_OS_WINDOWS
4330 uint8
*endPix
= dest
+ ((ptrdiff_t)numPix
<< 2);
4332 uint blendFact
= (uint
) factor
;
4333 uint invblendFact
= 256 - blendFact
;
4336 /// blend 4 component at each pass
4337 *dest
= (uint8
) (((blendFact
* *src1
) + (invblendFact
* *src0
)) >> 8);
4338 *(dest
+ 1) = (uint8
) (((blendFact
* *(src1
+ 1)) + (invblendFact
* *(src0
+ 1))) >> 8);
4339 *(dest
+ 2) = (uint8
) (((blendFact
* *(src1
+ 2)) + (invblendFact
* *(src0
+ 2))) >> 8);
4340 *(dest
+ 3) = (uint8
) (((blendFact
* *(src1
+ 3)) + (invblendFact
* *(src0
+ 3))) >> 8);
4346 while (dest
!= endPix
);
4352 //-----------------------------------------------
4353 CRGBA
CBitmap::getRGBAPixel(sint x
, sint y
, uint32 numMipMap
/*=0*/) const
4355 uint w
= getWidth(numMipMap
);
4356 uint h
= getHeight(numMipMap
);
4357 if (w
== 0 || (uint
) x
>= w
|| (uint
) y
>= h
) return CRGBA::Black
; // include negative cases
4358 const uint8
*pix
= &getPixels(numMipMap
)[(x
+ y
* w
) << 2];
4359 return CRGBA(pix
[0], pix
[1], pix
[2], pix
[3]);
4362 //-----------------------------------------------
4363 CRGBA
CBitmap::getDXTCColorFromBlock(const uint8
*block
, sint x
, sint y
)
4367 memcpy(&col0
, block
, sizeof(uint16
));
4368 memcpy(&col1
, block
+ 2, sizeof(uint16
));
4369 uint colIndex
= (block
[4 + (y
& 3)] >> ((x
& 3) << 1)) & 3;
4370 CRGBA result
, c0
, c1
;
4376 uncompress(col0
, result
);
4379 uncompress(col1
, result
);
4382 uncompress(col0
, c0
);
4383 uncompress(col1
, c1
);
4384 result
.blendFromui(c0
, c1
, 85);
4387 uncompress(col0
, c0
);
4388 uncompress(col1
, c1
);
4389 result
.blendFromui(c0
, c1
, 171);
4401 uncompress(col0
, result
);
4405 uncompress(col1
, result
);
4409 uncompress(col0
, c0
);
4410 uncompress(col1
, c1
);
4411 result
.blendFromui(c0
, c1
, 128);
4415 result
.set(0, 0, 0, 0);
4422 //-----------------------------------------------
4423 CRGBA
CBitmap::getDXTC1Texel(sint x
, sint y
, uint32 numMipMap
) const
4425 uint w
= getWidth(numMipMap
);
4426 uint h
= getHeight(numMipMap
);
4427 if (w
== 0 || h
== 0 || (uint
) x
>= w
|| (uint
) y
>= h
) return CRGBA::Black
; // include negative cases
4428 uint numRowBlocks
= std::max((w
+ 3) >> 2, 1u);
4429 const uint8
*pix
= &getPixels(numMipMap
)[0];
4430 const uint8
*block
= pix
+ ((y
>> 2) * (numRowBlocks
<< 3) + ((x
>> 2) << 3));
4431 return getDXTCColorFromBlock(block
, x
, y
);
4435 //-----------------------------------------------
4436 CRGBA
CBitmap::getDXTC3Texel(sint x
, sint y
, uint32 numMipMap
) const
4438 uint w
= getWidth(numMipMap
);
4439 uint h
= getHeight(numMipMap
);
4440 if (w
== 0 || h
== 0 || (uint
) x
>= w
|| (uint
) y
>= h
) return CRGBA::Black
; // include negative cases
4441 uint numRowBlocks
= std::max((w
+ 3) >> 2, 1u);
4442 const uint8
*pix
= &getPixels(numMipMap
)[0];
4443 const uint8
*block
= pix
+ ((y
>> 2) * (numRowBlocks
<< 4) + ((x
>> 2) << 4));
4444 CRGBA result
= getDXTCColorFromBlock(block
+ 8, x
, y
);
4446 uint8 alphaByte
= block
[((y
& 3) << 1) + ((x
& 2) >> 1)];
4447 result
.A
= (x
& 1) ? (alphaByte
& 0xf0) : ((alphaByte
& 0x0f) << 4);
4451 //-----------------------------------------------
4452 CRGBA
CBitmap::getDXTC5Texel(sint x
, sint y
, uint32 numMipMap
) const
4454 uint w
= getWidth(numMipMap
);
4455 uint h
= getHeight(numMipMap
);
4456 if (w
== 0 || h
== 0 || (uint
) x
>= w
|| (uint
) y
>= h
) return CRGBA::Black
; // include negative cases
4457 uint numRowBlocks
= std::max((w
+ 3) >> 2, 1u);
4458 const uint8
*pix
= &getPixels(numMipMap
)[0];
4459 const uint8
*block
= pix
+ ((y
>> 2) * (numRowBlocks
<< 4) + ((x
>> 2) << 4));
4460 CRGBA result
= getDXTCColorFromBlock(block
+ 8, x
, y
);
4462 uint8 alpha0
= block
[0];
4463 uint8 alpha1
= block
[1];
4466 uint tripletIndex
= (x
& 3) + ((y
& 3) << 2);
4467 if (tripletIndex
< 8)
4469 alphaIndex
= (((uint32
&) block
[2]) >> (tripletIndex
* 3)) & 7;
4473 alphaIndex
= (((uint32
&) block
[5]) >> ((tripletIndex
- 8) * 3)) & 7; // we can read a dword there because there are color datas following he alpha datas
4476 if (alpha0
> alpha1
)
4480 case 0: result
.A
= alpha0
; break;
4481 case 1: result
.A
= alpha1
; break;
4482 case 2: result
.A
= (uint8
) ((6 * (uint
) alpha0
+ (uint
) alpha1
) / 7); break;
4483 case 3: result
.A
= (uint8
) ((5 * (uint
) alpha0
+ 2 * (uint
) alpha1
) / 7); break;
4484 case 4: result
.A
= (uint8
) ((4 * (uint
) alpha0
+ 3 * (uint
) alpha1
) / 7); break;
4485 case 5: result
.A
= (uint8
) ((3 * (uint
) alpha0
+ 4 * (uint
) alpha1
) / 7); break;
4486 case 6: result
.A
= (uint8
) ((2 * (uint
) alpha0
+ 5 * (uint
) alpha1
) / 7); break;
4487 case 7: result
.A
= (uint8
) (((uint
) alpha0
+ (uint
) 6 * alpha1
) / 7); break;
4494 case 0: result
.A
= alpha0
; break;
4495 case 1: result
.A
= alpha1
; break;
4496 case 2: result
.A
= (uint8
) ((4 * (uint
) alpha0
+ (uint
) alpha1
) / 5); break;
4497 case 3: result
.A
= (uint8
) ((3 * (uint
) alpha0
+ 2 * (uint
) alpha1
) / 5); break;
4498 case 4: result
.A
= (uint8
) ((2 * (uint
) alpha0
+ 3 * (uint
) alpha1
) / 5); break;
4499 case 5: result
.A
= (uint8
) (((uint
) alpha0
+ 4 * (uint
) alpha1
) / 5); break;
4500 case 6: result
.A
= 0; break;
4501 case 7: result
.A
= 255; break;
4508 //-----------------------------------------------
4509 CRGBA
CBitmap::getPixelColor(sint x
, sint y
, uint32 numMipMap
/*=0*/) const
4512 switch (PixelFormat
)
4515 return getRGBAPixel(x
, y
, numMipMap
);
4518 return getDXTC1Texel(x
, y
, numMipMap
);
4520 return getDXTC3Texel(x
, y
, numMipMap
);
4522 return getDXTC5Texel(x
, y
, numMipMap
);
4527 return CRGBA::Black
;
4530 //-----------------------------------------------
4531 void CBitmap::setPixelColor(sint x
, sint y
, CRGBA c
, uint32 numMipMap
)
4533 nlassert(PixelFormat
== RGBA
);
4535 uint w
= getWidth(numMipMap
);
4536 uint h
= getHeight(numMipMap
);
4538 if (w
== 0 || x
< 0 || y
< 0 || x
>= (sint
)w
|| y
>= (sint
)h
) return;
4540 uint8
*pix
= &getPixels(numMipMap
)[(x
+ y
* w
) << 2];
4542 memcpy(pix
, &c
, sizeof(CRGBA
));
4545 //-----------------------------------------------
4546 void CBitmap::swap(CBitmap
&other
)
4548 std::swap(PixelFormat
, other
.PixelFormat
);
4549 std::swap(_MipMapCount
, other
._MipMapCount
);
4550 std::swap(_LoadGrayscaleAsAlpha
, other
._LoadGrayscaleAsAlpha
);
4551 std::swap(_Width
, other
._Width
);
4552 std::swap(_Height
, other
._Height
);
4553 for(uint k
= 0; k
< MAX_MIPMAP
; ++k
)
4555 _Data
[k
].swap(other
._Data
[k
]);
4559 //-----------------------------------------------
4560 void CBitmap::unattachPixels(CObjectVector
<uint8
> *mipmapDestArray
, uint maxMipMapCount
/*=MAX_MIPMAP*/)
4562 if (!mipmapDestArray
) return;
4564 for(k
= 0; k
< std::min((uint
) _MipMapCount
, maxMipMapCount
); ++k
)
4566 mipmapDestArray
[k
].swap(_Data
[k
]);
4569 for(; k
< _MipMapCount
; ++k
)
4574 // check that remaining mipmaps are empty
4575 for(; k
< _MipMapCount
; ++k
)
4577 nlassert(_Data
[k
].empty());
4584 _LoadGrayscaleAsAlpha
= true;
4590 void CBitmap::getData(uint8
*& extractData
)
4594 if(PixelFormat
==RGBA
)
4595 size
=_Width
*_Height
*4;
4596 else if(PixelFormat
==Alpha
||PixelFormat
==Luminance
)
4597 size
=_Width
*_Height
;
4603 for(uint32 pix
=0;pix
<size
;pix
++)
4604 extractData
[pix
]=_Data
[0][pix
];
4608 void CBitmap::getDibData(uint8
*& extractData
)
4611 uint32 lineSize
=0,size
;
4613 buf
=new uint8
*[_Height
];
4614 if(PixelFormat
==RGBA
)
4620 else if(PixelFormat
==Alpha
||PixelFormat
==Luminance
)
4629 for(sint32 i
=_Height
-1;i
>=0;i
--)
4631 buf
[_Height
-1-i
]=&_Data
[0][i
*lineSize
];
4634 size
=lineSize
*_Height
;
4636 for(uint32 line
=0;line
<_Height
;line
++)
4638 for(uint32 pix
=0;pix
<lineSize
;pix
++)
4639 extractData
[line
*lineSize
+pix
]=_Data
[0][size
-(line
+1)*lineSize
+pix
];