| 1 |
/* |
|---|
| 2 |
Redistribution and use in source and binary forms, with or without |
|---|
| 3 |
modification, are permitted provided that the following conditions |
|---|
| 4 |
are met: |
|---|
| 5 |
|
|---|
| 6 |
Redistributions of source code must retain the above copyright |
|---|
| 7 |
notice, this list of conditions and the following disclaimer. |
|---|
| 8 |
|
|---|
| 9 |
Redistributions in binary form must reproduce the above |
|---|
| 10 |
copyright notice, this list of conditions and the following |
|---|
| 11 |
disclaimer in the documentation and/or other materials provided |
|---|
| 12 |
with the distribution. |
|---|
| 13 |
|
|---|
| 14 |
Neither name of Victor Nakoryakov nor the names of |
|---|
| 15 |
its contributors may be used to endorse or promote products |
|---|
| 16 |
derived from this software without specific prior written |
|---|
| 17 |
permission. |
|---|
| 18 |
|
|---|
| 19 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|---|
| 20 |
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|---|
| 21 |
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|---|
| 22 |
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|---|
| 23 |
REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|---|
| 24 |
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|---|
| 25 |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|---|
| 26 |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|---|
| 27 |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
|---|
| 28 |
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|---|
| 29 |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
|---|
| 30 |
OF THE POSSIBILITY OF SUCH DAMAGE. |
|---|
| 31 |
|
|---|
| 32 |
Copyright (C) 2006. Victor Nakoryakov. |
|---|
| 33 |
*/ |
|---|
| 34 |
/** |
|---|
| 35 |
Module with classes and functions for working with _color values. |
|---|
| 36 |
|
|---|
| 37 |
There are structs for representation Red Green Blue _color (Color3), |
|---|
| 38 |
RGB+Alpha _color (Color4) and Hue Saturation Luminance triple (HSL). |
|---|
| 39 |
|
|---|
| 40 |
All components of those structs are float values, not integers. |
|---|
| 41 |
Rationale is that under different circumstances it is necessary to |
|---|
| 42 |
work with different standards of integer representation. Frequently |
|---|
| 43 |
one byte-wise integer layout needed for one API and another for second. |
|---|
| 44 |
One can require XRGB order, another BGRA. So it's better to operate with |
|---|
| 45 |
floats and to convert them to integer just when it is necessary. |
|---|
| 46 |
|
|---|
| 47 |
Normal range for float components' values is [0; 1]. Normal range for integer |
|---|
| 48 |
values is [0; 255] for Color3 and Color4, and [0; 240] for HSL. Each struct |
|---|
| 49 |
has several methods to convert native float representation to integer and |
|---|
| 50 |
back. |
|---|
| 51 |
|
|---|
| 52 |
Authors: |
|---|
| 53 |
Victor Nakoryakov, nail-mail[at]mail.ru |
|---|
| 54 |
*/ |
|---|
| 55 |
|
|---|
| 56 |
module helix.color; |
|---|
| 57 |
|
|---|
| 58 |
private import helix.basic, |
|---|
| 59 |
helix.config; |
|---|
| 60 |
|
|---|
| 61 |
/** Defines bytes orders for float to uint conversions. */ |
|---|
| 62 |
enum ByteOrder |
|---|
| 63 |
{ |
|---|
| 64 |
XRGB, /// |
|---|
| 65 |
XBGR, /// ditto |
|---|
| 66 |
RGBX, /// ditto |
|---|
| 67 |
BGRX, /// ditto |
|---|
| 68 |
ARGB = XRGB, /// ditto |
|---|
| 69 |
ABGR = XBGR, /// ditto |
|---|
| 70 |
RGBA = RGBX, /// ditto |
|---|
| 71 |
BGRA = BGRX /// ditto |
|---|
| 72 |
} |
|---|
| 73 |
|
|---|
| 74 |
/** |
|---|
| 75 |
Wrapper template to provide possibility to use different float types |
|---|
| 76 |
in implemented structs and routines. |
|---|
| 77 |
*/ |
|---|
| 78 |
private template Color(float_t) |
|---|
| 79 |
{ |
|---|
| 80 |
private alias helix.basic.clampBelow clampBelow; |
|---|
| 81 |
private alias helix.basic.clampAbove clampAbove; |
|---|
| 82 |
private alias helix.basic.clamp clamp; |
|---|
| 83 |
private alias helix.basic.equal equal; |
|---|
| 84 |
|
|---|
| 85 |
private alias .Color!(float).HSL HSLf; |
|---|
| 86 |
private alias .Color!(float).Color3 Color3f; |
|---|
| 87 |
private alias .Color!(float).Color4 Color4f; |
|---|
| 88 |
|
|---|
| 89 |
private alias .Color!(double).HSL HSLd; |
|---|
| 90 |
private alias .Color!(double).Color3 Color3d; |
|---|
| 91 |
private alias .Color!(double).Color4 Color4d; |
|---|
| 92 |
|
|---|
| 93 |
private alias .Color!(real).HSL HSLr; |
|---|
| 94 |
private alias .Color!(real).Color3 Color3r; |
|---|
| 95 |
private alias .Color!(real).Color4 Color4r; |
|---|
| 96 |
|
|---|
| 97 |
private static const float_t rgbK = 255; |
|---|
| 98 |
private static const float_t hslK = 240; |
|---|
| 99 |
|
|---|
| 100 |
/************************************************************************************ |
|---|
| 101 |
Hue, Saturation, Luminance triple. |
|---|
| 102 |
*************************************************************************************/ |
|---|
| 103 |
struct HSL |
|---|
| 104 |
{ |
|---|
| 105 |
float_t h; /// Hue. |
|---|
| 106 |
float_t s; /// Saturation. |
|---|
| 107 |
float_t l; /// Luminance. |
|---|
| 108 |
|
|---|
| 109 |
/** |
|---|
| 110 |
Method to construct struct in C-like syntax. |
|---|
| 111 |
|
|---|
| 112 |
Examples: |
|---|
| 113 |
------------ |
|---|
| 114 |
HSL hsl = HSL(0.1, 0.2, 0.3); |
|---|
| 115 |
------------ |
|---|
| 116 |
*/ |
|---|
| 117 |
static HSL opCall(float_t h, float_t s, float_t l) |
|---|
| 118 |
{ |
|---|
| 119 |
HSL hsl; |
|---|
| 120 |
hsl.set(h, s, l); |
|---|
| 121 |
return hsl; |
|---|
| 122 |
} |
|---|
| 123 |
|
|---|
| 124 |
/** Sets components to values of passed arguments. */ |
|---|
| 125 |
void set(float_t h, float_t s, float_t l) |
|---|
| 126 |
{ |
|---|
| 127 |
this.h = h; |
|---|
| 128 |
this.s = s; |
|---|
| 129 |
this.l = l; |
|---|
| 130 |
} |
|---|
| 131 |
|
|---|
| 132 |
/** Returns: Integer value of corresponding component in range [0; 240]. */ |
|---|
| 133 |
uint hi() |
|---|
| 134 |
{ |
|---|
| 135 |
return cast(uint)(h * hslK); |
|---|
| 136 |
} |
|---|
| 137 |
|
|---|
| 138 |
/** ditto */ |
|---|
| 139 |
uint si() |
|---|
| 140 |
{ |
|---|
| 141 |
return cast(uint)(s * hslK); |
|---|
| 142 |
} |
|---|
| 143 |
|
|---|
| 144 |
/** ditto */ |
|---|
| 145 |
uint li() |
|---|
| 146 |
{ |
|---|
| 147 |
return cast(uint)(l * hslK); |
|---|
| 148 |
} |
|---|
| 149 |
|
|---|
| 150 |
/** |
|---|
| 151 |
Set components to values of passed arguments. It is assumed that values of |
|---|
| 152 |
arguments are in range [0; 240]. |
|---|
| 153 |
*/ |
|---|
| 154 |
void hi(uint h) |
|---|
| 155 |
{ |
|---|
| 156 |
this.h = cast(float_t)h / hslK; |
|---|
| 157 |
} |
|---|
| 158 |
|
|---|
| 159 |
/** ditto */ |
|---|
| 160 |
void si(uint s) |
|---|
| 161 |
{ |
|---|
| 162 |
this.s = cast(float_t)s / hslK; |
|---|
| 163 |
} |
|---|
| 164 |
|
|---|
| 165 |
/** ditto */ |
|---|
| 166 |
void li(uint l) |
|---|
| 167 |
{ |
|---|
| 168 |
this.l = cast(float_t)l / hslK; |
|---|
| 169 |
} |
|---|
| 170 |
|
|---|
| 171 |
/** Component-wise equality operator. */ |
|---|
| 172 |
bool opEquals(HSL hsl) |
|---|
| 173 |
{ |
|---|
| 174 |
return h == hsl.h && s == hsl.s && l == hsl.l; |
|---|
| 175 |
} |
|---|
| 176 |
|
|---|
| 177 |
/** Returns: Color3 representing the same color as this triple. */ |
|---|
| 178 |
Color3 toColor3() |
|---|
| 179 |
{ |
|---|
| 180 |
const short rgbMax = cast(short)rgbK; |
|---|
| 181 |
const short hslMax = cast(short)hslK; |
|---|
| 182 |
short HueToRGB(short n1, short n2, short hue) |
|---|
| 183 |
{ |
|---|
| 184 |
// range check: note values passed add/subtract thirds of range |
|---|
| 185 |
if (hue < 0) |
|---|
| 186 |
hue += hslMax; |
|---|
| 187 |
|
|---|
| 188 |
if (hue > hslMax) |
|---|
| 189 |
hue -= hslMax; |
|---|
| 190 |
|
|---|
| 191 |
// return r,g, or b value from this tridrant |
|---|
| 192 |
if (hue < hslMax / 6) |
|---|
| 193 |
return n1 + ((n2 - n1) * hue + hslMax / 12) / (hslMax / 6); |
|---|
| 194 |
if (hue < hslMax / 2) |
|---|
| 195 |
return n2; |
|---|
| 196 |
if (hue < hslMax * 2 / 3) |
|---|
| 197 |
return n1 + ((n2 - n1) * ((hslMax * 2/3) - hue) + (hslMax / 12)) / (hslMax / 6); |
|---|
| 198 |
else |
|---|
| 199 |
return n1; |
|---|
| 200 |
} |
|---|
| 201 |
|
|---|
| 202 |
short hue = cast(short)hi; |
|---|
| 203 |
short lum = cast(short)li; |
|---|
| 204 |
short sat = cast(short)si; |
|---|
| 205 |
short magic1, magic2; // calculated magic numbers |
|---|
| 206 |
|
|---|
| 207 |
Color3 ret; |
|---|
| 208 |
|
|---|
| 209 |
if (sat == 0) // achromatic case |
|---|
| 210 |
{ |
|---|
| 211 |
ret.set(l, l, l); |
|---|
| 212 |
} |
|---|
| 213 |
else // chromatic case |
|---|
| 214 |
{ |
|---|
| 215 |
// set up magic numbers |
|---|
| 216 |
if (lum <= hslMax / 2) |
|---|
| 217 |
magic2 = (lum * (hslMax + sat) + hslMax / 2) / hslMax; |
|---|
| 218 |
else |
|---|
| 219 |
magic2 = lum + sat - (lum * sat + hslMax / 2) / hslMax; |
|---|
| 220 |
|
|---|
| 221 |
magic1 = 2 * lum - magic2; |
|---|
| 222 |
|
|---|
| 223 |
// get RGB, change units from hslMax to [0; 1] range |
|---|
| 224 |
ret.r = cast(float_t)(HueToRGB(magic1, magic2, hue + (hslMax / 3)) * rgbMax + hslMax / 2) / hslK / rgbK; |
|---|
| 225 |
ret.g = cast(float_t)(HueToRGB(magic1, magic2, hue) * rgbMax + hslMax / 2) / hslK / rgbK; |
|---|
| 226 |
ret.b = cast(float_t)(HueToRGB(magic1, magic2, hue - (hslMax / 3)) * rgbMax + hslMax / 2) / hslK / rgbK; |
|---|
| 227 |
} |
|---|
| 228 |
|
|---|
| 229 |
return ret; |
|---|
| 230 |
} |
|---|
| 231 |
} |
|---|
| 232 |
|
|---|
| 233 |
/** |
|---|
| 234 |
Approximate equality function. |
|---|
| 235 |
Params: |
|---|
| 236 |
relprec, absprec = Parameters passed to equal function while calculations. |
|---|
| 237 |
Have the same meaning as in equal function. |
|---|
| 238 |
*/ |
|---|
| 239 |
bool equal(HSL a, HSL b, int relprec = defrelprec, int absprec = defabsprec) |
|---|
| 240 |
{ |
|---|
| 241 |
HSL c; |
|---|
| 242 |
c.set(a.h - b.h, a.s - b.s, a.l - b.l); |
|---|
| 243 |
return .equal(c.h * c.h + c.s * c.s + c.l * c.l, 0, relprec, absprec); |
|---|
| 244 |
} |
|---|
| 245 |
|
|---|
| 246 |
/************************************************************************************ |
|---|
| 247 |
Red, Green, Blue triple. |
|---|
| 248 |
*************************************************************************************/ |
|---|
| 249 |
struct Color3 |
|---|
| 250 |
{ |
|---|
| 251 |
align(1) |
|---|
| 252 |
{ |
|---|
| 253 |
float_t r; /// Red. |
|---|
| 254 |
float_t g; /// Green. |
|---|
| 255 |
float_t b; /// Blue. |
|---|
| 256 |
} |
|---|
| 257 |
|
|---|
| 258 |
/// Color3 with all components seted to NaN. |
|---|
| 259 |
static Color3 nan = { float_t.nan, float_t.nan, float_t.nan }; |
|---|
| 260 |
|
|---|
| 261 |
/** |
|---|
| 262 |
Method to construct color in C-like syntax. |
|---|
| 263 |
|
|---|
| 264 |
Examples: |
|---|
| 265 |
------------ |
|---|
| 266 |
Color3 c = Color3(0.1, 0.2, 0.3); |
|---|
| 267 |
------------ |
|---|
| 268 |
*/ |
|---|
| 269 |
static Color3 opCall(float_t r, float_t g, float_t b) |
|---|
| 270 |
{ |
|---|
| 271 |
Color3 v; |
|---|
| 272 |
v.set(r, g, b); |
|---|
| 273 |
return v; |
|---|
| 274 |
} |
|---|
| 275 |
|
|---|
| 276 |
/** |
|---|
| 277 |
Method to construct color in C-like syntax from value specified |
|---|
| 278 |
in uint parameter. |
|---|
| 279 |
|
|---|
| 280 |
Params: |
|---|
| 281 |
src = uint to extract value from. |
|---|
| 282 |
order = specifies byte-wise _order in src. |
|---|
| 283 |
|
|---|
| 284 |
Examples: |
|---|
| 285 |
------------ |
|---|
| 286 |
Color3 c = Color3(0x00FFEEDD, ByteOrder.XRGB); |
|---|
| 287 |
------------ |
|---|
| 288 |
*/ |
|---|
| 289 |
static Color3 opCall(uint src, ByteOrder order) |
|---|
| 290 |
{ |
|---|
| 291 |
Color3 v; |
|---|
| 292 |
v.set(src, order); |
|---|
| 293 |
return v; |
|---|
| 294 |
} |
|---|
| 295 |
|
|---|
| 296 |
/** Sets components to values of passed arguments. */ |
|---|
| 297 |
void set(float_t r, float_t g, float_t b) |
|---|
| 298 |
{ |
|---|
| 299 |
this.r = r; |
|---|
| 300 |
this.g = g; |
|---|
| 301 |
this.b = b; |
|---|
| 302 |
} |
|---|
| 303 |
|
|---|
| 304 |
/** |
|---|
| 305 |
Sets components according to color packed in src uint argument. |
|---|
| 306 |
|
|---|
| 307 |
Params: |
|---|
| 308 |
src = uint to extract value from. |
|---|
| 309 |
order = specifies byte-wise component layout in src. |
|---|
| 310 |
*/ |
|---|
| 311 |
void set(uint src, ByteOrder order = ByteOrder.XRGB) |
|---|
| 312 |
{ |
|---|
| 313 |
switch (order) |
|---|
| 314 |
{ |
|---|
| 315 |
case ByteOrder.XRGB: |
|---|
| 316 |
ri = (src & 0x00FF0000) >> 16; |
|---|
| 317 |
gi = (src & 0x0000FF00) >> 8; |
|---|
| 318 |
bi = (src & 0x000000FF) >> 0; |
|---|
| 319 |
break; |
|---|
| 320 |
|
|---|
| 321 |
case ByteOrder.XBGR: |
|---|
| 322 |
bi = (src & 0x00FF0000) >> 16; |
|---|
| 323 |
gi = (src & 0x0000FF00) >> 8; |
|---|
| 324 |
ri = (src & 0x000000FF) >> 0; |
|---|
| 325 |
break; |
|---|
| 326 |
|
|---|
| 327 |
case ByteOrder.RGBX: |
|---|
| 328 |
ri = (src & 0xFF000000) >>> 24; |
|---|
| 329 |
gi = (src & 0x00FF0000) >>> 16; |
|---|
| 330 |
bi = (src & 0x0000FF00) >>> 8; |
|---|
| 331 |
break; |
|---|
| 332 |
|
|---|
| 333 |
case ByteOrder.BGRX: |
|---|
| 334 |
bi = (src & 0xFF000000) >>> 24; |
|---|
| 335 |
gi = (src & 0x00FF0000) >>> 16; |
|---|
| 336 |
ri = (src & 0x0000FF00) >>> 8; |
|---|
| 337 |
break; |
|---|
| 338 |
} |
|---|
| 339 |
} |
|---|
| 340 |
|
|---|
| 341 |
/** Returns: Whether all components are normalized numbers. */ |
|---|
| 342 |
bool isnormal() |
|---|
| 343 |
{ |
|---|
| 344 |
return std.math.isnormal(r) && std.math.isnormal(g) && std.math.isnormal(b); |
|---|
| 345 |
} |
|---|
| 346 |
|
|---|
| 347 |
/** |
|---|
| 348 |
Returns: Integer value of corresponding component. |
|---|
| 349 |
|
|---|
| 350 |
Float value 0 is mapped to integer 0. Float value 1 is mapped to |
|---|
| 351 |
integer 255. |
|---|
| 352 |
*/ |
|---|
| 353 |
int ri() |
|---|
| 354 |
{ |
|---|
| 355 |
return cast(int)(r * rgbK); |
|---|
| 356 |
} |
|---|
| 357 |
|
|---|
| 358 |
/** ditto */ |
|---|
| 359 |
int gi() |
|---|
| 360 |
{ |
|---|
| 361 |
return cast(int)(g * rgbK); |
|---|
| 362 |
} |
|---|
| 363 |
|
|---|
| 364 |
/** ditto */ |
|---|
| 365 |
int bi() |
|---|
| 366 |
{ |
|---|
| 367 |
return cast(int)(b * rgbK); |
|---|
| 368 |
} |
|---|
| 369 |
|
|---|
| 370 |
/** |
|---|
| 371 |
Sets corresponding component value to mapped value of passed argument. |
|---|
| 372 |
|
|---|
| 373 |
Integer value 0 is mapped to float 0. Integer value 255 is mapped to |
|---|
| 374 |
float 1. |
|---|
| 375 |
*/ |
|---|
| 376 |
void ri(int r) |
|---|
| 377 |
{ |
|---|
| 378 |
this.r = cast(float_t)r / rgbK; |
|---|
| 379 |
} |
|---|
| 380 |
|
|---|
| 381 |
/** ditto */ |
|---|
| 382 |
void gi(int g) |
|---|
| 383 |
{ |
|---|
| 384 |
this.g = cast(float_t)g / rgbK; |
|---|
| 385 |
} |
|---|
| 386 |
|
|---|
| 387 |
/** ditto */ |
|---|
| 388 |
void bi(int b) |
|---|
| 389 |
{ |
|---|
| 390 |
this.b = cast(float_t)b / rgbK; |
|---|
| 391 |
} |
|---|
| 392 |
|
|---|
| 393 |
/** |
|---|
| 394 |
Returns: |
|---|
| 395 |
This color packed to uint. |
|---|
| 396 |
Params: |
|---|
| 397 |
order = specifies byte-wise component layout in src. |
|---|
| 398 |
Throws: |
|---|
| 399 |
AssertError if any component is out of range [0; 1] and module was |
|---|
| 400 |
compiled with asserts. |
|---|
| 401 |
*/ |
|---|
| 402 |
uint toUint(ByteOrder order) |
|---|
| 403 |
{ |
|---|
| 404 |
assert(ri >= 0 && ri < 256); |
|---|
| 405 |
assert(gi >= 0 && gi < 256); |
|---|
| 406 |
assert(bi >= 0 && bi < 256); |
|---|
| 407 |
|
|---|
| 408 |
switch (order) |
|---|
| 409 |
{ |
|---|
| 410 |
case ByteOrder.XRGB: return (ri << 16) | (gi << 8) | (bi << 0); |
|---|
| 411 |
case ByteOrder.XBGR: return (bi << 16) | (gi << 8) | (ri << 0); |
|---|
| 412 |
case ByteOrder.RGBX: return (ri << 24) | (gi << 16) | (bi << 8); |
|---|
| 413 |
case ByteOrder.BGRX: return (bi << 24) | (gi << 16) | (ri << 8); |
|---|
| 414 |
} |
|---|
| 415 |
|
|---|
| 416 |
return 0; |
|---|
| 417 |
} |
|---|
| 418 |
|
|---|
| 419 |
/** |
|---|
| 420 |
Returns: |
|---|
| 421 |
HSL triple representing same color as this. |
|---|
| 422 |
*/ |
|---|
| 423 |
HSL toHSL() |
|---|
| 424 |
{ |
|---|
| 425 |
const short hslMax = cast(short)hslK; |
|---|
| 426 |
const short rgbMax = cast(short)rgbK; |
|---|
| 427 |
|
|---|
| 428 |
ubyte h, s, l; |
|---|
| 429 |
ubyte cMax, cMin; // max and min RGB values |
|---|
| 430 |
short rDelta, gDelta, bDelta; // intermediate value: % of spread from max |
|---|
| 431 |
|
|---|
| 432 |
// get R, G, and B out of DWORD |
|---|
| 433 |
short r = ri; |
|---|
| 434 |
short g = gi; |
|---|
| 435 |
short b = bi; |
|---|
| 436 |
|
|---|
| 437 |
// calculate lightness |
|---|
| 438 |
cMax = max(max(r, g), b); |
|---|
| 439 |
cMin = min(min(r, g), b); |
|---|
| 440 |
l = ((cMax + cMin) * hslMax + rgbMax) / (2 * rgbMax); |
|---|
| 441 |
|
|---|
| 442 |
if (cMax == cMin) // r = g = b --> achromatic case |
|---|
| 443 |
{ |
|---|
| 444 |
h = s = 0; |
|---|
| 445 |
} |
|---|
| 446 |
else |
|---|
| 447 |
{ // chromatic case |
|---|
| 448 |
// saturation |
|---|
| 449 |
if (l <= hslMax / 2) |
|---|
| 450 |
s = ((cMax - cMin) * hslMax + (cMax + cMin) / 2) / (cMax + cMin); |
|---|
| 451 |
else |
|---|
| 452 |
s = ((cMax - cMin) * hslMax + (2 * rgbMax - cMax - cMin) / 2) / (2 * rgbMax - cMax - cMin); |
|---|
| 453 |
|
|---|
| 454 |
// hue |
|---|
| 455 |
rDelta = ((cMax - r) * (hslMax / 6) + (cMax - cMin) / 2) / (cMax - cMin); |
|---|
| 456 |
gDelta = ((cMax - g) * (hslMax / 6) + (cMax - cMin) / 2) / (cMax - cMin); |
|---|
| 457 |
bDelta = ((cMax - b) * (hslMax / 6) + (cMax - cMin) / 2) / (cMax - cMin); |
|---|
| 458 |
|
|---|
| 459 |
if (r == cMax) |
|---|
| 460 |
h = bDelta - gDelta; |
|---|
| 461 |
else if (g == cMax) |
|---|
| 462 |
h = (hslMax / 3) + rDelta - bDelta; |
|---|
| 463 |
else // B == cMax |
|---|
| 464 |
h = (2 * hslMax) / 3 + gDelta - rDelta; |
|---|
| 465 |
|
|---|
| 466 |
if(h < 0) |
|---|
| 467 |
h += hslMax; |
|---|
| 468 |
|
|---|
| 469 |
if(h > hslMax) |
|---|
| 470 |
h -= hslMax; |
|---|
| 471 |
} |
|---|
| 472 |
|
|---|
| 473 |
HSL ret; |
|---|
| 474 |
ret.hi = h; |
|---|
| 475 |
ret.si = s; |
|---|
| 476 |
ret.li = l; |
|---|
| 477 |
return ret; |
|---|
| 478 |
} |
|---|
| 479 |
|
|---|
| 480 |
/** Returns: float_t pointer to r component of this color. It's like a _ptr method for arrays. */ |
|---|
| 481 |
float_t* ptr() |
|---|
| 482 |
{ |
|---|
| 483 |
return cast(float_t*)this; |
|---|
| 484 |
} |
|---|
| 485 |
|
|---|
| 486 |
/** |
|---|
| 487 |
Standard operators that have meaning exactly the same as for Vector3, i.e. do |
|---|
| 488 |
component-wise operations. |
|---|
| 489 |
|
|---|
| 490 |
Note that division operators do no cheks of value of k, so in case of division |
|---|
| 491 |
by 0 result vector will have infinity components. You can check this with isnormal() |
|---|
| 492 |
method. |
|---|
| 493 |
*/ |
|---|
| 494 |
bool opEquals(Color3 v) |
|---|
| 495 |
{ |
|---|
| 496 |
return r == v.r && g == v.g && b == v.b; |
|---|
| 497 |
} |
|---|
| 498 |
|
|---|
| 499 |
/** ditto */ |
|---|
| 500 |
Color3 opNeg() |
|---|
| 501 |
{ |
|---|
| 502 |
return Color3(-r, -g, -b); |
|---|
| 503 |
} |
|---|
| 504 |
|
|---|
| 505 |
/** ditto */ |
|---|
| 506 |
Color3 opAdd(Color3 v) |
|---|
| 507 |
{ |
|---|
| 508 |
return Color3(r + v.r, g + v.g, b + v.b); |
|---|
| 509 |
} |
|---|
| 510 |
|
|---|
| 511 |
/** ditto */ |
|---|
| 512 |
void opAddAssign(Color3 v) |
|---|
| 513 |
{ |
|---|
| 514 |
r += v.r; |
|---|
| 515 |
g += v.g; |
|---|
| 516 |
b += v.b; |
|---|
| 517 |
} |
|---|
| 518 |
|
|---|
| 519 |
/** ditto */ |
|---|
| 520 |
Color3 opSub(Color3 v) |
|---|
| 521 |
{ |
|---|
| 522 |
return Color3(r - v.r, g - v.g, b - v.b); |
|---|
| 523 |
} |
|---|
| 524 |
|
|---|
| 525 |
/** ditto */ |
|---|
| 526 |
void opSubAssign(Color3 v) |
|---|
| 527 |
{ |
|---|
| 528 |
r -= v.r; |
|---|
| 529 |
g -= v.g; |
|---|
| 530 |
b -= v.b; |
|---|
| 531 |
} |
|---|
| 532 |
|
|---|
| 533 |
/** ditto */ |
|---|
| 534 |
Color3 opMul(real k) |
|---|
| 535 |
{ |
|---|
| 536 |
return Color3(r * k, g * k, b * k); |
|---|
| 537 |
} |
|---|
| 538 |
|
|---|
| 539 |
/** ditto */ |
|---|
| 540 |
void opMulAssign(real k) |
|---|
| 541 |
{ |
|---|
| 542 |
r *= k; |
|---|
| 543 |
g *= k; |
|---|
| 544 |
b *= k; |
|---|
| 545 |
} |
|---|
| 546 |
|
|---|
| 547 |
/** ditto */ |
|---|
| 548 |
Color3 opMulr(real k) |
|---|
| 549 |
{ |
|---|
| 550 |
return Color3(r * k, g * k, b * k); |
|---|
| 551 |
} |
|---|
| 552 |
|
|---|
| 553 |
/** ditto */ |
|---|
| 554 |
Color3 opDiv(real k) |
|---|
| 555 |
{ |
|---|
| 556 |
return Color3(r / k, g / k, b / k); |
|---|
| 557 |
} |
|---|
| 558 |
|
|---|
| 559 |
/** ditto */ |
|---|
| 560 |
void opDivAssign(real k) |
|---|
| 561 |
{ |
|---|
| 562 |
r /= k; |
|---|
| 563 |
g /= k; |
|---|
| 564 |
b /= k; |
|---|
| 565 |
} |
|---|
| 566 |
|
|---|
| 567 |
/** Sets all components less than inf to inf. */ |
|---|
| 568 |
void clampBelow(float_t inf = 0) |
|---|
| 569 |
{ |
|---|
| 570 |
.clampBelow(r, inf); |
|---|
| 571 |
.clampBelow(g, inf); |
|---|
| 572 |
.clampBelow(b, inf); |
|---|
| 573 |
} |
|---|
| 574 |
|
|---|
| 575 |
/** Returns: Copy of this color with all components less than inf seted to inf. */ |
|---|
| 576 |
Color3 clampedBelow(float_t inf = 0) |
|---|
| 577 |
{ |
|---|
| 578 |
Color3 ret = *this; |
|---|
| 579 |
ret.clampBelow(inf); |
|---|
| 580 |
return ret; |
|---|
| 581 |
} |
|---|
| 582 |
|
|---|
| 583 |
/** Sets all components greater than sup to sup. */ |
|---|
| 584 |
void clampAbove(float_t sup = 1) |
|---|
| 585 |
{ |
|---|
| 586 |
.clampAbove(r, sup); |
|---|
| 587 |
.clampAbove(g, sup); |
|---|
| 588 |
.clampAbove(b, sup); |
|---|
| 589 |
} |
|---|
| 590 |
|
|---|
| 591 |
/** Returns: Copy of this color with all components greater than sup seted to sup. */ |
|---|
| 592 |
Color3 clampedAbove(float_t sup = 1) |
|---|
| 593 |
{ |
|---|
| 594 |
Color3 ret = *this; |
|---|
| 595 |
ret.clampBelow(sup); |
|---|
| 596 |
return ret; |
|---|
| 597 |
} |
|---|
| 598 |
|
|---|
| 599 |
/** |
|---|
| 600 |
Sets all components less than inf to inf and |
|---|
| 601 |
all components greater than sup to sup. |
|---|
| 602 |
*/ |
|---|
| 603 |
void clamp(float_t inf = 0, float_t sup = 1) |
|---|
| 604 |
{ |
|---|
| 605 |
clampBelow(inf); |
|---|
| 606 |
clampAbove(sup); |
|---|
| 607 |
} |
|---|
| 608 |
|
|---|
| 609 |
/** |
|---|
| 610 |
Returns: |
|---|
| 611 |
Copy of this color with all components less than inf seted to inf |
|---|
| 612 |
and all components greater than sup seted to sup. |
|---|
| 613 |
*/ |
|---|
| 614 |
Color3 clamped(float_t inf = 0, float_t sup = 1) |
|---|
| 615 |
{ |
|---|
| 616 |
Color3 ret = *this; |
|---|
| 617 |
ret.clamp(inf, sup); |
|---|
| 618 |
return ret; |
|---|
| 619 |
} |
|---|
| 620 |
|
|---|
| 621 |
/** Returns: Copy of this color with float type components. */ |
|---|
| 622 |
Color3f toColor3f() |
|---|
| 623 |
{ |
|---|
| 624 |
return Color3f(cast(float)r, cast(float |
|---|