abrasion/engine/physics/color.rs

98 lines
2.5 KiB
Rust

// Copyright 2020 Sergiusz 'q3k' Bazanski <q3k@q3k.org>
//
// This file is part of Abrasion.
//
// Abrasion is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, version 3.
//
// Abrasion is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// Abrasion. If not, see <https://www.gnu.org/licenses/>.
#[derive(Copy, Clone, Debug)]
pub struct XYZ {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl XYZ {
pub fn new(x: f32, y: f32, z: f32) -> Self {
Self {
x, y, z,
}
}
pub fn from_srgb(r: f32, g: f32, b: f32) -> Self {
let (x, y, z) = srgb_to_cie_xyz(r, g, b);
Self {
x, y, z
}
}
}
#[derive(Debug)]
pub struct LinearF32 {
pub d: f32,
}
impl LinearF32 {
pub fn new(d: f32) -> Self {
Self {
d,
}
}
}
/// Convert sRGB color space (in R8G8B8A8) to XYZ colorspace (floats).
pub fn srgb_packed_to_cie_xyz(rgba: u32) -> (f32, f32, f32, f32) {
// Unpack RGBA to R, G, B, A 0-255 values.
let r = ((rgba >> 24) & 0xff) as f32;
let g = ((rgba >> 16) & 0xff) as f32;
let b = ((rgba >> 8 ) & 0xff) as f32;
let a = ((rgba ) & 0xff) as f32;
let r = r/255.0;
let g = g/255.0;
let b = b/255.0;
let (x, y, z) = srgb_to_cie_xyz(r, g, b);
(x, y, z, a)
}
/// Convert sRGB color space (floats) to XYZ colorspace (floats).
/// The input are floats in the range 0-1.0.
/// The output is a tuple of (X, Y, Z) floats.
pub fn srgb_to_cie_xyz(r: f32, g: f32, b: f32) -> (f32, f32, f32) {
assert!(r >= 0.0 && r <= 1.0);
assert!(g >= 0.0 && g <= 1.0);
assert!(b >= 0.0 && b <= 1.0);
// Following DIN EN 61966-2-1:2003-09
// (which corresponds to IEC 61966-2-1:1999)
// Equations (5) and (6)
let eq56 = |v| {
if v < 0.004045 {
v / 12.92
} else {
let v: f32 = (v + 0.055) / (1.055);
v.powf(2.4) as f32
}
};
let r = eq56(r);
let g = eq56(g);
let b = eq56(b);
// Equation (7)
// (unrolled matrix multiplication)
let x = 0.4124 * r + 0.3576 * g + 0.1805 * b;
let y = 0.2126 * r + 0.7152 * g + 0.0722 * b;
let z = 0.0193 * r + 0.1192 * g + 0.9505 * b;
(x, y , z)
}