aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderBMP.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderBMP.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderBMP.cpp372
1 files changed, 372 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderBMP.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderBMP.cpp
new file mode 100644
index 0000000..2ccb64c
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderBMP.cpp
@@ -0,0 +1,372 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "CImageLoaderBMP.h"
6
7#ifdef _IRR_COMPILE_WITH_BMP_LOADER_
8
9#include "IReadFile.h"
10#include "SColor.h"
11#include "CColorConverter.h"
12#include "CImage.h"
13#include "os.h"
14#include "irrString.h"
15
16namespace irr
17{
18namespace video
19{
20
21
22//! constructor
23CImageLoaderBMP::CImageLoaderBMP()
24{
25 #ifdef _DEBUG
26 setDebugName("CImageLoaderBMP");
27 #endif
28}
29
30
31//! returns true if the file maybe is able to be loaded by this class
32//! based on the file extension (e.g. ".tga")
33bool CImageLoaderBMP::isALoadableFileExtension(const io::path& filename) const
34{
35 return core::hasFileExtension ( filename, "bmp" );
36}
37
38
39//! returns true if the file maybe is able to be loaded by this class
40bool CImageLoaderBMP::isALoadableFileFormat(io::IReadFile* file) const
41{
42 u16 headerID;
43 file->read(&headerID, sizeof(u16));
44#ifdef __BIG_ENDIAN__
45 headerID = os::Byteswap::byteswap(headerID);
46#endif
47 return headerID == 0x4d42;
48}
49
50
51void CImageLoaderBMP::decompress8BitRLE(u8*& bmpData, s32 size, s32 width, s32 height, s32 pitch) const
52{
53 u8* p = bmpData;
54 u8* newBmp = new u8[(width+pitch)*height];
55 u8* d = newBmp;
56 u8* destEnd = newBmp + (width+pitch)*height;
57 s32 line = 0;
58
59 while (bmpData - p < size && d < destEnd)
60 {
61 if (*p == 0)
62 {
63 ++p;
64
65 switch(*p)
66 {
67 case 0: // end of line
68 ++p;
69 ++line;
70 d = newBmp + (line*(width+pitch));
71 break;
72 case 1: // end of bmp
73 delete [] bmpData;
74 bmpData = newBmp;
75 return;
76 case 2:
77 ++p; d +=(u8)*p; // delta
78 ++p; d += ((u8)*p)*(width+pitch);
79 ++p;
80 break;
81 default:
82 {
83 // absolute mode
84 s32 count = (u8)*p; ++p;
85 s32 readAdditional = ((2-(count%2))%2);
86 s32 i;
87
88 for (i=0; i<count; ++i)
89 {
90 *d = *p;
91 ++p;
92 ++d;
93 }
94
95 for (i=0; i<readAdditional; ++i)
96 ++p;
97 }
98 }
99 }
100 else
101 {
102 s32 count = (u8)*p; ++p;
103 u8 color = *p; ++p;
104 for (s32 i=0; i<count; ++i)
105 {
106 *d = color;
107 ++d;
108 }
109 }
110 }
111
112 delete [] bmpData;
113 bmpData = newBmp;
114}
115
116
117void CImageLoaderBMP::decompress4BitRLE(u8*& bmpData, s32 size, s32 width, s32 height, s32 pitch) const
118{
119 s32 lineWidth = (width+1)/2+pitch;
120 u8* p = bmpData;
121 u8* newBmp = new u8[lineWidth*height];
122 u8* d = newBmp;
123 u8* destEnd = newBmp + lineWidth*height;
124 s32 line = 0;
125 s32 shift = 4;
126
127 while (bmpData - p < size && d < destEnd)
128 {
129 if (*p == 0)
130 {
131 ++p;
132
133 switch(*p)
134 {
135 case 0: // end of line
136 ++p;
137 ++line;
138 d = newBmp + (line*lineWidth);
139 shift = 4;
140 break;
141 case 1: // end of bmp
142 delete [] bmpData;
143 bmpData = newBmp;
144 return;
145 case 2:
146 {
147 ++p;
148 s32 x = (u8)*p; ++p;
149 s32 y = (u8)*p; ++p;
150 d += x/2 + y*lineWidth;
151 shift = x%2==0 ? 4 : 0;
152 }
153 break;
154 default:
155 {
156 // absolute mode
157 s32 count = (u8)*p; ++p;
158 s32 readAdditional = ((2-((count)%2))%2);
159 s32 readShift = 4;
160 s32 i;
161
162 for (i=0; i<count; ++i)
163 {
164 s32 color = (((u8)*p) >> readShift) & 0x0f;
165 readShift -= 4;
166 if (readShift < 0)
167 {
168 ++*p;
169 readShift = 4;
170 }
171
172 u8 mask = 0x0f << shift;
173 *d = (*d & (~mask)) | ((color << shift) & mask);
174
175 shift -= 4;
176 if (shift < 0)
177 {
178 shift = 4;
179 ++d;
180 }
181
182 }
183
184 for (i=0; i<readAdditional; ++i)
185 ++p;
186 }
187 }
188 }
189 else
190 {
191 s32 count = (u8)*p; ++p;
192 s32 color1 = (u8)*p; color1 = color1 & 0x0f;
193 s32 color2 = (u8)*p; color2 = (color2 >> 4) & 0x0f;
194 ++p;
195
196 for (s32 i=0; i<count; ++i)
197 {
198 u8 mask = 0x0f << shift;
199 u8 toSet = (shift==0 ? color1 : color2) << shift;
200 *d = (*d & (~mask)) | (toSet & mask);
201
202 shift -= 4;
203 if (shift < 0)
204 {
205 shift = 4;
206 ++d;
207 }
208 }
209 }
210 }
211
212 delete [] bmpData;
213 bmpData = newBmp;
214}
215
216
217
218//! creates a surface from the file
219IImage* CImageLoaderBMP::loadImage(io::IReadFile* file) const
220{
221 SBMPHeader header;
222
223 file->read(&header, sizeof(header));
224
225#ifdef __BIG_ENDIAN__
226 header.Id = os::Byteswap::byteswap(header.Id);
227 header.FileSize = os::Byteswap::byteswap(header.FileSize);
228 header.BitmapDataOffset = os::Byteswap::byteswap(header.BitmapDataOffset);
229 header.BitmapHeaderSize = os::Byteswap::byteswap(header.BitmapHeaderSize);
230 header.Width = os::Byteswap::byteswap(header.Width);
231 header.Height = os::Byteswap::byteswap(header.Height);
232 header.Planes = os::Byteswap::byteswap(header.Planes);
233 header.BPP = os::Byteswap::byteswap(header.BPP);
234 header.Compression = os::Byteswap::byteswap(header.Compression);
235 header.BitmapDataSize = os::Byteswap::byteswap(header.BitmapDataSize);
236 header.PixelPerMeterX = os::Byteswap::byteswap(header.PixelPerMeterX);
237 header.PixelPerMeterY = os::Byteswap::byteswap(header.PixelPerMeterY);
238 header.Colors = os::Byteswap::byteswap(header.Colors);
239 header.ImportantColors = os::Byteswap::byteswap(header.ImportantColors);
240#endif
241
242 s32 pitch = 0;
243
244 //! return if the header is false
245
246 if (header.Id != 0x4d42)
247 return 0;
248
249 if (header.Compression > 2) // we'll only handle RLE-Compression
250 {
251 os::Printer::log("Compression mode not supported.", ELL_ERROR);
252 return 0;
253 }
254
255 // adjust bitmap data size to dword boundary
256 header.BitmapDataSize += (4-(header.BitmapDataSize%4))%4;
257
258 // read palette
259
260 long pos = file->getPos();
261 s32 paletteSize = (header.BitmapDataOffset - pos) / 4;
262
263 s32* paletteData = 0;
264 if (paletteSize)
265 {
266 paletteData = new s32[paletteSize];
267 file->read(paletteData, paletteSize * sizeof(s32));
268#ifdef __BIG_ENDIAN__
269 for (s32 i=0; i<paletteSize; ++i)
270 paletteData[i] = os::Byteswap::byteswap(paletteData[i]);
271#endif
272 }
273
274 // read image data
275
276 if (!header.BitmapDataSize)
277 {
278 // okay, lets guess the size
279 // some tools simply don't set it
280 header.BitmapDataSize = static_cast<u32>(file->getSize()) - header.BitmapDataOffset;
281 }
282
283 file->seek(header.BitmapDataOffset);
284
285 f32 t = (header.Width) * (header.BPP / 8.0f);
286 s32 widthInBytes = (s32)t;
287 t -= widthInBytes;
288 if (t!=0.0f)
289 ++widthInBytes;
290
291 s32 lineData = widthInBytes + ((4-(widthInBytes%4)))%4;
292 pitch = lineData - widthInBytes;
293
294 u8* bmpData = new u8[header.BitmapDataSize];
295 file->read(bmpData, header.BitmapDataSize);
296
297 // decompress data if needed
298 switch(header.Compression)
299 {
300 case 1: // 8 bit rle
301 decompress8BitRLE(bmpData, header.BitmapDataSize, header.Width, header.Height, pitch);
302 break;
303 case 2: // 4 bit rle
304 decompress4BitRLE(bmpData, header.BitmapDataSize, header.Width, header.Height, pitch);
305 break;
306 }
307
308 // create surface
309
310 // no default constructor from packed area! ARM problem!
311 core::dimension2d<u32> dim;
312 dim.Width = header.Width;
313 dim.Height = header.Height;
314
315 IImage* image = 0;
316 switch(header.BPP)
317 {
318 case 1:
319 image = new CImage(ECF_A1R5G5B5, dim);
320 if (image)
321 CColorConverter::convert1BitTo16Bit(bmpData, (s16*)image->lock(), header.Width, header.Height, pitch, true);
322 break;
323 case 4:
324 image = new CImage(ECF_A1R5G5B5, dim);
325 if (image)
326 CColorConverter::convert4BitTo16Bit(bmpData, (s16*)image->lock(), header.Width, header.Height, paletteData, pitch, true);
327 break;
328 case 8:
329 image = new CImage(ECF_A1R5G5B5, dim);
330 if (image)
331 CColorConverter::convert8BitTo16Bit(bmpData, (s16*)image->lock(), header.Width, header.Height, paletteData, pitch, true);
332 break;
333 case 16:
334 image = new CImage(ECF_A1R5G5B5, dim);
335 if (image)
336 CColorConverter::convert16BitTo16Bit((s16*)bmpData, (s16*)image->lock(), header.Width, header.Height, pitch, true);
337 break;
338 case 24:
339 image = new CImage(ECF_R8G8B8, dim);
340 if (image)
341 CColorConverter::convert24BitTo24Bit(bmpData, (u8*)image->lock(), header.Width, header.Height, pitch, true, true);
342 break;
343 case 32: // thx to Reinhard Ostermeier
344 image = new CImage(ECF_A8R8G8B8, dim);
345 if (image)
346 CColorConverter::convert32BitTo32Bit((s32*)bmpData, (s32*)image->lock(), header.Width, header.Height, pitch, true);
347 break;
348 };
349 if (image)
350 image->unlock();
351
352 // clean up
353
354 delete [] paletteData;
355 delete [] bmpData;
356
357 return image;
358}
359
360
361//! creates a loader which is able to load windows bitmaps
362IImageLoader* createImageLoaderBMP()
363{
364 return new CImageLoaderBMP;
365}
366
367
368} // end namespace video
369} // end namespace irr
370
371#endif
372