1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // color calculation routines
17 
18 #ifndef INC_StdColors
19 #define INC_StdColors
20 
21 // helper function
RGBA(uint32_t r,uint32_t g,uint32_t b,uint32_t a)22 inline uint32_t RGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
23 {
24 	return ((a & 255) << 24) | ((r & 255) << 16) | ((g & 255) << 8) | (b & 255);
25 }
26 #define C4RGB(r, g, b) (((DWORD)(0xff)<<24)|(((DWORD)(r)&0xff)<<16)|(((DWORD)(g)&0xff)<<8)|((b)&0xff))
27 #define GetBlueValue(rgb) ((unsigned char)(rgb))
28 #define GetGreenValue(rgb) ((unsigned char)(((unsigned short)(rgb)) >> 8))
29 #define GetRedValue(rgb) ((unsigned char)((rgb)>>16))
30 
BltAlpha(DWORD & dwDst,DWORD dwSrc)31 inline void BltAlpha(DWORD &dwDst, DWORD dwSrc)
32 {
33 	// blit one color value w/alpha on another
34 	if (dwDst>>24 == 0x00) { dwDst=dwSrc; return; }
35 	BYTE byAlphaSrc=BYTE(dwSrc>>24); BYTE byAlphaDst=255-byAlphaSrc;
36 	dwDst = std::min<uint32_t>(((dwDst    & 0xff ) * byAlphaDst + (dwSrc & 0xff    ) * byAlphaSrc) >>8,            0xff)      | // blue
37 	        std::min<uint32_t>(((dwDst   & 0xff00) * byAlphaDst + (dwSrc & 0xff00  ) * byAlphaSrc) >>8 & 0xff00,   0xff00)    | // green
38 	        std::min<uint32_t>(((dwDst & 0xff0000) * byAlphaDst + (dwSrc & 0xff0000) * byAlphaSrc) >>8 & 0xff0000, 0xff0000)  | // red
39 	        std::min<uint32_t>( (dwDst >> 24) + byAlphaSrc, 255) << 24; // alpha
40 }
41 
BltAlphaAdd(DWORD & dwDst,DWORD dwSrc)42 inline void BltAlphaAdd(DWORD &dwDst, DWORD dwSrc)
43 {
44 	// blit one color value w/alpha on another in additive mode
45 	if (dwDst>>24 == 0x00) { dwDst=dwSrc; return; }
46 	BYTE byAlphaSrc=BYTE(dwSrc>>24);
47 	dwDst = std::min<uint32_t>((dwDst    & 0xff ) + ((int(dwSrc    & 0xff  ) * byAlphaSrc) >>8)       , 0xff)      | // blue
48 	        std::min<uint32_t>(((dwDst   & 0xff00) + (int(dwSrc>>8 & 0xff  ) * byAlphaSrc)) & 0x00ffff00, 0xff00)    | // green
49 	        std::min<uint32_t>(((dwDst & 0xff0000) + (int(dwSrc>>8 & 0xff00) * byAlphaSrc)) & 0xffff0000, 0xff0000)  | // red
50 	        std::min<uint32_t>( (dwDst >> 24) + byAlphaSrc, 255) << 24; // alpha
51 }
52 
ModulateClr(DWORD & dwDst,DWORD dwMod)53 inline void ModulateClr(DWORD &dwDst, DWORD dwMod) // modulate two color values
54 {
55 	// modulate two color values
56 	// get alpha
57 	int iA1=dwDst>>24, iA2=dwMod>>24;
58 	// modulate color values; mod alpha upwards
59 	dwDst = ((dwDst     & 0xff) * (dwMod     & 0xff) / 0xff)      | // blue
60 	        ((dwDst>> 8 & 0xff) * (dwMod>> 8 & 0xff) / 0xff) << 8 | // green
61 	        ((dwDst>>16 & 0xff) * (dwMod>>16 & 0xff) / 0xff) << 16| // red
62 	        std::min(iA1*iA2/0xff, 255)                           << 24; // alpha (TODO: We don't need std::min() here, do we?)
63 }
64 
ModulateClrA(DWORD & dwDst,DWORD dwMod)65 inline void ModulateClrA(DWORD &dwDst, DWORD dwMod) // modulate two color values and add alpha value
66 {
67 	// modulate two color values and add alpha value
68 	dwDst = ((dwDst     & 0xff) * (dwMod     & 0xff) / 0xff)      | // B
69 	        ((dwDst>> 8 & 0xff) * (dwMod>> 8 & 0xff) / 0xff) << 8 | // G
70 	        ((dwDst>>16 & 0xff) * (dwMod>>16 & 0xff) / 0xff) << 16| // R
71 	        (std::max<uint32_t>((dwDst>>24)+(dwMod>>24), 0xff) - 0xff)<<24;
72 }
ModulateClrMOD2(DWORD & dwDst,DWORD dwMod)73 inline void ModulateClrMOD2(DWORD &dwDst, DWORD dwMod) // clr1+clr2-0.5
74 {
75 	// signed color addition
76 	dwDst = (Clamp<int>(((int)(dwDst&0xff)+(dwMod&0xff)-0x7f)<<1,0,0xff)&0xff) |  // B
77 	        (Clamp<int>(((int)(dwDst&0xff00)+(dwMod&0xff00)-0x7f00)<<1,0,0xff00)&0xff00) | // G
78 	        (Clamp<int>(((int)(dwDst&0xff0000)+(dwMod&0xff0000)-0x7f0000)<<1,0,0xff0000)&0xff0000) | // R
79 	        (std::max<uint32_t>((dwDst>>24)+(dwMod>>24), 0xff) - 0xff)<<24;
80 }
81 
LightenClrBy(DWORD & dwDst,int iBy)82 inline DWORD LightenClrBy(DWORD &dwDst, int iBy) // enlight a color
83 {
84 	// enlight a color
85 	// quite a desaturating method...
86 	dwDst = std::min<int>((dwDst     & 0xff) + iBy, 255)       | // blue
87 	        std::min<int>((dwDst>> 8 & 0xff) + iBy, 255) <<  8 | // green
88 	        std::min<int>((dwDst>>16 & 0xff) + iBy, 255) << 16 | // red
89 	        (dwDst & 0xff000000);                     // alpha
90 	return dwDst;
91 }
92 
DarkenClrBy(DWORD & dwDst,int iBy)93 inline DWORD DarkenClrBy(DWORD &dwDst, int iBy) // darken a color
94 {
95 	// darken a color
96 	// quite a desaturating method...
97 	dwDst = std::max<int>(int(dwDst     & 0xff) - iBy, 0)       | // blue
98 	        std::max<int>(int(dwDst>> 8 & 0xff) - iBy, 0) <<  8 | // green
99 	        std::max<int>(int(dwDst>>16 & 0xff) - iBy, 0) << 16 | // red
100 	        (dwDst & 0xff000000);                     // alpha
101 	return dwDst;
102 }
103 
PlrClr2TxtClr(DWORD dwClr)104 inline DWORD PlrClr2TxtClr(DWORD dwClr)
105 {
106 	// convert player color to text color, lightening up when necessary
107 	int lgt=std::max(std::max(GetRedValue(dwClr), GetGreenValue(dwClr)), GetBlueValue(dwClr));
108 	if (lgt<0x8f) LightenClrBy(dwClr, 0x8f-lgt);
109 	return dwClr|0xff000000;
110 }
111 
GetClrModulation(DWORD dwSrcClr,DWORD dwDstClr,DWORD & dwBack)112 inline DWORD GetClrModulation(DWORD dwSrcClr, DWORD dwDstClr, DWORD &dwBack)
113 {
114 	// get modulation that is necessary to transform dwSrcClr to dwDstClr
115 	// does not support alpha values in dwSrcClr and dwDstClr
116 	// get source color
117 	BYTE sB=BYTE(dwSrcClr); dwSrcClr=dwSrcClr>>8;
118 	BYTE sG=BYTE(dwSrcClr); dwSrcClr=dwSrcClr>>8;
119 	BYTE sR=BYTE(dwSrcClr); dwSrcClr=dwSrcClr>>8;
120 	// get dest color
121 	BYTE dB=BYTE(dwDstClr); dwDstClr=dwDstClr>>8;
122 	BYTE dG=BYTE(dwDstClr); dwDstClr=dwDstClr>>8;
123 	BYTE dR=BYTE(dwDstClr); dwDstClr=dwDstClr>>8;
124 	// get difference
125 	int cR=(int) dR-sR;
126 	int cG=(int) dG-sG;
127 	int cB=(int) dB-sB;
128 	// get max enlightment
129 	int diffN=0;
130 	if (cR>0) diffN=cR;
131 	if (cG>0) diffN=std::max(diffN, cG);
132 	if (cB>0) diffN=std::max(diffN, cB);
133 	// is dest > src?
134 	if (diffN)
135 	{
136 		// so a back mask must be used
137 		int bR=sR+(cR*255)/diffN;
138 		int bG=sG+(cG*255)/diffN;
139 		int bB=sB+(cB*255)/diffN;
140 		dwBack=RGBA(bR, bG, bB, 255);
141 	}
142 	if (!sR) sR=1; if (!sG) sG=1; if (!sB) sB=1;
143 	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);
144 }
145 
rgb2xyY(double r,double g,double b,double * px,double * py,double * pY)146 inline bool rgb2xyY(double r, double g, double b, double *px, double *py, double *pY) // linear rgb to CIE xyY
147 {
148 	double X = 0.412453*r + 0.357580*g + 0.180423*b;
149 	double Y = 0.212671*r + 0.715160*g + 0.072169*b;
150 	double Z = 0.019334*r + 0.119193*g + 0.950227*b;
151 	double XYZ=X+Y+Z;
152 	if (!XYZ)
153 	{
154 		*px=*py=0.3; // assume grey cromaticity for black
155 	}
156 	else
157 	{
158 		*px = X/XYZ; *py = Y/XYZ;
159 	}
160 	*pY = Y;
161 	return true;
162 }
163 
xy2upvp(double x,double y,double * pu,double * pv)164 inline bool xy2upvp(double x, double y, double *pu, double *pv) // CIE xy to u'v'
165 {
166 	double n = -2.0*x+12.0*y+3.0;
167 	if (!n) return false;
168 	*pu = 4.0*x / n;
169 	*pv = 9.0*y / n;
170 	return true;
171 }
172 
173 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
174 {
175 	*pr = pow((double) R / 255.0, 1.0/gamma);
176 	*pg = pow((double) G / 255.0, 1.0/gamma);
177 	*pb = pow((double) B / 255.0, 1.0/gamma);
178 	return true;
179 }
180 
181 // a standard pal
182 struct CStdPalette
183 {
184 	DWORD Colors[256];
185 
GetClrCStdPalette186 	DWORD GetClr(BYTE byCol)
187 	{ return Colors[byCol]; }
188 };
189 
190 #endif
191