From 6a2d132873ce7b40405a3dc000a12539fffd969b Mon Sep 17 00:00:00 2001 From: tslil clingman <> Date: Wed, 1 Sep 2021 12:59:50 -0400 Subject: Init --- src/sfml/graphics/color.zig | 166 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 src/sfml/graphics/color.zig (limited to 'src/sfml/graphics/color.zig') diff --git a/src/sfml/graphics/color.zig b/src/sfml/graphics/color.zig new file mode 100644 index 0000000..d6aa850 --- /dev/null +++ b/src/sfml/graphics/color.zig @@ -0,0 +1,166 @@ +//! Utility class for manipulating RGBA colors. + +const sf = @import("../sfml_import.zig"); +const math = @import("std").math; + +pub const Color = packed struct { + /// Converts a color from a csfml object + /// For inner workings + pub fn fromCSFML(col: sf.c.sfColor) Color { + return @bitCast(Color, col); + } + + /// Converts this color to a csfml one + /// For inner workings + pub fn toCSFML(self: Color) sf.c.sfColor { + return @bitCast(sf.c.sfColor, self); + } + + /// Inits a color with rgb components + pub fn fromRGB(red: u8, green: u8, blue: u8) Color { + return Color{ + .r = red, + .g = green, + .b = blue, + .a = 0xff, + }; + } + + /// Inits a color with rgba components + pub fn fromRGBA(red: u8, green: u8, blue: u8, alpha: u8) Color { + return Color{ + .r = red, + .g = green, + .b = blue, + .a = alpha, + }; + } + + /// Inits a color from a 32bits value (RGBA in that order) + pub fn fromInteger(int: u32) Color { + return Color{ + .r = @truncate(u8, (int & 0xff000000) >> 24), + .g = @truncate(u8, (int & 0x00ff0000) >> 16), + .b = @truncate(u8, (int & 0x0000ff00) >> 8), + .a = @truncate(u8, (int & 0x000000ff) >> 0), + }; + } + + /// Gets a 32 bit integer representing the color + pub fn toInteger(self: Color) u32 { + return (@intCast(u32, self.r) << 24) | + (@intCast(u32, self.g) << 16) | + (@intCast(u32, self.b) << 8) | + (@intCast(u32, self.a) << 0); + } + + /// Creates a color with rgba floats from 0 to 1 + fn fromFloats(red: f32, green: f32, blue: f32, alpha: f32) Color { + return Color{ + .r = @floatToInt(u8, math.clamp(red, 0.0, 1.0) * 255.0), + .g = @floatToInt(u8, math.clamp(green, 0.0, 1.0) * 255.0), + .b = @floatToInt(u8, math.clamp(blue, 0.0, 1.0) * 255.0), + .a = @floatToInt(u8, math.clamp(alpha, 0.0, 1.0) * 255.0), + }; + } + + /// Creates a color from HSV and transparency components (this is not part of the SFML) + /// hue is in degrees, saturation and value are in percents + pub fn fromHSVA(hue: f32, saturation: f32, value: f32, alpha: f32) Color { + const h = hue; + const s = saturation / 100; + const v = value / 100; + const a = alpha; + + var hh: f32 = h; + + if (v <= 0.0) + return fromFloats(0, 0, 0, a); + + if (hh >= 360.0) + hh = 0; + hh /= 60.0; + + var ff: f32 = hh - math.floor(hh); + + var p: f32 = v * (1.0 - s); + var q: f32 = v * (1.0 - (s * ff)); + var t: f32 = v * (1.0 - (s * (1.0 - ff))); + + return switch (@floatToInt(usize, hh)) { + 0 => fromFloats(v, t, p, a), + 1 => fromFloats(q, v, p, a), + 2 => fromFloats(p, v, t, a), + 3 => fromFloats(p, q, v, a), + 4 => fromFloats(t, p, v, a), + else => fromFloats(v, p, q, a), + }; + } + + // Colors + /// Black color + pub const Black = Color.fromRGB(0, 0, 0); + /// White color + pub const White = Color.fromRGB(255, 255, 255); + /// Red color + pub const Red = Color.fromRGB(255, 0, 0); + /// Green color + pub const Green = Color.fromRGB(0, 255, 0); + /// Blue color + pub const Blue = Color.fromRGB(0, 0, 255); + /// Yellow color + pub const Yellow = Color.fromRGB(255, 255, 0); + /// Magenta color + pub const Magenta = Color.fromRGB(255, 0, 255); + /// Cyan color + pub const Cyan = Color.fromRGB(0, 255, 255); + /// Transparent color + pub const Transparent = Color.fromRGBA(0, 0, 0, 0); + + /// Red component + r: u8, + /// Green component + g: u8, + /// Blue component + b: u8, + /// Alpha (opacity) component + a: u8, +}; + +test "color: conversions" { + const tst = @import("std").testing; + + var code: u32 = 0x4BDA9CFF; + var col = Color.fromInteger(code); + + try tst.expectEqual(Color.fromRGB(75, 218, 156), col); + try tst.expectEqual(code, col.toInteger()); + + var csfml_col = sf.c.sfColor_fromInteger(@as(c_uint, code)); + + try tst.expectEqual(Color.fromCSFML(csfml_col), col); +} + +test "color: hsv to rgb" { + const tst = @import("std").testing; + + var col = Color.fromHSVA(10, 20, 100, 255); + + try tst.expectEqual(Color.fromRGB(255, 212, 204), col); +} + +test "color: sane from/to CSFML color" { + const tst = @import("std").testing; + + const col = Color.fromRGBA(5, 12, 28, 127); + const ccol = col.toCSFML(); + + try tst.expectEqual(col.r, ccol.r); + try tst.expectEqual(col.g, ccol.g); + try tst.expectEqual(col.b, ccol.b); + try tst.expectEqual(col.a, ccol.a); + + const col2 = Color.fromCSFML(ccol); + + try tst.expectEqual(col, col2); +} -- cgit v1.3.1