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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
use std::ops::{Add, Sub, Div, Mul};
use bindings::{AsNative, FromNative, ffi};

#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Color {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

impl AsNative<ffi::TCOD_color_t> for Color {
    unsafe fn as_native(&self) -> &ffi::TCOD_color_t {
        ::std::mem::transmute(self)
    }
}

impl FromNative<ffi::TCOD_color_t> for Color {
    unsafe fn from_native(input: ffi::TCOD_color_t) -> Color {
        ::std::mem::transmute(input)
    }
}

impl Color {
    pub fn new(r: u8, g: u8, b: u8) -> Color {
        Color {
            r: r,
            g: g,
            b: b,
        }
    }

    pub fn new_from_hsv(h: f32, s: f32, v: f32) -> Color {
        unsafe {
            FromNative::from_native(ffi::TCOD_color_HSV(h, s, v))
        }
    }

    pub fn hsv(self) -> (f32, f32, f32) {
        let mut h: f32 = 0.0;
        let mut s: f32 = 0.0;
        let mut v: f32 = 0.0;
        unsafe {
            ffi::TCOD_color_get_HSV(*self.as_native(), &mut h, &mut s, &mut v)
        }
        (h, s, v)
    }

    pub fn shift_hue(self, shift: f32) -> Color {
        unsafe {
            let mut c = *self.as_native();
            ffi::TCOD_color_shift_hue(&mut c, shift);
            FromNative::from_native(c)
        }
    }

    pub fn scale_hsv(self, scale: f32, value: f32) -> Color {
        unsafe {
            let mut c = *self.as_native();
            ffi::TCOD_color_scale_HSV(&mut c, scale, value);
            FromNative::from_native(c)
        }
    }
}

pub fn lerp(from: Color, to: Color, coefficient: f32) -> Color {
    unsafe {
        FromNative::from_native(ffi::TCOD_color_lerp(*from.as_native(),
                                                     *to.as_native(),
                                                     coefficient))
    }
}

impl Add<Color> for Color {
    type Output = Color;

    #[inline]
    fn add(self, rhs: Color) -> Color {
        unsafe {
            FromNative::from_native(
                ffi::TCOD_color_add(*self.as_native(), *rhs.as_native()))
        }
    }
}

impl Sub<Color> for Color {
    type Output = Color;

    #[inline]
    fn sub(self, rhs: Color) -> Color {
        unsafe {
            FromNative::from_native(
                ffi::TCOD_color_subtract(*self.as_native(), *rhs.as_native()))
        }
    }
}

impl Mul<Color> for Color {
    type Output = Color;

    #[inline]
    fn mul(self, rhs: Color) -> Color {
        unsafe {
            FromNative::from_native(
                ffi::TCOD_color_multiply(*self.as_native(), *rhs.as_native()))
        }
    }
}

impl Mul<f32> for Color {
    type Output = Color;

    #[inline]
    fn mul(self, rhs: f32) -> Color {
        unsafe {
            FromNative::from_native(
                ffi::TCOD_color_multiply_scalar(*self.as_native(), rhs))
        }
    }
}

impl Mul<Color> for f32 {
    type Output = Color;

    #[inline]
    fn mul(self, rhs: Color) -> Color {
        rhs * self
    }
}

impl Div<f32> for Color {
    type Output = Color;

    #[inline]
    fn div(self, rhs: f32) -> Color {
        self * (1.0 / rhs)
    }
}

// NOTE; colour names and values copied from:
// tcod-sys/libtcod/include/libtcod_int.h
//
// We cannot return statics exported by the DLL here because they have a
// different type (TCOD_color_t) and we cannot call `transmute` to convert
// them to `Color`.
pub const BLACK: Color = Color{r: 0, g: 0, b: 0};
pub const DARKEST_GREY: Color = Color{r: 31, g: 31, b: 31};
pub const DARKER_GREY: Color = Color{r: 63, g: 63, b: 63};
pub const DARK_GREY: Color = Color{r: 95, g: 95, b: 95};
pub const GREY: Color = Color{r: 127, g: 127, b: 127};
pub const LIGHT_GREY: Color = Color{r: 159, g: 159, b: 159};
pub const LIGHTER_GREY: Color = Color{r: 191, g: 191, b: 191};
pub const LIGHTEST_GREY: Color = Color{r: 223, g: 223, b: 223};
pub const WHITE: Color = Color{r: 255, g: 255, b: 255};
pub const DARKEST_SEPIA: Color = Color{r: 31, g: 24, b: 15};
pub const DARKER_SEPIA: Color = Color{r: 63, g: 50, b: 31};
pub const DARK_SEPIA: Color = Color{r: 94, g: 75, b: 47};
pub const SEPIA: Color = Color{r: 127, g: 101, b: 63};
pub const LIGHT_SEPIA: Color = Color{r: 158, g: 134, b: 100};
pub const LIGHTER_SEPIA: Color = Color{r: 191, g: 171, b: 143};
pub const LIGHTEST_SEPIA: Color = Color{r: 222, g: 211, b: 195};
pub const DESATURATED_RED: Color = Color{r: 127, g: 63, b: 63};
pub const DESATURATED_FLAME: Color = Color{r: 127, g: 79, b: 63};
pub const DESATURATED_ORANGE: Color = Color{r: 127, g: 95, b: 63};
pub const DESATURATED_AMBER: Color = Color{r: 127, g: 111, b: 63};
pub const DESATURATED_YELLOW: Color = Color{r: 127, g: 127, b: 63};
pub const DESATURATED_LIME: Color = Color{r: 111, g: 127, b: 63};
pub const DESATURATED_CHARTREUSE: Color = Color{r: 95, g: 127, b: 63};
pub const DESATURATED_GREEN: Color = Color{r: 63, g: 127, b: 63};
pub const DESATURATED_SEA: Color = Color{r: 63, g: 127, b: 95};
pub const DESATURATED_TURQUOISE: Color = Color{r: 63, g: 127, b: 111};
pub const DESATURATED_CYAN: Color = Color{r: 63, g: 127, b: 127};
pub const DESATURATED_SKY: Color = Color{r: 63, g: 111, b: 127};
pub const DESATURATED_AZURE: Color = Color{r: 63, g: 95, b: 127};
pub const DESATURATED_BLUE: Color = Color{r: 63, g: 63, b: 127};
pub const DESATURATED_HAN: Color = Color{r: 79, g: 63, b: 127};
pub const DESATURATED_VIOLET: Color = Color{r: 95, g: 63, b: 127};
pub const DESATURATED_PURPLE: Color = Color{r: 111, g: 63, b: 127};
pub const DESATURATED_FUCHSIA: Color = Color{r: 127, g: 63, b: 127};
pub const DESATURATED_MAGENTA: Color = Color{r: 127, g: 63, b: 111};
pub const DESATURATED_PINK: Color = Color{r: 127, g: 63, b: 95};
pub const DESATURATED_CRIMSON: Color = Color{r: 127, g: 63, b: 79};
pub const LIGHTEST_RED: Color = Color{r: 255, g: 191, b: 191};
pub const LIGHTEST_FLAME: Color = Color{r: 255, g: 207, b: 191};
pub const LIGHTEST_ORANGE: Color = Color{r: 255, g: 223, b: 191};
pub const LIGHTEST_AMBER: Color = Color{r: 255, g: 239, b: 191};
pub const LIGHTEST_YELLOW: Color = Color{r: 255, g: 255, b: 191};
pub const LIGHTEST_LIME: Color = Color{r: 239, g: 255, b: 191};
pub const LIGHTEST_CHARTREUSE: Color = Color{r: 223, g: 255, b: 191};
pub const LIGHTEST_GREEN: Color = Color{r: 191, g: 255, b: 191};
pub const LIGHTEST_SEA: Color = Color{r: 191, g: 255, b: 223};
pub const LIGHTEST_TURQUOISE: Color = Color{r: 191, g: 255, b: 239};
pub const LIGHTEST_CYAN: Color = Color{r: 191, g: 255, b: 255};
pub const LIGHTEST_SKY: Color = Color{r: 191, g: 239, b: 255};
pub const LIGHTEST_AZURE: Color = Color{r: 191, g: 223, b: 255};
pub const LIGHTEST_BLUE: Color = Color{r: 191, g: 191, b: 255};
pub const LIGHTEST_HAN: Color = Color{r: 207, g: 191, b: 255};
pub const LIGHTEST_VIOLET: Color = Color{r: 223, g: 191, b: 255};
pub const LIGHTEST_PURPLE: Color = Color{r: 239, g: 191, b: 255};
pub const LIGHTEST_FUCHSIA: Color = Color{r: 255, g: 191, b: 255};
pub const LIGHTEST_MAGENTA: Color = Color{r: 255, g: 191, b: 239};
pub const LIGHTEST_PINK: Color = Color{r: 255, g: 191, b: 223};
pub const LIGHTEST_CRIMSON: Color = Color{r: 255, g: 191, b: 207};
pub const LIGHTER_RED: Color = Color{r: 255, g: 127, b: 127};
pub const LIGHTER_FLAME: Color = Color{r: 255, g: 159, b: 127};
pub const LIGHTER_ORANGE: Color = Color{r: 255, g: 191, b: 127};
pub const LIGHTER_AMBER: Color = Color{r: 255, g: 223, b: 127};
pub const LIGHTER_YELLOW: Color = Color{r: 255, g: 255, b: 127};
pub const LIGHTER_LIME: Color = Color{r: 223, g: 255, b: 127};
pub const LIGHTER_CHARTREUSE: Color = Color{r: 191, g: 255, b: 127};
pub const LIGHTER_GREEN: Color = Color{r: 127, g: 255, b: 127};
pub const LIGHTER_SEA: Color = Color{r: 127, g: 255, b: 191};
pub const LIGHTER_TURQUOISE: Color = Color{r: 127, g: 255, b: 223};
pub const LIGHTER_CYAN: Color = Color{r: 127, g: 255, b: 255};
pub const LIGHTER_SKY: Color = Color{r: 127, g: 223, b: 255};
pub const LIGHTER_AZURE: Color = Color{r: 127, g: 191, b: 255};
pub const LIGHTER_BLUE: Color = Color{r: 127, g: 127, b: 255};
pub const LIGHTER_HAN: Color = Color{r: 159, g: 127, b: 255};
pub const LIGHTER_VIOLET: Color = Color{r: 191, g: 127, b: 255};
pub const LIGHTER_PURPLE: Color = Color{r: 223, g: 127, b: 255};
pub const LIGHTER_FUCHSIA: Color = Color{r: 255, g: 127, b: 255};
pub const LIGHTER_MAGENTA: Color = Color{r: 255, g: 127, b: 223};
pub const LIGHTER_PINK: Color = Color{r: 255, g: 127, b: 191};
pub const LIGHTER_CRIMSON: Color = Color{r: 255, g: 127, b: 159};
pub const LIGHT_RED: Color = Color{r: 255, g: 63, b: 63};
pub const LIGHT_FLAME: Color = Color{r: 255, g: 111, b: 63};
pub const LIGHT_ORANGE: Color = Color{r: 255, g: 159, b: 63};
pub const LIGHT_AMBER: Color = Color{r: 255, g: 207, b: 63};
pub const LIGHT_YELLOW: Color = Color{r: 255, g: 255, b: 63};
pub const LIGHT_LIME: Color = Color{r: 207, g: 255, b: 63};
pub const LIGHT_CHARTREUSE: Color = Color{r: 159, g: 255, b: 63};
pub const LIGHT_GREEN: Color = Color{r: 63, g: 255, b: 63};
pub const LIGHT_SEA: Color = Color{r: 63, g: 255, b: 159};
pub const LIGHT_TURQUOISE: Color = Color{r: 63, g: 255, b: 207};
pub const LIGHT_CYAN: Color = Color{r: 63, g: 255, b: 255};
pub const LIGHT_SKY: Color = Color{r: 63, g: 207, b: 255};
pub const LIGHT_AZURE: Color = Color{r: 63, g: 159, b: 255};
pub const LIGHT_BLUE: Color = Color{r: 63, g: 63, b: 255};
pub const LIGHT_HAN: Color = Color{r: 111, g: 63, b: 255};
pub const LIGHT_VIOLET: Color = Color{r: 159, g: 63, b: 255};
pub const LIGHT_PURPLE: Color = Color{r: 207, g: 63, b: 255};
pub const LIGHT_FUCHSIA: Color = Color{r: 255, g: 63, b: 255};
pub const LIGHT_MAGENTA: Color = Color{r: 255, g: 63, b: 207};
pub const LIGHT_PINK: Color = Color{r: 255, g: 63, b: 159};
pub const LIGHT_CRIMSON: Color = Color{r: 255, g: 63, b: 111};
pub const RED: Color = Color{r: 255, g: 0, b: 0};
pub const FLAME: Color = Color{r: 255, g: 63, b: 0};
pub const ORANGE: Color = Color{r: 255, g: 127, b: 0};
pub const AMBER: Color = Color{r: 255, g: 191, b: 0};
pub const YELLOW: Color = Color{r: 255, g: 255, b: 0};
pub const LIME: Color = Color{r: 191, g: 255, b: 0};
pub const CHARTREUSE: Color = Color{r: 127, g: 255, b: 0};
pub const GREEN: Color = Color{r: 0, g: 255, b: 0};
pub const SEA: Color = Color{r: 0, g: 255, b: 127};
pub const TURQUOISE: Color = Color{r: 0, g: 255, b: 191};
pub const CYAN: Color = Color{r: 0, g: 255, b: 255};
pub const SKY: Color = Color{r: 0, g: 191, b: 255};
pub const AZURE: Color = Color{r: 0, g: 127, b: 255};
pub const BLUE: Color = Color{r: 0, g: 0, b: 255};
pub const HAN: Color = Color{r: 63, g: 0, b: 255};
pub const VIOLET: Color = Color{r: 127, g: 0, b: 255};
pub const PURPLE: Color = Color{r: 191, g: 0, b: 255};
pub const FUCHSIA: Color = Color{r: 255, g: 0, b: 255};
pub const MAGENTA: Color = Color{r: 255, g: 0, b: 191};
pub const PINK: Color = Color{r: 255, g: 0, b: 127};
pub const CRIMSON: Color = Color{r: 255, g: 0, b: 63};
pub const DARK_RED: Color = Color{r: 191, g: 0, b: 0};
pub const DARK_FLAME: Color = Color{r: 191, g: 47, b: 0};
pub const DARK_ORANGE: Color = Color{r: 191, g: 95, b: 0};
pub const DARK_AMBER: Color = Color{r: 191, g: 143, b: 0};
pub const DARK_YELLOW: Color = Color{r: 191, g: 191, b: 0};
pub const DARK_LIME: Color = Color{r: 143, g: 191, b: 0};
pub const DARK_CHARTREUSE: Color = Color{r: 95, g: 191, b: 0};
pub const DARK_GREEN: Color = Color{r: 0, g: 191, b: 0};
pub const DARK_SEA: Color = Color{r: 0, g: 191, b: 95};
pub const DARK_TURQUOISE: Color = Color{r: 0, g: 191, b: 143};
pub const DARK_CYAN: Color = Color{r: 0, g: 191, b: 191};
pub const DARK_SKY: Color = Color{r: 0, g: 143, b: 191};
pub const DARK_AZURE: Color = Color{r: 0, g: 95, b: 191};
pub const DARK_BLUE: Color = Color{r: 0, g: 0, b: 191};
pub const DARK_HAN: Color = Color{r: 47, g: 0, b: 191};
pub const DARK_VIOLET: Color = Color{r: 95, g: 0, b: 191};
pub const DARK_PURPLE: Color = Color{r: 143, g: 0, b: 191};
pub const DARK_FUCHSIA: Color = Color{r: 191, g: 0, b: 191};
pub const DARK_MAGENTA: Color = Color{r: 191, g: 0, b: 143};
pub const DARK_PINK: Color = Color{r: 191, g: 0, b: 95};
pub const DARK_CRIMSON: Color = Color{r: 191, g: 0, b: 47};
pub const DARKER_RED: Color = Color{r: 127, g: 0, b: 0};
pub const DARKER_FLAME: Color = Color{r: 127, g: 31, b: 0};
pub const DARKER_ORANGE: Color = Color{r: 127, g: 63, b: 0};
pub const DARKER_AMBER: Color = Color{r: 127, g: 95, b: 0};
pub const DARKER_YELLOW: Color = Color{r: 127, g: 127, b: 0};
pub const DARKER_LIME: Color = Color{r: 95, g: 127, b: 0};
pub const DARKER_CHARTREUSE: Color = Color{r: 63, g: 127, b: 0};
pub const DARKER_GREEN: Color = Color{r: 0, g: 127, b: 0};
pub const DARKER_SEA: Color = Color{r: 0, g: 127, b: 63};
pub const DARKER_TURQUOISE: Color = Color{r: 0, g: 127, b: 95};
pub const DARKER_CYAN: Color = Color{r: 0, g: 127, b: 127};
pub const DARKER_SKY: Color = Color{r: 0, g: 95, b: 127};
pub const DARKER_AZURE: Color = Color{r: 0, g: 63, b: 127};
pub const DARKER_BLUE: Color = Color{r: 0, g: 0, b: 127};
pub const DARKER_HAN: Color = Color{r: 31, g: 0, b: 127};
pub const DARKER_VIOLET: Color = Color{r: 63, g: 0, b: 127};
pub const DARKER_PURPLE: Color = Color{r: 95, g: 0, b: 127};
pub const DARKER_FUCHSIA: Color = Color{r: 127, g: 0, b: 127};
pub const DARKER_MAGENTA: Color = Color{r: 127, g: 0, b: 95};
pub const DARKER_PINK: Color = Color{r: 127, g: 0, b: 63};
pub const DARKER_CRIMSON: Color = Color{r: 127, g: 0, b: 31};
pub const DARKEST_RED: Color = Color{r: 63, g: 0, b: 0};
pub const DARKEST_FLAME: Color = Color{r: 63, g: 15, b: 0};
pub const DARKEST_ORANGE: Color = Color{r: 63, g: 31, b: 0};
pub const DARKEST_AMBER: Color = Color{r: 63, g: 47, b: 0};
pub const DARKEST_YELLOW: Color = Color{r: 63, g: 63, b: 0};
pub const DARKEST_LIME: Color = Color{r: 47, g: 63, b: 0};
pub const DARKEST_CHARTREUSE: Color = Color{r: 31, g: 63, b: 0};
pub const DARKEST_GREEN: Color = Color{r: 0, g: 63, b: 0};
pub const DARKEST_SEA: Color = Color{r: 0, g: 63, b: 31};
pub const DARKEST_TURQUOISE: Color = Color{r: 0, g: 63, b: 47};
pub const DARKEST_CYAN: Color = Color{r: 0, g: 63, b: 63};
pub const DARKEST_SKY: Color = Color{r: 0, g: 47, b: 63};
pub const DARKEST_AZURE: Color = Color{r: 0, g: 31, b: 63};
pub const DARKEST_BLUE: Color = Color{r: 0, g: 0, b: 63};
pub const DARKEST_HAN: Color = Color{r: 15, g: 0, b: 63};
pub const DARKEST_VIOLET: Color = Color{r: 31, g: 0, b: 63};
pub const DARKEST_PURPLE: Color = Color{r: 47, g: 0, b: 63};
pub const DARKEST_FUCHSIA: Color = Color{r: 63, g: 0, b: 63};
pub const DARKEST_MAGENTA: Color = Color{r: 63, g: 0, b: 47};
pub const DARKEST_PINK: Color = Color{r: 63, g: 0, b: 31};
pub const DARKEST_CRIMSON: Color = Color{r: 63, g: 0, b: 15};
pub const BRASS: Color = Color{r: 191, g: 151, b: 96};
pub const COPPER: Color = Color{r: 197, g: 136, b: 124};
pub const GOLD: Color = Color{r: 229, g: 191, b: 0};
pub const SILVER: Color = Color{r: 203, g: 203, b: 203};
pub const CELADON: Color = Color{r: 172, g: 255, b: 175};
pub const PEACH: Color = Color{r: 255, g: 159, b: 127};


#[cfg(all(feature = "serialization", test))]
mod test_serialization {
    use colors::Color;
    use serde_json;

    #[test]
    fn color_encode() {
        let encoded = serde_json::to_string(&Color{r: 1, g: 2, b: 3}).unwrap();
        assert_eq!("{\"r\":1,\"g\":2,\"b\":3}", encoded);
    }

    #[test]
    fn color_decode() {
        let decoded: Color = serde_json::from_str("{\"r\":1,\"g\":2,\"b\":3}").unwrap();
        assert_eq!(Color{r: 1, g: 2, b: 3}, decoded);
    }
}