use core::cast::transmute; use core::cmp::{Eq, Ord}; use core::ptr::to_unsafe_ptr; use core::sys::size_of; use core::vec::raw::buf_as_slice; use angle::Degrees; use channel::Channel; use dim::{Dimensional, ToPtr}; use funs::common::Sign; use num::cast::{cast, NumCast}; use num::ext::Float; pub trait Color: Dimensional, ToPtr, Eq { pure fn inverse(&self) -> self; pure fn to_rgb_u8(&self) -> RGB; pure fn to_rgb_u16(&self) -> RGB; pure fn to_rgb_u32(&self) -> RGB; pure fn to_rgb_u64(&self) -> RGB; pure fn to_rgb_f32(&self) -> RGB; pure fn to_rgb_f64(&self) -> RGB; pure fn to_hsv_f32(&self) -> HSV; pure fn to_hsv_f64(&self) -> HSV; } // pub trait ColorRGB { // static pure fn from_hex(hex: u8) -> self; // } pub trait Color3: Color { pure fn to_rgba_u8(&self, a: u8) -> RGBA; pure fn to_rgba_u16(&self, a: u16) -> RGBA; pure fn to_rgba_u32(&self, a: u32) -> RGBA; pure fn to_rgba_u64(&self, a: u64) -> RGBA; pure fn to_rgba_f32(&self, a: f32) -> RGBA; pure fn to_rgba_f64(&self, a: f64) -> RGBA; pure fn to_hsva_f32(&self, a: f32) -> HSVA; pure fn to_hsva_f64(&self, a: f64) -> HSVA; } pub trait Color4: Color { pure fn to_rgba_u8(&self) -> RGBA; pure fn to_rgba_u16(&self) -> RGBA; pure fn to_rgba_u32(&self) -> RGBA; pure fn to_rgba_u64(&self) -> RGBA; pure fn to_rgba_f32(&self) -> RGBA; pure fn to_rgba_f64(&self) -> RGBA; pure fn to_hsva_f32(&self) -> HSVA; pure fn to_hsva_f64(&self) -> HSVA; } /** * A generic rgb to hsv conversion * * Assumes that T is a floating point type * * TODO: Use some sort of 'Float' trait bound to make this safer */ #[inline(always)] pub pure fn to_hsv(color: &RGB) -> HSV { // Algorithm taken from the Wikipedia article on HSL and HSV: // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV let _0 = cast(0); let mx = [color.r, color.g, color.b].max(); let mn = [color.r, color.g, color.b].min(); let chr = mx - mn; if chr != cast(0) { let h = Degrees(if color.r == mx { ((color.g - color.b) / chr) % cast(6) } else if color.g == mx { ((color.b - color.r) / chr) + cast(2) } else /* color.b == mx */{ ((color.r - color.g) / chr) + cast(4) } * cast(60)); let s = chr / mx; HSV::new(h, s, mx) } else { HSV::new(Degrees(_0), _0, mx) } } /** * A generic hsv to rgb conversion * * Assumes that T is a floating point type * * TODO: Use some sort of 'Float' trait bound to make this safer */ #[inline(always)] pub pure fn to_rgb(color: &HSV) -> RGB { // Algorithm taken from the Wikipedia article on HSL and HSV: // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV let _0: T = cast(0); let _1: T = cast(1); let _2: T = cast(2); let chr = color.v * color.s; let h_ = *(color.h) / cast(60); // TODO: it'd be nice if Degrees / Degrees returned a scalar // the 2nd largest component let x = chr * (_1 - ((h_ % _2) - _1).abs()); let mut color_rgb = if h_ < cast(1) { RGB::new(chr, x, _0) } else if h_ < cast(2) { RGB::new( x, chr, _0) } else if h_ < cast(3) { RGB::new( _0, chr, x) } else if h_ < cast(4) { RGB::new( _0, x, chr) } else if h_ < cast(5) { RGB::new( x, _0, chr) } else if h_ < cast(6) { RGB::new(chr, _0, x) } else { RGB::new( _0, _0, _0) }; // match the value by adding the same amount to each component let mn = color.v - chr; color_rgb.r += mn; color_rgb.g += mn; color_rgb.b += mn; return color_rgb; } pub struct RGB { r: T, g: T, b: T } pub impl RGB { #[inline(always)] static pure fn new(r: T, g: T, b: T) -> RGB { RGB { r: move r, g: move g, b: move b } } } pub impl RGB: Dimensional { #[inline(always)] static pure fn dim() -> uint { 3 } #[inline(always)] static pure fn size_of() -> uint { size_of::>() } } pub impl RGB: Index { #[inline(always)] pure fn index(i: uint) -> T { unsafe { do buf_as_slice( transmute::<*RGB, *T>( to_unsafe_ptr(&self)), 3) |slice| { slice[i] } } } } pub impl RGB: ToPtr { #[inline(always)] pure fn to_ptr(&self) -> *T { ptr::to_unsafe_ptr(&self[0]) } } pub impl RGB: Color { #[inline(always)] pure fn inverse(&self) -> RGB { RGB::new(self.r.inverse(), self.g.inverse(), self.b.inverse()) } #[inline(always)] pure fn to_rgb_u8(&self) -> RGB { RGB::new(self.r.to_channel_u8(), self.g.to_channel_u8(), self.b.to_channel_u8()) } #[inline(always)] pure fn to_rgb_u16(&self) -> RGB { RGB::new(self.r.to_channel_u16(), self.g.to_channel_u16(), self.b.to_channel_u16()) } #[inline(always)] pure fn to_rgb_u32(&self) -> RGB { RGB::new(self.r.to_channel_u32(), self.g.to_channel_u32(), self.b.to_channel_u32()) } #[inline(always)] pure fn to_rgb_u64(&self) -> RGB { RGB::new(self.r.to_channel_u64(), self.g.to_channel_u64(), self.b.to_channel_u64()) } #[inline(always)] pure fn to_rgb_f32(&self) -> RGB { RGB::new(self.r.to_channel_f32(), self.g.to_channel_f32(), self.b.to_channel_f32()) } #[inline(always)] pure fn to_rgb_f64(&self) -> RGB { RGB::new(self.r.to_channel_f64(), self.g.to_channel_f64(), self.b.to_channel_f64()) } #[inline(always)] pure fn to_hsv_f32(&self) -> HSV { to_hsv(&self.to_rgb_f32()) } #[inline(always)] pure fn to_hsv_f64(&self) -> HSV { to_hsv(&self.to_rgb_f64()) } } pub impl RGB: Color3 { #[inline(always)] pure fn to_rgba_u8(&self, a: u8) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u8(), a) } #[inline(always)] pure fn to_rgba_u16(&self, a: u16) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u16(), a) } #[inline(always)] pure fn to_rgba_u32(&self, a: u32) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u32(), a) } #[inline(always)] pure fn to_rgba_u64(&self, a: u64) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u64(), a) } #[inline(always)] pure fn to_rgba_f32(&self, a: f32) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_f32(), a) } #[inline(always)] pure fn to_rgba_f64(&self, a: f64) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_f64(), a) } #[inline(always)] pure fn to_hsva_f32(&self, a: f32) -> HSVA { HSVA::from_hsv_a(&self.to_hsv_f32(), a) } #[inline(always)] pure fn to_hsva_f64(&self, a: f64) -> HSVA { HSVA::from_hsv_a(&self.to_hsv_f64(), a) } } pub impl RGB: Eq { pure fn eq(&self, other: &RGB) -> bool { self.r == other.r && self.g == other.g && self.b == other.b } pure fn ne(&self, other: &RGB) -> bool { !(self == other) } } pub struct RGBA { r: T, g: T, b: T, a: T } pub impl RGBA { #[inline(always)] static pure fn new(r: T, g: T, b: T, a: T) -> RGBA { RGBA { r: move r, g: move g, b: move b, a: move a } } #[inline(always)] static pure fn from_rgb_a(rgb: &RGB, a: T) -> RGBA { RGBA::new(rgb.r, rgb.g, rgb.b, move a) } } pub impl RGBA: Dimensional { #[inline(always)] static pure fn dim() -> uint { 4 } #[inline(always)] static pure fn size_of() -> uint { size_of::>() } } pub impl RGBA: Index { #[inline(always)] pure fn index(i: uint) -> T { unsafe { do buf_as_slice( transmute::<*RGBA, *T>( to_unsafe_ptr(&self)), 4) |slice| { slice[i] } } } } pub impl RGBA: ToPtr { #[inline(always)] pure fn to_ptr(&self) -> *T { ptr::to_unsafe_ptr(&self[0]) } } pub impl RGBA: Color { #[inline(always)] pure fn inverse(&self) -> RGBA { RGBA::new(self.r.inverse(), self.g.inverse(), self.b.inverse(), self.a.inverse()) } #[inline(always)] pure fn to_rgb_u8(&self) -> RGB { RGB::new(self.r.to_channel_u8(), self.g.to_channel_u8(), self.b.to_channel_u8()) } #[inline(always)] pure fn to_rgb_u16(&self) -> RGB { RGB::new(self.r.to_channel_u16(), self.g.to_channel_u16(), self.b.to_channel_u16()) } #[inline(always)] pure fn to_rgb_u32(&self) -> RGB { RGB::new(self.r.to_channel_u32(), self.g.to_channel_u32(), self.b.to_channel_u32()) } #[inline(always)] pure fn to_rgb_u64(&self) -> RGB { RGB::new(self.r.to_channel_u64(), self.g.to_channel_u64(), self.b.to_channel_u64()) } #[inline(always)] pure fn to_rgb_f32(&self) -> RGB { RGB::new(self.r.to_channel_f32(), self.g.to_channel_f32(), self.b.to_channel_f32()) } #[inline(always)] pure fn to_rgb_f64(&self) -> RGB { RGB::new(self.r.to_channel_f64(), self.g.to_channel_f64(), self.b.to_channel_f64()) } #[inline(always)] pure fn to_hsv_f32(&self) -> HSV { to_hsv(&self.to_rgb_f32()) } #[inline(always)] pure fn to_hsv_f64(&self) -> HSV { to_hsv(&self.to_rgb_f64()) } } pub impl RGBA: Color4 { #[inline(always)] pure fn to_rgba_u8(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u8(), self.a.to_channel_u8()) } #[inline(always)] pure fn to_rgba_u16(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u16(), self.a.to_channel_u16()) } #[inline(always)] pure fn to_rgba_u32(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u32(), self.a.to_channel_u32()) } #[inline(always)] pure fn to_rgba_u64(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u64(), self.a.to_channel_u64()) } #[inline(always)] pure fn to_rgba_f32(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_f32(), self.a.to_channel_f32()) } #[inline(always)] pure fn to_rgba_f64(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_f64(), self.a.to_channel_f64()) } #[inline(always)] pure fn to_hsva_f32(&self) -> HSVA { HSVA::from_hsv_a(&self.to_hsv_f32(), self.a.to_channel_f32()) } #[inline(always)] pure fn to_hsva_f64(&self) -> HSVA { HSVA::from_hsv_a(&self.to_hsv_f64(), self.a.to_channel_f64()) } } pub impl RGBA: Eq { pure fn eq(&self, other: &RGBA) -> bool { self.r == other.r && self.g == other.g && self.b == other.b && self.a == other.a } pure fn ne(&self, other: &RGBA) -> bool { !(self == other) } } pub struct HSV { h: Degrees, s: T, v: T } pub impl HSV { static pure fn new(h: Degrees, s: T, v: T) -> HSV { HSV { h: move h, s: move s, v: move v } } } pub impl HSV: Dimensional { #[inline(always)] static pure fn dim() -> uint { 3 } #[inline(always)] static pure fn size_of() -> uint { size_of::>() } } pub impl HSV: Index { #[inline(always)] pure fn index(i: uint) -> T { unsafe { do buf_as_slice( transmute::<*HSV, *T>( to_unsafe_ptr(&self)), 3) |slice| { slice[i] } } } } pub impl HSV: ToPtr { #[inline(always)] pure fn to_ptr(&self) -> *T { ptr::to_unsafe_ptr(&self[0]) } } pub impl HSV: Color { #[inline(always)] pure fn inverse(&self) -> HSV { HSV::new(self.h.opposite(), self.s.inverse(), self.v.inverse()) } #[inline(always)] pure fn to_rgb_u8(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_u8() } #[inline(always)] pure fn to_rgb_u16(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_u16() } #[inline(always)] pure fn to_rgb_u32(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_u32() } #[inline(always)] pure fn to_rgb_u64(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_u64() } #[inline(always)] pure fn to_rgb_f32(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_f32() } #[inline(always)] pure fn to_rgb_f64(&self) -> RGB { to_rgb(&self.to_hsv_f64()).to_rgb_f64() } #[inline(always)] pure fn to_hsv_f32(&self) -> HSV { HSV::new(Degrees((*self.h).to_f32()), self.s.to_channel_f32(), self.v.to_channel_f32()) } #[inline(always)] pure fn to_hsv_f64(&self) -> HSV { HSV::new(Degrees((*self.h).to_f64()), self.s.to_channel_f64(), self.v.to_channel_f64()) } } pub impl HSV: Color3 { #[inline(always)] pure fn to_rgba_u8(&self, a: u8) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u8(), a) } #[inline(always)] pure fn to_rgba_u16(&self, a: u16) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u16(), a) } #[inline(always)] pure fn to_rgba_u32(&self, a: u32) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u32(), a) } #[inline(always)] pure fn to_rgba_u64(&self, a: u64) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u64(), a) } #[inline(always)] pure fn to_rgba_f32(&self, a: f32) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_f32(), a) } #[inline(always)] pure fn to_rgba_f64(&self, a: f64) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_f64(), a) } #[inline(always)] pure fn to_hsva_f32(&self, a: f32) -> HSVA { HSVA::from_hsv_a(&self.to_hsv_f32(), a) } #[inline(always)] pure fn to_hsva_f64(&self, a: f64) -> HSVA { HSVA::from_hsv_a(&self.to_hsv_f64(), a) } } pub impl HSV: Eq { pure fn eq(&self, other: &HSV) -> bool { self.h == other.h && self.s == other.s && self.v == other.v } pure fn ne(&self, other: &HSV) -> bool { !(self == other) } } pub struct HSVA { h: Degrees, s: T, v: T, a: T } pub impl HSVA { #[inline(always)] static pure fn new(h: Degrees, s: T, v: T, a: T) -> HSVA { HSVA { h: move h, s: move s, v: move v, a: move a } } #[inline(always)] static pure fn from_hsv_a(hsv: &HSV, a: T) -> HSVA { HSVA::new(hsv.h, hsv.s, hsv.v, move a) } } pub impl HSVA: Dimensional { #[inline(always)] static pure fn dim() -> uint { 4 } #[inline(always)] static pure fn size_of() -> uint { size_of::>() } } pub impl HSVA: Index { #[inline(always)] pure fn index(i: uint) -> T { unsafe { do buf_as_slice( transmute::<*HSVA, *T>( to_unsafe_ptr(&self)), 4) |slice| { slice[i] } } } } pub impl HSVA: ToPtr { #[inline(always)] pure fn to_ptr(&self) -> *T { ptr::to_unsafe_ptr(&self[0]) } } pub impl HSVA: Color { #[inline(always)] pure fn inverse(&self) -> HSVA { HSVA::new(self.h.opposite(), self.s.inverse(), self.v.inverse(), self.a.inverse()) } #[inline(always)] pure fn to_rgb_u8(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_u8() } #[inline(always)] pure fn to_rgb_u16(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_u16() } #[inline(always)] pure fn to_rgb_u32(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_u32() } #[inline(always)] pure fn to_rgb_u64(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_u64() } #[inline(always)] pure fn to_rgb_f32(&self) -> RGB { to_rgb(&self.to_hsv_f32()).to_rgb_f32() } #[inline(always)] pure fn to_rgb_f64(&self) -> RGB { to_rgb(&self.to_hsv_f64()).to_rgb_f64() } #[inline(always)] pure fn to_hsv_f32(&self) -> HSV { HSV::new(Degrees((*self.h).to_f32()), self.s.to_channel_f32(), self.v.to_channel_f32()) } #[inline(always)] pure fn to_hsv_f64(&self) -> HSV { HSV::new(Degrees((*self.h).to_f64()), self.s.to_channel_f64(), self.v.to_channel_f64()) } } pub impl HSVA: Color4 { #[inline(always)] pure fn to_rgba_u8(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u8(), self.a.to_channel_u8()) } #[inline(always)] pure fn to_rgba_u16(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u16(), self.a.to_channel_u16()) } #[inline(always)] pure fn to_rgba_u32(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u32(), self.a.to_channel_u32()) } #[inline(always)] pure fn to_rgba_u64(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_u64(), self.a.to_channel_u64()) } #[inline(always)] pure fn to_rgba_f32(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_f32(), self.a.to_channel_f32()) } #[inline(always)] pure fn to_rgba_f64(&self) -> RGBA { RGBA::from_rgb_a(&self.to_rgb_f64(), self.a.to_channel_f64()) } #[inline(always)] pure fn to_hsva_f32(&self) -> HSVA { HSVA::from_hsv_a(&self.to_hsv_f32(), self.a.to_channel_f32()) } #[inline(always)] pure fn to_hsva_f64(&self) -> HSVA { HSVA::from_hsv_a(&self.to_hsv_f64(), self.a.to_channel_f64()) } } pub impl HSVA: Eq { pure fn eq(&self, other: &HSVA) -> bool { self.h == other.h && self.s == other.s && self.v == other.v && self.a == other.a } pure fn ne(&self, other: &HSVA) -> bool { !(self == other) } }