taisei/src/color.c
2024-05-17 14:11:48 +02:00

197 lines
3.7 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "color.h"
#include "util/stringops.h"
#define COLOR_OP(c1, op, c2) do { \
(c1)->r = (c1)->r op (c2)->r; \
(c1)->g = (c1)->g op (c2)->g; \
(c1)->b = (c1)->b op (c2)->b; \
(c1)->a = (c1)->a op (c2)->a; \
} while(0);
Color* color_copy(Color *dst, const Color *src) {
*dst = *src;
return dst;
}
Color* color_add(Color *clr, const Color *clr2) {
COLOR_OP(clr, +, clr2);
return clr;
}
Color* color_sub(Color *clr, const Color *clr2) {
COLOR_OP(clr, -, clr2);
return clr;
}
Color* color_mul(Color *clr, const Color *clr2) {
COLOR_OP(clr, *, clr2);
return clr;
}
Color* color_mul_alpha(Color *clr) {
clr->r *= clr->a;
clr->g *= clr->a;
clr->b *= clr->a;
return clr;
}
Color* color_mul_scalar(Color *clr, float scalar) {
clr->r *= scalar;
clr->g *= scalar;
clr->b *= scalar;
clr->a *= scalar;
return clr;
}
Color* color_div(Color *clr, const Color *clr2) {
COLOR_OP(clr, /, clr2);
return clr;
}
Color* color_div_alpha(Color *clr) {
if(clr->a != 0) {
clr->r /= clr->a;
clr->g /= clr->a;
clr->b /= clr->a;
}
return clr;
}
Color* color_div_scalar(Color *clr, float scalar) {
clr->r /= scalar;
clr->g /= scalar;
clr->b /= scalar;
clr->a /= scalar;
return clr;
}
Color* color_lerp(Color *clr, const Color *clr2, float a) {
float ia = 1 - a;
clr->r = clr->r * ia + clr2->r * a;
clr->g = clr->g * ia + clr2->g * a;
clr->b = clr->b * ia + clr2->b * a;
clr->a = clr->a * ia + clr2->a * a;
return clr;
}
Color* color_approach(Color *clr, const Color *clr2, float delta) {
clr->r += (clr2->r - clr->r) * delta;
clr->g += (clr2->g - clr->g) * delta;
clr->b += (clr2->b - clr->b) * delta;
clr->a += (clr2->a - clr->a) * delta;
return clr;
}
static float hue_to_rgb(float v1, float v2, float vH) {
if(vH < 0) {
vH += 1;
}
if(vH > 1) {
vH -= 1;
}
if((6 * vH) < 1) {
return (v1 + (v2 - v1) * 6 * vH);
}
if((2 * vH) < 1) {
return v2;
}
if((3 * vH) < 2) {
return (v1 + (v2 - v1) * ((2.0f / 3) - vH) * 6);
}
return v1;
}
Color* color_hsla(Color *clr, float h, float s, float l, float a) {
if(s == 0) {
clr->r = clr->g = clr->b = l;
} else {
float v1, v2;
h = fmod(h, 1.0);
if(l < 0.5) {
v2 = l * (1.0 + s);
} else {
v2 = l + s - s * l;
}
v1 = 2.0 * l - v2;
clr->r = hue_to_rgb(v1, v2, h + (1.0/3.0));
clr->g = hue_to_rgb(v1, v2, h);
clr->b = hue_to_rgb(v1, v2, h - (1.0/3.0));
}
clr->a = a;
return clr;
}
void color_get_hsl(const Color *c, float *out_h, float *out_s, float *out_l) {
float r = clamp(c->r, 0, 1);
float g = clamp(c->g, 0, 1);
float b = clamp(c->b, 0, 1);
float maxv = max(max(r, g), b);
float minv = min(min(r, g), b);
float h = 0, s = 0, d = maxv - minv, l = (maxv + minv) / 2;
if(maxv != minv) {
s = l > 0.5 ? d / (2 - maxv - minv) : d / (maxv + minv);
if(maxv == r) {
h = (g - b) / d + (g < b ? 6 : 0);
} else if(maxv == g) {
h = (b - r) / d + 2;
} else if(maxv == b) {
h = (r - g) / d + 4;
}
h /= 6;
}
if(out_h) *out_h = h;
if(out_s) *out_s = s;
if(out_l) *out_l = l;
}
Color* color_set_opacity(Color *clr, float opacity) {
// FIXME: is this correct?
if(clr->a != 0) {
opacity /= clr->a;
}
color_mul_scalar(clr, opacity);
return clr;
}
bool color_equals(const Color *clr, const Color *clr2) {
return (
clr->r == clr2->r &&
clr->g == clr2->g &&
clr->b == clr2->b &&
clr->a == clr2->a
);
}
char *color_str(const Color *clr) {
return strfmt(
"RGBA(%f, %f, %f, %f) at %p",
clr->r,
clr->g,
clr->b,
clr->a,
(void*)clr
);
}