Files
addr2line
adler
adler32
ahash
aho_corasick
angle
approx
backtrace
bitflags
blender
bytemuck
byteorder
case
cast_trait
cfg_if
chrono
color
color_quant
const_fn
crc32fast
crossbeam
crossbeam_channel
crossbeam_deque
crossbeam_epoch
crossbeam_queue
crossbeam_skiplist
crossbeam_utils
darling
darling_core
darling_macro
dds
deflate
densevec
derive_builder
derive_builder_core
dot
downcast_rs
dual_quat
either
erased_serde
failure
failure_derive
fixedbitset
float_cmp
fnv
freeimage
freeimage_sys
freetype
freetype_gl_sys
freetype_sys
freetypegl
futures
futures_channel
futures_core
futures_executor
futures_io
futures_macro
futures_sink
futures_task
futures_util
async_await
future
io
lock
sink
stream
task
fxhash
generational_arena
generic_array
getrandom
gif
gimli
glfw
glfw_sys
glin
glin_derive
glsl
half
harfbuzz
harfbuzz_ft_sys
harfbuzz_sys
hashbrown
human_sort
ident_case
image
indexmap
instant
itertools
itoa
jpeg_decoder
lazy_static
libc
libm
lock_api
log
lut_parser
matrixmultiply
memchr
memoffset
meshopt
miniz_oxide
monotonic_clock
mopa
mutiny_derive
na
nalgebra
base
geometry
linalg
ncollide3d
bounding_volume
interpolation
partitioning
pipeline
procedural
query
algorithms
closest_points
contact
distance
nonlinear_time_of_impact
point
proximity
ray
time_of_impact
visitors
shape
transformation
utils
nom
num_complex
num_cpus
num_integer
num_iter
num_rational
num_traits
numext_constructor
numext_fixed_uint
numext_fixed_uint_core
numext_fixed_uint_hack
object
once_cell
parking_lot
parking_lot_core
pathfinding
pennereq
petgraph
pin_project_lite
pin_utils
png
polygon2
ppv_lite86
proc_macro2
proc_macro_crate
proc_macro_hack
proc_macro_nested
quote
rand
rand_chacha
rand_core
rand_distr
raw_window_handle
rawpointer
rayon
rayon_core
rect_packer
regex
regex_syntax
retain_mut
rin
rin_app
rin_blender
rin_core
rin_gl
rin_graphics
rin_gui
rin_material
rin_math
rin_postpo
rin_scene
rin_util
rin_window
rinblender
rinecs
rinecs_derive
rinecs_derive_utils
ringui_derive
rustc_demangle
rusty_pool
ryu
scopeguard
seitan
seitan_derive
semver
semver_parser
serde
serde_derive
serde_json
shaderdata_derive
simba
slab
slice_of_array
slotmap
smallvec
std140_data
streaming_iterator
strsim
syn
synstructure
thiserror
thiserror_impl
thread_local
tiff
time
toml
typenum
unchecked_unwrap
unicode_xid
vec2
vec3
weezl
x11
zlib_sys
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
use channel::Channel;
use color_space::{WhitePoint};
use num_traits::{Float, NumCast, cast, zero};
use xyz::{Xyz, ToXyz};
use std::ops::{Add, Mul};

#[derive(Clone, Copy, Debug)]
pub struct Lab<T, Wp>{
    pub l: T,
    pub a: T,
    pub b: T,
    pub white_point: Wp,
}

impl<T, Wp: WhitePoint> Lab<T, Wp>{
    pub fn new(l: T, a: T, b: T) -> Lab<T, Wp>{
        Lab { l, a, b, white_point: Wp::default() }
    }
}


impl<T: Copy, Wp: WhitePoint> Lab<T, Wp>{
    pub fn brightness(&self) -> T {
        self.l
    }
}

impl<T: Float, Wp: WhitePoint> Lab<T, Wp>{
    pub fn chromacity(&self) -> T {
        (self.a.powi(2) + self.b.powi(2)).sqrt()
    }

    pub fn hue(&self) -> T {
        let h = self.b.atan2(self.a);
        if h < zero() {
            h + cast(std::f64::consts::TAU).unwrap()
        }else{
            h
        }
    }

    pub fn offset_chromacity(&self, chroma_offset: T) -> Lab<T, Wp>{
        let current_croma = self.chromacity();
        let offset_a = self.a / current_croma * chroma_offset;
        let offset_b = self.b / current_croma * chroma_offset;
        Lab::new(
            self.l,
            self.a + offset_a,
            self.b + offset_b,
        )
    }
}

pub trait ToLab {
    type WhitePoint: WhitePoint;
    fn to_lab<T: Channel>(&self) -> Lab<T, Self::WhitePoint>;
}

impl<T: Channel + Float + NumCast, Wp: WhitePoint> ToXyz for Lab<T, Wp> {
    type WhitePoint = Wp;
    fn to_xyz<U: Channel + Float>(&self) -> Xyz<U, Wp> {
        let fy = (self.l + cast(16).unwrap()) / cast(116).unwrap();
        let fx = self.a / cast(500).unwrap() + fy;
        let fz = fy - self.b / cast(200).unwrap();
        let fxcb=fx*fx*fx;
        let fzcb=fz*fz*fz;
        let mut xyz = [fxcb, cast(0.).unwrap(), fzcb];
        let eps= cast(216.0 / 24389.).unwrap(); // See BruceLindbloom.com
        if fxcb <= eps {
            xyz[0] = (cast::<f64,T>(108.0).unwrap() * fx / cast(841).unwrap()) - cast::<f64,T>(432.0).unwrap() / cast(24389.).unwrap()
        };
        if fzcb <= eps{
             xyz[2] = (cast::<f64,T>(108.0).unwrap() * fz / cast(841).unwrap()) - cast::<f64,T>(432.0).unwrap() / cast(24389.).unwrap()
        }
        if self.l > cast(8.).unwrap() { // See BruceLindbloom.com
            xyz[1]=fy.powi(3)
        }else{
            xyz[1]=self.l * cast(27.0).unwrap() / cast(24389).unwrap(); // See BruceLindbloom.com
        }
        xyz[0] = xyz[0] * Wp::xyz().x;
        xyz[1] = xyz[1] * Wp::xyz().y;
        xyz[2] = xyz[2] * Wp::xyz().z;

        Xyz::new(xyz[0].to_channel(), xyz[1].to_channel(), xyz[2].to_channel())
    }
}

impl<T: Channel + Float + NumCast, Wp: WhitePoint> Add for Lab<T,Wp>{
    type Output = Lab<T, Wp>;
    fn add(self, other: Lab<T, Wp>) -> Lab<T, Wp> {
        Lab::new(self.l + other.l, self.a + other.a, self.b + other.b)
    }
}

impl<T: Channel + Float + NumCast, Wp: WhitePoint> Mul<T> for Lab<T,Wp>{
    type Output = Lab<T, Wp>;
    fn mul(self, other: T) -> Lab<T, Wp> {
        Lab::new(self.l * other, self.a * other, self.b * other)
    }
}