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
// Copyright 2013 The color-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use channel::Channel;
use num_traits::Float;
use rgb::{Rgb, ToRgb};
use yxy::{Yxy, ToYxy};
use color_space::{D65, WhitePoint, MatrixColorSpace, Srgb, TransferFunction};
use num_traits::{zero, NumCast, cast};
// use srgb::{Srgb, ToSrgb};
use lab::{Lab, ToLab};

#[derive(Clone, Copy, Debug)]
pub struct Xyz<T = f32, Wp = D65>
where T: Channel + Float
{
    pub x: T,
    pub y: T,
    pub z: T,
    pub white_point: Wp,
}

impl<T: Channel + Float, Wp: WhitePoint> Xyz<T,Wp> {
    pub fn new(x: T, y: T, z: T) -> Xyz<T,Wp> {
        Xyz{
            x,
            y,
            z,
            white_point: Wp::default(),
        }
    }
}

pub trait ToXyz {
    type WhitePoint: WhitePoint;
    fn to_xyz<T: Channel + Float + std::fmt::Debug>(&self) -> Xyz<T, Self::WhitePoint>;
}

impl<T: Channel + Float + Clone> ToRgb for Xyz<T, D65> {
    type Standard = Srgb;
    fn to_rgb<U: Channel>(&self) -> Rgb<U, Srgb> {
        let rgb = Srgb::to_rgb_matrix() * self.clone().into();
        Rgb::new(
            Srgb::from_linear(rgb[0]).to_channel(),
            Srgb::from_linear(rgb[1]).to_channel(),
            Srgb::from_linear(rgb[2]).to_channel(),
        )
    }
}

impl<T: Channel + Float + NumCast, Wp: WhitePoint> ToLab for Xyz<T, Wp> {
    type WhitePoint = Wp;
    fn to_lab<U:Channel>(&self) -> Lab<U, Wp> {
        let mut xyz = [self.x / Wp::xyz().x , self.y / Wp::xyz().y, self.z / Wp::xyz().z];
        for i in 0..3 {
            if xyz[i] > cast::<_, T>(216.0).unwrap() / cast(24389.).unwrap() {// See BruceLindbloom.com
                xyz[i] = xyz[i].cbrt()
            }else{
                let k = cast::<_, T>(24389.0).unwrap() / cast(27).unwrap(); // See BruceLindbloom.com
                xyz[i] = (cast::<_, T>(16.0).unwrap() + k * xyz[i]) / cast(116).unwrap()
            }
        }

        return Lab::new(
            (cast::<_, T>(116.0).unwrap() * xyz[1] - cast(16).unwrap()).to_channel(),
            (cast::<_, T>(500).unwrap() * (xyz[0] - xyz[1])).to_channel(),
            (cast::<_, T>(200).unwrap() * (xyz[1] - xyz[2])).to_channel()
        )
    }
}

impl<T: Channel + Float, Wp: WhitePoint> ToYxy for Xyz<T, Wp> {
    type WhitePoint = Wp;
    fn to_yxy<U: Channel + Float>(&self) -> Yxy<U, Wp> {
        let sum = self.x + self.y + self.z;
        let x;
        let y;
        let luma = self.y;
        if sum < zero() || sum > zero() {
            x = self.x / sum;
            y = self.y / sum;
        }else{
            x = zero();
            y = zero();
        }
        Yxy{x: x.to_channel(), y: y.to_channel(), luma: luma.to_channel(), white_point: Wp::default()}
    }
}