1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2009 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11<languageVersion : 1.0;>
12kernel Saturation
13<   namespace : "Flame";
14    vendor : "Adobe";
15    version : 1;
16    description : "Saturation blend mode";
17>
18{
19    input image4 dst;
20    input image4 src;
21    output pixel4 result;
22
23    // PB bytecode can't do functions, use macros to define common functions
24    // gets the max number out of the three
25    #define max3( x, y, z ) ( max((x), max((y), (z))) )
26    // gets the min number out of the three
27    #define min3( x, y, z ) ( min((x), min((y), (z))) )
28
29    // gets the max number out of the three elements in a vector
30    #define max3v(C) ( max3((C.x), (C.y), (C.z)) )
31    // gets the min number out of the three elements in a vector
32    #define min3v(C) ( min3((C.x), (C.y), (C.z)) )
33
34    // Sat - returns float, takes in a pixel3, or pixel4
35    #define saturation(C) ( (max3((C.r), (C.g), (C.b)) - min3((C.r), (C.g), (C.b))) )
36
37    // Luminance - returns float, takes in a pixel3, or pixel4
38    #define luminance(C) ( (((C.r) * 0.3) + ((C.g) * 0.59) + ((C.b) * 0.11)) )
39
40    void
41    evaluatePixel()
42    {
43        pixel4 a = sampleNearest(dst,outCoord()); // cb
44        pixel4 b = sampleNearest(src,outCoord()); // cs
45
46        // remove premultiplied (srcCP/srcA, dstCP/dstA)
47        pixel3 cb = a.rgb;
48        pixel3 cs = b.rgb;
49        if (a.a > 0.0) {
50            cb.rgb = a.rgb / a.a;
51        }
52        if (b.a > 0.0) {
53            cs.rgb = b.rgb / b.a;
54        }
55
56        // dstA' = (1-srcA)*dstA + srcA
57        result.a = (1.0-b.a)*a.a + b.a;
58
59        // record old version of cb
60        //float3 old_cb.rgb = cb.rgb;
61
62        // SetSat(cb, Sat(cs))
63
64        // setSat (setSatColor, sat) -> setSatResult
65        /* --------------------------------------------------------
66         * void setsaturation(inout float3 color, in float satVal)
67         *     makes color have the target saturation.
68         * input and output of float3 color
69         * input of the target saturation
70         *
71         * --------------------------------------------------------
72         void setsatcomponents(inout float minComp, inout float midComp, inout float maxComp, in float satVal)
73         {
74             midComp -= minComp;
75             maxComp -= minComp;
76             minComp = 0.0;
77             if (maxComp > 0.0) {
78                 // max(..., 0.0000001) prevents divide by 0
79                 midComp *= satVal/max(maxComp, 0.0000001);
80                 maxComp = satVal;
81             }
82         }
83         */
84
85        float3 color = cb.rgb;
86        float satVal = saturation(cs);
87
88        if (color.x <= color.y) {
89            if (color.y <= color.z) {
90                // x <= y <= z
91                // setsatcomponents(color.x, color.y, color.z, satVal);
92                // min, mid, max, val
93
94                color.y -= color.x;
95                color.z -= color.x;
96                color.x = 0.0;
97                if (color.z > 0.0) {
98                    // max(..., 0.0000001) prevents divide by 0
99                    color.y *= satVal/max(color.z, 0.0000001);
100                    color.z = satVal;
101                }
102
103            } else {
104                if (color.x <= color.z) {
105                    // x <= z <= y
106                    // setsatcomponents(color.x, color.z, color.y, satVal);
107                    // min, mid, max, value
108
109                    color.z -= color.x;
110                    color.y -= color.x;
111                    color.x = 0.0;
112                    if (color.y > 0.0) {
113                        // max(..., 0.0000001) prevents divide by 0
114                        color.z *= satVal/max(color.y, 0.0000001);
115                        color.y = satVal;
116                    }
117                } else {
118                    // z <= x <= y
119                    // setsatcomponents(color.z, color.x, color.y, satVal);
120                    // min, mid, max, val
121
122                    color.x -= color.z;
123                    color.y -= color.z;
124                    color.z = 0.0;
125                    if (color.y > 0.0) {
126                        // max(..., 0.0000001) prevents divide by 0
127                        color.x *= satVal/max(color.y, 0.0000001);
128                        color.y = satVal;
129                    }
130                }
131            }
132        } else {
133            if (color.x <= color.z) {
134                // y <= x <= z
135                // setsatcomponents(color.y, color.x, color.z, satVal);
136
137                color.x -= color.y;
138                color.z -= color.y;
139                color.y = 0.0;
140                if (color.z > 0.0) {
141                    // max(..., 0.0000001) prevents divide by 0
142                    color.x *= satVal/max(color.z, 0.0000001);
143                    color.z = satVal;
144                }
145            } else {
146                if (color.y <= color.z) {
147                    // y <= z <= x
148                    // setsatcomponents(color.y, color.z, color.x, satVal);
149                    // min, mid, max, val
150
151                    color.z -= color.y;
152                    color.x -= color.y;
153                    color.y = 0.0;
154                    if (color.x > 0.0) {
155                        // max(..., 0.0000001) prevents divide by 0
156                        color.z *= satVal/max(color.x, 0.0000001);
157                        color.x = satVal;
158                    }
159                } else {
160                    // z <= y <= x
161                    // setsatcomponents(color.z, color.y, color.x, satVal);
162                    // min, mid, max, val
163
164                    color.y -= color.z;
165                    color.x -= color.z;
166                    color.z = 0.0;
167                    if (color.x > 0.0) {
168                        // max(..., 0.0000001) prevents divide by 0
169                        color.y *= satVal/max(color.x, 0.0000001);
170                        color.x = satVal;
171                    }
172                }
173            }
174        }
175        // end setSaturation - result: color ---------------------- //
176
177        // adjustment
178        //color = color + lum_cb - luminance(color);
179        //dstColorOld - dstColor
180        float3 adjVec = cb.rgb - color.rgb;
181        float adjustment = luminance(adjVec);
182        float3 adjustedColor = color + adjustment;
183
184        // ClipRGB(adjustedColor) -> color_cl
185
186        /* --------------------------------------------------------
187         * void clipcolor(inout float3 color)
188         *     clips color.
189         * input and output float3 color_cl
190         *
191         * -------------------------------------------------------- */
192        float3 color_cl = adjustedColor;
193        float lum_cl = luminance(color_cl);
194        float3 lumVec = float3(lum_cl, lum_cl, lum_cl);
195        float mini = min3v(color_cl);
196        float maxi = max3v(color_cl);
197        if (mini < 0.0) {
198            mini = lum_cl - mini;
199            // max(..., 0.0000001) prevents divide by 0
200            color_cl = lumVec + (color_cl - lumVec)*lum_cl/max(mini, 0.0000001);
201        }
202        if (maxi > 1.0) {
203            maxi = maxi - lum_cl;
204            // max(..., 0.0000001) prevents divide by 0
205            color_cl = lumVec + (color_cl - lumVec)*(1.0 - lum_cl)/max(maxi, 0.0000001);
206        }
207        // end clipcolor - result: color_cl ---------------------- //
208
209
210        // dstCP' = (1-srcA)*dstCP + (1-dstA)*srcCP + srcA*dstA*Blend(srcCP/srcA, dstCP/dstA)
211        result .rgb = ((1.0-b.a)*a.rgb) + ((1.0-a.a)*b.rgb) + b.a*a.a*color_cl.rgb;
212    }
213}
214