]> git.lizzy.rs Git - nothing.git/blob - src/color.c
b0fc3728ceb0e8b39b5eddec55e3b4eef7c08f32
[nothing.git] / src / color.c
1 #include <SDL.h>
2 #include <string.h>
3 #include <math.h>
4
5 #include "color.h"
6
7 Color rgba(float r, float g, float b, float a)
8 {
9     const Color result = {
10         .r = r,
11         .g = g,
12         .b = b,
13         .a = a
14     };
15
16     return result;
17 }
18
19 /* TODO(#928): Should the Hue in HSLA representation be in degrees? */
20 Color hsla(float h, float s, float l, float a)
21 {
22     h = fmodf(h, 360.0f);
23
24     const float c = (1.0f - fabsf(2.0f * l - 1.0f)) * s;
25     const float x = c * (1 - fabsf(fmodf(h / 60.0f, 2.0f) - 1.0f));
26     const float m = l - c / 2.0f;
27
28     Color color = {0.0f, 0.0f, 0.0f, a};
29
30     if (0.0f <= h && h < 60.0f) {
31         color = rgba(c, x, 0.0f, a);
32     } else if (60.0f <= h && h < 120.0f) {
33         color = rgba(x, c, 0.0f, a);
34     } else if (120.0f <= h && h < 180.0f) {
35         color = rgba(0.0f, c, x, a);
36     } else if (180.0f <= h && h < 240.0f) {
37         color = rgba(0.0f, x, c, a);
38     } else if (240.0f <= h && h < 300.0f) {
39         color = rgba(x, 0.0f, c, a);
40     } else if (300.0f <= h && h < 360.0f) {
41         color = rgba(c, 0.0f, x, a);
42     }
43
44     color.r += m;
45     color.g += m;
46     color.b += m;
47
48     return color;
49 }
50
51 static Uint8 hex2dec_digit(char c)
52 {
53     if (c >= '0' && c <= '9') {
54         return (Uint8) (c - '0');
55     }
56
57     if (c >= 'A' && c <= 'F') {
58         return (Uint8) (10 + c - 'A');
59     }
60
61     if (c >= 'a' && c <= 'f') {
62         return (Uint8) (10 + c - 'a');
63     }
64
65     return 0;
66 }
67
68 static Uint8 parse_color_component(const char *component)
69 {
70     return (Uint8) (hex2dec_digit(component[0]) * 16 + hex2dec_digit(component[1]));
71 }
72
73 Color hexstr(const char *hexstr)
74 {
75     if (strlen(hexstr) != 6) {
76         return rgba(0.0f, 0.0f, 0.0f, 1.0f);
77     }
78
79     return rgba(
80         parse_color_component(hexstr) / 255.0f,
81         parse_color_component(hexstr + 2) / 255.0f,
82         parse_color_component(hexstr + 4) / 255.0f,
83         1.0f);
84 }
85
86 SDL_Color color_for_sdl(Color color)
87 {
88     const SDL_Color result = {
89         .r = (Uint8)roundf(color.r * 255.0f),
90         .g = (Uint8)roundf(color.g * 255.0f),
91         .b = (Uint8)roundf(color.b * 255.0f),
92         .a = (Uint8)roundf(color.a * 255.0f)
93     };
94
95     return result;
96 }
97
98 Color color_desaturate(Color c)
99 {
100     const float k = (c.r + c.g + c.b) / 3.0f;
101     return rgba(k, k, k, c.a);
102 }
103
104 Color color_darker(Color c, float d)
105 {
106     return rgba(fmaxf(c.r - d, 0.0f),
107                 fmaxf(c.g - d, 0.0f),
108                 fmaxf(c.b - d, 0.0f),
109                 c.a);
110 }
111
112 Color color_invert(Color c)
113 {
114     return rgba(1.0f - c.r, 1.0f - c.g, 1.0f - c.b, c.a);
115 }
116
117 Color color_scale(Color c, Color fc)
118 {
119     return rgba(
120         fmaxf(fminf(c.r * fc.r, 1.0f), 0.0f),
121         fmaxf(fminf(c.g * fc.g, 1.0f), 0.0f),
122         fmaxf(fminf(c.b * fc.b, 1.0f), 0.0f),
123         fmaxf(fminf(c.a * fc.a, 1.0f), 0.0f));
124 }
125
126 int color_hex_to_stream(Color color, FILE *stream)
127 {
128     SDL_Color sdl = color_for_sdl(color);
129     return fprintf(stream, "%02x%02x%02x", sdl.r, sdl.g, sdl.b);
130 }
131
132 int color_hex_to_string(Color color, char *buffer, size_t buffer_size)
133 {
134     SDL_Color sdl = color_for_sdl(color);
135     return snprintf(buffer, buffer_size, "%02x%02x%02x", sdl.r, sdl.g, sdl.b);
136 }
137
138 Color rgba_to_hsla(Color color)
139 {
140     const float max = fmaxf(color.r, fmaxf(color.g, color.b));
141     const float min = fminf(color.r, fminf(color.g, color.b));
142     const float c = max - min;
143     float hue = 0.0f;
144     float saturation = 0.0f;
145     const float lightness = (max + min) * 0.5f;
146
147     if (fabsf(c) > 1e-6) {
148         if (fabs(max - color.r) <= 1e-6) {
149             hue = 60.0f * fmodf((color.g - color.b) / c, 6.0f);
150         } else if (fabs(max - color.g) <= 1e-6) {
151             hue = 60.0f * ((color.b - color.r) / c + 2.0f);
152         } else {
153             hue = 60.0f * ((color.r - color.g) / c + 4.0f);
154         }
155
156         saturation = c / (1.0f - fabsf(2.0f * lightness - 1.0f));
157     }
158
159     // TODO(#929): Color struct is used not only for RGBA
160     //   But also for HSLA. We should make another similar struct but for HSLA
161     return rgba(hue, saturation, lightness, color.a);
162 }