Name the tiles to make everything better because I'm a bloody idiot
[SmugglerRL.git] / src / colour.d
blob0b133872beaea4e03fbb427d1f77af6ca4fd5a0f
1 import stdlib;
2 import util;
5 // Many thanks, FIQ
6 bool isvalidcolour(string hexcolour) {
7 char nam;
8 ubyte index, count;
10 if (hexcolour[0] == '#') {
11 index++;
14 for (;index < hexcolour.length; index++) {
15 nam = hexcolour[index];
16 if (!nam) {
17 break;
20 if (!((('0' <= nam) && (nam <= '9')) || (('A' <= nam) && (nam <= 'F')))) {
21 return false;
24 count++;
25 if (count > 6) {
26 return false;
30 return count == 6;
33 static if(0) {
34 bool isvalidcolour(string hexcolour) {
35 import std.regex: ctRegex, matchFirst;
36 auto hexcolourmatch = ctRegex!("#?[0-9a-fA-F]{3,6}");
38 if (matchFirst(hexcolour, hexcolourmatch).empty) {
39 return false;
40 } else {
41 return true;
46 struct RGBColour {
47 ubyte r=0xFF, g=0xFF, b=0xFF;
48 pragma(inline, true) pure this(ubyte in_r, ubyte in_g, ubyte in_b) {
49 r = in_r;
50 g = in_g;
51 b = in_b;
55 // No constructor for colours of the form 0xFFF, because there's no way to tell the difference between 0xFFF and 0x000FFF
56 pragma(inline, true) pure this(uint clr) {
57 b = clr % 256;
59 /* An interesting optimization. Ordinarily, you do b = clr % 256,
60 * g = (clr / 256) % 256, r = (clr / 256 / 256) % 256. left/right
61 * shifts are cheaper than multiplication, and by reassigning clr,
62 * there's an extra multiplication step that doesn't occur.
64 g = (clr >>= 8) % 256;
65 r = (clr >> 8) % 256;
68 pure this(string hexcolour, bool hasvalidated=false) {
69 // strip leading #, if present
70 if ((hexcolour.length == 7) || (hexcolour.length == 4)) {
71 hexcolour = hexcolour[1..$];
74 if (hasvalidated) {
75 if (hexcolour.length == 6) {
76 r = hexcolour[0..2].to!ubyte(16);
77 g = hexcolour[2..4].to!ubyte(16);
78 b = hexcolour[4..6].to!ubyte(16);
79 } else {
80 // The ranges here are to get a string just one character long so to!ubyte works
81 r = cast(ubyte)(hexcolour[0..1].to!ubyte(16)*16);
82 g = cast(ubyte)(hexcolour[1..2].to!ubyte(16)*16);
83 b = cast(ubyte)(hexcolour[2..3].to!ubyte(16)*16);
85 } else {
86 throw new InternalError("RGBColour constructor called but rgbcolour not validated!");
90 // shamelessly stolen from https://github.com/adamdruppe/arsd/blob/master/color.d#L448
91 // HSL conersion
92 pure this(HSLColour hsl) {
93 nothrow @safe @nogc pure real absInternal(real a) { return a < 0 ? -a : a; }
94 real h = hsl.h, s = hsl.s, l = hsl.l;
96 h = h % 360;
98 real C = (1 - absInternal(2 * l - 1)) * s;
100 real hPrime = h / 60;
102 real X = C * (1 - absInternal(hPrime % 2 - 1));
104 real tmpr, tmpg, tmpb;
106 if (h is real.nan) {
107 tmpr = tmpg = tmpb = 0;
108 } else if (hPrime >= 0 && hPrime < 1) {
109 tmpr = C;
110 tmpg = X;
111 tmpb = 0;
112 } else if (hPrime >= 1 && hPrime < 2) {
113 tmpr = X;
114 tmpg = C;
115 tmpb = 0;
116 } else if (hPrime >= 2 && hPrime < 3) {
117 tmpr = 0;
118 tmpg = C;
119 tmpb = X;
120 } else if (hPrime >= 3 && hPrime < 4) {
121 tmpr = 0;
122 tmpg = X;
123 tmpb = C;
124 } else if (hPrime >= 4 && hPrime < 5) {
125 tmpr = X;
126 tmpg = 0;
127 tmpb = C;
128 } else if (hPrime >= 5 && hPrime < 6) {
129 tmpr = C;
130 tmpg = 0;
131 tmpb = X;
134 real m = l - C / 2;
136 tmpr += m;
137 tmpg += m;
138 tmpb += m;
140 r = cast(ubyte)(tmpr * 255);
141 g = cast(ubyte)(tmpg * 255);
142 b = cast(ubyte)(tmpb * 255);
145 pragma(inline, true) this(string hexcolour) {
146 if (!isvalidcolour(hexcolour)) {
147 throw new InternalError("RGBColour constructor called with faulty colour.");
149 this(hexcolour, true);
152 pragma(inline, true) pure uint toint() {
153 return (255 << 24) | (r << 16) | (g << 8) | b;
155 alias toint this;
157 RGBColour darken(ubyte level) {
158 RGBColour tmp;
159 tmp.r = cast(ubyte) ((r < level) ? 0 : r-level);
160 tmp.g = cast(ubyte) ((g < level) ? 0 : g-level);
161 tmp.b = cast(ubyte) ((b < level) ? 0 : b-level);
163 return tmp;
166 RGBColour lighten(ubyte level) {
167 RGBColour tmp;
169 tmp.r = cast(ubyte) (((255-r) < level) ? 255 : r+level);
170 tmp.g = cast(ubyte) (((255-g) < level) ? 255 : g+level);
171 tmp.b = cast(ubyte) (((255-b) < level) ? 255 : b+level);
173 return tmp;
177 struct HSLColour {
178 union {
179 struct {
180 real h, s, l;
182 real[3] colours;
185 // stolen from https://github.com/adamdruppe/arsd/blob/master/color.d#L501
186 pure this(RGBColour rgb) {
187 pragma(inline, true) {
188 real maxInternal(real a, real b, real c) {
189 auto m = a;
190 if (b > m) m = b;
191 if (c > m) m = c;
192 return m;
194 real minInternal(real a, real b, real c) {
195 real m = a;
196 if (b < m) m = b;
197 if (c < m) m = c;
198 return m;
202 real r1 = cast(real) rgb.r / 255.0;
203 real g1 = cast(real) rgb.g / 255.0;
204 real b1 = cast(real) rgb.b / 255.0;
206 real maxColor = maxInternal(r1, g1, b1);
207 real minColor = minInternal(r1, g1, b1);
209 real tmpl = (maxColor + minColor) / 2;
210 real tmps = 0;
211 real tmph = 0;
213 if (maxColor != minColor) {
214 if(tmpl < 0.5) {
215 tmps = (maxColor - minColor) / (maxColor + minColor);
216 } else {
217 tmps = (maxColor - minColor) / (2.0 - maxColor - minColor);
219 if(r1 == maxColor) {
220 tmph = (g1-b1) / (maxColor - minColor);
221 } else if(g1 == maxColor) {
222 tmph = 2.0 + (b1 - r1) / (maxColor - minColor);
223 } else {
224 tmph = 4.0 + (r1 - g1) / (maxColor - minColor);
228 tmph = tmph * 60;
229 if(tmph < 0){
230 tmph += 360;
233 h = tmph;
234 s = tmps;
235 l = tmpl;