1 // Hyperbolic Rogue -- color routines
2 // Copyright (C) 2011-2020 Zeno Rogue, see 'hyper.cpp' for details
3 
4 /** \file colors.cpp
5  *  \brief This file implements routines related to colors
6  */
7 
8 #include "hyper.h"
9 namespace hr {
10 
11 /** \brief Return a reference to i-th component of col.
12  *  \arg i For colors with alpha, A=0, R=1, G=2, B=3. For colors without alpha, R=0, G=1, B=2.
13  */
part(color_t & col,int i)14 EX unsigned char& part(color_t& col, int i) {
15   unsigned char* c = (unsigned char*) &col;
16 #if ISMOBILE
17   return c[i];
18 #else
19 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
20   return c[sizeof(col) - 1 - i];
21 #else
22   return c[i];
23 #endif
24 #endif
25   }
26 
27 #if HDR
28 static const color_t NOCOLOR = 0;
29 
30 struct colortable: vector<color_t> {
operator []hr::colortable31   color_t& operator [] (int i) { i %= size(); if(i<0) i += size(); return ((vector<color_t>&)(*this)) [i]; }
operator []hr::colortable32   const color_t& operator [] (int i) const { i %= size(); if(i<0) i += size(); return ((vector<color_t>&)(*this)) [i]; }
colortablehr::colortable33   colortable(std::initializer_list<color_t> v) : vector(v) {}
colortablehr::colortable34   colortable() : vector({0}) {}
35   };
36 #endif
37 
38 /* darkening routines */
39 
darkena3(color_t c,int lev,int a)40 EX color_t darkena3(color_t c, int lev, int a) {
41   return (darkenedby(c, lev) << 8) + a;
42   }
43 
darkena(color_t c,int lev,int a)44 EX color_t darkena(color_t c, int lev, int a) {
45   return darkena3(c, lev, GDIM == 3 ? 255 : a);
46   }
47 
darkenedby(int c,int lev)48 EX int darkenedby(int c, int lev) {
49   for(int i=0; i<lev; i++)
50     c = ((c & 0xFEFEFE) >> 1);
51   return c;
52   }
53 
54 bool fading = false;
55 
56 ld fadeout = 1;
57 
darkened(color_t c)58 EX color_t darkened(color_t c) {
59   if(inmirrorcount&1)
60     c = gradient(c, winf[waMirror].color, 0, 0.5, 1);
61   else if(inmirrorcount)
62     c = gradient(c, winf[waCloud].color, 0, 0.5, 1);
63   if(fading) c = gradient(backcolor, c, 0, fadeout, 1);
64   if(vid.desaturate) {
65     ld luminance = 0.2125 * part(c,2) + 0.7154 * part(c,1) + 0.0721 * part(c, 0);
66     c = gradient(c, int(luminance+.5) * 0x10101, 0, vid.desaturate, 100);
67     }
68   for(int i=0; i<darken; i++)
69     c = ((c & 0xFEFEFE) >> 1) + ((backcolor & 0xFEFEFE) >> 1);
70   return c;
71   }
72 
73 /* gradient interpolation */
74 
gradient(color_t c0,color_t c1,ld v0,ld v,ld v1)75 EX color_t gradient(color_t c0, color_t c1, ld v0, ld v, ld v1) {
76   int vv = int(256 * ((v-v0) / (v1-v0)));
77   color_t c = 0;
78   for(int a=0; a<4; a++) {
79     int p0 = part(c0, a);
80     int p1 = part(c1, a);
81     part(c, a) = (p0*(256-vv) + p1*vv + 127) >> 8;
82     }
83   return c;
84   }
85 
rcolor()86 EX color_t rcolor() {
87   color_t res;
88   part(res, 0) = hrand(0x80);
89   part(res, 1) = hrand(256);
90   part(res, 2) = hrand(0x80) + 128;
91   swap(part(res, 1), part(res, rand() % 2));
92   swap(part(res, 2), part(res, rand() % 3));
93   return res;
94   }
95 
rainbow_color(ld sat,ld hue)96 EX color_t rainbow_color(ld sat, ld hue) {
97   hue = frac(hue);
98 
99   if(hue < 0) hue++;
100 
101   hue *= 6;
102 
103   color_t res = 0;
104 
105   if(hue<1) res = gradient(0xFF0000, 0xFFFF00, 0, hue, 1);
106   else if(hue<2) res = gradient(0x00FF00, 0xFFFF00, 2, hue, 1);
107   else if(hue<3) res = gradient(0x00FF00, 0x00FFFF, 2, hue, 3);
108   else if(hue<4) res = gradient(0x0000FF, 0x00FFFF, 4, hue, 3);
109   else if(hue<5) res = gradient(0x0000FF, 0xFF00FF, 4, hue, 5);
110   else if(hue<6) res = gradient(0xFF0000, 0xFF00FF, 6, hue, 5);
111 
112   return gradient(0xFFFFFF, res, 0, sat, 1);
113   }
114 
115 /** Adjust col to SDL_gfx functions. No adjustment is needed in SDL 1.2, but it is needed in SDL2 */
align(color_t col)116 EX color_t align(color_t col) {
117   #if CAP_SDL2
118   swap(part(col, 0), part(col, 3));
119   swap(part(col, 1), part(col, 2));
120   #endif
121   return col;
122   }
123 
124 #if HDR
125 enum class eNeon { none, neon, no_boundary, neon2, illustration};
126 #endif
127 
128 EX eNeon neon_mode;
129 EX bool neon_nofill;
130 
apply_neon(color_t & col,int & r)131 EX void apply_neon(color_t& col, int& r) {
132   switch(neon_mode) {
133     case eNeon::none:
134     case eNeon::illustration:
135       break;
136     case eNeon::neon:
137       poly_outline = col << 8; col = 0;
138       break;
139     case eNeon::no_boundary:
140       r = 0;
141       break;
142     case eNeon::neon2:
143       poly_outline = col << 8; col &= 0xFEFEFE; col >>= 1;
144       break;
145     }
146   }
147 
148 /** used when neon_mode is eNeon::illustration */
magentize(color_t x)149 EX color_t magentize(color_t x) {
150   if(neon_mode != eNeon::illustration) return x;
151   int green = part(x,2);
152   int magenta = (part(x, 1) + part(x, 3)) / 2;
153   int nm = max(magenta, green);
154   int gm = (magenta + green)/2;
155   nm = (nm + 255) / 2;
156   gm = gm / 2;
157 
158   return (nm * 0x1000100) | (gm * 0x10000) | (part(x, 0));
159   }
160 
monochromatize(color_t x)161 EX color_t monochromatize(color_t x) {
162   int c = part(x,2) + part(x,1) + part(x, 3);
163   c ++;
164   c /= 3;
165   return c * 0x1010100 | (part(x, 0));
166   }
167 
168 /** colorblind mode */
169 EX bool cblind;
170 
171 /** apply neon_mode and cblind */
apply_neon_color(color_t col,color_t & pcolor,color_t & poutline,flagtype flags)172 EX void apply_neon_color(color_t col, color_t& pcolor, color_t& poutline, flagtype flags) {
173   if(cblind) {
174     // protanopia
175     /* int r = (56 * part(col,3) + 43 * part(col,2)) / 100;
176     int g = (58 * part(col,3) + 42 * part(col,2)) / 100;
177     int b = (24 * part(col,2) + 75 * part(col,1)) / 100; */
178     // deuteranopia
179     /* int r = (625 * part(col,3) + 375 * part(col,2)) / 1000;
180     int g = (700 * part(col,3) + 300 * part(col,2)) / 1000;
181     int b = (300 * part(col,2) + 700 * part(col,1)) / 1000;
182     part(col,3) = r;
183     part(col,2) = g;
184     part(col,1) = b; */
185     part(col,2) = part(col,3) = (part(col,2) * 2 + part(col,3) + 1)/3;
186     }
187   if(neon_mode == eNeon::none) {
188     pcolor = (darkened(col >> 8) << 8) + (col & 0xFF);
189     poutline = poly_outline;
190     if(flags & POLY_TRIANGLES) poutline = 0;
191     }
192   else switch(neon_mode) {
193     case eNeon::neon:
194       pcolor = (poly_outline & 0xFFFFFF00) | (col & 0xFF);
195       poutline = (darkened(col >> 8) << 8) | (col & 0xFF);
196       if(col == 0xFF) poutline = 0xFFFFFFFF;
197       if(neon_nofill && pcolor == 0xFF) pcolor = 0;
198       break;
199     case eNeon::no_boundary:
200       pcolor = (darkened(col >> 8) << 8) + (col & 0xFF);
201       poutline = 0;
202       break;
203     case eNeon::neon2:
204       pcolor = (darkened(col >> 8) << 8) + (col & 0xFF) + ((col & 0xFF) >> 2);
205       poutline = (darkened(col >> 8) << 8) + (col & 0xFF);
206       if(col == 0xFF) poutline = 0xFFFFFFFF;
207       if(poly_outline != 0xFF) poutline = poly_outline;
208       if(neon_nofill && pcolor == 0xFF) pcolor = 0;
209       break;
210     case eNeon::illustration: {
211       if(poly_outline && (poly_outline>>8) != bordcolor) {
212         pcolor = magentize(col);
213         poutline = 0xFF;
214         }
215       else {
216         poutline = poly_outline;
217         pcolor = monochromatize(col);
218         }
219       if(pcolor & 0xFF) pcolor |= 0xFF;
220       if(poutline & 0xFF) poutline |= 0xFF;
221       break;
222       }
223     case eNeon::none: ;
224     }
225   }
226 
227 /* color of various stuff */
228 
229 /** cloak color for the given table radius */
cloakcolor(int rtr)230 EX int cloakcolor(int rtr) {
231   rtr -= 28;
232   rtr /= 2;
233   rtr %= 10;
234   if(rtr < 0) rtr += 10;
235   // rtr = time(NULL) % 10;
236   int cc[10] = {
237     0x8080FF, 0x80FFFF, 0x80FF80, 0xFF8080, 0xFF80FF, 0xFFFF80,
238     0xFFFFC0, 0xFFD500, 0x421C52, 0
239     };
240   return cc[rtr];
241   }
242 
firegradient(double p)243 EX int firegradient(double p) {
244   return gradient(0xFFFF00, 0xFF0000, 0, p, 1);
245   }
246 
247 EX int firecolor(int phase IS(0), int mul IS(1)) {
248   return gradient(0xFFFF00, 0xFF0000, -1, sintick(100*mul, phase/200./M_PI), 1);
249   }
250 
watercolor(int phase)251 EX int watercolor(int phase) {
252   return 0x0080C0FF + 256 * int(63 * sintick(50, phase/100./M_PI));
253   }
254 
aircolor(int phase)255 EX int aircolor(int phase) {
256   return 0x8080FF00 | int(32 + 32 * sintick(200, phase * 1. / cgi.S21));
257   }
258 
fghostcolor(cell * c)259 EX int fghostcolor(cell *c) {
260   int phase = int(fractick(650, (int)(size_t)c) * 4000);
261   if(phase < 1000)      return gradient(0xFFFF80, 0xA0C0FF,    0, phase, 1000);
262   else if(phase < 2000) return gradient(0xA0C0FF, 0xFF80FF, 1000, phase, 2000);
263   else if(phase < 3000) return gradient(0xFF80FF, 0xFF8080, 2000, phase, 3000);
264   else if(phase < 4000) return gradient(0xFF8080, 0xFFFF80, 3000, phase, 4000);
265   return 0xFFD500;
266   }
267 
weakfirecolor(int phase)268 EX int weakfirecolor(int phase) {
269   return gradient(0xFF8000, 0xFF0000, -1, sintick(500, phase/1000./M_PI), 1);
270   }
271 
272 
273 }
274