diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CImage.cpp | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CImage.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CImage.cpp new file mode 100644 index 0000000..d567732 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CImage.cpp | |||
@@ -0,0 +1,462 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten | ||
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 "CImage.h" | ||
6 | #include "irrString.h" | ||
7 | #include "CColorConverter.h" | ||
8 | #include "CBlit.h" | ||
9 | |||
10 | namespace irr | ||
11 | { | ||
12 | namespace video | ||
13 | { | ||
14 | |||
15 | //! Constructor of empty image | ||
16 | CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size) | ||
17 | :Data(0), Size(size), Format(format), DeleteMemory(true) | ||
18 | { | ||
19 | initData(); | ||
20 | } | ||
21 | |||
22 | |||
23 | //! Constructor from raw data | ||
24 | CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size, void* data, | ||
25 | bool ownForeignMemory, bool deleteForeignMemory) | ||
26 | : Data(0), Size(size), Format(format), DeleteMemory(deleteForeignMemory) | ||
27 | { | ||
28 | if (ownForeignMemory) | ||
29 | { | ||
30 | Data = (u8*)0xbadf00d; | ||
31 | initData(); | ||
32 | Data = (u8*)data; | ||
33 | } | ||
34 | else | ||
35 | { | ||
36 | Data = 0; | ||
37 | initData(); | ||
38 | memcpy(Data, data, Size.Height * Pitch); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | |||
43 | //! assumes format and size has been set and creates the rest | ||
44 | void CImage::initData() | ||
45 | { | ||
46 | #ifdef _DEBUG | ||
47 | setDebugName("CImage"); | ||
48 | #endif | ||
49 | BytesPerPixel = getBitsPerPixelFromFormat(Format) / 8; | ||
50 | |||
51 | // Pitch should be aligned... | ||
52 | Pitch = BytesPerPixel * Size.Width; | ||
53 | |||
54 | if (!Data) | ||
55 | { | ||
56 | DeleteMemory=true; | ||
57 | Data = new u8[Size.Height * Pitch]; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | |||
62 | //! destructor | ||
63 | CImage::~CImage() | ||
64 | { | ||
65 | if ( DeleteMemory ) | ||
66 | delete [] Data; | ||
67 | } | ||
68 | |||
69 | |||
70 | //! Returns width and height of image data. | ||
71 | const core::dimension2d<u32>& CImage::getDimension() const | ||
72 | { | ||
73 | return Size; | ||
74 | } | ||
75 | |||
76 | |||
77 | //! Returns bits per pixel. | ||
78 | u32 CImage::getBitsPerPixel() const | ||
79 | { | ||
80 | return getBitsPerPixelFromFormat(Format); | ||
81 | } | ||
82 | |||
83 | |||
84 | //! Returns bytes per pixel | ||
85 | u32 CImage::getBytesPerPixel() const | ||
86 | { | ||
87 | return BytesPerPixel; | ||
88 | } | ||
89 | |||
90 | |||
91 | //! Returns image data size in bytes | ||
92 | u32 CImage::getImageDataSizeInBytes() const | ||
93 | { | ||
94 | return Pitch * Size.Height; | ||
95 | } | ||
96 | |||
97 | |||
98 | //! Returns image data size in pixels | ||
99 | u32 CImage::getImageDataSizeInPixels() const | ||
100 | { | ||
101 | return Size.Width * Size.Height; | ||
102 | } | ||
103 | |||
104 | |||
105 | //! returns mask for red value of a pixel | ||
106 | u32 CImage::getRedMask() const | ||
107 | { | ||
108 | switch(Format) | ||
109 | { | ||
110 | case ECF_A1R5G5B5: | ||
111 | return 0x1F<<10; | ||
112 | case ECF_R5G6B5: | ||
113 | return 0x1F<<11; | ||
114 | case ECF_R8G8B8: | ||
115 | return 0x00FF0000; | ||
116 | case ECF_A8R8G8B8: | ||
117 | return 0x00FF0000; | ||
118 | default: | ||
119 | return 0x0; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | |||
124 | //! returns mask for green value of a pixel | ||
125 | u32 CImage::getGreenMask() const | ||
126 | { | ||
127 | switch(Format) | ||
128 | { | ||
129 | case ECF_A1R5G5B5: | ||
130 | return 0x1F<<5; | ||
131 | case ECF_R5G6B5: | ||
132 | return 0x3F<<5; | ||
133 | case ECF_R8G8B8: | ||
134 | return 0x0000FF00; | ||
135 | case ECF_A8R8G8B8: | ||
136 | return 0x0000FF00; | ||
137 | default: | ||
138 | return 0x0; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | |||
143 | //! returns mask for blue value of a pixel | ||
144 | u32 CImage::getBlueMask() const | ||
145 | { | ||
146 | switch(Format) | ||
147 | { | ||
148 | case ECF_A1R5G5B5: | ||
149 | return 0x1F; | ||
150 | case ECF_R5G6B5: | ||
151 | return 0x1F; | ||
152 | case ECF_R8G8B8: | ||
153 | return 0x000000FF; | ||
154 | case ECF_A8R8G8B8: | ||
155 | return 0x000000FF; | ||
156 | default: | ||
157 | return 0x0; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | |||
162 | //! returns mask for alpha value of a pixel | ||
163 | u32 CImage::getAlphaMask() const | ||
164 | { | ||
165 | switch(Format) | ||
166 | { | ||
167 | case ECF_A1R5G5B5: | ||
168 | return 0x1<<15; | ||
169 | case ECF_R5G6B5: | ||
170 | return 0x0; | ||
171 | case ECF_R8G8B8: | ||
172 | return 0x0; | ||
173 | case ECF_A8R8G8B8: | ||
174 | return 0xFF000000; | ||
175 | default: | ||
176 | return 0x0; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | |||
181 | //! sets a pixel | ||
182 | void CImage::setPixel(u32 x, u32 y, const SColor &color, bool blend) | ||
183 | { | ||
184 | if (x >= Size.Width || y >= Size.Height) | ||
185 | return; | ||
186 | |||
187 | switch(Format) | ||
188 | { | ||
189 | case ECF_A1R5G5B5: | ||
190 | { | ||
191 | u16 * dest = (u16*) (Data + ( y * Pitch ) + ( x << 1 )); | ||
192 | *dest = video::A8R8G8B8toA1R5G5B5( color.color ); | ||
193 | } break; | ||
194 | |||
195 | case ECF_R5G6B5: | ||
196 | { | ||
197 | u16 * dest = (u16*) (Data + ( y * Pitch ) + ( x << 1 )); | ||
198 | *dest = video::A8R8G8B8toR5G6B5( color.color ); | ||
199 | } break; | ||
200 | |||
201 | case ECF_R8G8B8: | ||
202 | { | ||
203 | u8* dest = Data + ( y * Pitch ) + ( x * 3 ); | ||
204 | dest[0] = (u8)color.getRed(); | ||
205 | dest[1] = (u8)color.getGreen(); | ||
206 | dest[2] = (u8)color.getBlue(); | ||
207 | } break; | ||
208 | |||
209 | case ECF_A8R8G8B8: | ||
210 | { | ||
211 | u32 * dest = (u32*) (Data + ( y * Pitch ) + ( x << 2 )); | ||
212 | *dest = blend ? PixelBlend32 ( *dest, color.color ) : color.color; | ||
213 | } break; | ||
214 | #ifndef _DEBUG | ||
215 | default: | ||
216 | break; | ||
217 | #endif | ||
218 | } | ||
219 | } | ||
220 | |||
221 | |||
222 | //! returns a pixel | ||
223 | SColor CImage::getPixel(u32 x, u32 y) const | ||
224 | { | ||
225 | if (x >= Size.Width || y >= Size.Height) | ||
226 | return SColor(0); | ||
227 | |||
228 | switch(Format) | ||
229 | { | ||
230 | case ECF_A1R5G5B5: | ||
231 | return A1R5G5B5toA8R8G8B8(((u16*)Data)[y*Size.Width + x]); | ||
232 | case ECF_R5G6B5: | ||
233 | return R5G6B5toA8R8G8B8(((u16*)Data)[y*Size.Width + x]); | ||
234 | case ECF_A8R8G8B8: | ||
235 | return ((u32*)Data)[y*Size.Width + x]; | ||
236 | case ECF_R8G8B8: | ||
237 | { | ||
238 | u8* p = Data+(y*3)*Size.Width + (x*3); | ||
239 | return SColor(255,p[0],p[1],p[2]); | ||
240 | } | ||
241 | #ifndef _DEBUG | ||
242 | default: | ||
243 | break; | ||
244 | #endif | ||
245 | } | ||
246 | |||
247 | return SColor(0); | ||
248 | } | ||
249 | |||
250 | |||
251 | //! returns the color format | ||
252 | ECOLOR_FORMAT CImage::getColorFormat() const | ||
253 | { | ||
254 | return Format; | ||
255 | } | ||
256 | |||
257 | |||
258 | //! copies this surface into another at given position | ||
259 | void CImage::copyTo(IImage* target, const core::position2d<s32>& pos) | ||
260 | { | ||
261 | Blit(BLITTER_TEXTURE, target, 0, &pos, this, 0, 0); | ||
262 | } | ||
263 | |||
264 | |||
265 | //! copies this surface partially into another at given position | ||
266 | void CImage::copyTo(IImage* target, const core::position2d<s32>& pos, const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect) | ||
267 | { | ||
268 | Blit(BLITTER_TEXTURE, target, clipRect, &pos, this, &sourceRect, 0); | ||
269 | } | ||
270 | |||
271 | |||
272 | //! copies this surface into another, using the alpha mask, a cliprect and a color to add with | ||
273 | void CImage::copyToWithAlpha(IImage* target, const core::position2d<s32>& pos, const core::rect<s32>& sourceRect, const SColor &color, const core::rect<s32>* clipRect) | ||
274 | { | ||
275 | // color blend only necessary on not full spectrum aka. color.color != 0xFFFFFFFF | ||
276 | Blit(color.color == 0xFFFFFFFF ? BLITTER_TEXTURE_ALPHA_BLEND: BLITTER_TEXTURE_ALPHA_COLOR_BLEND, | ||
277 | target, clipRect, &pos, this, &sourceRect, color.color); | ||
278 | } | ||
279 | |||
280 | |||
281 | //! copies this surface into another, scaling it to the target image size | ||
282 | // note: this is very very slow. | ||
283 | void CImage::copyToScaling(void* target, u32 width, u32 height, ECOLOR_FORMAT format, u32 pitch) | ||
284 | { | ||
285 | if (!target || !width || !height) | ||
286 | return; | ||
287 | |||
288 | const u32 bpp=getBitsPerPixelFromFormat(format)/8; | ||
289 | if (0==pitch) | ||
290 | pitch = width*bpp; | ||
291 | |||
292 | if (Format==format && Size.Width==width && Size.Height==height) | ||
293 | { | ||
294 | if (pitch==Pitch) | ||
295 | { | ||
296 | memcpy(target, Data, height*pitch); | ||
297 | return; | ||
298 | } | ||
299 | else | ||
300 | { | ||
301 | u8* tgtpos = (u8*) target; | ||
302 | u8* srcpos = Data; | ||
303 | const u32 bwidth = width*bpp; | ||
304 | const u32 rest = pitch-bwidth; | ||
305 | for (u32 y=0; y<height; ++y) | ||
306 | { | ||
307 | // copy scanline | ||
308 | memcpy(tgtpos, srcpos, bwidth); | ||
309 | // clear pitch | ||
310 | memset(tgtpos+bwidth, 0, rest); | ||
311 | tgtpos += pitch; | ||
312 | srcpos += Pitch; | ||
313 | } | ||
314 | return; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | const f32 sourceXStep = (f32)Size.Width / (f32)width; | ||
319 | const f32 sourceYStep = (f32)Size.Height / (f32)height; | ||
320 | s32 yval=0, syval=0; | ||
321 | f32 sy = 0.0f; | ||
322 | for (u32 y=0; y<height; ++y) | ||
323 | { | ||
324 | f32 sx = 0.0f; | ||
325 | for (u32 x=0; x<width; ++x) | ||
326 | { | ||
327 | CColorConverter::convert_viaFormat(Data+ syval + ((s32)sx)*BytesPerPixel, Format, 1, ((u8*)target)+ yval + (x*bpp), format); | ||
328 | sx+=sourceXStep; | ||
329 | } | ||
330 | sy+=sourceYStep; | ||
331 | syval=((s32)sy)*Pitch; | ||
332 | yval+=pitch; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | |||
337 | //! copies this surface into another, scaling it to the target image size | ||
338 | // note: this is very very slow. | ||
339 | void CImage::copyToScaling(IImage* target) | ||
340 | { | ||
341 | if (!target) | ||
342 | return; | ||
343 | |||
344 | const core::dimension2d<u32>& targetSize = target->getDimension(); | ||
345 | |||
346 | if (targetSize==Size) | ||
347 | { | ||
348 | copyTo(target); | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | copyToScaling(target->lock(), targetSize.Width, targetSize.Height, target->getColorFormat()); | ||
353 | target->unlock(); | ||
354 | } | ||
355 | |||
356 | |||
357 | //! copies this surface into another, scaling it to fit it. | ||
358 | void CImage::copyToScalingBoxFilter(IImage* target, s32 bias, bool blend) | ||
359 | { | ||
360 | const core::dimension2d<u32> destSize = target->getDimension(); | ||
361 | |||
362 | const f32 sourceXStep = (f32) Size.Width / (f32) destSize.Width; | ||
363 | const f32 sourceYStep = (f32) Size.Height / (f32) destSize.Height; | ||
364 | |||
365 | target->lock(); | ||
366 | |||
367 | s32 fx = core::ceil32( sourceXStep ); | ||
368 | s32 fy = core::ceil32( sourceYStep ); | ||
369 | f32 sx; | ||
370 | f32 sy; | ||
371 | |||
372 | sy = 0.f; | ||
373 | for ( u32 y = 0; y != destSize.Height; ++y ) | ||
374 | { | ||
375 | sx = 0.f; | ||
376 | for ( u32 x = 0; x != destSize.Width; ++x ) | ||
377 | { | ||
378 | target->setPixel( x, y, | ||
379 | getPixelBox( core::floor32(sx), core::floor32(sy), fx, fy, bias ), blend ); | ||
380 | sx += sourceXStep; | ||
381 | } | ||
382 | sy += sourceYStep; | ||
383 | } | ||
384 | |||
385 | target->unlock(); | ||
386 | } | ||
387 | |||
388 | |||
389 | //! fills the surface with given color | ||
390 | void CImage::fill(const SColor &color) | ||
391 | { | ||
392 | u32 c; | ||
393 | |||
394 | switch ( Format ) | ||
395 | { | ||
396 | case ECF_A1R5G5B5: | ||
397 | c = color.toA1R5G5B5(); | ||
398 | c |= c << 16; | ||
399 | break; | ||
400 | case ECF_R5G6B5: | ||
401 | c = video::A8R8G8B8toR5G6B5( color.color ); | ||
402 | c |= c << 16; | ||
403 | break; | ||
404 | case ECF_A8R8G8B8: | ||
405 | c = color.color; | ||
406 | break; | ||
407 | case ECF_R8G8B8: | ||
408 | { | ||
409 | u8 rgb[3]; | ||
410 | CColorConverter::convert_A8R8G8B8toR8G8B8(&color, 1, rgb); | ||
411 | const u32 size = getImageDataSizeInBytes(); | ||
412 | for (u32 i=0; i<size; i+=3) | ||
413 | { | ||
414 | memcpy(Data+i, rgb, 3); | ||
415 | } | ||
416 | return; | ||
417 | } | ||
418 | break; | ||
419 | default: | ||
420 | // TODO: Handle other formats | ||
421 | return; | ||
422 | } | ||
423 | memset32( Data, c, getImageDataSizeInBytes() ); | ||
424 | } | ||
425 | |||
426 | |||
427 | //! get a filtered pixel | ||
428 | inline SColor CImage::getPixelBox( s32 x, s32 y, s32 fx, s32 fy, s32 bias ) const | ||
429 | { | ||
430 | SColor c; | ||
431 | s32 a = 0, r = 0, g = 0, b = 0; | ||
432 | |||
433 | for ( s32 dx = 0; dx != fx; ++dx ) | ||
434 | { | ||
435 | for ( s32 dy = 0; dy != fy; ++dy ) | ||
436 | { | ||
437 | c = getPixel( core::s32_min ( x + dx, Size.Width - 1 ) , | ||
438 | core::s32_min ( y + dy, Size.Height - 1 ) | ||
439 | ); | ||
440 | |||
441 | a += c.getAlpha(); | ||
442 | r += c.getRed(); | ||
443 | g += c.getGreen(); | ||
444 | b += c.getBlue(); | ||
445 | } | ||
446 | |||
447 | } | ||
448 | |||
449 | s32 sdiv = s32_log2_s32(fx * fy); | ||
450 | |||
451 | a = core::s32_clamp( ( a >> sdiv ) + bias, 0, 255 ); | ||
452 | r = core::s32_clamp( ( r >> sdiv ) + bias, 0, 255 ); | ||
453 | g = core::s32_clamp( ( g >> sdiv ) + bias, 0, 255 ); | ||
454 | b = core::s32_clamp( ( b >> sdiv ) + bias, 0, 255 ); | ||
455 | |||
456 | c.set( a, r, g, b ); | ||
457 | return c; | ||
458 | } | ||
459 | |||
460 | |||
461 | } // end namespace video | ||
462 | } // end namespace irr | ||