1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
|
/* Starshatter OpenSource Distribution
Copyright (c) 1997-2004, Destroyer Studios LLC.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name "Destroyer Studios" nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
SUBSYSTEM: nGenEx.lib
FILE: Color.h
AUTHOR: John DiCamillo
OVERVIEW
========
Universal Color Format class
*/
#ifndef Color_h
#define Color_h
#include "Types.h"
// +--------------------------------------------------------------------+
class Video;
// +--------------------------------------------------------------------+
struct ColorFormat
{
ColorFormat(int palsize)
: pal(palsize), bpp(8),
rdown(0), rshift(0), rmask(0),
gdown(0), gshift(0), gmask(0),
bdown(0), bshift(0), bmask(0),
adown(0), ashift(0), amask(0) { }
ColorFormat(int size, BYTE r, BYTE rs, BYTE g, BYTE gs, BYTE b, BYTE bs, BYTE a=0, BYTE as=0)
: pal(0), bpp(size),
rdown(8-r), rshift(rs), rmask(((1<<r)-1)<<rs),
gdown(8-g), gshift(gs), gmask(((1<<g)-1)<<gs),
bdown(8-b), bshift(bs), bmask(((1<<b)-1)<<bs),
adown(8-a), ashift(as), amask(((1<<a)-1)<<as) { }
int pal;
int bpp;
BYTE rdown, rshift;
BYTE gdown, gshift;
BYTE bdown, bshift;
BYTE adown, ashift;
DWORD rmask;
DWORD gmask;
DWORD bmask;
DWORD amask;
};
// +--------------------------------------------------------------------+
class Color
{
friend class ColorIndex;
friend class ColorValue;
public:
static const char* TYPENAME() { return "Color"; }
enum Misc { SHADE_LEVELS = 64 }; // max 128!
enum Mask { RMask = 0x00ff0000,
GMask = 0x0000ff00,
BMask = 0x000000ff,
AMask = 0xff000000,
RGBMask = 0x00ffffff };
enum Shift { RShift = 16,
GShift = 8,
BShift = 0,
AShift = 24 };
Color() : rgba(0) { }
Color(const Color& c) : rgba(c.rgba) { }
Color(BYTE r, BYTE g, BYTE b, BYTE a=255) {
rgba = (r<<RShift)|(g<<GShift)|(b<<BShift)|(a<<AShift); }
Color(BYTE index);
Color& operator= (const Color& c) { rgba = c.rgba; return *this; }
int operator==(const Color& c) const { return rgba == c.rgba; }
int operator!=(const Color& c) const { return rgba != c.rgba; }
Color& operator+=(const Color& c); // simple summation
Color operator+(DWORD d) const;
Color operator+(const Color& c) const; // color alpha blending
Color operator*(const Color& c) const; // color modulation
Color operator*(double scale) const;
Color dim(double scale) const;
void Set(DWORD value) { rgba = value; }
void Set(BYTE r, BYTE g, BYTE b, BYTE a=255) {
rgba = (r<<RShift)|(g<<GShift)|(b<<BShift)|(a<<AShift); }
DWORD Value() const { return rgba; }
void SetRed(BYTE r) { rgba = (rgba & ~RMask) | (r << RShift); }
void SetGreen(BYTE g) { rgba = (rgba & ~GMask) | (g << GShift); }
void SetBlue(BYTE b) { rgba = (rgba & ~BMask) | (b << BShift); }
void SetAlpha(BYTE a) { rgba = (rgba & ~AMask) | (a << AShift); }
DWORD Red() const { return (rgba & RMask) >> RShift; }
DWORD Green() const { return (rgba & GMask) >> GShift; }
DWORD Blue() const { return (rgba & BMask) >> BShift; }
DWORD Alpha() const { return (rgba & AMask) >> AShift; }
float fRed() const { return (float)(Red() /255.0); }
float fGreen() const { return (float)(Green()/255.0); }
float fBlue() const { return (float)(Blue() /255.0); }
float fAlpha() const { return (float)(Alpha()/255.0); }
BYTE Index() const { return table[((rgba&RMask)>>(RShift+3)<<10)|
((rgba&GMask)>>(GShift+3)<< 5)|
((rgba&BMask)>>(BShift+3))]; }
inline BYTE IndexedBlend(BYTE dst) const;
static DWORD FormattedBlend(DWORD c1, DWORD c2);
DWORD TextureFormat(int keep_alpha=0) const;
DWORD Formatted() const;
DWORD Unfaded() const;
Color ShadeColor(int shade) const;
DWORD Shaded(int shade) const;
Color Faded() const;
// some useful colors
static Color White;
static Color Black;
static Color Gray;
static Color LightGray;
static Color DarkGray;
static Color BrightRed;
static Color BrightBlue;
static Color BrightGreen;
static Color DarkRed;
static Color DarkBlue;
static Color DarkGreen;
static Color Yellow;
static Color Cyan;
static Color Magenta;
static Color Tan;
static Color Brown;
static Color Violet;
static Color Orange;
static void UseVideo(Video* v);
static void UseFormat(const ColorFormat& cf);
static void UseTextureFormat(const ColorFormat& cf, int alpha_level=0);
static void WithTextureFormat(int alpha_level=0);
static void SetPalette(PALETTEENTRY* pal, int palsize, BYTE* invpal=0);
static void SavePalette(const char* basename);
static void SetFade(double f, Color c=Black, int build_shade=false);
static const ColorFormat& GetTextureFormat(int alpha_level=0) { return texture_format[alpha_level]; }
static const ColorFormat& GetScreenFormat() { return format; }
// indexed color initialization:
static void BuildShadeTable();
static void SaveShadeTable(const char* basename);
static void BuildBlendTable();
static double GetFade() { return fade; }
static Color GetFadeColor() { return fade_color; }
static Color Scale(const Color& c1, const Color& c2, double scale);
static Color Unformat(DWORD formatted_color);
private:
DWORD rgba;
static bool standard_format;
static PALETTEENTRY palette[256];
static BYTE table[32768];
static ColorFormat format;
static int texture_alpha_level;
static ColorFormat texture_format[4];
static double fade;
static Color fade_color;
static Video* video;
};
// +--------------------------------------------------------------------+
class ColorValue
{
friend class Color;
public:
static const char* TYPENAME() { return "ColorValue"; }
ColorValue() : r(0), g(0), b(0), a(0) { }
ColorValue(const ColorValue& c) : r(c.r), g(c.g), b(c.b), a(c.a) { }
ColorValue(const Color& c) : r( c.fRed() ),
g( c.fGreen() ),
b( c.fBlue() ),
a( c.fAlpha() ) { }
ColorValue(float ar,
float ag,
float ab,
float aa=1.0f) : r(ar), g(ag), b(ab), a(aa) { }
int operator==(const ColorValue& c) const { return r==c.r && g==c.g && b==c.b && a==c.a; }
int operator!=(const ColorValue& c) const { return r!=c.r || g!=c.g || b!=c.b || a!=c.a; }
ColorValue& operator+=(const ColorValue& c); // simple summation
ColorValue operator+(const ColorValue& c) const; // color alpha blending
ColorValue operator*(const ColorValue& c) const; // color modulation
ColorValue operator*(double scale) const;
ColorValue dim(double scale) const;
void Set(float ar, float ag, float ab, float aa=1.0f) { r=ar; g=ag; b=ab; a=aa; }
void SetRed(float ar) { r=ar; }
void SetGreen(float ag) { g=ag; }
void SetBlue(float ab) { b=ab; }
void SetAlpha(float aa) { a=aa; }
float Red() const { return r; }
float Green() const { return g; }
float Blue() const { return b; }
float Alpha() const { return a; }
Color ToColor() const;
DWORD TextureFormat(int keep_alpha=0) const { return ToColor().TextureFormat(keep_alpha); }
DWORD Formatted() const { return ToColor().Formatted(); }
DWORD Unfaded() const { return ToColor().Unfaded(); }
Color ShadeColor(int shade) const { return ToColor().ShadeColor(shade); }
DWORD Shaded(int shade) const { return ToColor().Shaded(shade); }
Color Faded() const { return ToColor().Faded(); }
private:
float r, g, b, a;
};
// +--------------------------------------------------------------------+
class ColorIndex
{
friend class Color;
public:
static const char* TYPENAME() { return "ColorIndex"; }
ColorIndex() : index(0) { }
ColorIndex(const ColorIndex& c) : index(c.index) { }
ColorIndex(BYTE r, BYTE g, BYTE b) { index = Color(r,g,b).Index(); }
ColorIndex(BYTE i) : index(i) { }
ColorIndex& operator= (const ColorIndex& c) { index = c.index; return *this; }
int operator==(const ColorIndex& c) const { return index == c.index; }
int operator!=(const ColorIndex& c) const { return index != c.index; }
BYTE Index() const { return index; }
DWORD Red() const { return Color::palette[index].peRed; }
DWORD Green() const { return Color::palette[index].peGreen; }
DWORD Blue() const { return Color::palette[index].peBlue; }
float fRed() const { return (float)(Red() /255.0); }
float fGreen() const { return (float)(Green()/255.0); }
float fBlue() const { return (float)(Blue() /255.0); }
DWORD TextureFormat() const { return texture_palette[index]; }
DWORD Unfaded() const { return unfaded_palette[index]; }
DWORD Formatted() const { return formatted_palette[index]; }
DWORD Shaded(int shade) const { return shade_table[shade*256+index]; }
ColorIndex Faded() const { return ColorIndex(index); }
// note: this will only work in 8-bit color mode...
ColorIndex ShadeColor(int s) const { return ColorIndex((BYTE)(shade_table[s*256+index])); }
// for poly shading optimization
static DWORD* ShadeTable() { return shade_table; }
BYTE IndexedBlend(BYTE dst) const { return blend_table[dst*256+index]; }
private:
BYTE index;
static DWORD* texture_palette;
static DWORD texture_palettes[4][256];
static DWORD unfaded_palette[256];
static DWORD formatted_palette[256];
static DWORD shade_table[256*256];
static BYTE blend_table[256*256];
};
inline BYTE Color::IndexedBlend(BYTE dst) const { return ColorIndex::blend_table[dst*256+Index()]; }
#endif // Color_h
|