Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Color.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: nGenEx.lib
6  FILE: Color.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Universal Color Format class
13 */
14 
15 #include "MemDebug.h"
16 #include "Color.h"
17 #include "Video.h"
18 #include "PCX.h"
19 #include "Fix.h"
20 
21 // +--------------------------------------------------------------------+
22 
23 void Print(const char* fmt, ...);
24 
25 Color Color::White = Color(255,255,255);
26 Color Color::Black = Color( 0, 0, 0);
27 Color Color::Gray = Color(128,128,128);
28 Color Color::LightGray = Color(192,192,192);
29 Color Color::DarkGray = Color( 64, 64, 64);
30 Color Color::BrightRed = Color(255, 0, 0);
31 Color Color::BrightBlue = Color( 0, 0,255);
32 Color Color::BrightGreen= Color( 0,255, 0);
33 Color Color::DarkRed = Color(128, 0, 0);
34 Color Color::DarkBlue = Color( 0, 0,128);
35 Color Color::DarkGreen = Color( 0,128, 0);
36 Color Color::Yellow = Color(255,255, 0);
37 Color Color::Cyan = Color( 0,255,255);
38 Color Color::Magenta = Color(255, 0,255);
39 Color Color::Tan = Color(180,150,120);
40 Color Color::Brown = Color(128,100, 80);
41 Color Color::Violet = Color(128, 0,128);
42 Color Color::Orange = Color(255,150, 20);
43 
44 bool Color::standard_format = false;
45 int Color::texture_alpha_level = 0;
46 ColorFormat Color::format = ColorFormat(256);
47 ColorFormat Color::texture_format[4] = { ColorFormat(256), ColorFormat(256), ColorFormat(256), ColorFormat(256) };
48 PALETTEENTRY Color::palette[256];
49 BYTE Color::table[32768];
50 double Color::fade = 1.0;
51 Color Color::fade_color;
52 Video* Color::video = 0;
53 DWORD ColorIndex::texture_palettes[4][256];
54 DWORD ColorIndex::unfaded_palette[256];
55 DWORD ColorIndex::formatted_palette[256];
56 DWORD ColorIndex::shade_table[256*256];
57 BYTE ColorIndex::blend_table[256*256];
58 DWORD* ColorIndex::texture_palette = ColorIndex::texture_palettes[0];
59 
60 // +--------------------------------------------------------------------+
61 
62 Color::Color(BYTE index)
63 {
64  PALETTEENTRY* p = &palette[index];
65 
66  Set(p->peRed, p->peGreen, p->peBlue);
67 }
68 
69 // +--------------------------------------------------------------------+
70 
71 Color&
73 {
74  int r = Red() + c.Red(); if (r > 255) r = 255;
75  int g = Green() + c.Green(); if (g > 255) g = 255;
76  int b = Blue() + c.Blue(); if (b > 255) b = 255;
77 
78  Set((BYTE) r, (BYTE) g, (BYTE) b);
79  return *this;
80 }
81 
82 Color
83 Color::operator+(DWORD d) const
84 {
85  int r = Red() + ((d & RMask) >> RShift); if (r > 255) r = 255;
86  int g = Green() + ((d & GMask) >> GShift); if (g > 255) g = 255;
87  int b = Blue() + ((d & BMask) >> BShift); if (b > 255) b = 255;
88 
89  return Color((BYTE) r,(BYTE) g,(BYTE) b);
90 }
91 
92 // +--------------------------------------------------------------------+
93 
94 Color
95 Color::operator+(const Color& c) const
96 {
97  float src_alpha = c.fAlpha();
98  float dst_alpha = 1.0f - src_alpha;
99 
100  BYTE r = (BYTE)((fRed() *dst_alpha + c.fRed() *src_alpha)*255.0f);
101  BYTE g = (BYTE)((fGreen()*dst_alpha + c.fGreen()*src_alpha)*255.0f);
102  BYTE b = (BYTE)((fBlue() *dst_alpha + c.fBlue() *src_alpha)*255.0f);
103 
104  return Color(r, g, b);
105 }
106 
107 // +--------------------------------------------------------------------+
108 
109 Color
110 Color::operator*(const Color& c) const
111 {
112  BYTE r = (BYTE) ((fRed() * c.fRed()) *255.0f);
113  BYTE g = (BYTE) ((fGreen() * c.fGreen()) *255.0f);
114  BYTE b = (BYTE) ((fBlue() * c.fBlue()) *255.0f);
115 
116  return Color(r, g, b);
117 }
118 
119 // +--------------------------------------------------------------------+
120 
121 Color
122 Color::operator*(double scale) const
123 {
124  int r = fast_f2i(Red() * scale); if (r > 255) r = 255;
125  int g = fast_f2i(Green() * scale); if (g > 255) g = 255;
126  int b = fast_f2i(Blue() * scale); if (b > 255) b = 255;
127  int a = fast_f2i(Alpha() * scale); if (a > 255) a = 255;
128 
129  return Color((BYTE) r, (BYTE) g, (BYTE) b, (BYTE) a);
130 }
131 
132 Color
133 Color::dim(double scale) const
134 {
135  int r = fast_f2i(Red() * scale);
136  int g = fast_f2i(Green() * scale);
137  int b = fast_f2i(Blue() * scale);
138 
139  return Color((BYTE) r, (BYTE) g, (BYTE) b, (BYTE) Alpha());
140 }
141 
142 // +--------------------------------------------------------------------+
143 
144 DWORD
146 {
147  if (format.pal) {
148  return Index();
149  }
150 
151  else {
152  if (fade != 1.0) {
153  double step = (1.0 - fade);
154 
155  DWORD r = ((int) ((fRed() - (fRed() - fade_color.fRed()) * step)*255.0)) >> format.rdown;
156  DWORD g = ((int) ((fGreen() - (fGreen() - fade_color.fGreen())* step)*255.0)) >> format.gdown;
157  DWORD b = ((int) ((fBlue() - (fBlue() - fade_color.fBlue()) * step)*255.0)) >> format.bdown;
158  DWORD a = Alpha()>>format.adown;
159 
160  return (r<<format.rshift)|(g<<format.gshift)|(b<<format.bshift)|(a<<format.ashift);
161 
162  }
163 
164  else if (standard_format) {
165  return rgba;
166  }
167 
168  else {
169  DWORD r = Red() >>format.rdown;
170  DWORD g = Green()>>format.gdown;
171  DWORD b = Blue() >>format.bdown;
172  DWORD a = Alpha()>>format.adown;
173 
174  return (r<<format.rshift)|(g<<format.gshift)|(b<<format.bshift)|(a<<format.ashift);
175  }
176  }
177 }
178 
179 // +--------------------------------------------------------------------+
180 
181 Color
183 {
184  if (fade != 1.0) {
185  double step = (1.0 - fade);
186 
187  DWORD r = ((int) ((fRed() - (fRed() - fade_color.fRed()) * step)*255.0));
188  DWORD g = ((int) ((fGreen() - (fGreen() - fade_color.fGreen())* step)*255.0));
189  DWORD b = ((int) ((fBlue() - (fBlue() - fade_color.fBlue()) * step)*255.0));
190  DWORD a = Alpha();
191 
192  return Color((BYTE) r, (BYTE) g, (BYTE) b, (BYTE) a);
193 
194  }
195 
196  else {
197  return *this;
198  }
199 }
200 
201 // +--------------------------------------------------------------------+
202 
203 DWORD
205 {
206  if (standard_format) {
207  return rgba;
208  }
209 
210  if (format.pal) {
211  return Index();
212  }
213  else {
214  DWORD r = Red() >>format.rdown;
215  DWORD g = Green()>>format.gdown;
216  DWORD b = Blue() >>format.bdown;
217  DWORD a = Alpha()>>format.adown;
218 
219  return (r<<format.rshift)|(g<<format.gshift)|(b<<format.bshift)|(a<<format.ashift);
220  }
221 }
222 
223 // +--------------------------------------------------------------------+
224 
225 DWORD
226 Color::TextureFormat(int keep_alpha) const
227 {
228  if (texture_format[texture_alpha_level].pal) {
229  return Index();
230  }
231  else if (rgba == 0) {
232  return 0;
233  }
234  else {
235  ColorFormat& tf = texture_format[texture_alpha_level];
236 
237  DWORD r = Red();
238  DWORD g = Green();
239  DWORD b = Blue();
240  DWORD a = 0;
241 
242  if (keep_alpha) {
243  a = Alpha()>>tf.adown;
244  }
245 
246  else if (texture_alpha_level == 1) {
247  // transparent:
248  a = 255>>tf.adown;
249  }
250 
251  else if (texture_alpha_level == 2) {
252  // translucent:
253  if (r || g || b)
254  a = ((r+g+b+255)>>2)>>tf.adown;
255  }
256 
257  r = r >>tf.rdown;
258  g = g >>tf.gdown;
259  b = b >>tf.bdown;
260 
261  return (r<<tf.rshift)|(g<<tf.gshift)|(b<<tf.bshift)|(a<<tf.ashift);
262  }
263 }
264 
265 // +--------------------------------------------------------------------+
266 
267 Color
268 Color::ShadeColor(int shade) const
269 {
270  double fr = fRed(), sr = fr;
271  double fg = fGreen(), sg = fg;
272  double fb = fBlue(), sb = fb;
273  double range = SHADE_LEVELS;
274 
275  // first shade:
276  if (shade < SHADE_LEVELS) { // shade towards black
277  sr = fr * (shade/range);
278  sg = fg * (shade/range);
279  sb = fb * (shade/range);
280  }
281  else if (shade > SHADE_LEVELS) { // shade towards white
282  double step = (shade - range)/range;
283 
284  sr = fr - (fr - 1.0) * step;
285  sg = fg - (fg - 1.0) * step;
286  sb = fb - (fb - 1.0) * step;
287  }
288 
289  return Color((BYTE) (sr*255.0), (BYTE) (sg*255.0), (BYTE) (sb*255.0), (BYTE) Alpha());
290 }
291 
292 // +--------------------------------------------------------------------+
293 
294 DWORD
295 Color::Shaded(int shade) const
296 {
297  return ShadeColor(shade).Formatted();
298 }
299 
300 // +--------------------------------------------------------------------+
301 
302 Color
303 Color::Unformat(DWORD formatted_color)
304 {
305  if (format.pal) {
306  return Color((BYTE) formatted_color);
307  }
308  else if (standard_format) {
309  Color c;
310  c.Set(formatted_color);
311  return c;
312  }
313  else {
314  BYTE r = (BYTE) ((formatted_color & format.rmask)>>format.rshift) << format.rdown;
315  BYTE g = (BYTE) ((formatted_color & format.gmask)>>format.gshift) << format.gdown;
316  BYTE b = (BYTE) ((formatted_color & format.bmask)>>format.bshift) << format.bdown;
317  BYTE a = (BYTE) ((formatted_color & format.amask)>>format.ashift) << format.adown;
318 
319  return Color(r,g,b,a);
320  }
321 }
322 
323 // +--------------------------------------------------------------------+
324 
325 Color
326 Color::Scale(const Color& c1, const Color& c2, double scale)
327 {
328  BYTE r = (BYTE) ((c1.fRed() + (c2.fRed() - c1.fRed() )*scale) * 255);
329  BYTE g = (BYTE) ((c1.fGreen() + (c2.fGreen() - c1.fGreen())*scale) * 255);
330  BYTE b = (BYTE) ((c1.fBlue() + (c2.fBlue() - c1.fBlue() )*scale) * 255);
331  BYTE a = (BYTE) ((c1.fAlpha() + (c2.fAlpha() - c1.fAlpha())*scale) * 255);
332 
333  return Color(r,g,b,a);
334 }
335 
336 // +--------------------------------------------------------------------+
337 
338 DWORD
339 Color::FormattedBlend(DWORD c1, DWORD c2)
340 {
341  if (format.pal) {
342  return ColorIndex::blend_table[(BYTE) c1 * 256 + (BYTE) c2];
343  }
344  else {
345  ColorFormat& cf = format;
346 
347  DWORD r = (c1 & cf.rmask) + (c2 & cf.rmask);
348  DWORD g = (c1 & cf.gmask) + (c2 & cf.gmask);
349  DWORD b = (c1 & cf.bmask) + (c2 & cf.bmask);
350 
351  if (r & ~cf.rmask) r = cf.rmask;
352  if (g & ~cf.gmask) g = cf.gmask;
353  if (b & ~cf.bmask) b = cf.bmask;
354 
355  return (DWORD) (r|g|b);
356  }
357 }
358 
359 // +--------------------------------------------------------------------+
360 
361 void
363 {
364  video = v;
365 }
366 
367 // +--------------------------------------------------------------------+
368 
369 void
371 {
372  format = cf;
373 
374  if (format.rmask == RMask && format.gmask == GMask && format.bmask == BMask)
375  standard_format = true;
376  else
377  standard_format = false;
378 
379  if (cf.pal) {
380  for (int i = 0; i < 256; i++) {
381  ColorIndex::formatted_palette[i] = i;
382  ColorIndex::unfaded_palette[i] = i;
383  }
384  }
385  else {
386  double old_fade = fade;
387 
388  for (int i = 0; i < 256; i++) {
389  ColorIndex::formatted_palette[i] = Color(i).Formatted();
390 
391  fade = 1.0;
392  ColorIndex::unfaded_palette[i] = Color(i).Formatted();
393  fade = old_fade;
394  }
395  }
396 }
397 
398 // +--------------------------------------------------------------------+
399 
400 void
401 Color::UseTextureFormat(const ColorFormat& cf, int alpha_level)
402 {
403  texture_format[alpha_level] = cf;
404 
405  if (cf.pal) {
406  for (int i = 0; i < 256; i++) {
407  ColorIndex::texture_palettes[alpha_level][i] = i;
408  }
409  }
410  else {
411  double old_fade = fade;
412 
413  for (int i = 0; i < 256; i++) {
414  int old_texture_alpha_level = texture_alpha_level;
415  texture_alpha_level = alpha_level;
416  ColorIndex::texture_palettes[alpha_level][i] = Color(i).TextureFormat();
417  texture_alpha_level = old_texture_alpha_level;
418  }
419  }
420 }
421 
422 // +--------------------------------------------------------------------+
423 
424 void
425 Color::WithTextureFormat(int alpha_level)
426 {
427  texture_alpha_level = alpha_level;
428  ColorIndex::texture_palette = ColorIndex::texture_palettes[alpha_level];
429 }
430 
431 // +--------------------------------------------------------------------+
432 
433 static BYTE MatchRGB(PALETTEENTRY* pal, BYTE r, BYTE g, BYTE b)
434 {
435  double mindist = 100000000.0;
436  BYTE match = 0;
437 
438  for (int i = 0; i < 256; i++) {
439  PALETTEENTRY* p = pal++;
440 
441  double dr = p->peRed - r;
442  double dg = p->peGreen - g;
443  double db = p->peBlue - b;
444 
445  double d = (dr*dr) + (dg*dg) + (db*db);
446 
447  if (d < mindist) {
448  mindist = d;
449  match = i;
450 
451  if (d < 1.0)
452  return match;
453  }
454  }
455 
456  return match;
457 }
458 
459 // +--------------------------------------------------------------------+
460 
461 void
462 Color::SetPalette(PALETTEENTRY* pal, int palsize, BYTE* invpal)
463 {
464  for (int i = 0; i < palsize; i++)
465  palette[i] = pal[i];
466 
467  if (invpal) {
468  for (int i = 0; i < 32768; i++)
469  table[i] = invpal[i];
470  }
471  else {
472  for (int i = 0; i < 32768; i++) {
473  BYTE r = (i >> 10) & 0x1f;
474  BYTE g = (i >> 5) & 0x1f;
475  BYTE b = (i ) & 0x1f;
476 
477  Color c(r<<3, g<<3, b<<3);
478 
479  table[i] = MatchRGB(palette, r<<3, g<<3, b<<3);
480  }
481  }
482 
483  // set up formatted palette:
484  UseFormat(format);
485 
486  for (int i = 0; i < 4; i++)
487  UseTextureFormat(texture_format[i], i);
488 
489  // set up shade table:
490  double old_fade = fade;
491  fade = 1.0;
492  BuildShadeTable();
493  fade = old_fade;
494 
495  // and blend table:
496  BuildBlendTable();
497 }
498 
499 // +--------------------------------------------------------------------+
500 
501 void
502 Color::SavePalette(const char* basename)
503 {
504  char filename[256];
505 
506  sprintf_s(filename, "%s.ipl", basename);
507  FILE* f;
508  fopen_s(&f, filename, "wb");
509  if (f) {
510  fwrite(table, sizeof(table), 1, f);
511  fclose(f);
512  }
513 }
514 
515 // +--------------------------------------------------------------------+
516 
517 void
518 Color::SetFade(double f, Color c, int build_shade)
519 {
520  static int shade_built = 0;
521 
522  if (fade == f && fade_color == c && (build_shade ? shade_built : 1))
523  return;
524 
525  fade = f;
526  fade_color = c;
527 
528  // set up formatted palette:
529  UseFormat(format);
530 
531  // if this is a paletted video mode,
532  // modify the video palette as well:
533  if (format.pal && video) {
534  PALETTEENTRY fade_palette[256];
535 
536  double step = (1.0 - fade);
537  for (int i = 0; i < 256; i++) {
538  PALETTEENTRY& entry = fade_palette[i];
539  ColorIndex c = ColorIndex(i);
540 
541  entry.peRed = ((int) ((c.fRed() - (c.fRed() - fade_color.fRed()) * step)*255.0));
542  entry.peGreen = ((int) ((c.fGreen() - (c.fGreen() - fade_color.fGreen())* step)*255.0));
543  entry.peBlue = ((int) ((c.fBlue() - (c.fBlue() - fade_color.fBlue()) * step)*255.0));
544  entry.peFlags = 0;
545  }
546  }
547 
548  // otherwise, we need to re-compute
549  // the shade table:
550  else {
551  if (build_shade) {
552  BuildShadeTable();
553  shade_built = 1;
554  }
555  else {
556  shade_built = 0;
557  }
558  }
559 }
560 
561 // +--------------------------------------------------------------------+
562 
563 void
565 {
566  for (int shade = 0; shade < SHADE_LEVELS*2; shade++)
567  for (int index = 0; index < 256; index++)
568  ColorIndex::shade_table[shade*256+index] = Color(index).Shaded(shade);
569 }
570 
571 // +--------------------------------------------------------------------+
572 
573 void
575 {
576  for (int src = 0; src < 256; src++) {
577  for (int dst = 0; dst < 256; dst++) {
578  ColorIndex src_clr = ColorIndex(src);
579  ColorIndex dst_clr = ColorIndex(dst);
580 
581  int r = src_clr.Red() + dst_clr.Red();
582  int g = src_clr.Green() + dst_clr.Green();
583  int b = src_clr.Blue() + dst_clr.Blue();
584 
585  if (r>255) r=255;
586  if (g>255) g=255;
587  if (b>255) b=255;
588 
589  ColorIndex::blend_table[src*256+dst] = Color((BYTE)r,(BYTE)g,(BYTE)b).Index();
590  }
591  }
592 }
593 
594 // +--------------------------------------------------------------------+
595 
596 void
597 Color::SaveShadeTable(const char* basename)
598 {
599  if (!format.pal)
600  return;
601 
602  char filename[256];
603  sprintf_s(filename, "%s_clut.pcx", basename);
604 
605  BYTE clut[256*256];
606  BYTE* pc = clut;
607  int i;
608  for (i = 0; i < SHADE_LEVELS*2; i++)
609  for (int j = 0; j < 256; j++)
610  *pc++ = (BYTE) ColorIndex::shade_table[i*256+j];
611 
612  for (; i < 256; i++)
613  for (int j = 0; j < 256; j++)
614  *pc++ = (BYTE) 0;
615 
616  PcxImage pcx(256, 256, clut, (BYTE*) palette);
617  pcx.Save(filename);
618 }
619 
620 
621 // +--------------------------------------------------------------------+
622 // +--------------------------------------------------------------------+
623 // +--------------------------------------------------------------------+
624 
625 
626 ColorValue&
628 {
629  r += c.r;
630  g += c.g;
631  b += c.b;
632 
633  return *this;
634 }
635 
638 {
639  float src_alpha = c.a;
640  float dst_alpha = 1.0f - a;
641 
642  float fr = (r * dst_alpha) + (c.r * src_alpha);
643  float fg = (g * dst_alpha) + (c.g * src_alpha);
644  float fb = (b * dst_alpha) + (c.b * src_alpha);
645 
646  return ColorValue(fr, fg, fb);
647 }
648 
651 {
652  return ColorValue(r*c.r, g*c.g, b*c.b);
653 }
654 
656 ColorValue::operator*(double scale) const
657 {
658  return ColorValue((float) (r*scale),
659  (float) (g*scale),
660  (float) (b*scale),
661  (float) (a*scale));
662 }
663 
665 ColorValue::dim(double scale) const
666 {
667  return ColorValue((float) (r*scale),
668  (float) (g*scale),
669  (float) (b*scale));
670 }
671 
672 // +--------------------------------------------------------------------+
673 
674 inline BYTE bclamp(float x) { return (BYTE) ((x<0) ? 0 : (x>255) ? 255 : x); }
675 
676 Color
678 {
679  return Color(bclamp(r * 255.0f),
680  bclamp(g * 255.0f),
681  bclamp(b * 255.0f),
682  bclamp(a * 255.0f));
683 }