1 /*
2 * The ManaPlus Client
3 * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
4 * Copyright (C) 2009 The Mana World Development Team
5 * Copyright (C) 2009-2010 The Mana Developers
6 * Copyright (C) 2011-2019 The ManaPlus Developers
7 * Copyright (C) 2019-2021 Andrei Karas
8 *
9 * This file is part of The ManaPlus Client.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "gui/palette.h"
26
27 #include "utils/foreach.h"
28 #include "utils/timer.h"
29
30 #ifndef USE_SDL2
31 #include <cmath>
32 #endif // USE_SDL2
33
34 #include "debug.h"
35
36 const Color Palette::BLACK = Color(0, 0, 0, 255);
37 Palette::Palettes Palette::mInstances;
38
39 const Color Palette::RAINBOW_COLORS[7] =
40 {
41 Color(255, 0, 0, 255),
42 Color(255, 153, 0, 255),
43 Color(255, 255, 0, 255),
44 Color(0, 153, 0, 255),
45 Color(0, 204, 204, 255),
46 Color(51, 0, 153, 255),
47 Color(153, 0, 153, 255)
48 };
49
50 const int Palette::RAINBOW_COLOR_COUNT = 7;
51
Palette(const int size)52 Palette::Palette(const int size) :
53 mRainbowTime(tick_time),
54 mColors(Colors(size)),
55 mCharColors(),
56 mGradVector()
57 {
58 mInstances.insert(this);
59 }
60
~Palette()61 Palette::~Palette()
62 {
63 mInstances.erase(this);
64 }
65
getCharColor(const signed char c,bool & valid) const66 const Color& Palette::getCharColor(const signed char c, bool &valid) const
67 {
68 const CharColors::const_iterator it = mCharColors.find(c);
69 if (it != mCharColors.end())
70 {
71 valid = true;
72 return mColors[(*it).second].color;
73 }
74
75 valid = false;
76 return BLACK;
77 }
78
advanceGradients()79 void Palette::advanceGradients()
80 {
81 FOR_EACH (Palettes::const_iterator, it, mInstances)
82 (*it)->advanceGradient();
83 }
84
advanceGradient()85 void Palette::advanceGradient()
86 {
87 const int time = get_elapsed_time(mRainbowTime);
88 if (time > 5)
89 {
90 // For slower systems, advance can be greater than one (advance > 1
91 // skips advance-1 steps). Should make gradient look the same
92 // independent of the framerate.
93 const int advance = time / 5;
94
95 for (size_t i = 0, sz = mGradVector.size(); i < sz; i++)
96 {
97 ColorElem *const elem A_NONNULLPOINTER = mGradVector[i];
98 if (elem == nullptr)
99 continue;
100
101 int delay = elem->delay;
102 const GradientTypeT &grad = elem->grad;
103
104 if (grad == GradientType::PULSE)
105 delay = delay / 20;
106
107 const int numOfColors = (elem->grad == GradientType::SPECTRUM ? 6 :
108 grad == GradientType::PULSE ? 127 :
109 RAINBOW_COLOR_COUNT);
110
111 elem->gradientIndex = (elem->gradientIndex + advance)
112 % (delay * numOfColors);
113
114 const int gradIndex = elem->gradientIndex;
115 const int pos = delay != 0 ? (gradIndex % delay) : gradIndex;
116 int colIndex;
117 if (delay != 0)
118 colIndex = gradIndex / delay;
119 else
120 colIndex = gradIndex;
121
122 Color &color = elem->color;
123 int colVal;
124
125 if (grad == GradientType::PULSE)
126 {
127 colVal = CAST_S32(255.0 *
128 sin(M_PI * colIndex / numOfColors));
129
130 const Color &col = elem->testColor;
131
132 color.r = ((colVal * col.r) / 255) % (col.r + 1);
133 color.g = ((colVal * col.g) / 255) % (col.g + 1);
134 color.b = ((colVal * col.b) / 255) % (col.b + 1);
135 }
136 else if (grad == GradientType::SPECTRUM)
137 {
138 if ((colIndex % 2) != 0)
139 { // falling curve
140 if (delay != 0)
141 {
142 colVal = CAST_S32(255.0 *
143 (cos(M_PI * pos / delay) + 1) / 2);
144 }
145 else
146 {
147 colVal = CAST_S32(255.0 *
148 (cos(M_PI * pos) + 1) / 2);
149 }
150 }
151 else
152 { // ascending curve
153 if (delay != 0)
154 {
155 colVal = CAST_S32(255.0 * (cos(M_PI *
156 (delay - pos) / delay) + 1) / 2);
157 }
158 else
159 {
160 colVal = CAST_S32(255.0 * (cos(M_PI *
161 (delay - pos)) + 1) / 2);
162 }
163 }
164
165 color.r = (colIndex == 0 || colIndex == 5) ? 255 :
166 (colIndex == 1 || colIndex == 4) ? colVal : 0;
167 color.g = (colIndex == 1 || colIndex == 2) ? 255 :
168 (colIndex == 0 || colIndex == 3) ? colVal : 0;
169 color.b = (colIndex == 3 || colIndex == 4) ? 255 :
170 (colIndex == 2 || colIndex == 5) ? colVal : 0;
171 }
172 else if (elem->grad == GradientType::RAINBOW)
173 {
174 const Color &startCol = RAINBOW_COLORS[colIndex];
175 const Color &destCol
176 = RAINBOW_COLORS[(colIndex + 1) % numOfColors];
177 double startColVal;
178 double destColVal;
179
180 if (delay != 0)
181 startColVal = (cos(M_PI * pos / delay) + 1) / 2;
182 else
183 startColVal = 0;
184
185 destColVal = 1 - startColVal;
186
187 color.r = CAST_S32(startColVal
188 * startCol.r + destColVal * destCol.r);
189
190 color.g = CAST_S32(startColVal
191 * startCol.g + destColVal * destCol.g);
192
193 color.b = CAST_S32(startColVal
194 * startCol.b + destColVal * destCol.b);
195 }
196 }
197
198 mRainbowTime = tick_time;
199 }
200 }
201