From c0929014bf6cb2d5d77d6e87125c4118c6c2e654 Mon Sep 17 00:00:00 2001 From: Gray Olson Date: Thu, 20 May 2021 11:09:52 -0700 Subject: [PATCH] Add support for `cint` (conversions to and from color types) (#393) * implement cint for color types under feature flag * upgrade to cint 0.2, remove from default features * upgrade to cint 0.2.1, add a couple more from/into implementations * changelog entry * fix typo in changelog * sort dependency * fmt --- CHANGELOG.md | 1 + Cargo.lock | 7 ++ egui/Cargo.toml | 3 + epaint/Cargo.toml | 1 + epaint/src/color.rs | 177 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 189 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 755878fd..05982d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md) and [ ## Unreleased ### Added ⭐ +* Add support for [cint](https://crates.io/crates/cint) under `cint` feature. * Add features `extra_asserts` and `extra_debug_asserts` to enable additional checks. ## 0.12.0 - 2021-05-10 - Multitouch, user memory, window pivots, and improved plots diff --git a/Cargo.lock b/Cargo.lock index 808b531a..1e2b95b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,6 +294,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" +[[package]] +name = "cint" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00709959bb62458ca8d7f043b1039e0d99e91f5500f004164ec371f546eadc47" + [[package]] name = "clang-sys" version = "1.2.0" @@ -846,6 +852,7 @@ version = "0.12.0" dependencies = [ "ahash", "atomic_refcell", + "cint", "emath", "ordered-float", "parking_lot", diff --git a/egui/Cargo.toml b/egui/Cargo.toml index ee79b2eb..c03ea743 100644 --- a/egui/Cargo.toml +++ b/egui/Cargo.toml @@ -39,6 +39,9 @@ extra_asserts = ["epaint/extra_asserts"] # Add compatability with https://github.com/kvark/mint mint = ["epaint/mint"] +# add compatibility with https://crates.io/crates/cint +cint = ["epaint/cint"] + persistence = ["serde", "epaint/persistence", "ron"] # Only needed if you plan to use the same egui::Context from multiple threads. diff --git a/epaint/Cargo.toml b/epaint/Cargo.toml index 2506984b..9a621bf3 100644 --- a/epaint/Cargo.toml +++ b/epaint/Cargo.toml @@ -26,6 +26,7 @@ emath = { version = "0.12.0", path = "../emath" } ahash = { version = "0.7", features = ["std"], default-features = false } atomic_refcell = { version = "0.1", optional = true } # Used instead of parking_lot when you are always using epaint in a single thread. About as fast as parking_lot. Panics on multi-threaded use. +cint = { version = "^0.2.1", optional = true } ordered-float = "2" parking_lot = { version = "0.11", optional = true } # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios. rusttype = "0.9" diff --git a/epaint/src/color.rs b/epaint/src/color.rs index 3fd2fea6..7903f898 100644 --- a/epaint/src/color.rs +++ b/epaint/src/color.rs @@ -292,6 +292,18 @@ impl Rgba { ) } } + + /// Premultiplied RGBA + #[inline(always)] + pub fn to_array(&self) -> [f32; 4] { + [self.r(), self.g(), self.b(), self.a()] + } + + /// Premultiplied RGBA + #[inline(always)] + pub fn to_tuple(&self) -> (f32, f32, f32, f32) { + (self.r(), self.g(), self.b(), self.a()) + } } impl std::ops::Add for Rgba { @@ -759,3 +771,168 @@ pub fn tint_color_towards(color: Color32, target: Color32) -> Color32 { } Color32::from_rgba_premultiplied(r, g, b, a) } + +#[cfg(feature = "cint")] +mod impl_cint { + use super::*; + use cint::{Alpha, ColorInterop, EncodedSrgb, Hsv, LinearSrgb, PremultipliedAlpha}; + + // ---- Color32 ---- + + impl From>> for Color32 { + fn from(srgba: Alpha>) -> Self { + let Alpha { + color: EncodedSrgb { r, g, b }, + alpha: a, + } = srgba; + + Color32::from_rgba_unmultiplied(r, g, b, a) + } + } + + // No From for Alpha<_> because Color32 is premultiplied + + impl From>> for Color32 { + fn from(srgba: PremultipliedAlpha>) -> Self { + let PremultipliedAlpha { + color: EncodedSrgb { r, g, b }, + alpha: a, + } = srgba; + + Color32::from_rgba_premultiplied(r, g, b, a) + } + } + + impl From for PremultipliedAlpha> { + fn from(col: Color32) -> Self { + let (r, g, b, a) = col.to_tuple(); + + PremultipliedAlpha { + color: EncodedSrgb { r, g, b }, + alpha: a, + } + } + } + + impl From>> for Color32 { + fn from(srgba: PremultipliedAlpha>) -> Self { + let PremultipliedAlpha { + color: EncodedSrgb { r, g, b }, + alpha: a, + } = srgba; + + // This is a bit of an abuse of the function name but it does what we want. + let r = linear_u8_from_linear_f32(r); + let g = linear_u8_from_linear_f32(g); + let b = linear_u8_from_linear_f32(b); + let a = linear_u8_from_linear_f32(a); + + Color32::from_rgba_premultiplied(r, g, b, a) + } + } + + impl From for PremultipliedAlpha> { + fn from(col: Color32) -> Self { + let (r, g, b, a) = col.to_tuple(); + + // This is a bit of an abuse of the function name but it does what we want. + let r = linear_f32_from_linear_u8(r); + let g = linear_f32_from_linear_u8(g); + let b = linear_f32_from_linear_u8(b); + let a = linear_f32_from_linear_u8(a); + + PremultipliedAlpha { + color: EncodedSrgb { r, g, b }, + alpha: a, + } + } + } + + impl ColorInterop for Color32 { + type CintTy = PremultipliedAlpha>; + } + + // ---- Rgba ---- + + impl From>> for Rgba { + fn from(srgba: PremultipliedAlpha>) -> Self { + let PremultipliedAlpha { + color: LinearSrgb { r, g, b }, + alpha: a, + } = srgba; + + Rgba([r, g, b, a]) + } + } + + impl From for PremultipliedAlpha> { + fn from(col: Rgba) -> Self { + let (r, g, b, a) = col.to_tuple(); + + PremultipliedAlpha { + color: LinearSrgb { r, g, b }, + alpha: a, + } + } + } + + impl ColorInterop for Rgba { + type CintTy = PremultipliedAlpha>; + } + + // ---- Hsva ---- + + impl From>> for Hsva { + fn from(srgba: Alpha>) -> Self { + let Alpha { + color: Hsv { h, s, v }, + alpha: a, + } = srgba; + + Hsva::new(h, s, v, a) + } + } + + impl From for Alpha> { + fn from(col: Hsva) -> Self { + let Hsva { h, s, v, a } = col; + + Alpha { + color: Hsv { h, s, v }, + alpha: a, + } + } + } + + impl ColorInterop for Hsva { + type CintTy = Alpha>; + } + + // ---- HsvaGamma ---- + + impl ColorInterop for HsvaGamma { + type CintTy = Alpha>; + } + + impl From>> for HsvaGamma { + fn from(srgba: Alpha>) -> Self { + let Alpha { + color: Hsv { h, s, v }, + alpha: a, + } = srgba; + + Hsva::new(h, s, v, a).into() + } + } + + impl From for Alpha> { + fn from(col: HsvaGamma) -> Self { + let Hsva { h, s, v, a } = col.into(); + + Alpha { + color: Hsv { h, s, v }, + alpha: a, + } + } + } +}