1 /** color functions and utilities */
2 
3 module re.gfx.color_ext;
4 
5 import re.gfx.raytypes;
6 import re.math;
7 import std.math;
8 static import raylib;
9 
10 // - color functions
11 
12 pragma(inline) {
13     /// gets a color that is white with a given alpha
14     public Color color_alpha_white(float alpha) {
15         return raylib.ColorFromNormalized(raylib.Vector4(1, 1, 1, alpha));
16     }
17 
18     /// gets a color from floats
19     public Color color_alpha_white(float r, float g, float b, float a = 1) {
20         return raylib.ColorFromNormalized(raylib.Vector4(r, g, b, a));
21     }
22 
23     /// fades a color
24     public Color color_fade(Color color, float fade) {
25         return raylib.Fade(color, fade);
26     }
27 
28     /// gets a color from hsv
29     public Color color_hsv(float h, float s, float v) {
30         return raylib.ColorFromHSV(h, s, v);
31     }
32 
33     /// gets a color from rgb
34     public Color color_rgb(float r, float g, float b, float a = 1.0) {
35         return raylib.ColorFromNormalized(Vector4(r, g, b, a));
36     }
37 
38     /// gets a color from rgb
39     public Color color_rgb(ubyte r, ubyte g, ubyte b, ubyte a = 255) {
40         return Color(r, g, b, 255);
41     }
42 
43     /// gets a color from rgb in a single value
44     public Color color_rgb(ubyte v) {
45         return color_rgb(v, v, v);
46     }
47 }
48 
49 /// color blending algorithm - from https://stackoverflow.com/a/39924008/13240621
50 public Color color_blend(Color c1, Color c2, float mix) {
51     // Mix [0..1]
52     //  0   --> all c1
53     //  0.5 --> equal mix of c1 and c2
54     //  1   --> all c2
55 
56     // Invert sRGB gamma compression
57     c1 = inverse_srgb_companding(c1);
58     c2 = inverse_srgb_companding(c2);
59 
60     Color result;
61     result.r = cast(ubyte)(c1.r * (1 - mix) + c2.r * (mix));
62     result.g = cast(ubyte)(c1.g * (1 - mix) + c2.g * (mix));
63     result.b = cast(ubyte)(c1.b * (1 - mix) + c2.b * (mix));
64 
65     // Reapply sRGB gamma compression
66     result = srgb_companding(result);
67 
68     return result;
69 }
70 
71 private Color inverse_srgb_companding(Color c) {
72     // Convert color from 0..255 to 0..1
73     float r = c.r / 255;
74     float g = c.g / 255;
75     float b = c.b / 255;
76 
77     // Inverse Red, Green, and Blue
78     if (r > 0.04045)
79         r = pow((r + 0.055) / 1.055, 2.4);
80     else
81         r = r / 12.92;
82     if (g > 0.04045)
83         g = pow((g + 0.055) / 1.055, 2.4);
84     else
85         g = g / 12.92;
86     if (b > 0.04045)
87         b = pow((b + 0.055) / 1.055, 2.4);
88     else
89         b = b / 12.92;
90 
91     // Convert 0..1 back into 0..255
92     Color result;
93     result.r = cast(ubyte)(r * 255);
94     result.g = cast(ubyte)(g * 255);
95     result.b = cast(ubyte)(b * 255);
96 
97     return result;
98 }
99 
100 private Color srgb_companding(Color c) {
101     // Convert color from 0..255 to 0..1
102     float r = c.r / 255;
103     float g = c.g / 255;
104     float b = c.b / 255;
105 
106     // Apply companding to Red, Green, and Blue
107     if (r > 0.0031308)
108         r = 1.055 * pow(r, 1 / 2.4) - 0.055;
109     else
110         r = r * 12.92;
111     if (g > 0.0031308)
112         g = 1.055 * pow(g, 1 / 2.4) - 0.055;
113     else
114         g = g * 12.92;
115     if (b > 0.0031308)
116         b = 1.055 * pow(b, 1 / 2.4) - 0.055;
117     else
118         b = b * 12.92;
119 
120     // Convert 0..1 back into 0..255
121     Color result;
122     result.r = cast(ubyte)(r * 255);
123     result.g = cast(ubyte)(g * 255);
124     result.b = cast(ubyte)(b * 255);
125 
126     return result;
127 }