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