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
//! Defines the `Pixel` trait as well as basic pixel formats, like RBG/RBGA. 

use core::hash::Hash;
use color::Color;
use zerocopy::FromBytes;

/// A pixel provides methods to blend with others.
pub trait Pixel: Copy + Hash + FromBytes {
    /// Composites the `src` pixel slice to the `dest` pixel slice.
    fn composite_buffer(src: &[Self], dest: &mut[Self]);
    
    /// blend with another pixel considering their extra channel.
    fn blend(self, other: Self) -> Self;

    /// Blend two pixels linearly with weights, as `blend` for `origin` and (1-`blend`) for `other`.
    fn weight_blend(origin: Self, other: Self, blend: f32) -> Self;
}


#[derive(Hash, Debug, Clone, Copy, FromBytes)]
/// An RGB Pixel is a pixel with no extra channel.
pub struct RGBPixel {
    pub blue: u8,
    pub green: u8,
    pub red: u8,
    _channel: u8,
}

#[derive(Hash, Debug, Clone, Copy, FromBytes)]
/// An Alpha Pixel is a pixel with an alpha channel
pub struct AlphaPixel {
    pub blue: u8,
    pub green: u8,
    pub red: u8,
    pub alpha: u8
}

impl Pixel for RGBPixel {
    #[inline]
    fn composite_buffer(src: &[Self], dest: &mut[Self]) {
        dest.copy_from_slice(src)
    }
    
    #[inline]
    fn blend(self, _other: Self) -> Self {
        self
    }

    fn weight_blend(origin: Self, other: Self, blend: f32) -> Self {
        let blend = if blend < 0f32 {
            0f32
        } else if blend > 1f32 {
            1f32
        } else {
            blend
        };

        let new_red =
            ((origin.red as f32) * blend + (other.red as f32) * (1f32 - blend)) as u8;
        let new_green =
            ((origin.green as f32) * blend + (other.green as f32) * (1f32 - blend)) as u8;
        let new_blue =
            ((origin.blue as f32) * blend + (other.blue as f32) * (1f32 - blend)) as u8;
        
        RGBPixel{
            _channel: 0,
            red: new_red,
            green: new_green,
            blue: new_blue
        }
    }
}

impl From<Color> for RGBPixel {
    fn from(color: Color) -> Self {
        RGBPixel {
            _channel: 0,
            red: color.red(),
            green: color.green(),
            blue: color.blue(),
        }
    }
}

impl Pixel for AlphaPixel {   
    fn composite_buffer(src: &[Self], dest: &mut[Self]) {
        for i in 0..src.len() {
            dest[i] = src[i].blend(dest[i]);
        }
    }

    fn blend(self, other: Self) -> Self {
        let alpha = self.alpha as u16;
        let red = self.red;
        let green = self.green;
        let blue = self.blue;
        // let ori_alpha = other.alpha;
        let ori_red = other.red;
        let ori_green = other.green;
        let ori_blue = other.blue;
        // let new_alpha = (((alpha as u16) * (255 - alpha) + (ori_alpha as u16) * alpha) / 255) as u8;
        let new_red = (((red as u16) * (255 - alpha) + (ori_red as u16) * alpha) / 255) as u8;
        let new_green = (((green as u16) * (255 - alpha) + (ori_green as u16) * alpha) / 255) as u8;
        let new_blue = (((blue as u16) * (255 - alpha) + (ori_blue as u16) * alpha) / 255) as u8;
        AlphaPixel {
            alpha: alpha as u8,
            red: new_red,
            green: new_green,
            blue: new_blue
        }
    }

    fn weight_blend(origin: Self, other: Self, blend: f32) -> Self {
        let blend = if blend < 0f32 {
            0f32
        } else if blend > 1f32 {
            1f32
        } else {
            blend
        };

        let new_channel =
            ((origin.alpha as f32) * blend + (other.alpha as f32) * (1f32 - blend)) as u8;
        let new_red =
            ((origin.red as f32) * blend + (other.red as f32) * (1f32 - blend)) as u8;
        let new_green =
            ((origin.green as f32) * blend + (other.green as f32) * (1f32 - blend)) as u8;
        let new_blue =
            ((origin.blue as f32) * blend + (other.blue as f32) * (1f32 - blend)) as u8;
        AlphaPixel {
            alpha: new_channel,
            red: new_red,
            green: new_green,
            blue: new_blue
        }
    }
}

impl From<Color> for AlphaPixel {
    fn from(color: Color) -> Self {
        AlphaPixel {
            alpha: color.transparency(),
            red: color.red(),
            green: color.green(),
            blue: color.blue(),
        }
    }
}