-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhell_colors.h
More file actions
304 lines (258 loc) · 7.58 KB
/
hell_colors.h
File metadata and controls
304 lines (258 loc) · 7.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/* hell_colors - v0.0.1 - MIT LICENSE
*
* This is header only stb style INSPIRED library ;
* It was created for my needs, use at your own risk.
*
* It contains couple of useful functions
* to help with manual colors manipulation
*
* --------------------------------------
*
* To start add this to you code and enjoy
*
* #define HELL_COLORS_IMPLEMENTATION
* #include "hell_colors.h"
*
*/
#ifndef HELL_COLORS_H
#define HELL_COLORS_H
#ifdef __cplusplus
extern "C" {
#endif
/* Version information */
#define HELL_COLORS_VERSION "0.0.1"
/* Configurable Options */
#ifndef HELL_COLORS_DEF
#define HELL_COLORS_DEF static inline
#else
#define HELL_COLORS_DEF extern
#endif
#include <math.h>
#include <stdio.h>
#include <stdint.h>
/*
* Structures
*/
/* RGB, what can I say huh
* it speaks for itself */
typedef struct
{
uint8_t R; // Red [0, 255]
uint8_t G; // Green [0, 255]
uint8_t B; // Blue [0, 255]
} RGB;
typedef struct {
float H; // Hue [0, 360]
float S; // Saturation [0, 1]
float L; // Luminance [0, 1]
} HSL;
/*
* Function declarations
*/
HELL_COLORS_DEF void print_rgb(RGB col);
HELL_COLORS_DEF float calculate_luminance(RGB c);
HELL_COLORS_DEF float calculate_color_distance(RGB a, RGB b);
HELL_COLORS_DEF uint8_t clamp_uint8(int value);
HELL_COLORS_DEF int compare_luminance(RGB a, RGB b);
HELL_COLORS_DEF HSL rgb_to_hsl(RGB color);
HELL_COLORS_DEF RGB hsl_to_rgb(HSL hsl);
HELL_COLORS_DEF RGB clamp_rgb(RGB color);
HELL_COLORS_DEF RGB darken_color(RGB color, float factor);
HELL_COLORS_DEF RGB lighten_color(RGB color, float factor);
HELL_COLORS_DEF RGB saturate_color(RGB color, float factor);
HELL_COLORS_DEF RGB adjust_luminance(RGB color, float factor);
HELL_COLORS_DEF RGB blend_colors(const RGB color1, const RGB color2, float blend_factor);
HELL_COLORS_DEF RGB blend_with_brightness(RGB bright_color, RGB mix_color, float mix_ratio);
#ifdef HELL_COLORS_IMPLEMENTATION
/* Function definitions */
/* Writes color as block to stdout - no new lines by itself */
HELL_COLORS_DEF void print_rgb(RGB col)
{
/* Write color from as colored block */
fprintf(stdout, "\x1b[48;2;%d;%d;%dm \033[0m", col.R, col.G, col.B);
fprintf(stdout, "\x1b[48;2;%d;%d;%dm \033[0m", col.R, col.G, col.B);
}
/* calculate how bright is color from RGB
* https://en.wikipedia.org/wiki/Relative_luminance
*/
HELL_COLORS_DEF float calculate_luminance(RGB c)
{
return (0.2126 * c.R + 0.7152 * c.G + 0.0722 * c.B);
}
/* compare luminance of two RGB colors
* returns 1 if a > b
* returns -1 if a < b
* returns 0 if a == b
*/
HELL_COLORS_DEF int compare_luminance(RGB a, RGB b)
{
float lum_a = calculate_luminance(a);
float lum_b = calculate_luminance(b);
if (lum_a < lum_b)
return -1;
else if (lum_a > lum_b)
return 1;
else
return 0;
}
/* check Euclidean distance between two colors to ensure diversity */
HELL_COLORS_DEF float calculate_color_distance(RGB a, RGB b)
{
return sqrtf(powf(a.R - b.R, 2) + powf(a.G - b.G, 2) + powf(a.B - b.B, 2));
}
/* Convert RGB to HSL */
HELL_COLORS_DEF HSL rgb_to_hsl(RGB color)
{
float r = color.R / 255.0f;
float g = color.G / 255.0f;
float b = color.B / 255.0f;
float max_val = fmaxf(r, fmaxf(g, b));
float min_val = fminf(r, fminf(g, b));
float delta = max_val - min_val;
HSL hsl;
hsl.L = max_val;
if (max_val != 0)
{
hsl.S = delta / max_val; // Saturation
}
else
{
hsl.S = 0;
hsl.H = -1;
return hsl;
}
if (delta == 0)
{
hsl.H = 0;
}
else
{
if (r == max_val)
{
hsl.H = (g - b) / delta;
}
else if (g == max_val)
{
hsl.H = 2 + (b - r) / delta;
}
else
{
hsl.H = 4 + (r - g) / delta;
}
hsl.H *= 60;
if (hsl.H < 0)
{
hsl.H += 360;
}
}
return hsl;
}
/* Convert HSL to RGB */
HELL_COLORS_DEF RGB hsl_to_rgb(HSL hsl)
{
float C = (1 - fabsf(2 * hsl.L - 1)) * hsl.S;
float X = C * (1 - fabsf(fmodf(hsl.H / 60.0f, 2) - 1));
float m = hsl.L - C / 2;
float r = 0, g = 0, b = 0;
if (hsl.H >= 0 && hsl.H < 60) {
r = C, g = X, b = 0;
} else if (hsl.H >= 60 && hsl.H < 120) {
r = X, g = C, b = 0;
} else if (hsl.H >= 120 && hsl.H < 180) {
r = 0, g = C, b = X;
} else if (hsl.H >= 180 && hsl.H < 240) {
r = 0, g = X, b = C;
} else if (hsl.H >= 240 && hsl.H < 300) {
r = X, g = 0, b = C;
} else if (hsl.H >= 300 && hsl.H < 360) {
r = C, g = 0, b = X;
}
RGB rgb;
rgb.R = (uint8_t)((r + m) * 255);
rgb.G = (uint8_t)((g + m) * 255);
rgb.B = (uint8_t)((b + m) * 255);
return rgb;
}
/* avoid exceeding max value */
HELL_COLORS_DEF uint8_t clamp_uint8(int value)
{
if (value < 0) return 0;
if (value > 255) return 255;
return (uint8_t)value;
}
/* avoid exceeding max value for each */
HELL_COLORS_DEF RGB clamp_rgb(RGB color)
{
return (RGB)
{
.R = clamp_uint8(color.R),
.G = clamp_uint8(color.G),
.B = clamp_uint8(color.B)
};
}
/* adjust luminance of a color */
HELL_COLORS_DEF RGB adjust_luminance(RGB color, float factor)
{
return (RGB){
.R = (uint8_t)fminf(color.R * factor, 255),
.G = (uint8_t)fminf(color.G * factor, 255),
.B = (uint8_t)fminf(color.B * factor, 255)
};
}
/* lighten a color by a factor */
HELL_COLORS_DEF RGB lighten_color(RGB color, float factor)
{
return adjust_luminance(color, 1.0f + factor);
}
/* darken a color by a factor */
HELL_COLORS_DEF RGB darken_color(RGB color, float factor)
{
return adjust_luminance(color, 1.0f - factor);
}
/* saturate a color, based on a factor */
HELL_COLORS_DEF RGB saturate_color(RGB color, float factor)
{
float max_val = fmaxf(color.R, fmaxf(color.G, color.B));
color.R = (uint8_t)(color.R + (max_val - color.R) * factor);
color.G = (uint8_t)(color.G + (max_val - color.G) * factor);
color.B = (uint8_t)(color.B + (max_val - color.B) * factor);
return color;
}
/* blend two colors together based on a blend factor */
HELL_COLORS_DEF RGB blend_colors(RGB c1, RGB c2, float weight) {
weight = (weight < 0.0f) ? 0.0f : (weight > 1.0f) ? 1.0f : weight; // Clamp weight
return clamp_rgb((RGB){
.R = (int)(c1.R * (1 - weight) + c2.R * weight),
.G = (int)(c1.G * (1 - weight) + c2.G * weight),
.B = (int)(c1.B * (1 - weight) + c2.B * weight)
});
}
/*
* blend two colors together based on a blend factor,
* bright mode - leave little color accent on white surface
*/
HELL_COLORS_DEF RGB blend_with_brightness(RGB bright_color, RGB mix_color, float mix_ratio)
{
if (mix_ratio < 0.0f) mix_ratio = 0.0f;
if (mix_ratio > 1.0f) mix_ratio = 1.0f;
RGB blended;
blended.R = bright_color.R + mix_ratio * (mix_color.R - bright_color.R);
blended.G = bright_color.G + mix_ratio * (mix_color.G - bright_color.G);
blended.B = bright_color.B + mix_ratio * (mix_color.B - bright_color.B);
uint8_t max_channel = blended.R > blended.G ?
(blended.R > blended.B ? blended.R : blended.B) :
(blended.G > blended.B ? blended.G : blended.B);
if (max_channel > 0 && max_channel < 255)
{
float adjustment = 255.0f / (float)max_channel;
blended.R = (uint8_t)(blended.R * adjustment);
blended.G = (uint8_t)(blended.G * adjustment);
blended.B = (uint8_t)(blended.B * adjustment);
}
return blended;
}
#endif /* HELL_COLORS_IMPLEMENTATION */
#ifdef __cplusplus
}
#endif
#endif /* HELL_COLORS_H */