GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/sdlimagehelper.cpp Lines: 94 106 88.7 %
Date: 2021-03-17 Branches: 33 65 50.8 %

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

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