openclonk/src/lib/StdColors.h

193 lines
6.9 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
// color calculation routines
#ifndef INC_StdColors
#define INC_StdColors
// helper function
inline uint32_t RGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
{
return ((a & 255) << 24) | ((r & 255) << 16) | ((g & 255) << 8) | (b & 255);
}
#define C4RGB(r, g, b) (((DWORD)(0xff)<<24)|(((DWORD)(r)&0xff)<<16)|(((DWORD)(g)&0xff)<<8)|((b)&0xff))
#define GetBlueValue(rgb) ((unsigned char)(rgb))
#define GetGreenValue(rgb) ((unsigned char)(((unsigned short)(rgb)) >> 8))
#define GetRedValue(rgb) ((unsigned char)((rgb)>>16))
inline void BltAlpha(DWORD &dwDst, DWORD dwSrc)
{
// blit one color value w/alpha on another
if (dwDst>>24 == 0x00) { dwDst=dwSrc; return; }
BYTE byAlphaSrc=BYTE(dwSrc>>24); BYTE byAlphaDst=255-byAlphaSrc;
dwDst = std::min<uint32_t>(((dwDst & 0xff ) * byAlphaDst + (dwSrc & 0xff ) * byAlphaSrc) >>8, 0xff) | // blue
std::min<uint32_t>(((dwDst & 0xff00) * byAlphaDst + (dwSrc & 0xff00 ) * byAlphaSrc) >>8 & 0xff00, 0xff00) | // green
std::min<uint32_t>(((dwDst & 0xff0000) * byAlphaDst + (dwSrc & 0xff0000) * byAlphaSrc) >>8 & 0xff0000, 0xff0000) | // red
std::min<uint32_t>( (dwDst >> 24) + byAlphaSrc, 255) << 24; // alpha
}
inline void BltAlphaAdd(DWORD &dwDst, DWORD dwSrc)
{
// blit one color value w/alpha on another in additive mode
if (dwDst>>24 == 0x00) { dwDst=dwSrc; return; }
BYTE byAlphaSrc=BYTE(dwSrc>>24);
dwDst = std::min<uint32_t>((dwDst & 0xff ) + ((int(dwSrc & 0xff ) * byAlphaSrc) >>8) , 0xff) | // blue
std::min<uint32_t>(((dwDst & 0xff00) + (int(dwSrc>>8 & 0xff ) * byAlphaSrc)) & 0x00ffff00, 0xff00) | // green
std::min<uint32_t>(((dwDst & 0xff0000) + (int(dwSrc>>8 & 0xff00) * byAlphaSrc)) & 0xffff0000, 0xff0000) | // red
std::min<uint32_t>( (dwDst >> 24) + byAlphaSrc, 255) << 24; // alpha
}
inline void ModulateClr(DWORD &dwDst, DWORD dwMod) // modulate two color values
{
// modulate two color values
// get alpha
int iA1=dwDst>>24, iA2=dwMod>>24;
// modulate color values; mod alpha upwards
dwDst = ((dwDst & 0xff) * (dwMod & 0xff) / 0xff) | // blue
((dwDst>> 8 & 0xff) * (dwMod>> 8 & 0xff) / 0xff) << 8 | // green
((dwDst>>16 & 0xff) * (dwMod>>16 & 0xff) / 0xff) << 16| // red
std::min(iA1*iA2/0xff, 255) << 24; // alpha (TODO: We don't need std::min() here, do we?)
}
inline void ModulateClrA(DWORD &dwDst, DWORD dwMod) // modulate two color values and add alpha value
{
// modulate two color values and add alpha value
dwDst = ((dwDst & 0xff) * (dwMod & 0xff) / 0xff) | // B
((dwDst>> 8 & 0xff) * (dwMod>> 8 & 0xff) / 0xff) << 8 | // G
((dwDst>>16 & 0xff) * (dwMod>>16 & 0xff) / 0xff) << 16| // R
(std::max<uint32_t>((dwDst>>24)+(dwMod>>24), 0xff) - 0xff)<<24;
}
inline void ModulateClrMOD2(DWORD &dwDst, DWORD dwMod) // clr1+clr2-0.5
{
// signed color addition
dwDst = (Clamp<int>(((int)(dwDst&0xff)+(dwMod&0xff)-0x7f)<<1,0,0xff)&0xff) | // B
(Clamp<int>(((int)(dwDst&0xff00)+(dwMod&0xff00)-0x7f00)<<1,0,0xff00)&0xff00) | // G
(Clamp<int>(((int)(dwDst&0xff0000)+(dwMod&0xff0000)-0x7f0000)<<1,0,0xff0000)&0xff0000) | // R
(std::max<uint32_t>((dwDst>>24)+(dwMod>>24), 0xff) - 0xff)<<24;
}
inline DWORD LightenClrBy(DWORD &dwDst, int iBy) // enlight a color
{
// enlight a color
// quite a desaturating method...
dwDst = std::min<int>((dwDst & 0xff) + iBy, 255) | // blue
std::min<int>((dwDst>> 8 & 0xff) + iBy, 255) << 8 | // green
std::min<int>((dwDst>>16 & 0xff) + iBy, 255) << 16 | // red
(dwDst & 0xff000000); // alpha
return dwDst;
}
inline DWORD DarkenClrBy(DWORD &dwDst, int iBy) // darken a color
{
// darken a color
// quite a desaturating method...
dwDst = std::max<int>(int(dwDst & 0xff) - iBy, 0) | // blue
std::max<int>(int(dwDst>> 8 & 0xff) - iBy, 0) << 8 | // green
std::max<int>(int(dwDst>>16 & 0xff) - iBy, 0) << 16 | // red
(dwDst & 0xff000000); // alpha
return dwDst;
}
inline DWORD PlrClr2TxtClr(DWORD dwClr)
{
// convert player color to text color, lightening up when necessary
int lgt=std::max(std::max(GetRedValue(dwClr), GetGreenValue(dwClr)), GetBlueValue(dwClr));
if (lgt<0x8f) LightenClrBy(dwClr, 0x8f-lgt);
return dwClr|0xff000000;
}
inline DWORD GetClrModulation(DWORD dwSrcClr, DWORD dwDstClr, DWORD &dwBack)
{
// get modulation that is necessary to transform dwSrcClr to dwDstClr
// does not support alpha values in dwSrcClr and dwDstClr
// get source color
BYTE sB=BYTE(dwSrcClr); dwSrcClr=dwSrcClr>>8;
BYTE sG=BYTE(dwSrcClr); dwSrcClr=dwSrcClr>>8;
BYTE sR=BYTE(dwSrcClr); dwSrcClr=dwSrcClr>>8;
// get dest color
BYTE dB=BYTE(dwDstClr); dwDstClr=dwDstClr>>8;
BYTE dG=BYTE(dwDstClr); dwDstClr=dwDstClr>>8;
BYTE dR=BYTE(dwDstClr); dwDstClr=dwDstClr>>8;
// get difference
int cR=(int) dR-sR;
int cG=(int) dG-sG;
int cB=(int) dB-sB;
// get max enlightment
int diffN=0;
if (cR>0) diffN=cR;
if (cG>0) diffN=std::max(diffN, cG);
if (cB>0) diffN=std::max(diffN, cB);
// is dest > src?
if (diffN)
{
// so a back mask must be used
int bR=sR+(cR*255)/diffN;
int bG=sG+(cG*255)/diffN;
int bB=sB+(cB*255)/diffN;
dwBack=RGBA(bR, bG, bB, 255);
}
if (!sR) sR=1;
if (!sG) sG=1;
if (!sB) sB=1;
return RGBA(std::min((int)dR*256/sR, 255), std::min((int)dG*256/sG, 255), std::min((int)dB*256/sB, 255), 255-diffN);
}
inline bool rgb2xyY(double r, double g, double b, double *px, double *py, double *pY) // linear rgb to CIE xyY
{
double X = 0.412453*r + 0.357580*g + 0.180423*b;
double Y = 0.212671*r + 0.715160*g + 0.072169*b;
double Z = 0.019334*r + 0.119193*g + 0.950227*b;
double XYZ=X+Y+Z;
if (!XYZ)
{
*px=*py=0.3; // assume grey cromaticity for black
}
else
{
*px = X/XYZ; *py = Y/XYZ;
}
*pY = Y;
return true;
}
inline bool xy2upvp(double x, double y, double *pu, double *pv) // CIE xy to u'v'
{
double n = -2.0*x+12.0*y+3.0;
if (!n) return false;
*pu = 4.0*x / n;
*pv = 9.0*y / n;
return true;
}
inline bool RGB2rgb(int R, int G, int B, double *pr, double *pg, double *pb, double gamma=2.2) // monitor RGB (0 to 255) to linear rgb (0.0 to 1.0) assuming default gamma 2.2
{
*pr = pow((double) R / 255.0, 1.0/gamma);
*pg = pow((double) G / 255.0, 1.0/gamma);
*pb = pow((double) B / 255.0, 1.0/gamma);
return true;
}
// a standard pal
struct CStdPalette
{
DWORD Colors[256];
DWORD GetClr(BYTE byCol)
{ return Colors[byCol]; }
};
#endif