GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/dye/dyepalette.cpp Lines: 97 145 66.9 %
Date: 2017-11-29 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-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
#include "resources/dye/dyepalette.h"
24
25
#include "logger.h"
26
27
#ifndef DYECMD
28
#include "resources/db/palettedb.h"
29
#endif  // DYECMD
30
31
#include "utils/stringutils.h"
32
33
#ifndef USE_SDL2
34
#include <cmath>
35
#endif  // USE_SDL2
36
37
PRAGMA48(GCC diagnostic push)
38
PRAGMA48(GCC diagnostic ignored "-Wshadow")
39
#ifndef SDL_BIG_ENDIAN
40
#include <SDL_endian.h>
41
#endif  // SDL_BYTEORDER
42
PRAGMA48(GCC diagnostic pop)
43
44
#ifdef SIMD_SUPPORTED
45
#include "utils/cpu.h"
46
#endif  // SIMD_SUPPORTED
47
#include "utils/foreach.h"
48
49
#include "debug.h"
50
51
DyeFunctionPtr DyePalette::funcReplaceSColor = nullptr;
52
DyeFunctionPtr DyePalette::funcReplaceSColorSse2 = nullptr;
53
DyeFunctionPtr DyePalette::funcReplaceSColorAvx2 = nullptr;
54
DyeFunctionPtr DyePalette::funcReplaceAColor = nullptr;
55
DyeFunctionPtr DyePalette::funcReplaceAColorSse2 = nullptr;
56
DyeFunctionPtr DyePalette::funcReplaceAColorAvx2 = nullptr;
57
58
#ifdef USE_OPENGL
59
DyeFunctionPtr DyePalette::funcReplaceSOGLColor = nullptr;
60
DyeFunctionPtr DyePalette::funcReplaceSOGLColorSse2 = nullptr;
61
DyeFunctionPtr DyePalette::funcReplaceSOGLColorAvx2 = nullptr;
62
DyeFunctionPtr DyePalette::funcReplaceAOGLColor = nullptr;
63
DyeFunctionPtr DyePalette::funcReplaceAOGLColorSse2 = nullptr;
64
DyeFunctionPtr DyePalette::funcReplaceAOGLColorAvx2 = nullptr;
65
#endif  // USE_OPENGL
66
67
5192
DyePalette::DyePalette(const std::string &restrict description,
68
                       const uint8_t blockSize) :
69
10384
    mColors()
70
{
71
5192
    const size_t size = CAST_SIZE(description.length());
72
5192
    if (size == 0)
73
5192
        return;
74
75
5192
    StringVect parts;
76

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

31910
         i < blockSize && colorIdx < 4;
130
24044
         i += 2, colorIdx ++)
131
    {
132
24044
        color.value[colorIdx] = CAST_U8((
133
48088
            hexDecode(hexStr[i]) << 4)
134
72132
            + hexDecode(hexStr[i + 1]));
135
    }
136
7866
    color.update();
137
7866
}
138
139
unsigned int DyePalette::hexDecode(const signed char c) noexcept2
140
{
141


48116
    if ('0' <= c && c <= '9')
142
32556
        return c - '0';
143


15560
    else if ('A' <= c && c <= 'F')
144
28
        return c - 'A' + 10;
145


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