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
This commit is contained in:
Gray Olson 2021-05-20 11:09:52 -07:00 committed by GitHub
parent ac82cc7be3
commit c0929014bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 189 additions and 0 deletions

View file

@ -8,6 +8,7 @@ NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md) and [
## Unreleased ## Unreleased
### Added ⭐ ### 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. * 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 ## 0.12.0 - 2021-05-10 - Multitouch, user memory, window pivots, and improved plots

7
Cargo.lock generated
View file

@ -294,6 +294,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
[[package]]
name = "cint"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00709959bb62458ca8d7f043b1039e0d99e91f5500f004164ec371f546eadc47"
[[package]] [[package]]
name = "clang-sys" name = "clang-sys"
version = "1.2.0" version = "1.2.0"
@ -846,6 +852,7 @@ version = "0.12.0"
dependencies = [ dependencies = [
"ahash", "ahash",
"atomic_refcell", "atomic_refcell",
"cint",
"emath", "emath",
"ordered-float", "ordered-float",
"parking_lot", "parking_lot",

View file

@ -39,6 +39,9 @@ extra_asserts = ["epaint/extra_asserts"]
# Add compatability with https://github.com/kvark/mint # Add compatability with https://github.com/kvark/mint
mint = ["epaint/mint"] mint = ["epaint/mint"]
# add compatibility with https://crates.io/crates/cint
cint = ["epaint/cint"]
persistence = ["serde", "epaint/persistence", "ron"] persistence = ["serde", "epaint/persistence", "ron"]
# Only needed if you plan to use the same egui::Context from multiple threads. # Only needed if you plan to use the same egui::Context from multiple threads.

View file

@ -26,6 +26,7 @@ emath = { version = "0.12.0", path = "../emath" }
ahash = { version = "0.7", features = ["std"], default-features = false } 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. 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" 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. 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" rusttype = "0.9"

View file

@ -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 { 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) 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<Alpha<EncodedSrgb<u8>>> for Color32 {
fn from(srgba: Alpha<EncodedSrgb<u8>>) -> Self {
let Alpha {
color: EncodedSrgb { r, g, b },
alpha: a,
} = srgba;
Color32::from_rgba_unmultiplied(r, g, b, a)
}
}
// No From<Color32> for Alpha<_> because Color32 is premultiplied
impl From<PremultipliedAlpha<EncodedSrgb<u8>>> for Color32 {
fn from(srgba: PremultipliedAlpha<EncodedSrgb<u8>>) -> Self {
let PremultipliedAlpha {
color: EncodedSrgb { r, g, b },
alpha: a,
} = srgba;
Color32::from_rgba_premultiplied(r, g, b, a)
}
}
impl From<Color32> for PremultipliedAlpha<EncodedSrgb<u8>> {
fn from(col: Color32) -> Self {
let (r, g, b, a) = col.to_tuple();
PremultipliedAlpha {
color: EncodedSrgb { r, g, b },
alpha: a,
}
}
}
impl From<PremultipliedAlpha<EncodedSrgb<f32>>> for Color32 {
fn from(srgba: PremultipliedAlpha<EncodedSrgb<f32>>) -> 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<Color32> for PremultipliedAlpha<EncodedSrgb<f32>> {
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<EncodedSrgb<u8>>;
}
// ---- Rgba ----
impl From<PremultipliedAlpha<LinearSrgb<f32>>> for Rgba {
fn from(srgba: PremultipliedAlpha<LinearSrgb<f32>>) -> Self {
let PremultipliedAlpha {
color: LinearSrgb { r, g, b },
alpha: a,
} = srgba;
Rgba([r, g, b, a])
}
}
impl From<Rgba> for PremultipliedAlpha<LinearSrgb<f32>> {
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<LinearSrgb<f32>>;
}
// ---- Hsva ----
impl From<Alpha<Hsv<f32>>> for Hsva {
fn from(srgba: Alpha<Hsv<f32>>) -> Self {
let Alpha {
color: Hsv { h, s, v },
alpha: a,
} = srgba;
Hsva::new(h, s, v, a)
}
}
impl From<Hsva> for Alpha<Hsv<f32>> {
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<Hsv<f32>>;
}
// ---- HsvaGamma ----
impl ColorInterop for HsvaGamma {
type CintTy = Alpha<Hsv<f32>>;
}
impl From<Alpha<Hsv<f32>>> for HsvaGamma {
fn from(srgba: Alpha<Hsv<f32>>) -> Self {
let Alpha {
color: Hsv { h, s, v },
alpha: a,
} = srgba;
Hsva::new(h, s, v, a).into()
}
}
impl From<HsvaGamma> for Alpha<Hsv<f32>> {
fn from(col: HsvaGamma) -> Self {
let Hsva { h, s, v, a } = col.into();
Alpha {
color: Hsv { h, s, v },
alpha: a,
}
}
}
}