GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/imagehelper.cpp Lines: 61 91 67.0 %
Date: 2021-03-17 Branches: 13 29 44.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
#include "resources/imagehelper.h"
25
26
#include "logger.h"
27
28
#include "resources/dye/dye.h"
29
#include "resources/dye/dyepalette.h"
30
31
#include "utils/sdlcheckutils.h"
32
33
PRAGMA48(GCC diagnostic push)
34
PRAGMA48(GCC diagnostic ignored "-Wshadow")
35
#include <SDL_image.h>
36
PRAGMA48(GCC diagnostic pop)
37
38
#include "debug.h"
39
40
#ifndef SDL_BIG_ENDIAN
41
#error missing SDL_endian.h
42
#endif  // SDL_BYTEORDER
43
44
ImageHelper *imageHelper = nullptr;
45
ImageHelper *surfaceImageHelper = nullptr;
46
47
bool ImageHelper::mEnableAlpha = true;
48
RenderType ImageHelper::mUseOpenGL = RENDER_SOFTWARE;
49
50
1545
Image *ImageHelper::load(SDL_RWops *const rw)
51
{
52
1545
    SDL_Surface *const tmpImage = loadPng(rw);
53
1545
    if (tmpImage == nullptr)
54
    {
55
        logger->log("Error, image load failed: %s", SDL_GetError());
56
        return nullptr;
57
    }
58
59
1545
    Image *const image = loadSurface(tmpImage);
60
61
1545
    MSDL_FreeSurface(tmpImage);
62
1545
    return image;
63
}
64
65
5
Image *ImageHelper::load(SDL_RWops *const rw, Dye const &dye)
66
{
67
    BLOCK_START("ImageHelper::load")
68
5
    SDL_Surface *const tmpImage = loadPng(rw);
69
5
    if (tmpImage == nullptr)
70
    {
71
        logger->log("Error, image load failed: %s", SDL_GetError());
72
        BLOCK_END("ImageHelper::load")
73
        return nullptr;
74
    }
75
76
    SDL_PixelFormat rgba;
77
5
    rgba.palette = nullptr;
78
5
    rgba.BitsPerPixel = 32;
79
5
    rgba.BytesPerPixel = 4;
80
81
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
82
    rgba.Rmask = 0x000000FFU;
83
    rgba.Gmask = 0x0000FF00U;
84
    rgba.Bmask = 0x00FF0000U;
85
    rgba.Amask = 0xFF000000U;
86
#else  // SDL_BYTEORDER == SDL_BIG_ENDIAN
87
88
5
    rgba.Rmask = 0xFF000000U;
89
5
    rgba.Gmask = 0x00FF0000U;
90
5
    rgba.Bmask = 0x0000FF00U;
91
5
    rgba.Amask = 0x000000FFU;
92
#endif  // SDL_BYTEORDER == SDL_BIG_ENDIAN
93
94
5
    SDL_Surface *const surf = MSDL_ConvertSurface(
95
        tmpImage, &rgba, SDL_SWSURFACE);
96
5
    MSDL_FreeSurface(tmpImage);
97
98
5
    if (surf == nullptr)
99
        return nullptr;
100
101
5
    uint32_t *const pixels = static_cast<uint32_t *>(surf->pixels);
102
5
    const int type = dye.getType();
103
104
5
    switch (type)
105
    {
106
        case 1:
107
        {
108
3
            const DyePalette *const pal = dye.getSPalete();
109
3
            if (pal != nullptr)
110
3
                DYEPALETTEP(pal, SColor)(pixels, surf->w * surf->h);
111
            break;
112
        }
113
        case 2:
114
        {
115
1
            const DyePalette *const pal = dye.getAPalete();
116
1
            if (pal != nullptr)
117
1
                DYEPALETTEP(pal, AColor)(pixels, surf->w * surf->h);
118
            break;
119
        }
120
        case 0:
121
        default:
122
        {
123
1
            dye.normalDye(pixels, surf->w * surf->h);
124
            break;
125
        }
126
    }
127
128
5
    Image *const image = loadSurface(surf);
129
5
    MSDL_FreeSurface(surf);
130
    BLOCK_END("ImageHelper::load")
131
    return image;
132
}
133
134
137
SDL_Surface* ImageHelper::convertTo32Bit(SDL_Surface *const tmpImage)
135
{
136
137
    if (tmpImage == nullptr)
137
        return nullptr;
138
    SDL_PixelFormat RGBAFormat;
139
137
    RGBAFormat.palette = nullptr;
140
#ifndef USE_SDL2
141
    RGBAFormat.colorkey = 0;
142
    RGBAFormat.alpha = 0;
143
#endif  // USE_SDL2
144
145
137
    RGBAFormat.BitsPerPixel = 32;
146
137
    RGBAFormat.BytesPerPixel = 4;
147
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
148
    RGBAFormat.Rmask = 0xFF000000U;
149
    RGBAFormat.Rshift = 0;
150
    RGBAFormat.Rloss = 0;
151
    RGBAFormat.Gmask = 0x00FF0000U;
152
    RGBAFormat.Gshift = 8;
153
    RGBAFormat.Gloss = 0;
154
    RGBAFormat.Bmask = 0x0000FF00U;
155
    RGBAFormat.Bshift = 16;
156
    RGBAFormat.Bloss = 0;
157
    RGBAFormat.Amask = 0x000000FFU;
158
    RGBAFormat.Ashift = 24;
159
    RGBAFormat.Aloss = 0;
160
#else  // SDL_BYTEORDER == SDL_BIG_ENDIAN
161
162
137
    RGBAFormat.Rmask = 0x000000FFU;
163
137
    RGBAFormat.Rshift = 24;
164
137
    RGBAFormat.Rloss = 0;
165
137
    RGBAFormat.Gmask = 0x0000FF00U;
166
137
    RGBAFormat.Gshift = 16;
167
137
    RGBAFormat.Gloss = 0;
168
137
    RGBAFormat.Bmask = 0x00FF0000U;
169
137
    RGBAFormat.Bshift = 8;
170
137
    RGBAFormat.Bloss = 0;
171
137
    RGBAFormat.Amask = 0xFF000000U;
172
137
    RGBAFormat.Ashift = 0;
173
137
    RGBAFormat.Aloss = 0;
174
#endif  // SDL_BYTEORDER == SDL_BIG_ENDIAN
175
176
137
    return MSDL_ConvertSurface(tmpImage, &RGBAFormat, SDL_SWSURFACE);
177
}
178
179
void ImageHelper::dumpSurfaceFormat(const SDL_Surface *const image)
180
{
181
    if (image == nullptr)
182
        return;
183
    if (image->format != nullptr)
184
    {
185
        const SDL_PixelFormat * const format = image->format;
186
        logger->log("Bytes per pixel: %d", format->BytesPerPixel);
187
#ifdef USE_SDL2
188
        logger->log("Format: %u", format->format);
189
#else  // USE_SDL2
190
191
        logger->log("Alpha: %d", format->alpha);
192
        logger->log("Color key: %u", format->colorkey);
193
#endif  // USE_SDL2
194
195
        logger->log("Loss: %02x, %02x, %02x, %02x",
196
            CAST_U32(format->Rloss),
197
            CAST_U32(format->Gloss),
198
            CAST_U32(format->Bloss),
199
            CAST_U32(format->Aloss));
200
        logger->log("Shift: %02x, %02x, %02x, %02x",
201
            CAST_U32(format->Rshift),
202
            CAST_U32(format->Gshift),
203
            CAST_U32(format->Bshift),
204
            CAST_U32(format->Ashift));
205
        logger->log("Mask: %08x, %08x, %08x, %08x", format->Rmask,
206
            format->Gmask, format->Bmask, format->Amask);
207
    }
208
    logger->log("Flags: %u", image->flags);
209
    logger->log("Pitch: %d", CAST_S32(image->pitch));
210
#ifndef USE_SDL2
211
    logger->log("Offset: %d", image->offset);
212
#endif  // USE_SDL2
213
}
214
215
1550
SDL_Surface *ImageHelper::loadPng(SDL_RWops *const rw)
216
{
217
1550
    if (rw == nullptr)
218
        return nullptr;
219
220
1550
    if (IMG_isPNG(rw) != 0)
221
    {
222
1550
        SDL_Surface *const tmpImage = MIMG_LoadPNG_RW(rw);
223
1550
        SDL_RWclose(rw);
224
1550
        return tmpImage;
225
    }
226
227
    if (IMG_isJPG(rw) != 0)
228
    {
229
        SDL_Surface *const tmpImage = MIMG_LoadJPG_RW(rw);
230
        SDL_RWclose(rw);
231
        return tmpImage;
232
    }
233
234
    logger->log("Error, image is not png");
235
    SDL_RWclose(rw);
236
    return nullptr;
237
}
238
239
130
SDL_Surface *ImageHelper::create32BitSurface(int width,
240
                                             int height) const
241
{
242
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
243
    const uint32_t rmask = 0xff000000U;
244
    const uint32_t gmask = 0x00ff0000U;
245
    const uint32_t bmask = 0x0000ff00U;
246
    const uint32_t amask = 0x000000ffU;
247
#else  // SDL_BYTEORDER == SDL_BIG_ENDIAN
248
249
130
    const uint32_t rmask = 0x000000ffU;
250
130
    const uint32_t gmask = 0x0000ff00U;
251
130
    const uint32_t bmask = 0x00ff0000U;
252
130
    const uint32_t amask = 0xff000000U;
253
#endif  // SDL_BYTEORDER == SDL_BIG_ENDIAN
254
255
130
    return MSDL_CreateRGBSurface(SDL_SWSURFACE,
256
        width, height, 32, rmask, gmask, bmask, amask);
257
}