GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/dye/dyepalette.cpp Lines: 97 144 67.4 %
Date: 2021-03-17 Branches: 49 90 54.4 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2007-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/dye/dyepalette.h"
25
26
#include "logger.h"
27
28
#ifndef DYECMD
29
#include "resources/db/palettedb.h"
30
#endif  // DYECMD
31
32
#include "utils/stringutils.h"
33
34
#ifndef USE_SDL2
35
#include <cmath>
36
#endif  // USE_SDL2
37
38
PRAGMA48(GCC diagnostic push)
39
PRAGMA48(GCC diagnostic ignored "-Wshadow")
40
#ifndef SDL_BIG_ENDIAN
41
#include <SDL_endian.h>
42
#endif  // SDL_BYTEORDER
43
PRAGMA48(GCC diagnostic pop)
44
45
#ifdef SIMD_SUPPORTED
46
#include "utils/cpu.h"
47
#endif  // SIMD_SUPPORTED
48
#include "utils/foreach.h"
49
50
#include "debug.h"
51
52
DyeFunctionPtr DyePalette::funcReplaceSColor = nullptr;
53
DyeFunctionPtr DyePalette::funcReplaceSColorSse2 = nullptr;
54
DyeFunctionPtr DyePalette::funcReplaceSColorAvx2 = nullptr;
55
DyeFunctionPtr DyePalette::funcReplaceAColor = nullptr;
56
DyeFunctionPtr DyePalette::funcReplaceAColorSse2 = nullptr;
57
DyeFunctionPtr DyePalette::funcReplaceAColorAvx2 = nullptr;
58
59
#ifdef USE_OPENGL
60
DyeFunctionPtr DyePalette::funcReplaceSOGLColor = nullptr;
61
DyeFunctionPtr DyePalette::funcReplaceSOGLColorSse2 = nullptr;
62
DyeFunctionPtr DyePalette::funcReplaceSOGLColorAvx2 = nullptr;
63
DyeFunctionPtr DyePalette::funcReplaceAOGLColor = nullptr;
64
DyeFunctionPtr DyePalette::funcReplaceAOGLColorSse2 = nullptr;
65
DyeFunctionPtr DyePalette::funcReplaceAOGLColorAvx2 = nullptr;
66
#endif  // USE_OPENGL
67
68
2740
DyePalette::DyePalette(const std::string &restrict description,
69
                       const uint8_t blockSize) :
70
5480
    mColors()
71
{
72
2740
    const size_t size = CAST_SIZE(description.length());
73
2740
    if (size == 0)
74
2740
        return;
75
76
2740
    StringVect parts;
77

5480
    splitToStringVector(parts, description.substr(1), ',');
78
2740
    if (description[0] == '#')
79
    {
80
17740
        FOR_EACH (StringVectCIter, it, parts)
81
        {
82
4125
            DyeColor color(0, 0, 0, 0);
83
4125
            hexToColor(*it, blockSize, color);
84
4125
            mColors.push_back(color);
85
        }
86
2740
        return;
87
    }
88
#ifndef DYECMD
89
17
    else if (description[0] == '@')
90
    {
91
17
        uint8_t alpha = 255;
92
118
        FOR_EACH (StringVectCIter, it, parts)
93
        {
94
92
            const std::string str = *it;
95
33
            if (str.empty())
96
7
                continue;
97
33
            if (str[0] == '+')
98
            {
99
7
                if (str.size() != 3)
100
                    continue;
101
28
                alpha = CAST_U8((hexDecode(str[1]) << 4) + hexDecode(str[2]));
102
7
                continue;
103
            }
104
26
            const DyeColor *const color = PaletteDB::getColor(str);
105
26
            if (color != nullptr)
106
            {
107
14
                DyeColor color2 = *color;
108
14
                color2.value[3] = alpha;
109
14
                mColors.push_back(color2);
110
            }
111
            else
112
            {
113
12
                DyeColor color2(0, 0, 0, 0);
114
12
                hexToColor(str, blockSize, color2);
115
12
                mColors.push_back(color2);
116
            }
117
        }
118
        return;
119
    }
120
#endif  // DYECMD
121
122
    logger->log("Error, invalid embedded palette: %s", description.c_str());
123
}
124
125
4137
void DyePalette::hexToColor(const std::string &restrict hexStr,
126
                            const uint8_t blockSize,
127
                            DyeColor &color) noexcept2
128
{
129
16771
    for (size_t i = 0, colorIdx = 0;
130

16771
         i < blockSize && colorIdx < 4;
131
12634
         i += 2, colorIdx ++)
132
    {
133
12634
        color.value[colorIdx] = CAST_U8((
134
25268
            hexDecode(hexStr[i]) << 4)
135
37902
            + hexDecode(hexStr[i + 1]));
136
    }
137
4137
    color.update();
138
4137
}
139
140
unsigned int DyePalette::hexDecode(const signed char c) noexcept2
141
{
142


25282
    if ('0' <= c && c <= '9')
143
17070
        return c - '0';
144


8212
    else if ('A' <= c && c <= 'F')
145
14
        return c - 'A' + 10;
146


8198
    else if ('a' <= c && c <= 'f')
147
8198
        return c - 'a' + 10;
148
    else
149
        return 0;
150
}
151
152
213
void DyePalette::getColor(const unsigned int intensity,
153
                          unsigned int (&restrict color)[3]) const restrict2
154
{
155
213
    if (intensity == 0)
156
    {
157
        color[0] = 0;
158
        color[1] = 0;
159
        color[2] = 0;
160
        return;
161
    }
162
163
426
    const int last = CAST_S32(mColors.size());
164
213
    if (last == 0)
165
        return;
166
167
213
    const int intLast = intensity * last;
168
213
    const int i = intLast / 255;
169
213
    const int t = intLast % 255;
170
171
213
    int j = t != 0 ? i : i - 1;
172
173
213
    if (j >= last)
174
        j = 0;
175
176
    // Get the exact color if any, the next color otherwise.
177
426
    const DyeColor &colorJ = mColors[j];
178
213
    const int r2 = colorJ.value[0];
179
213
    const int g2 = colorJ.value[1];
180
213
    const int b2 = colorJ.value[2];
181
182
213
    if (t == 0)
183
    {
184
        // Exact color.
185
210
        color[0] = r2;
186
210
        color[1] = g2;
187
210
        color[2] = b2;
188
210
        return;
189
    }
190
191
    // Get the previous color. First color is implicitly black.
192
3
    if (i > 0 && i < last + 1)
193
    {
194
        const DyeColor &colorI = mColors[i - 1];
195
        const int t2 = 255 - t;
196
        // Perform a linear interpolation.
197
        color[0] = (t2 * colorI.value[0] + t * r2) / 255;
198
        color[1] = (t2 * colorI.value[1] + t * g2) / 255;
199
        color[2] = (t2 * colorI.value[2] + t * b2) / 255;
200
    }
201
    else
202
    {
203
        // Perform a linear interpolation.
204
3
        color[0] = (t * r2) / 255;
205
3
        color[1] = (t * g2) / 255;
206
3
        color[2] = (t * b2) / 255;
207
    }
208
}
209
210
24
void DyePalette::getColor(double intensity,
211
                          int (&restrict color)[3]) const restrict2
212
{
213
    // Nothing to do here
214
48
    if (mColors.empty())
215
        return;
216
217
    // Force range
218
24
    if (intensity > 1.0)
219
        intensity = 1.0;
220
23
    else if (intensity < 0.0)
221
        intensity = 0.0;
222
223
    // Scale up
224
48
    intensity *= static_cast<double>(mColors.size() - 1);
225
226
    // Color indices
227
24
    const int i = CAST_S32(floor(intensity));
228
24
    const int j = CAST_S32(ceil(intensity));
229
48
    const DyeColor &colorI = mColors[i];
230
231
24
    if (i == j)
232
    {
233
        // Exact color.
234
24
        color[0] = colorI.value[0];
235
24
        color[1] = colorI.value[1];
236
24
        color[2] = colorI.value[2];
237
24
        return;
238
    }
239
240
    intensity -= i;
241
    const double rest = 1 - intensity;
242
    const DyeColor &colorJ = mColors[j];
243
244
    // Perform the interpolation.
245
    color[0] = CAST_S32(rest * colorI.value[0] +
246
        intensity * colorJ.value[0]);
247
    color[1] = CAST_S32(rest * colorI.value[1] +
248
        intensity * colorJ.value[1]);
249
    color[2] = CAST_S32(rest * colorI.value[2] +
250
        intensity * colorJ.value[2]);
251
}
252
253
1
void DyePalette::initFunctions()
254
{
255
#ifdef SIMD_SUPPORTED
256
1
    const uint32_t flags = Cpu::getFlags();
257
1
    if ((flags & Cpu::FEATURE_AVX2) != 0U)
258
    {
259
1
        funcReplaceSColor = &DyePalette::replaceSColorAvx2;
260
1
        funcReplaceSColorAvx2 = &DyePalette::replaceSColorAvx2;
261
1
        funcReplaceSColorSse2 = &DyePalette::replaceSColorSse2;
262
1
        funcReplaceAColor = &DyePalette::replaceAColorAvx2;
263
1
        funcReplaceAColorAvx2 = &DyePalette::replaceAColorAvx2;
264
1
        funcReplaceAColorSse2 = &DyePalette::replaceAColorSse2;
265
266
#ifdef USE_OPENGL
267
1
        funcReplaceSOGLColor = &DyePalette::replaceSOGLColorAvx2;
268
1
        funcReplaceSOGLColorAvx2 = &DyePalette::replaceSOGLColorAvx2;
269
1
        funcReplaceSOGLColorSse2 = &DyePalette::replaceSOGLColorSse2;
270
1
        funcReplaceAOGLColor = &DyePalette::replaceAOGLColorAvx2;
271
1
        funcReplaceAOGLColorAvx2 = &DyePalette::replaceAOGLColorAvx2;
272
1
        funcReplaceAOGLColorSse2 = &DyePalette::replaceAOGLColorSse2;
273
#endif  // USE_OPENGL
274
    }
275
    else if ((flags & Cpu::FEATURE_SSE2) != 0U)
276
    {
277
        funcReplaceSColor = &DyePalette::replaceSColorSse2;
278
        funcReplaceSColorAvx2 = &DyePalette::replaceSColorSse2;
279
        funcReplaceSColorSse2 = &DyePalette::replaceSColorSse2;
280
        funcReplaceAColor = &DyePalette::replaceAColorSse2;
281
        funcReplaceAColorAvx2 = &DyePalette::replaceAColorSse2;
282
        funcReplaceAColorSse2 = &DyePalette::replaceAColorSse2;
283
284
#ifdef USE_OPENGL
285
        funcReplaceSOGLColor = &DyePalette::replaceSOGLColorSse2;
286
        funcReplaceSOGLColorAvx2 = &DyePalette::replaceSOGLColorSse2;
287
        funcReplaceSOGLColorSse2 = &DyePalette::replaceSOGLColorSse2;
288
        funcReplaceAOGLColor = &DyePalette::replaceAOGLColorSse2;
289
        funcReplaceAOGLColorAvx2 = &DyePalette::replaceAOGLColorSse2;
290
        funcReplaceAOGLColorSse2 = &DyePalette::replaceAOGLColorSse2;
291
#endif  // USE_OPENGL
292
    }
293
    else
294
#endif  // SIMD_SUPPORTED
295
    {
296
        funcReplaceSColor = &DyePalette::replaceSColorDefault;
297
        funcReplaceSColorAvx2 = &DyePalette::replaceSColorDefault;
298
        funcReplaceSColorSse2 = &DyePalette::replaceSColorDefault;
299
        funcReplaceAColor = &DyePalette::replaceAColorDefault;
300
        funcReplaceAColorAvx2 = &DyePalette::replaceAColorDefault;
301
        funcReplaceAColorSse2 = &DyePalette::replaceAColorDefault;
302
303
#ifdef USE_OPENGL
304
        funcReplaceSOGLColor = &DyePalette::replaceSOGLColorDefault;
305
        funcReplaceSOGLColorAvx2 = &DyePalette::replaceSOGLColorDefault;
306
        funcReplaceSOGLColorSse2 = &DyePalette::replaceSOGLColorDefault;
307
        funcReplaceAOGLColor = &DyePalette::replaceAOGLColorDefault;
308
        funcReplaceAOGLColorAvx2 = &DyePalette::replaceAOGLColorDefault;
309
        funcReplaceAOGLColorSse2 = &DyePalette::replaceAOGLColorDefault;
310
#endif  // USE_OPENGL
311
    }
312
1
}