fix deprecation warnings from latest dmd
[SmugglerRL.git] / src / colour.d
blob086b1152a61186ebc6e93047042753233ffb7e3e
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 pragma(inline, true) pure this(float in_r, float in_g, float in_b) {
69 r = cast(ubyte)(in_r * 255.8);
70 g = cast(ubyte)(in_g * 255.8);
71 b = cast(ubyte)(in_b * 255.8);
75 pure this(string hexcolour, bool hasvalidated=false) {
76 // strip leading #, if present
77 if ((hexcolour.length == 7) || (hexcolour.length == 4)) {
78 hexcolour = hexcolour[1..$];
81 if (hasvalidated) {
82 if (hexcolour.length == 6) {
83 r = hexcolour[0..2].to!ubyte(16);
84 g = hexcolour[2..4].to!ubyte(16);
85 b = hexcolour[4..6].to!ubyte(16);
86 } else {
87 // The ranges here are to get a string just one character long so to!ubyte works
88 r = cast(ubyte)(hexcolour[0..1].to!ubyte(16)*16);
89 g = cast(ubyte)(hexcolour[1..2].to!ubyte(16)*16);
90 b = cast(ubyte)(hexcolour[2..3].to!ubyte(16)*16);
92 } else {
93 throw new InternalError("RGBColour constructor called but rgbcolour not validated!");
97 // shamelessly stolen from https://github.com/adamdruppe/arsd/blob/master/color.d#L448
98 // HSL conersion
99 pure this(HSLColour hsl) {
100 nothrow @safe @nogc pure real absInternal(real a) { return a < 0 ? -a : a; }
101 real h = hsl.h, s = hsl.s, l = hsl.l;
103 h = h % 360;
105 real C = (1 - absInternal(2 * l - 1)) * s;
107 real hPrime = h / 60;
109 real X = C * (1 - absInternal(hPrime % 2 - 1));
111 real tmpr, tmpg, tmpb;
113 if (h is real.nan) {
114 tmpr = tmpg = tmpb = 0;
115 } else if (hPrime >= 0 && hPrime < 1) {
116 tmpr = C;
117 tmpg = X;
118 tmpb = 0;
119 } else if (hPrime >= 1 && hPrime < 2) {
120 tmpr = X;
121 tmpg = C;
122 tmpb = 0;
123 } else if (hPrime >= 2 && hPrime < 3) {
124 tmpr = 0;
125 tmpg = C;
126 tmpb = X;
127 } else if (hPrime >= 3 && hPrime < 4) {
128 tmpr = 0;
129 tmpg = X;
130 tmpb = C;
131 } else if (hPrime >= 4 && hPrime < 5) {
132 tmpr = X;
133 tmpg = 0;
134 tmpb = C;
135 } else if (hPrime >= 5 && hPrime < 6) {
136 tmpr = C;
137 tmpg = 0;
138 tmpb = X;
141 real m = l - C / 2;
143 tmpr += m;
144 tmpg += m;
145 tmpb += m;
147 r = cast(ubyte)(tmpr * 255);
148 g = cast(ubyte)(tmpg * 255);
149 b = cast(ubyte)(tmpb * 255);
152 pragma(inline, true) this(string hexcolour) {
153 if (!isvalidcolour(hexcolour)) {
154 throw new InternalError("RGBColour constructor called with faulty colour.");
156 this(hexcolour, true);
159 pragma(inline, true) pure uint toint() {
160 return (255 << 24) | (r << 16) | (g << 8) | b;
162 alias toint this;
164 RGBColour darken(ubyte level) {
165 RGBColour tmp;
166 tmp.r = cast(ubyte) ((r < level) ? 0 : r-level);
167 tmp.g = cast(ubyte) ((g < level) ? 0 : g-level);
168 tmp.b = cast(ubyte) ((b < level) ? 0 : b-level);
170 return tmp;
173 RGBColour lighten(ubyte level) {
174 RGBColour tmp;
176 tmp.r = cast(ubyte) (((255-r) < level) ? 255 : r+level);
177 tmp.g = cast(ubyte) (((255-g) < level) ? 255 : g+level);
178 tmp.b = cast(ubyte) (((255-b) < level) ? 255 : b+level);
180 return tmp;
184 struct HSLColour {
185 union {
186 struct {
187 real h, s, l;
189 real[3] colours;
192 private import std.traits: isFloatingPoint;
193 pure this(T)(T h, T s, T l) if (isFloatingPoint!T) {
194 this.h = cast(real)h;
195 this.s = cast(real)s;
196 this.l = cast(real)l;
199 // stolen from https://github.com/adamdruppe/arsd/blob/master/color.d#L501
200 pure this(RGBColour rgb) {
201 pragma(inline, true) {
202 real maxInternal(real a, real b, real c) {
203 auto m = a;
204 if (b > m) m = b;
205 if (c > m) m = c;
206 return m;
208 real minInternal(real a, real b, real c) {
209 real m = a;
210 if (b < m) m = b;
211 if (c < m) m = c;
212 return m;
216 real r1 = cast(real) rgb.r / 255.0;
217 real g1 = cast(real) rgb.g / 255.0;
218 real b1 = cast(real) rgb.b / 255.0;
220 real maxColor = maxInternal(r1, g1, b1);
221 real minColor = minInternal(r1, g1, b1);
223 real tmpl = (maxColor + minColor) / 2;
224 real tmps = 0;
225 real tmph = 0;
227 if (maxColor != minColor) {
228 if(tmpl < 0.5) {
229 tmps = (maxColor - minColor) / (maxColor + minColor);
230 } else {
231 tmps = (maxColor - minColor) / (2.0 - maxColor - minColor);
233 if(r1 == maxColor) {
234 tmph = (g1-b1) / (maxColor - minColor);
235 } else if(g1 == maxColor) {
236 tmph = 2.0 + (b1 - r1) / (maxColor - minColor);
237 } else {
238 tmph = 4.0 + (r1 - g1) / (maxColor - minColor);
242 tmph = tmph * 60;
243 if(tmph < 0){
244 tmph += 360;
247 h = tmph;
248 s = tmps;
249 l = tmpl;