GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/sdlimagehelper.cpp Lines: 99 112 88.4 %
Date: 2017-11-29 Branches: 32 61 52.5 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#ifndef USE_SDL2
24
25
#include "resources/sdlimagehelper.h"
26
27
#include "resources/dye/dye.h"
28
#include "resources/dye/dyepalette.h"
29
30
#include "resources/image/image.h"
31
32
#include "utils/checkutils.h"
33
#include "utils/sdlcheckutils.h"
34
35
#include "localconsts.h"
36
37
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
38
#include "resources/sdlgfxblitfunc.h"
39
#else  // SDL_BYTEORDER == SDL_LIL_ENDIAN
40
PRAGMA48(GCC diagnostic push)
41
PRAGMA48(GCC diagnostic ignored "-Wshadow")
42
#include <SDL_gfxBlitFunc.h>
43
PRAGMA48(GCC diagnostic pop)
44
#endif  // SDL_BYTEORDER == SDL_LIL_ENDIAN
45
46
#ifndef SDL_BIG_ENDIAN
47
#error missing SDL_endian.h
48
#endif  // SDL_BYTEORDER
49
50
#include "debug.h"
51
52
bool SDLImageHelper::mEnableAlphaCache = false;
53
54
10
Image *SDLImageHelper::load(SDL_RWops *const rw, Dye const &dye)
55
{
56
10
    SDL_Surface *const tmpImage = loadPng(rw);
57
10
    if (tmpImage == nullptr)
58
    {
59
        reportAlways("Error, image load failed: %s",
60
            SDL_GetError());
61
        return nullptr;
62
    }
63
64
    SDL_PixelFormat rgba;
65
10
    rgba.palette = nullptr;
66
10
    rgba.BitsPerPixel = 32;
67
10
    rgba.BytesPerPixel = 4;
68
10
    rgba.colorkey = 0;
69
10
    rgba.alpha = 255;
70
10
    rgba.Rloss = 0;
71
10
    rgba.Gloss = 0;
72
10
    rgba.Bloss = 0;
73
10
    rgba.Aloss = 0;
74
75
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
76
    rgba.Rmask = 0x000000FF;
77
    rgba.Rshift = 24;
78
    rgba.Gmask = 0x0000FF00;
79
    rgba.Gshift = 16;
80
    rgba.Bmask = 0x00FF0000;
81
    rgba.Bshift = 8;
82
    rgba.Amask = 0xFF000000;
83
    rgba.Ashift = 0;
84
#else  // SDL_BYTEORDER == SDL_BIG_ENDIAN
85
86
10
    rgba.Rmask = 0xFF000000;
87
10
    rgba.Rshift = 0;
88
10
    rgba.Gmask = 0x00FF0000;
89
10
    rgba.Gshift = 8;
90
10
    rgba.Bmask = 0x0000FF00;
91
10
    rgba.Bshift = 16;
92
10
    rgba.Amask = 0x000000FF;
93
10
    rgba.Ashift = 24;
94
#endif  // SDL_BYTEORDER == SDL_BIG_ENDIAN
95
96
    // +++ here is bug on ppc64le
97
10
    SDL_Surface *const surf = MSDL_ConvertSurface(
98
        tmpImage, &rgba, SDL_SWSURFACE);
99
100
10
    MSDL_FreeSurface(tmpImage);
101
10
    if (surf == nullptr)
102
        return nullptr;
103
104
10
    uint32_t *pixels = static_cast<uint32_t *>(surf->pixels);
105
10
    const int type = dye.getType();
106
107
10
    switch (type)
108
    {
109
6
        case 1:
110
        {
111
6
            const DyePalette *const pal = dye.getSPalete();
112
6
            if (pal != nullptr)
113
6
                DYEPALETTEP(pal, SColor)(pixels, surf->w * surf->h);
114
            break;
115
        }
116
2
        case 2:
117
        {
118
2
            const DyePalette *const pal = dye.getAPalete();
119
2
            if (pal != nullptr)
120
2
                DYEPALETTEP(pal, AColor)(pixels, surf->w * surf->h);
121
            break;
122
        }
123
2
        case 0:
124
        default:
125
        {
126
2
            dye.normalDye(pixels, surf->w * surf->h);
127
            break;
128
        }
129
    }
130
131
10
    Image *const image = loadSurface(surf);
132
10
    MSDL_FreeSurface(surf);
133
    return image;
134
}
135
136
2934
Image *SDLImageHelper::loadSurface(SDL_Surface *const tmpImage)
137
{
138
2944
    return _SDLload(tmpImage);
139
}
140
141
486
Image *SDLImageHelper::createTextSurface(SDL_Surface *const tmpImage,
142
                                         const int width A_UNUSED,
143
                                         const int height A_UNUSED,
144
                                         const float alpha)
145
{
146
486
    if (tmpImage == nullptr)
147
        return nullptr;
148
149
486
    bool hasAlpha = false;
150
486
    const size_t sz = tmpImage->w * tmpImage->h;
151
152
    // The alpha channel to be filled with alpha values
153
486
    uint8_t *alphaChannel = new uint8_t[sz];
154
155
486
    const SDL_PixelFormat *const fmt = tmpImage->format;
156
486
    if (fmt->Amask != 0u)
157
    {
158
1664886
        for (size_t i = 0; i < sz; ++ i)
159
        {
160
832200
            uint32_t c = (static_cast<uint32_t*>(tmpImage->pixels))[i];
161
162
832200
            const unsigned v = (c & fmt->Amask) >> fmt->Ashift;
163
1664400
            const uint8_t a = static_cast<uint8_t>((v << fmt->Aloss)
164
832200
                + (v >> (8 - (fmt->Aloss << 1))));
165
166
832200
            const uint8_t a2 = CAST_U8(
167
832200
                static_cast<float>(a) * alpha);
168
169
832200
            c &= ~fmt->Amask;
170
832200
            c |= ((a2 >> fmt->Aloss) << fmt->Ashift & fmt->Amask);
171
832200
            (static_cast<uint32_t*>(tmpImage->pixels))[i] = c;
172
173
832200
            if (a != 255)
174
727248
                hasAlpha = true;
175
176
832200
            alphaChannel[i] = a;
177
        }
178
    }
179
180
    SDL_Surface *image;
181
182
    // Convert the surface to the current display format
183
486
    if (hasAlpha)
184
    {
185
486
        image = MSDL_DisplayFormatAlpha(tmpImage);
186
    }
187
    else
188
    {
189
        image = MSDL_DisplayFormat(tmpImage);
190
191
        // We also delete the alpha channel since
192
        // it's not used.
193
        delete [] alphaChannel;
194
        alphaChannel = nullptr;
195
    }
196
197
486
    if (image == nullptr)
198
    {
199
        reportAlways("Error: Image convert failed.");
200
        delete [] alphaChannel;
201
        return nullptr;
202
    }
203
204
486
    Image *const img = new Image(image, hasAlpha, alphaChannel);
205
486
    img->mAlpha = alpha;
206
486
    return img;
207
}
208
209
4
SDL_Surface* SDLImageHelper::SDLDuplicateSurface(SDL_Surface *const tmpImage)
210
{
211

4
    if ((tmpImage == nullptr) || (tmpImage->format == nullptr))
212
        return nullptr;
213
214
4
    return MSDL_ConvertSurface(tmpImage, tmpImage->format, SDL_SWSURFACE);
215
}
216
217
2944
Image *SDLImageHelper::_SDLload(SDL_Surface *tmpImage)
218
{
219
2944
    if (tmpImage == nullptr)
220
        return nullptr;
221
222
2944
    bool hasAlpha = false;
223
2944
    bool converted = false;
224
225
2944
    if (tmpImage->format->BitsPerPixel != 32)
226
    {
227
        reportAlways("Non 32 bit image detected");
228
        tmpImage = convertTo32Bit(tmpImage);
229
230
        if (tmpImage == nullptr)
231
            return nullptr;
232
        converted = true;
233
    }
234
235
2944
    const size_t sz = tmpImage->w * tmpImage->h;
236
237
    // The alpha channel to be filled with alpha values
238
2944
    uint8_t *alphaChannel = new uint8_t[sz];
239
240
    // Figure out whether the image uses its alpha layer
241
2944
    if (tmpImage->format->palette == nullptr)
242
    {
243
2944
        const SDL_PixelFormat *const fmt = tmpImage->format;
244
2944
        if (fmt->Amask != 0u)
245
        {
246
2944
            const uint32_t amask = fmt->Amask;
247
2944
            const uint8_t ashift = fmt->Ashift;
248
2944
            const uint8_t aloss = fmt->Aloss;
249
2944
            const uint32_t *pixels = static_cast<uint32_t*>(tmpImage->pixels);
250
238371996
            cilk_for (size_t i = 0; i < sz; ++ i)
251
            {
252
238369052
                const unsigned v = (pixels[i] & amask) >> ashift;
253
476738104
                const uint8_t a = static_cast<uint8_t>((v << aloss)
254
238369052
                    + (v >> (8 - (aloss << 1))));
255
256
238369052
                if (a != 255)
257
230549902
                    hasAlpha = true;
258
259
238369052
                alphaChannel[i] = a;
260
            }
261
        }
262
        else
263
        {
264
            ifconstexpr (SDL_ALPHA_OPAQUE != 255)
265
            {
266
                hasAlpha = true;
267
                memset(alphaChannel, SDL_ALPHA_OPAQUE, sz);
268
            }
269
        }
270
    }
271
    else
272
    {
273
        ifconstexpr (SDL_ALPHA_OPAQUE != 255)
274
        {
275
            hasAlpha = true;
276
            memset(alphaChannel, SDL_ALPHA_OPAQUE, sz);
277
        }
278
    }
279
280
    SDL_Surface *image;
281
282
    // Convert the surface to the current display format
283
2944
    if (hasAlpha)
284
    {
285
2942
        image = MSDL_DisplayFormatAlpha(tmpImage);
286
    }
287
    else
288
    {
289
2
        image = MSDL_DisplayFormat(tmpImage);
290
291
        // We also delete the alpha channel since
292
        // it's not used.
293
2
        delete [] alphaChannel;
294
2
        alphaChannel = nullptr;
295
    }
296
297
2944
    if (image == nullptr)
298
    {
299
        reportAlways("Error: Image convert failed.");
300
        delete [] alphaChannel;
301
        return nullptr;
302
    }
303
304
    if (converted)
305
        MSDL_FreeSurface(tmpImage);
306
2944
    return new Image(image, hasAlpha, alphaChannel);
307
}
308
309
1312
int SDLImageHelper::combineSurface(SDL_Surface *restrict const src,
310
                                   SDL_Rect *restrict const srcrect,
311
                                   SDL_Surface *restrict const dst,
312
                                   SDL_Rect *restrict const dstrect)
313
{
314
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
315
1312
    return SDLgfxBlitRGBA(src, srcrect, dst, dstrect);
316
#else  // SDL_BYTEORDER == SDL_LIL_ENDIAN
317
318
    return SDL_gfxBlitRGBA(src, srcrect, dst, dstrect);
319
#endif  // SDL_BYTEORDER == SDL_LIL_ENDIAN
320
}
321
322
void SDLImageHelper::copySurfaceToImage(const Image *const image,
323
                                        const int x, const int y,
324
                                        SDL_Surface *const surface) const
325
{
326
    if ((image == nullptr) || (surface == nullptr))
327
        return;
328
329
    SDL_SetAlpha(surface, 0, SDL_ALPHA_OPAQUE);
330
    SDL_Rect rect =
331
    {
332
        CAST_S16(x), CAST_S16(y),
333
        CAST_U16(surface->w), static_cast<uint16_t>(surface->h)
334
    };
335
336
    SDL_BlitSurface(surface, nullptr, image->mSDLSurface, &rect);
337
}
338
339
#endif  // USE_SDL2