diff --git a/CMYK.zig b/CMYK.zig index 738c5dcc631d1c2c6abd6adf4382b4821838c67f..1bcf2914fb6ee01858b407fd3668fb7cb22b89b3 100644 --- a/CMYK.zig +++ b/CMYK.zig @@ -27,3 +27,13 @@ pub fn initCMYKA(c: f32, m: f32, y: f32, k: f32, a: f32) Self { pub fn eql(x: Self, y: Self) bool { return x.c == y.c and x.m == y.m and x.y == y.y and x.k == y.k and x.a == y.a; } + +pub fn to_array(x: Self) [5]f32 { + return .{ + x.c, + x.m, + x.y, + x.k, + x.a, + }; +} diff --git a/HSL.zig b/HSL.zig index e88ad72d5c87b33b6db69088fbda5da5512545de..014d251ac50795416aae9790e839cbfce4967377 100644 --- a/HSL.zig +++ b/HSL.zig @@ -2,6 +2,7 @@ const std = @import("std"); const Self = @This(); +const _x = @import("./_x.zig"); h: f32, // hue s: f32, // saturation @@ -24,3 +25,5 @@ pub fn initHSLA(h: f32, s: f32, l: f32, a: f32) Self { pub fn eql(x: Self, y: Self) bool { return x.h == y.h and x.s == y.s and x.l == y.l and x.a == y.a; } + +pub usingnamespace _x.mixin(@This(), f32, .h, .s, .l); diff --git a/HSV.zig b/HSV.zig index 7db51d0da3c2cf12a5f161c6b1f087071598508c..a6effd09afebde58e337a141eff10bd734846422 100644 --- a/HSV.zig +++ b/HSV.zig @@ -2,6 +2,7 @@ const std = @import("std"); const Self = @This(); +const _x = @import("./_x.zig"); h: f32, // hue s: f32, // saturation @@ -24,3 +25,5 @@ pub fn initHSVA(h: f32, s: f32, v: f32, a: f32) Self { pub fn eql(x: Self, y: Self) bool { return x.h == y.h and x.s == y.s and x.v == y.v and x.a == y.a; } + +pub usingnamespace _x.mixin(@This(), f32, .h, .s, .v); diff --git a/LinearRgb.zig b/LinearRgb.zig index 4cf3c4cad6045990f94c0f7a60f9ed2a46685023..2e143cc37e0b864af697ffe6f11ca034ba5c5e98 100644 --- a/LinearRgb.zig +++ b/LinearRgb.zig @@ -2,6 +2,7 @@ const std = @import("std"); const Self = @This(); +const _x = @import("./_x.zig"); r: f32, // red g: f32, // green @@ -28,3 +29,5 @@ pub fn eql(x: Self, y: Self) bool { pub fn relative_luminance(x: Self) f32 { return (0.2126 * x.r) + (0.7152 * x.g) + (0.0722 * x.b); } + +pub usingnamespace _x.mixin(@This(), f32, .r, .g, .b); diff --git a/_x.zig b/_x.zig index 2bb5c9ba0c5bd95667a181bafae2be9e731ca4c0..5a0bd07ff9b35c860a9a2b4167c482c3cf676eb6 100644 --- a/_x.zig +++ b/_x.zig @@ -2,6 +2,7 @@ const std = @import("std"); pub fn mixin( comptime T: type, + comptime I: type, comptime f1: std.meta.FieldEnum(T), comptime f2: std.meta.FieldEnum(T), comptime f3: std.meta.FieldEnum(T), @@ -25,7 +26,7 @@ pub fn mixin( return x; } - pub fn to_array(x: T, comptime I: type) [4]I { + pub fn to_array(x: T) [4]I { return .{ @field(x, @tagName(f1)), @field(x, @tagName(f2)), diff --git a/build.zig b/build.zig index 3ca210217535d10e2f201a8b24a219328fd2fd0b..14bc91256a79ccb7fc1ca4159f415626ae409fd9 100644 --- a/build.zig +++ b/build.zig @@ -25,6 +25,15 @@ pub fn build(b: *std.Build) void { const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); - const test_step = b.step("test", "dummy test step to pass CI checks"); - _ = test_step; + const tests = b.addTest(.{ + .root_source_file = b.path("test.zig"), + .target = target, + .optimize = mode, + }); + deps.addAllTo(tests); + + const test_step = b.step("test", "Run all library tests"); + const tests_run = b.addRunArtifact(tests); + tests_run.has_side_effects = true; + test_step.dependOn(&tests_run.step); } diff --git a/sRGB.zig b/sRGB.zig index 68bc85a8f815155ce078e19d48b29ae96c906745..8114e489097f202c7244b2660cdac7182a4ab6c8 100644 --- a/sRGB.zig +++ b/sRGB.zig @@ -73,7 +73,7 @@ pub fn format(x: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, }); } -pub usingnamespace _x.mixin(@This(), .r, .g, .b); +pub usingnamespace _x.mixin(@This(), u8, .r, .g, .b); pub fn to_linear_rgb(x: Self) color.LinearRgb { const lut = comptime blk: { @@ -94,7 +94,7 @@ pub fn to_linear_rgb(x: Self) color.LinearRgb { } pub fn to_float(x: Self) Float { - return Self{ + return .{ .r = @as(f32, @floatFromInt(x.r)) / 255.0, .g = @as(f32, @floatFromInt(x.g)) / 255.0, .b = @as(f32, @floatFromInt(x.b)) / 255.0, @@ -119,9 +119,9 @@ pub fn to_hsl(x: Self) color.HSL { const delta = cmax - cmin; const h = blk: { if (delta == 0) break :blk 0; - if (cmax == f.r) break :blk ((((f.g - f.b) / delta) % 6) * 60) % 360; - if (cmax == f.g) break :blk ((((f.b - f.r) / delta) + 2) * 60) % 360; - if (cmax == f.b) break :blk ((((f.r - f.g) / delta) + 4) * 60) % 360; + if (cmax == f.r) break :blk @rem(((f.g - f.b) / delta), 6.0) / 6.0; + if (cmax == f.g) break :blk (((f.b - f.r) / delta) + 2) / 6.0; + if (cmax == f.b) break :blk (((f.r - f.g) / delta) + 4) / 6.0; unreachable; }; const l = (cmax + cmin) / 2; @@ -137,9 +137,9 @@ pub fn to_hsv(x: Self) color.HSV { const delta = cmax - cmin; const h = blk: { if (delta == 0) break :blk 0; - if (cmax == f.r) break :blk ((((f.g - f.b) / delta) % 6) * 60) % 360; - if (cmax == f.g) break :blk ((((f.b - f.r) / delta) + 2) * 60) % 360; - if (cmax == f.b) break :blk ((((f.r - f.g) / delta) + 4) * 60) % 360; + if (cmax == f.r) break :blk (@rem(((f.g - f.b) / delta), 6.0) / 6.0); + if (cmax == f.g) break :blk ((((f.b - f.r) / delta) + 2) / 6.0); + if (cmax == f.b) break :blk ((((f.r - f.g) / delta) + 4) / 6.0); unreachable; }; const s = if (cmax == 0) 0 else delta / cmax; diff --git a/test.zig b/test.zig new file mode 100644 index 0000000000000000000000000000000000000000..6a976c9fe59c29eedba6b8920fd684f31e70052d --- /dev/null +++ b/test.zig @@ -0,0 +1,47 @@ +const std = @import("std"); +const color = @import("color"); + +test { + // https://www.colorhexa.com/4fc3f7 + const o = color.sRGB.parseHexConst("#4FC3F7"); + { + const r, const g, const b, const a = o.to_array(); + try std.testing.expect(r == 79); + try std.testing.expect(g == 195); + try std.testing.expect(b == 247); + try std.testing.expect(a == 255); + } + { + // 68% cyan, 21.1% magenta, 0% yellow and 3.1% black + const c, const m, const y, const k, const a = o.to_cmyk().to_array(); + try std.testing.expectApproxEqAbs(0.68, c, 0.01); + try std.testing.expectApproxEqAbs(0.21, m, 0.01); + try std.testing.expectApproxEqAbs(0.00, y, 0.01); + try std.testing.expectApproxEqAbs(0.03, k, 0.01); + try std.testing.expect(a == 1.0); + } + { + // 198.6°, 91.3, 63.9 + const h, const s, const l, const a = o.to_hsl().to_array(); + try std.testing.expectApproxEqAbs(0.552, h, 0.001); + try std.testing.expectApproxEqAbs(0.913, s, 0.001); + try std.testing.expectApproxEqAbs(0.639, l, 0.001); + try std.testing.expect(a == 1.0); + } + { + // 198.6°, 68, 96.9 + const h, const s, const v, const a = o.to_hsv().to_array(); + try std.testing.expectApproxEqAbs(0.552, h, 0.001); + try std.testing.expectApproxEqAbs(0.680, s, 0.001); + try std.testing.expectApproxEqAbs(0.969, v, 0.001); + try std.testing.expect(a == 1.0); + } + { + // 0.0781874218051863, 0.545724461370187, 0.930110858375424 + const r, const g, const b, const a = o.to_linear_rgb().to_array(); + try std.testing.expectApproxEqAbs(0.078, r, 0.001); + try std.testing.expectApproxEqAbs(0.545, g, 0.001); + try std.testing.expectApproxEqAbs(0.930, b, 0.001); + try std.testing.expect(a == 1.0); + } +}