~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to source/Irrlicht/CImage.cpp

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (C) 2002-2011 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
        }
 
215
}
 
216
 
 
217
 
 
218
//! returns a pixel
 
219
SColor CImage::getPixel(u32 x, u32 y) const
 
220
{
 
221
        if (x >= Size.Width || y >= Size.Height)
 
222
                return SColor(0);
 
223
 
 
224
        switch(Format)
 
225
        {
 
226
        case ECF_A1R5G5B5:
 
227
                return A1R5G5B5toA8R8G8B8(((u16*)Data)[y*Size.Width + x]);
 
228
        case ECF_R5G6B5:
 
229
                return R5G6B5toA8R8G8B8(((u16*)Data)[y*Size.Width + x]);
 
230
        case ECF_A8R8G8B8:
 
231
                return ((u32*)Data)[y*Size.Width + x];
 
232
        case ECF_R8G8B8:
 
233
                {
 
234
                        u8* p = Data+(y*3)*Size.Width + (x*3);
 
235
                        return SColor(255,p[0],p[1],p[2]);
 
236
                }
 
237
        }
 
238
 
 
239
        return SColor(0);
 
240
}
 
241
 
 
242
 
 
243
//! returns the color format
 
244
ECOLOR_FORMAT CImage::getColorFormat() const
 
245
{
 
246
        return Format;
 
247
}
 
248
 
 
249
 
 
250
//! copies this surface into another at given position
 
251
void CImage::copyTo(IImage* target, const core::position2d<s32>& pos)
 
252
{
 
253
        Blit(BLITTER_TEXTURE, target, 0, &pos, this, 0, 0);
 
254
}
 
255
 
 
256
 
 
257
//! copies this surface partially into another at given position
 
258
void CImage::copyTo(IImage* target, const core::position2d<s32>& pos, const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect)
 
259
{
 
260
        Blit(BLITTER_TEXTURE, target, clipRect, &pos, this, &sourceRect, 0);
 
261
}
 
262
 
 
263
 
 
264
//! copies this surface into another, using the alpha mask, a cliprect and a color to add with
 
265
void CImage::copyToWithAlpha(IImage* target, const core::position2d<s32>& pos, const core::rect<s32>& sourceRect, const SColor &color, const core::rect<s32>* clipRect)
 
266
{
 
267
        // color blend only necessary on not full spectrum aka. color.color != 0xFFFFFFFF
 
268
        Blit(color.color == 0xFFFFFFFF ? BLITTER_TEXTURE_ALPHA_BLEND: BLITTER_TEXTURE_ALPHA_COLOR_BLEND,
 
269
                        target, clipRect, &pos, this, &sourceRect, color.color);
 
270
}
 
271
 
 
272
 
 
273
//! copies this surface into another, scaling it to the target image size
 
274
// note: this is very very slow.
 
275
void CImage::copyToScaling(void* target, u32 width, u32 height, ECOLOR_FORMAT format, u32 pitch)
 
276
{
 
277
        if (!target || !width || !height)
 
278
                return;
 
279
 
 
280
        const u32 bpp=getBitsPerPixelFromFormat(format)/8;
 
281
        if (0==pitch)
 
282
                pitch = width*bpp;
 
283
 
 
284
        if (Format==format && Size.Width==width && Size.Height==height)
 
285
        {
 
286
                if (pitch==Pitch)
 
287
                {
 
288
                        memcpy(target, Data, height*pitch);
 
289
                        return;
 
290
                }
 
291
                else
 
292
                {
 
293
                        u8* tgtpos = (u8*) target;
 
294
                        u8* srcpos = Data;
 
295
                        const u32 bwidth = width*bpp;
 
296
                        const u32 rest = pitch-bwidth;
 
297
                        for (u32 y=0; y<height; ++y)
 
298
                        {
 
299
                                // copy scanline
 
300
                                memcpy(tgtpos, srcpos, bwidth);
 
301
                                // clear pitch
 
302
                                memset(tgtpos+bwidth, 0, rest);
 
303
                                tgtpos += pitch;
 
304
                                srcpos += Pitch;
 
305
                        }
 
306
                        return;
 
307
                }
 
308
        }
 
309
 
 
310
        const f32 sourceXStep = (f32)Size.Width / (f32)width;
 
311
        const f32 sourceYStep = (f32)Size.Height / (f32)height;
 
312
        s32 yval=0, syval=0;
 
313
        f32 sy = 0.0f;
 
314
        for (u32 y=0; y<height; ++y)
 
315
        {
 
316
                f32 sx = 0.0f;
 
317
                for (u32 x=0; x<width; ++x)
 
318
                {
 
319
                        CColorConverter::convert_viaFormat(Data+ syval + ((s32)sx)*BytesPerPixel, Format, 1, ((u8*)target)+ yval + (x*bpp), format);
 
320
                        sx+=sourceXStep;
 
321
                }
 
322
                sy+=sourceYStep;
 
323
                syval=((s32)sy)*Pitch;
 
324
                yval+=pitch;
 
325
        }
 
326
}
 
327
 
 
328
 
 
329
//! copies this surface into another, scaling it to the target image size
 
330
// note: this is very very slow.
 
331
void CImage::copyToScaling(IImage* target)
 
332
{
 
333
        if (!target)
 
334
                return;
 
335
 
 
336
        const core::dimension2d<u32>& targetSize = target->getDimension();
 
337
 
 
338
        if (targetSize==Size)
 
339
        {
 
340
                copyTo(target);
 
341
                return;
 
342
        }
 
343
 
 
344
        copyToScaling(target->lock(), targetSize.Width, targetSize.Height, target->getColorFormat());
 
345
        target->unlock();
 
346
}
 
347
 
 
348
 
 
349
//! copies this surface into another, scaling it to fit it.
 
350
void CImage::copyToScalingBoxFilter(IImage* target, s32 bias, bool blend)
 
351
{
 
352
        const core::dimension2d<u32> destSize = target->getDimension();
 
353
 
 
354
        const f32 sourceXStep = (f32) Size.Width / (f32) destSize.Width;
 
355
        const f32 sourceYStep = (f32) Size.Height / (f32) destSize.Height;
 
356
 
 
357
        target->lock();
 
358
 
 
359
        s32 fx = core::ceil32( sourceXStep );
 
360
        s32 fy = core::ceil32( sourceYStep );
 
361
        f32 sx;
 
362
        f32 sy;
 
363
 
 
364
        sy = 0.f;
 
365
        for ( u32 y = 0; y != destSize.Height; ++y )
 
366
        {
 
367
                sx = 0.f;
 
368
                for ( u32 x = 0; x != destSize.Width; ++x )
 
369
                {
 
370
                        target->setPixel( x, y,
 
371
                                getPixelBox( core::floor32(sx), core::floor32(sy), fx, fy, bias ), blend );
 
372
                        sx += sourceXStep;
 
373
                }
 
374
                sy += sourceYStep;
 
375
        }
 
376
 
 
377
        target->unlock();
 
378
}
 
379
 
 
380
 
 
381
//! fills the surface with given color
 
382
void CImage::fill(const SColor &color)
 
383
{
 
384
        u32 c;
 
385
 
 
386
        switch ( Format )
 
387
        {
 
388
                case ECF_A1R5G5B5:
 
389
                        c = color.toA1R5G5B5();
 
390
                        c |= c << 16;
 
391
                        break;
 
392
                case ECF_R5G6B5:
 
393
                        c = video::A8R8G8B8toR5G6B5( color.color );
 
394
                        c |= c << 16;
 
395
                        break;
 
396
                case ECF_A8R8G8B8:
 
397
                        c = color.color;
 
398
                        break;
 
399
                case ECF_R8G8B8:
 
400
                {
 
401
                        u8 rgb[3];
 
402
                        CColorConverter::convert_A8R8G8B8toR8G8B8(&color, 1, rgb);
 
403
                        const u32 size = getImageDataSizeInBytes();
 
404
                        for (u32 i=0; i<size; i+=3)
 
405
                        {
 
406
                                memcpy(Data+i, rgb, 3);
 
407
                        }
 
408
                        return;
 
409
                }
 
410
                break;
 
411
        }
 
412
        if (Format != ECF_A1R5G5B5 && Format != ECF_R5G6B5 &&
 
413
                        Format != ECF_A8R8G8B8)
 
414
                return;
 
415
 
 
416
        memset32( Data, c, getImageDataSizeInBytes() );
 
417
}
 
418
 
 
419
 
 
420
//! get a filtered pixel
 
421
inline SColor CImage::getPixelBox( s32 x, s32 y, s32 fx, s32 fy, s32 bias ) const
 
422
{
 
423
        SColor c;
 
424
        s32 a = 0, r = 0, g = 0, b = 0;
 
425
 
 
426
        for ( s32 dx = 0; dx != fx; ++dx )
 
427
        {
 
428
                for ( s32 dy = 0; dy != fy; ++dy )
 
429
                {
 
430
                        c = getPixel(   core::s32_min ( x + dx, Size.Width - 1 ) ,
 
431
                                                        core::s32_min ( y + dy, Size.Height - 1 )
 
432
                                                );
 
433
 
 
434
                        a += c.getAlpha();
 
435
                        r += c.getRed();
 
436
                        g += c.getGreen();
 
437
                        b += c.getBlue();
 
438
                }
 
439
 
 
440
        }
 
441
 
 
442
        s32 sdiv = s32_log2_s32(fx * fy);
 
443
 
 
444
        a = core::s32_clamp( ( a >> sdiv ) + bias, 0, 255 );
 
445
        r = core::s32_clamp( ( r >> sdiv ) + bias, 0, 255 );
 
446
        g = core::s32_clamp( ( g >> sdiv ) + bias, 0, 255 );
 
447
        b = core::s32_clamp( ( b >> sdiv ) + bias, 0, 255 );
 
448
 
 
449
        c.set( a, r, g, b );
 
450
        return c;
 
451
}
 
452
 
 
453
 
 
454
} // end namespace video
 
455
} // end namespace irr