1//! object representing a single color in the Linear RGB colorspace with channel values from 0-1
2
3const std = @import("std");
4const Self = @This();
5const color = @import("./mod.zig");
6const _x = @import("./_x.zig");
7const vec4 = @Vector(4, f32);
8
9r: f32, // red [ 0 .. 1]
10g: f32, // green [ 0 .. 1]
11b: f32, // blue [ 0 .. 1]
12a: f32, // alpha [ 0 .. 1]
13
14pub fn initRGBA(r: f32, g: f32, b: f32, a: f32) Self {
15 std.debug.assert(r >= 0.0 and r <= 1.0);
16 std.debug.assert(g >= 0.0 and g <= 1.0);
17 std.debug.assert(b >= 0.0 and b <= 1.0);
18 std.debug.assert(a >= 0.0 and a <= 1.0);
19 return Self{
20 .r = r,
21 .g = g,
22 .b = b,
23 .a = a,
24 };
25}
26
27pub fn eql(x: Self, y: Self) bool {
28 return x.r == y.r and x.g == y.g and x.b == y.b and x.a == y.a;
29}
30
31// https://www.w3.org/TR/WCAG/#dfn-relative-luminance
32pub fn relative_luminance(x: Self) f32 {
33 const r, const g, const b, _ = x.to_array();
34 return (0.2126 * r) + (0.7152 * g) + (0.0722 * b);
35}
36
37const M = _x.mixin(@This(), f32, .r, .g, .b);
38pub const to_vec = M.to_vec;
39pub const from_vec = M.from_vec;
40pub const to_array = M.to_array;
41
42// https://gamedev.stackexchange.com/a/194038
43pub fn to_srgb(x: Self) color.sRGB {
44 const v = x.to_vec();
45 const cutoff = v < @as(vec4, @splat(0.0031308));
46 const higher = @as(vec4, @splat(1.055)) * std.math.pow(vec4, v, @splat(1.0 / 2.4)) - @as(vec4, @splat(0.055));
47 const lower = v * @as(vec4, @splat(12.92));
48 return color.sRGB.from_float(@select(f32, cutoff, higher, lower));
49}