1/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6// Helper functions.
7float hardlight(float dest, float src) {
8  if (src <= 0.5) {
9    return dest * (2.0 * src);
10  } else {
11    // Note: we substitute (2*src-1) into the screen formula below.
12    return 2.0 * dest + 2.0 * src - 1.0 - 2.0 * dest * src;
13  }
14}
15
16float dodge(float dest, float src) {
17  if (dest == 0.0) {
18    return 0.0;
19  } else if (src == 1.0) {
20    return 1.0;
21  } else {
22    return min(1.0, dest / (1.0 - src));
23  }
24}
25
26float burn(float dest, float src) {
27  if (dest == 1.0) {
28    return 1.0;
29  } else if (src == 0.0) {
30    return 0.0;
31  } else {
32    return 1.0 - min(1.0, (1.0 - dest) / src);
33  }
34}
35
36float darken(float dest) {
37  if (dest <= 0.25) {
38    return ((16.0 * dest - 12.0) * dest + 4.0) * dest;
39  } else {
40    return sqrt(dest);
41  }
42}
43
44float softlight(float dest, float src) {
45  if (src <= 0.5) {
46    return dest - (1.0 - 2.0 * src) * dest * (1.0 - dest);
47  } else {
48    return dest + (2.0 * src - 1.0) * (darken(dest) - dest);
49  }
50}
51
52float Lum(float3 c) {
53  return dot(float3(0.3, 0.59, 0.11), c);
54}
55
56float3 ClipColor(float3 c) {
57  float L = Lum(c);
58  float n = min(min(c.r, c.g), c.b);
59  float x = max(max(c.r, c.g), c.b);
60  if (n < 0.0) {
61    c = L + (((c - L) * L) / (L - n));
62  }
63  if (x > 1.0) {
64    c = L + (((c - L) * (1.0 - L)) / (x - L));
65  }
66  return c;
67}
68
69float3 SetLum(float3 c, float L) {
70  float d = L - Lum(c);
71  return ClipColor(float3(
72    c.r + d,
73    c.g + d,
74    c.b + d));
75}
76
77float Sat(float3 c) {
78  return max(max(c.r, c.g), c.b) - min(min(c.r, c.g), c.b);
79}
80
81// To use this helper, re-arrange rgb such that r=min, g=mid, and b=max.
82float3 SetSatInner(float3 c, float s) {
83  if (c.b > c.r) {
84    c.g = (((c.g - c.r) * s) / (c.b - c.r));
85    c.b = s;
86  } else {
87    c.gb = float2(0.0, 0.0);
88  }
89  return float3(0.0, c.g, c.b);
90}
91
92float3 SetSat(float3 c, float s) {
93  if (c.r <= c.g) {
94    if (c.g <= c.b) {
95      c.rgb = SetSatInner(c.rgb, s);
96    } else if (c.r <= c.b) {
97      c.rbg = SetSatInner(c.rbg, s);
98    } else {
99      c.brg = SetSatInner(c.brg, s);
100    }
101  } else if (c.r <= c.b) {
102    c.grb = SetSatInner(c.grb, s);
103  } else if (c.g <= c.b) {
104    c.gbr = SetSatInner(c.gbr, s);
105  } else {
106    c.bgr = SetSatInner(c.bgr, s);
107  }
108  return c;
109}
110
111float3 BlendMultiply(float3 dest, float3 src) {
112  return dest * src;
113}
114
115float3 BlendScreen(float3 dest, float3 src) {
116  return dest + src - (dest * src);
117}
118
119float3 BlendOverlay(float3 dest, float3 src) {
120  return float3(
121    hardlight(src.r, dest.r),
122    hardlight(src.g, dest.g),
123    hardlight(src.b, dest.b));
124}
125
126float3 BlendDarken(float3 dest, float3 src) {
127  return min(dest, src);
128}
129
130float3 BlendLighten(float3 dest, float3 src) {
131  return max(dest, src);
132}
133
134float3 BlendColorDodge(float3 dest, float3 src) {
135  return float3(
136    dodge(dest.r, src.r),
137    dodge(dest.g, src.g),
138    dodge(dest.b, src.b));
139}
140
141float3 BlendColorBurn(float3 dest, float3 src) {
142  return float3(
143    burn(dest.r, src.r),
144    burn(dest.g, src.g),
145    burn(dest.b, src.b));
146}
147
148float3 BlendHardLight(float3 dest, float3 src) {
149  return float3(
150    hardlight(dest.r, src.r),
151    hardlight(dest.g, src.g),
152    hardlight(dest.b, src.b));
153}
154
155float3 BlendSoftLight(float3 dest, float3 src) {
156  return float3(
157    softlight(dest.r, src.r),
158    softlight(dest.g, src.g),
159    softlight(dest.b, src.b));
160}
161
162float3 BlendDifference(float3 dest, float3 src) {
163  return abs(dest - src);
164}
165
166float3 BlendExclusion(float3 dest, float3 src) {
167  return dest + src - 2.0 * dest * src;
168}
169
170float3 BlendHue(float3 dest, float3 src) {
171  return SetLum(SetSat(src, Sat(dest)), Lum(dest));
172}
173
174float3 BlendSaturation(float3 dest, float3 src) {
175  return SetLum(SetSat(dest, Sat(src)), Lum(dest));
176}
177
178float3 BlendColor(float3 dest, float3 src) {
179  return SetLum(src, Lum(dest));
180}
181
182float3 BlendLuminosity(float3 dest, float3 src) {
183  return SetLum(dest, Lum(src));
184}
185