1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2006 The GemRB Project
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 *
19 */
20
21 #include "Palette.h"
22
23 #include "Interface.h"
24
25 namespace GemRB {
26
27 #define MINCOL 2
28 #define MUL 2
29
Palette(const Color & color,const Color & back)30 Palette::Palette(const Color &color, const Color &back)
31 : Palette()
32 {
33 col[0] = Color(0, 0xff, 0, 0);
34 for (int i = 1; i < 256; i++) {
35 float p = i / 255.0f;
36 col[i].r = std::min<int>(back.r * (1 - p) + color.r * p, 255);
37 col[i].g = std::min<int>(back.g * (1 - p) + color.g * p, 255);
38 col[i].b = std::min<int>(back.b * (1 - p) + color.b * p, 255);
39 // FIXME: alpha value changed to opaque to fix these palettes on SDL 2
40 // I'm not sure if the previous implementation had a purpose, but historically the alpha is ignored in IE
41 col[i].a = 0xff;
42 }
43 }
44
UpdateAlpha()45 void Palette::UpdateAlpha()
46 {
47 // skip index 0 which is always the color key
48 for (int i = 1; i < 256; ++i) {
49 if (col[i].a != 0xff) {
50 alpha = true;
51 return;
52 }
53 }
54
55 alpha = false;
56 }
57
CopyColorRangePrivate(const Color * srcBeg,const Color * srcEnd,Color * dst)58 void Palette::CopyColorRangePrivate(const Color* srcBeg, const Color* srcEnd, Color* dst)
59 {
60 // no update to alpha or version, hence being private
61 std::copy(srcBeg, srcEnd, dst);
62 }
63
CopyColorRange(const Color * srcBeg,const Color * srcEnd,uint8_t dst)64 void Palette::CopyColorRange(const Color* srcBeg, const Color* srcEnd, uint8_t dst)
65 {
66 CopyColorRangePrivate(srcBeg, srcEnd, &col[dst]);
67 UpdateAlpha();
68 version++;
69 }
70
CreateShadedAlphaChannel()71 void Palette::CreateShadedAlphaChannel()
72 {
73 for (int i = 1; i < 256; ++i) {
74 Color& c = col[i];
75 unsigned int m = (c.r + c.g + c.b) / 3;
76 if (m > MINCOL) {
77 int tmp = m * MUL;
78 c.a = std::min(tmp, 0xff);
79 } else {
80 c.a = 0;
81 }
82 }
83 alpha = true;
84 version++;
85 }
86
Brighten()87 void Palette::Brighten()
88 {
89 for (int i = 0; i<256;i++) {
90 col[i].r = (col[i].r+256)/2;
91 col[i].g = (col[i].g+256)/2;
92 col[i].b = (col[i].b+256)/2;
93 }
94 version++;
95 }
96
Copy() const97 PaletteHolder Palette::Copy() const
98 {
99 return new Palette(std::begin(col), std::end(col));
100 }
101
SetupPaperdollColours(const ieDword * Colors,unsigned int type)102 void Palette::SetupPaperdollColours(const ieDword* Colors, unsigned int type)
103 {
104 unsigned int s = Clamp<ieDword>(8*type, 0, 8*sizeof(ieDword)-1);
105 constexpr uint8_t numCols = 12;
106
107 enum PALETTES : uint8_t
108 {
109 METAL = 0, MINOR, MAJOR, SKIN, LEATHER, ARMOR, HAIR,
110 END
111 };
112
113 for (uint8_t idx = METAL; idx < END; ++idx) {
114 const auto& pal16 = core->GetPalette16(Colors[idx]>>s);
115 Color* dest = &col[0x04 + (idx * 12)];
116 CopyColorRangePrivate(&pal16[0], &pal16[numCols], dest);
117 }
118
119 //minor
120 memcpy( &col[0x58], &col[0x11], 8 * sizeof( Color ) );
121 //major
122 memcpy( &col[0x60], &col[0x1d], 8 * sizeof( Color ) );
123 //minor
124 memcpy( &col[0x68], &col[0x11], 8 * sizeof( Color ) );
125 //metal
126 memcpy( &col[0x70], &col[0x05], 8 * sizeof( Color ) );
127 //leather
128 memcpy( &col[0x78], &col[0x35], 8 * sizeof( Color ) );
129 //leather
130 memcpy( &col[0x80], &col[0x35], 8 * sizeof( Color ) );
131 //minor
132 memcpy( &col[0x88], &col[0x11], 8 * sizeof( Color ) );
133
134 int i;
135 for (i = 0x90; i < 0xA8; i += 0x08)
136 //leather
137 memcpy( &col[i], &col[0x35], 8 * sizeof( Color ) );
138
139 //skin
140 memcpy( &col[0xB0], &col[0x29], 8 * sizeof( Color ) );
141
142 for (i = 0xB8; i < 0xFF; i += 0x08)
143 //leather
144 memcpy( &col[i], &col[0x35], 8 * sizeof( Color ) );
145
146 col[1] = Color(0, 0, 0, 128); // shadows are always half trans black
147
148 version++;
149 }
150
151
applyMod(const Color & src,Color & dest,const RGBModifier & mod)152 static inline void applyMod(const Color& src, Color& dest,
153 const RGBModifier& mod) {
154 if (mod.speed == -1) {
155 if (mod.type == RGBModifier::TINT) {
156 dest.r = ((unsigned int)src.r * mod.rgb.r)>>8;
157 dest.g = ((unsigned int)src.g * mod.rgb.g)>>8;
158 dest.b = ((unsigned int)src.b * mod.rgb.b)>>8;
159 } else if (mod.type == RGBModifier::BRIGHTEN) {
160 unsigned int r = (unsigned int)src.r * mod.rgb.r;
161 if (r & (~0x7FF)) r = 0x7FF;
162 dest.r = r >> 3;
163
164 unsigned int g = (unsigned int)src.g * mod.rgb.g;
165 if (g & (~0x7FF)) g = 0x7FF;
166 dest.g = g >> 3;
167
168 unsigned int b = (unsigned int)src.b * mod.rgb.b;
169 if (b & (~0x7FF)) b = 0x7FF;
170 dest.b = b >> 3;
171 } else if (mod.type == RGBModifier::ADD) {
172 unsigned int r = (unsigned int)src.r + mod.rgb.r;
173 if (r & (~0xFF)) r = 0xFF;
174 dest.r = r;
175
176 unsigned int g = (unsigned int)src.g + mod.rgb.g;
177 if (g & (~0xFF)) g = 0xFF;
178 dest.g = g;
179
180 unsigned int b = (unsigned int)src.b + mod.rgb.b;
181 if (b & (~0xFF)) b = 0xFF;
182 dest.b = b;
183 } else {
184 dest = src;
185 }
186 } else if (mod.speed > 0) {
187
188 // TODO: a sinewave will probably look better
189 int phase = (mod.phase % (2*mod.speed));
190 if (phase > mod.speed) {
191 phase = 512 - (256*phase)/mod.speed;
192 } else {
193 phase = (256*phase)/mod.speed;
194 }
195
196 if (mod.type == RGBModifier::TINT) {
197 dest.r = ((unsigned int)src.r * (256*256 + phase*mod.rgb.r - 256*phase))>>16;
198 dest.g = ((unsigned int)src.g * (256*256 + phase*mod.rgb.g - 256*phase))>>16;
199 dest.b = ((unsigned int)src.b * (256*256 + phase*mod.rgb.b - 256*phase))>>16;
200 } else if (mod.type == RGBModifier::BRIGHTEN) {
201 unsigned int r = src.r + (256*256 + phase*mod.rgb.r - 256*phase);
202 if (r & (~0x7FFFF)) r = 0x7FFFF;
203 dest.r = r >> 11;
204
205 unsigned int g = src.g * (256*256 + phase*mod.rgb.g - 256*phase);
206 if (g & (~0x7FFFF)) g = 0x7FFFF;
207 dest.g = g >> 11;
208
209 unsigned int b = src.b * (256*256 + phase*mod.rgb.b - 256*phase);
210 if (b & (~0x7FFFF)) b = 0x7FFFF;
211 dest.b = b >> 11;
212 } else if (mod.type == RGBModifier::ADD) {
213 unsigned int r = src.r + ((phase*mod.rgb.r)>>8);
214 if (r & (~0xFF)) r = 0xFF;
215 dest.r = r;
216
217 unsigned int g = src.g + ((phase*mod.rgb.g)>>8);
218 if (g & (~0xFF)) g = 0xFF;
219 dest.g = g;
220
221 unsigned int b = src.b + ((phase*mod.rgb.b)>>8);
222 if (b & (~0xFF)) b = 0xFF;
223 dest.b = b;
224 } else {
225 dest = src;
226 }
227 } else {
228 dest = src;
229 }
230 }
231
SetupRGBModification(const PaletteHolder src,const RGBModifier * mods,unsigned int type)232 void Palette::SetupRGBModification(const PaletteHolder src, const RGBModifier* mods,
233 unsigned int type)
234 {
235 const RGBModifier* tmods = mods+(8*type);
236 int i;
237
238 for (i = 0; i < 4; ++i)
239 col[i] = src->col[i];
240
241 for (i = 0; i < 12; ++i)
242 applyMod(src->col[0x04+i],col[0x04+i],tmods[0]);
243 for (i = 0; i < 12; ++i)
244 applyMod(src->col[0x10+i],col[0x10+i],tmods[1]);
245 for (i = 0; i < 12; ++i)
246 applyMod(src->col[0x1c+i],col[0x1c+i],tmods[2]);
247 for (i = 0; i < 12; ++i)
248 applyMod(src->col[0x28+i],col[0x28+i],tmods[3]);
249 for (i = 0; i < 12; ++i)
250 applyMod(src->col[0x34+i],col[0x34+i],tmods[4]);
251 for (i = 0; i < 12; ++i)
252 applyMod(src->col[0x40+i],col[0x40+i],tmods[5]);
253 for (i = 0; i < 12; ++i)
254 applyMod(src->col[0x4c+i],col[0x4c+i],tmods[6]);
255 for (i = 0; i < 8; ++i)
256 applyMod(src->col[0x58+i],col[0x58+i],tmods[1]);
257 for (i = 0; i < 8; ++i)
258 applyMod(src->col[0x60+i],col[0x60+i],tmods[2]);
259 for (i = 0; i < 8; ++i)
260 applyMod(src->col[0x68+i],col[0x68+i],tmods[1]);
261 for (i = 0; i < 8; ++i)
262 applyMod(src->col[0x70+i],col[0x70+i],tmods[0]);
263 for (i = 0; i < 8; ++i)
264 applyMod(src->col[0x78+i],col[0x78+i],tmods[4]);
265 for (i = 0; i < 8; ++i)
266 applyMod(src->col[0x80+i],col[0x80+i],tmods[4]);
267 for (i = 0; i < 8; ++i)
268 applyMod(src->col[0x88+i],col[0x88+i],tmods[1]);
269 for (i = 0; i < 24; ++i)
270 applyMod(src->col[0x90+i],col[0x90+i],tmods[4]);
271
272 for (i = 0; i < 8; ++i)
273 col[0xA8+i] = src->col[0xA8+i];
274
275 for (i = 0; i < 8; ++i)
276 applyMod(src->col[0xB0+i],col[0xB0+i],tmods[3]);
277 for (i = 0; i < 72; ++i)
278 applyMod(src->col[0xB8+i],col[0xB8+i],tmods[4]);
279
280 version++;
281 }
282
SetupGlobalRGBModification(const PaletteHolder src,const RGBModifier & mod)283 void Palette::SetupGlobalRGBModification(const PaletteHolder src,
284 const RGBModifier& mod)
285 {
286 int i;
287 // don't modify the transparency and shadow colour
288 for (i = 0; i < 2; ++i)
289 col[i] = src->col[i];
290
291 for (i = 2; i < 256; ++i)
292 applyMod(src->col[i],col[i],mod);
293
294 version++;
295 }
296
operator ==(const Palette & other) const297 bool Palette::operator==(const Palette& other) const {
298 return memcmp(col, other.col, sizeof(col)) == 0;
299 }
300
operator !=(const Palette & other) const301 bool Palette::operator!=(const Palette& other) const {
302 return !(*this == other);
303 }
304
305 }
306