// Colors.h #ifndef Colorsh #define Colorsh #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include // For modf #define NoColor ((COLORREF)-1) // Used to indicate an unset color class CColors { /* Mixing 3 cos waves gives a spectrum with no pure R,G or B. static BYTE GetGreen(double Hue) {return (BYTE)min(max(0, (int)(255 * cos(2*PI * Hue) + 128)), 255);} Clipping gives a proper spectrum and what is left is a nice quick straight-line: Green is simplest wave to model. This version doesn't need slow 'cos' calls: */ static BYTE GetGreen(double Hue) { // Hue should be 0-1 double Scrap; // Since GetGreen(0)==GetGreen(1) modf is the fastest clamping method. Hue=modf(Hue,&Scrap); // _ _ if(Hue<0) Hue+=1; // Map negatives from the end. Red: | \__/ | if(Hue<1/6.) return (BYTE)(0.5+255*Hue*6);// 0 __ 1 else if(Hue<1/2.) return 255; // Green: |/ \__| else if(Hue<2/3.) return (BYTE)(0.5+255*(2/3.-Hue)*6);// 0 __ 1 return 0; // Blue: |__/ \| } public: CColors() {} virtual ~CColors() {} static COLORREF GetRainbowColor(double Ratio) { ASSERT(Ratio>=0.0); ASSERT(Ratio<=1.0); return RGB(GetGreen(Ratio+1/3.), GetGreen(Ratio), GetGreen(Ratio-1/3.)); } static DWORD BGR2RGB(DWORD Colour) { BYTE* it=reinterpret_cast(&Colour); BYTE t=*it; *it=it[2]; it[2]=t; // Compilers and processors optimise for basic swaps return Colour; } static DWORD MixColours(COLORREF Color1, COLORREF Color2) {return((Color1>>1) & 0x7F7F7F)+((Color2>>1) & 0x7F7F7F);} static DWORD AlphaBlend(COLORREF Paper, COLORREF Paint, BYTE Transparency) { // double a=Transparency/255.0; return RGB(BYTE((a*GetRValue(Paper)+(1-a)*GetRValue(Paint))), BYTE((a*GetGValue(Paper)+(1-a)*GetGValue(Paint))), BYTE((a*GetBValue(Paper)+(1-a)*GetBValue(Paint)))); switch(Transparency) { // Catch values that are easy to optimise: case 0: case 1: return Paint; case 63: case 64: return MixColours(Paint,MixColours(Paint,Paper)); case 127: case 128: return MixColours(Paint,Paper); case 191: case 192: return MixColours(Paper,MixColours(Paper,Paint)); case 254: case 255: return Paper; default : const BYTE Visibility=~Transparency; return (((((Paint&0x0000FF)*Visibility)+((Paper&0x0000FF)*Transparency))&0x0000FF00) | ((((Paint&0x00FF00)*Visibility)+((Paper&0x00FF00)*Transparency))&0x00FF0000) | ((((Paint&0xFF0000)*Visibility)+((Paper&0xFF0000)*Transparency))&0xFF000000))>>8; } } static bool IsGray(COLORREF Color, BYTE Tolerance=0) { // Tolerance specifies how close to Gray, 0 means R=G=B, 1 means that there may be a difference of at most 1 between two components BYTE R=GetRValue(Color); BYTE G=GetGValue(Color); BYTE B=GetBValue(Color); return ((abs(R-G)<=Tolerance) && (abs(R-B)<=Tolerance) && (abs(G-B)<=Tolerance)); } static BYTE GetGrayLevel (COLORREF Color) {return (19595*GetRValue(Color) + 38470*GetGValue(Color) + 7471*GetBValue(Color))>>16;} // Fast BYTE version of Standard NTSC weights for eye response static double GetGrayBrightness (COLORREF Color) {return (0.299*GetRValue(Color) + 0.587*GetGValue(Color) + 0.114*GetBValue(Color))/255;} // Returns 0 to 1,Standard NTSC weights for eye response static double GetAverageBrightness(COLORREF Color) {return (GetRValue(Color)+GetGValue(Color)+GetBValue(Color))/(255/3.0);} // Avarage static COLORREF BrightenColor(COLORREF Color, double Brightness) { // Brightness 0 to 1 ASSERT(Brightness>=0.0); ASSERT(Brightness<=1.0); double dR=GetRValue(Color)/255.0; double dG=GetGValue(Color)/255.0; double dB=GetBValue(Color)/255.0; double d=3.0*Brightness/(dR+dG+dB); dR*=d; dG*=d; dB*=d; int R=(int)(dR*255); int G=(int)(dG*255); int B=(int)(dB*255); NormalizeColor(R,G,B); return RGB(R,G,B); } static void NormalizeColor(int& R, int& G, int& B) { ASSERT(R+G+B<=3*255); if(R>255) Distribute(R,G,B); else if(G>255) Distribute(G,R,B); else if(B>255) Distribute(B,R,G); } private: static void Distribute(int& A, int& B, int& C) { int h=(A-255)/2; A=255; B+=h; C+=h; if(B>255) { int h=B-255; B=255; C+=h; ASSERT(C<=255); }else if(C>255) { int h= C-255; C=255; B+=h; ASSERT(B<=255); } } }; #endif // ndef Colorsh