1 /*
2     C-Dogs SDL
3     A port of the legendary (and fun) action/arcade cdogs.
4 
5     Copyright (c) 2013-2018 Cong Xu
6     All rights reserved.
7 
8     Redistribution and use in source and binary forms, with or without
9     modification, are permitted provided that the following conditions are met:
10 
11     Redistributions of source code must retain the above copyright notice, this
12     list of conditions and the following disclaimer.
13     Redistributions in binary form must reproduce the above copyright notice,
14     this list of conditions and the following disclaimer in the documentation
15     and/or other materials provided with the distribution.
16 
17     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20     ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21     LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27     POSSIBILITY OF SUCH DAMAGE.
28 */
29 #include "color.h"
30 
31 #include <math.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "utils.h"
36 
37 color_t colorWhite = { 255, 255, 255, 255 };
38 color_t colorRed = { 255, 0, 0, 255 };
39 color_t colorGreen = { 0, 255, 0, 255 };
40 color_t colorBlue = { 0, 0, 255, 255 };
41 color_t colorPoison = { 64, 192, 64, 255 };
42 color_t colorBlack = { 0, 0, 0, 255 };
43 color_t colorDarker = { 192, 192, 192, 255 };
44 color_t colorPurple = { 192, 0, 192, 255 };
45 color_t colorGray = { 128, 128, 128, 255 };
46 color_t colorYellow = { 255, 255, 128, 255 };
47 color_t colorMagenta = { 255, 0, 255, 255 };
48 color_t colorCyan = { 0, 255, 255, 255 };
49 color_t colorFog = { 96, 96, 96, 255 };
50 color_t colorOrange = { 255, 128, 0, 255 };
51 color_t colorTransparent = { 0, 0, 0, 0 };
52 
53 color_t colorMaroon = { 0x84, 0, 0, 255 };
54 color_t colorLonestar = { 0x70, 0, 0, 255 };
55 color_t colorRusticRed = { 0x48, 0, 0, 255 };
56 color_t colorOfficeGreen = { 0, 0x84, 0, 255 };
57 color_t colorPakistanGreen = { 0, 0x70, 0, 255 };
58 color_t colorDarkFern = { 0, 0x48, 0, 255 };
59 color_t colorNavyBlue = { 0, 0, 0x84, 255 };
60 color_t colorArapawa = { 0, 0, 0x70, 255 };
61 color_t colorStratos = { 0, 0, 0x48, 255 };
62 color_t colorPatriarch = { 0x84, 0, 0x84, 255 };
63 color_t colorPompadour = { 0x70, 0, 0x70, 255 };
64 color_t colorLoulou = { 0x48, 0, 0x48, 255 };
65 color_t colorBattleshipGrey = { 0x84, 0x84, 0x84, 255 };
66 color_t colorDoveGray = { 0x70, 0x70, 0x70, 255 };
67 color_t colorGravel = { 0x48, 0x48, 0x48, 255 };
68 color_t colorComet = { 0x5C, 0x5C, 0x84, 255 };
69 color_t colorFiord = { 0x48, 0x48, 0x70, 255 };
70 color_t colorTuna = { 0x34, 0x34, 0x48, 255 };
71 color_t colorHacienda = { 0x94, 0x80, 0x2C, 255 };
72 color_t colorKumera = { 0x84, 0x70, 0x24, 255 };
73 color_t colorHimalaya = { 0x74, 0x60, 0x1C, 255 };
74 color_t colorChocolate = { 0x84, 0x44, 0, 255 };
75 color_t colorNutmeg = { 0x70, 0x38, 0, 255 };
76 color_t colorBracken = { 0x48, 0x24, 0, 255 };
77 color_t colorTeal = { 0, 0x84, 0x84, 255 };
78 color_t colorSkobeloff = { 0, 0x70, 0x70, 255 };
79 color_t colorDeepJungleGreen = { 0, 0x48, 0x48, 255 };
80 
81 color_t colorSkin = { 0xF4, 0x94, 0x4C, 255 };
82 color_t colorDarkSkin = { 0x93, 0x5D, 0x37, 255 };
83 color_t colorAsianSkin = { 0xFF, 0xCC, 0x99, 255 };
84 
85 color_t colorLightBlue = { 80, 80, 160, 255 };
86 
ColorMult(color_t c,color_t m)87 color_t ColorMult(color_t c, color_t m)
88 {
89 	c.r = (uint8_t)((int)c.r * m.r / 255);
90 	c.g = (uint8_t)((int)c.g * m.g / 255);
91 	c.b = (uint8_t)((int)c.b * m.b / 255);
92 	c.a = (uint8_t)((int)c.a * m.a / 255);
93 	return c;
94 }
ColorAlphaBlend(color_t a,color_t b)95 color_t ColorAlphaBlend(color_t a, color_t b)
96 {
97 	a.r = (uint8_t)(((int)a.r*(255 - b.a) + (int)b.r*b.a)/255);
98 	a.g = (uint8_t)(((int)a.g*(255 - b.a) + (int)b.g*b.a)/255);
99 	a.b = (uint8_t)(((int)a.b*(255 - b.a) + (int)b.b*b.a)/255);
100 	a.a = 255;
101 	return a;
102 }
103 
104 HSV tintNone = { -1.0, 1.0, 1.0 };
105 HSV tintRed = { 0.0, 1.0, 1.0 };
106 HSV tintYellow = { 60.0, 1.0, 1.0 };
107 HSV tintGreen = { 120.0, 1.0, 1.0 };
108 HSV tintCyan = { 180.0, 1.0, 1.0 };
109 HSV tintPoison = { 120.0, 0.33, 2.0 };
110 HSV tintGray = { -1.0, 0.0, 1.0 };
111 HSV tintPurple = { 300, 1.0, 1.0 };
112 HSV tintDarker = { -1.0, 1.0, 0.75 };
113 
ColorTint(color_t c,HSV hsv)114 color_t ColorTint(color_t c, HSV hsv)
115 {
116 	// Adapted from answer by David H
117 	// http://stackoverflow.com/a/6930407/2038264
118 	// License: http://creativecommons.org/licenses/by-sa/3.0/
119 	// Author profile: http://stackoverflow.com/users/1633251/david-h
120 	color_t out;
121 	int vAvg = ((int)c.r + c.g + c.b) / 3;
122 	uint8_t vComponent = (uint8_t)CLAMP(hsv.v * vAvg, 0, 255);
123 
124 	if (hsv.s <= 0.0)
125 	{
126 		// No saturation; just gray
127 		out.r = vComponent;
128 		out.g = vComponent;
129 		out.b = vComponent;
130 	}
131 	else if (hsv.h >= 0)
132 	{
133 		// set hue to h; use regular HSV to RGB conversion
134 		double ff;
135 		uint8_t p, q, t;
136 		long i;
137 		double hh = hsv.h;
138 		if (hh >= 360.0)
139 		{
140 			hh = 0.0;
141 		}
142 		hh /= 60.0;
143 		i = (long)hh;
144 		ff = hh - i;
145 		p = (uint8_t)CLAMP(vComponent * (1.0 - hsv.s), 0, 255);
146 		q = (uint8_t)CLAMP(vComponent * (1.0 - (hsv.s * ff)), 0, 255);
147 		t = (uint8_t)CLAMP(vComponent * (1.0 - (hsv.s * (1.0 - ff))), 0, 255);
148 
149 		switch(i)
150 		{
151 		case 0:
152 			out.r = vComponent;
153 			out.g = t;
154 			out.b = p;
155 			break;
156 		case 1:
157 			out.r = q;
158 			out.g = vComponent;
159 			out.b = p;
160 			break;
161 		case 2:
162 			out.r = p;
163 			out.g = vComponent;
164 			out.b = t;
165 			break;
166 
167 		case 3:
168 			out.r = p;
169 			out.g = q;
170 			out.b = vComponent;
171 			break;
172 		case 4:
173 			out.r = t;
174 			out.g = p;
175 			out.b = vComponent;
176 			break;
177 		case 5:
178 		default:
179 			out.r = vComponent;
180 			out.g = p;
181 			out.b = q;
182 			break;
183 		}
184 	}
185 	else
186 	{
187 		// Just set saturation and value
188 		// Use weighted average to shift components towards grey for saturation
189 		out.r = (uint8_t)CLAMP(hsv.v * (vAvg*(1.0-hsv.s) + hsv.s*c.r), 0, 255);
190 		out.g = (uint8_t)CLAMP(hsv.v * (vAvg*(1.0-hsv.s) + hsv.s*c.g), 0, 255);
191 		out.b = (uint8_t)CLAMP(hsv.v * (vAvg*(1.0-hsv.s) + hsv.s*c.b), 0, 255);
192 	}
193 	out.a = c.a;
194 	return out;
195 }
196 
ColorEquals(const color_t a,const color_t b)197 bool ColorEquals(const color_t a, const color_t b)
198 {
199 	return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
200 }
HSVEquals(const HSV a,const HSV b)201 bool HSVEquals(const HSV a, const HSV b)
202 {
203 	const double epsilon = 0.000001;
204 	return fabs(a.h - b.h) < epsilon && fabs(a.s - b.s) < epsilon &&
205 		fabs(a.v - b.v) < epsilon;
206 }
207 
StrColor(const char * s)208 color_t StrColor(const char *s)
209 {
210 	if (s == NULL)
211 	{
212 		return colorBlack;
213 	}
214 	const int len = (int)strlen(s);
215 	if (len != 6 && len != 8)
216 	{
217 		return colorBlack;
218 	}
219 	long long hex = strtoll(s, NULL, 16);
220 	color_t c;
221 	if (len == 6)
222 	{
223 		c.a = 255;
224 	}
225 	else
226 	{
227 		c.a = hex & 255;
228 		hex >>= 8;
229 	}
230 	c.r = (hex >> 16) & 255;
231 	c.g = (hex >> 8) & 255;
232 	c.b = hex & 255;
233 	return c;
234 }
ColorStr(char * s,const color_t c)235 void ColorStr(char *s, const color_t c)
236 {
237 	sprintf(s, "%02x%02x%02x%02x", c.r, c.g, c.b, c.a);
238 }
239