1 | // [Blend2D] |
2 | // 2D Vector Graphics Powered by a JIT Compiler. |
3 | // |
4 | // [License] |
5 | // Zlib - See LICENSE.md file in the package. |
6 | |
7 | #include "./blapi-build_p.h" |
8 | #include "./blcompop_p.h" |
9 | |
10 | // ============================================================================ |
11 | // [BLCompOpInfo] |
12 | // ============================================================================ |
13 | |
14 | struct BLCompOpInfoGen { |
15 | #define F(VALUE) BL_COMP_OP_FLAG_##VALUE |
16 | |
17 | static constexpr BLCompOpInfo value(size_t op) noexcept { |
18 | return BLCompOpInfo { |
19 | op == BL_COMP_OP_SRC_OVER ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
20 | op == BL_COMP_OP_SRC_COPY ? F(TYPE_B) | 0 | 0 | F(SC) | F(SA) | 0 | 0 : |
21 | op == BL_COMP_OP_SRC_IN ? F(TYPE_B) | 0 | F(DA) | F(SC) | F(SA) | F(NOP_IF_DA_0) | 0 : |
22 | op == BL_COMP_OP_SRC_OUT ? F(TYPE_B) | 0 | F(DA) | F(SC) | F(SA) | 0 | 0 : |
23 | op == BL_COMP_OP_SRC_ATOP ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | F(NOP_IF_DA_0) | F(NOP_IF_SA_0) : |
24 | op == BL_COMP_OP_DST_OVER ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | F(NOP_IF_DA_1) | F(NOP_IF_SA_0) : |
25 | op == BL_COMP_OP_DST_COPY ? F(TYPE_C) | F(DC) | F(DA) | 0 | 0 | F(NOP) | F(NOP) : |
26 | op == BL_COMP_OP_DST_IN ? F(TYPE_B) | F(DC) | F(DA) | 0 | F(SA) | 0 | F(NOP_IF_SA_1) : |
27 | op == BL_COMP_OP_DST_OUT ? F(TYPE_A) | F(DC) | F(DA) | 0 | F(SA) | 0 | F(NOP_IF_SA_0) : |
28 | op == BL_COMP_OP_DST_ATOP ? F(TYPE_B) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | 0 : |
29 | op == BL_COMP_OP_XOR ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
30 | op == BL_COMP_OP_CLEAR ? F(TYPE_C) | 0 | 0 | 0 | 0 | F(NOP_IF_DA_0) | 0 : |
31 | |
32 | op == BL_COMP_OP_PLUS ? F(TYPE_C) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
33 | op == BL_COMP_OP_MINUS ? F(TYPE_C) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
34 | op == BL_COMP_OP_MULTIPLY ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | F(NOP_IF_DA_0) | F(NOP_IF_SA_0) : |
35 | op == BL_COMP_OP_SCREEN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
36 | op == BL_COMP_OP_OVERLAY ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
37 | op == BL_COMP_OP_DARKEN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
38 | op == BL_COMP_OP_LIGHTEN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
39 | op == BL_COMP_OP_COLOR_DODGE ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
40 | op == BL_COMP_OP_COLOR_BURN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
41 | op == BL_COMP_OP_LINEAR_BURN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
42 | op == BL_COMP_OP_LINEAR_LIGHT ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
43 | op == BL_COMP_OP_PIN_LIGHT ? F(TYPE_C) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
44 | op == BL_COMP_OP_HARD_LIGHT ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
45 | op == BL_COMP_OP_SOFT_LIGHT ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
46 | op == BL_COMP_OP_DIFFERENCE ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
47 | op == BL_COMP_OP_EXCLUSION ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) : |
48 | |
49 | op == BL_COMP_OP_INTERNAL_ALPHA_SET ? F(TYPE_C) | 0 | 0 | 0 | 0 | F(NOP_IF_SA_1) | 0 : |
50 | op == BL_COMP_OP_INTERNAL_ALPHA_INV ? F(TYPE_C) | 0 | 0 | 0 | 0 | 0 | 0 : 0 |
51 | }; |
52 | } |
53 | |
54 | #undef F |
55 | }; |
56 | |
57 | const BLLookupTable<BLCompOpInfo, BL_COMP_OP_INTERNAL_COUNT> blCompOpInfo = |
58 | blLookupTable<BLCompOpInfo, BL_COMP_OP_INTERNAL_COUNT, BLCompOpInfoGen>(); |
59 | |
60 | // ============================================================================ |
61 | // [BLCompOpSimplifyInfo] |
62 | // ============================================================================ |
63 | |
64 | struct BLCompOpSimplifyInfoGen { |
65 | // Simplify formats as we work with them here a lot. |
66 | enum Format : uint32_t { |
67 | NONE = BL_FORMAT_NONE, |
68 | A8 = BL_FORMAT_A8, |
69 | PRGB32 = BL_FORMAT_PRGB32, |
70 | ZERO32 = BL_FORMAT_ZERO32, |
71 | XRGB32 = BL_FORMAT_XRGB32, |
72 | FRGB32 = BL_FORMAT_FRGB32 |
73 | }; |
74 | |
75 | enum CompOp : uint32_t { |
76 | SrcOver = BL_COMP_OP_SRC_OVER, |
77 | SrcCopy = BL_COMP_OP_SRC_COPY, |
78 | SrcIn = BL_COMP_OP_SRC_IN, |
79 | SrcOut = BL_COMP_OP_SRC_OUT, |
80 | SrcAtop = BL_COMP_OP_SRC_ATOP, |
81 | DstOver = BL_COMP_OP_DST_OVER, |
82 | DstCopy = BL_COMP_OP_DST_COPY, |
83 | DstIn = BL_COMP_OP_DST_IN, |
84 | DstOut = BL_COMP_OP_DST_OUT, |
85 | DstAtop = BL_COMP_OP_DST_ATOP, |
86 | Xor = BL_COMP_OP_XOR, |
87 | Clear = BL_COMP_OP_CLEAR, |
88 | Plus = BL_COMP_OP_PLUS, |
89 | Minus = BL_COMP_OP_MINUS, |
90 | Multiply = BL_COMP_OP_MULTIPLY, |
91 | Screen = BL_COMP_OP_SCREEN, |
92 | Overlay = BL_COMP_OP_OVERLAY, |
93 | Darken = BL_COMP_OP_DARKEN, |
94 | Lighten = BL_COMP_OP_LIGHTEN, |
95 | ColorDodge = BL_COMP_OP_COLOR_DODGE, |
96 | ColorBurn = BL_COMP_OP_COLOR_BURN, |
97 | LinearBurn = BL_COMP_OP_LINEAR_BURN, |
98 | LinearLight = BL_COMP_OP_LINEAR_LIGHT, |
99 | PinLight = BL_COMP_OP_PIN_LIGHT, |
100 | HardLight = BL_COMP_OP_HARD_LIGHT, |
101 | SoftLight = BL_COMP_OP_SOFT_LIGHT, |
102 | Difference = BL_COMP_OP_DIFFERENCE, |
103 | Exclusion = BL_COMP_OP_EXCLUSION |
104 | }; |
105 | |
106 | // Legend: |
107 | // |
108 | // - Sca - Source color, premultiplied: `Sc * Sa`. |
109 | // - Sc - Source color. |
110 | // - Sa - Source alpha. |
111 | // |
112 | // - Dca - Destination color, premultiplied: `Dc * Da`. |
113 | // - Dc - Destination color. |
114 | // - Da - Destination alpha. |
115 | // |
116 | // - Dca' - Resulting color, premultiplied. |
117 | // - Da' - Resulting alpha. |
118 | // |
119 | // - m - Mask (if used). |
120 | // |
121 | // Blending function F(Sc, Dc) is used in the following way if destination |
122 | // or source contains alpha channel (otherwise it's assumed to be `1.0`): |
123 | // |
124 | // - Dca' = Func(Sc, Dc) * Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) |
125 | // - Da' = Da + Sa.(1 - Da) |
126 | |
127 | static constexpr BLCompOpSimplifyInfo makeOp(uint32_t compOp, uint32_t d, uint32_t s) noexcept { |
128 | return BLCompOpSimplifyInfo { uint8_t(compOp), uint8_t(BL_COMP_OP_SOLID_ID_NONE), uint8_t(d), uint8_t(s) }; |
129 | } |
130 | |
131 | static constexpr BLCompOpSimplifyInfo transparent(uint32_t compOp, uint32_t d, uint32_t s) noexcept { |
132 | return BLCompOpSimplifyInfo { uint8_t(compOp), uint8_t(BL_COMP_OP_SOLID_ID_TRANSPARENT), uint8_t(d), uint8_t(s) }; |
133 | } |
134 | |
135 | static constexpr BLCompOpSimplifyInfo opaqueBlack(uint32_t compOp, uint32_t d, uint32_t s) noexcept { |
136 | return BLCompOpSimplifyInfo { uint8_t(compOp), uint8_t(BL_COMP_OP_SOLID_ID_OPAQUE_BLACK), uint8_t(d), uint8_t(s) }; |
137 | } |
138 | |
139 | static constexpr BLCompOpSimplifyInfo opaqueWhite(uint32_t compOp, uint32_t d, uint32_t s) noexcept { |
140 | return BLCompOpSimplifyInfo { uint8_t(compOp), uint8_t(BL_COMP_OP_SOLID_ID_OPAQUE_WHITE), uint8_t(d), uint8_t(s) }; |
141 | } |
142 | |
143 | // Clear |
144 | // ----- |
145 | // |
146 | // [Clear PRGBxPRGB] |
147 | // Dca' = 0 Dca' = Dca.(1 - m) |
148 | // Da' = 0 Da' = Da .(1 - m) |
149 | // |
150 | // [Clear XRGBxPRGB] |
151 | // Dc' = 0 Dc' = Dca.(1 - m) |
152 | // |
153 | // [Clear PRGBxXRGB] ~= [Clear PRGBxPRGB] |
154 | // [Clear XRGBxXRGB] ~= [Clear XRGBxPRGB] |
155 | static constexpr BLCompOpSimplifyInfo clear(uint32_t d, uint32_t s) noexcept { |
156 | return d == PRGB32 ? transparent(SrcCopy, PRGB32, PRGB32) : |
157 | d == XRGB32 ? opaqueBlack(SrcCopy, PRGB32, PRGB32) : makeOp(Clear, d, s); |
158 | } |
159 | |
160 | // SrcCopy |
161 | // ------- |
162 | // |
163 | // [Src PRGBxPRGB] |
164 | // Dca' = Sca Dca' = Sca.m + Dca.(1 - m) |
165 | // Da' = Sa Da' = Sa .m + Da .(1 - m) |
166 | // |
167 | // [Src PRGBxXRGB] ~= [Src PRGBxPRGB] |
168 | // Dca' = Sc Dca' = Sc.m + Dca.(1 - m) |
169 | // Da' = 1 Da' = 1 .m + Da .(1 - m) |
170 | // |
171 | // [Src XRGBxPRGB] ~= [Src PRGBxPRGB] |
172 | // Dc' = Sca Dc' = Sca.m + Dc.(1 - m) |
173 | // |
174 | // [Src XRGBxXRGB] ~= [Src PRGBxPRGB] |
175 | // Dc' = Sc Dc' = Sc.m + Dc.(1 - m) |
176 | static constexpr BLCompOpSimplifyInfo srcCopy(uint32_t d, uint32_t s) noexcept { |
177 | return d == PRGB32 && s == ZERO32 ? makeOp(SrcCopy, PRGB32, PRGB32) : |
178 | d == PRGB32 && s == FRGB32 ? makeOp(SrcCopy, PRGB32, PRGB32) : |
179 | d == XRGB32 && s == PRGB32 ? makeOp(SrcCopy, PRGB32, PRGB32) : |
180 | d == XRGB32 && s == ZERO32 ? makeOp(SrcCopy, PRGB32, PRGB32) : |
181 | d == XRGB32 && s == XRGB32 ? makeOp(SrcCopy, PRGB32, PRGB32) : |
182 | d == XRGB32 && s == FRGB32 ? makeOp(SrcCopy, PRGB32, PRGB32) : makeOp(SrcCopy, d, s); |
183 | } |
184 | |
185 | // DstCopy |
186 | // ------- |
187 | // |
188 | // [DstCopy ANYxANY] |
189 | // Dca' = Dca |
190 | // Da = Da |
191 | static constexpr BLCompOpSimplifyInfo dstCopy(uint32_t d, uint32_t s) noexcept { |
192 | return transparent(DstCopy, d, s); |
193 | } |
194 | |
195 | // SrcOver |
196 | // ------- |
197 | // |
198 | // [SrcOver PRGBxPRGB] |
199 | // Dca' = Sca + Dca.(1 - Sa) Dca' = Sca.m + Dca.(1 - Sa.m) |
200 | // Da' = Sa + Da .(1 - Sa) Da' = Sa .m + Da .(1 - Sa.m) |
201 | // |
202 | // [SrcOver PRGBxXRGB] ~= [Src PRGBxPRGB] |
203 | // Dca' = Sc Dca' = Sc.m + Dca.(1 - m) |
204 | // Da' = 1 Da' = 1 .m + Da .(1 - m) |
205 | // |
206 | // [SrcOver XRGBxPRGB] ~= [SrcOver PRGBxPRGB] |
207 | // Dc' = Sca + Dc.(1 - Sa ) Dc' = Sca.m + Dc.(1 - Sa.m) |
208 | // |
209 | // [SrcOver XRGBxXRGB] ~= [Src PRGBxPRGB] |
210 | // Dc' = Sc Dc' = Sc.m + Dc.(1 - m) |
211 | static constexpr BLCompOpSimplifyInfo srcOver(uint32_t d, uint32_t s) noexcept { |
212 | return d == PRGB32 && s == ZERO32 ? dstCopy(PRGB32, PRGB32) : |
213 | d == PRGB32 && s == XRGB32 ? srcCopy(PRGB32, XRGB32) : |
214 | d == PRGB32 && s == FRGB32 ? srcCopy(PRGB32, FRGB32) : |
215 | d == XRGB32 && s == PRGB32 ? srcOver(PRGB32, PRGB32) : |
216 | d == XRGB32 && s == ZERO32 ? dstCopy(PRGB32, PRGB32) : |
217 | d == XRGB32 && s == XRGB32 ? srcCopy(PRGB32, XRGB32) : |
218 | d == XRGB32 && s == FRGB32 ? makeOp(SrcOver, PRGB32, FRGB32) : makeOp(SrcOver, d, s); |
219 | } |
220 | |
221 | // DstOver |
222 | // ------- |
223 | // |
224 | // [DstOver PRGBxPRGB] |
225 | // Dca' = Dca + Sca.(1 - Da) Dca' = Dca + Sca.m.(1 - Da) |
226 | // Da' = Da + Sa .(1 - Da) Da' = Da + Sa .m.(1 - Da) |
227 | // |
228 | // [DstOver PRGBxXRGB] ~= [DstOver PRGBxPRGB] |
229 | // Dca' = Dca + Sc.(1 - Da) Dca' = Dca + Sc.m.(1 - Da) |
230 | // Da' = Da + 1 .(1 - Da) Da' = Da + 1 .m.(1 - Da) |
231 | // |
232 | // [DstOver XRGBxPRGB] ~= [Dst] |
233 | // Dc' = Dc |
234 | // |
235 | // [DstOver XRGBxXRGB] ~= [Dst] |
236 | // Dc' = Dc |
237 | static constexpr BLCompOpSimplifyInfo dstOver(uint32_t d, uint32_t s) noexcept { |
238 | return d == PRGB32 && s == ZERO32 ? dstCopy(PRGB32, PRGB32) : |
239 | d == PRGB32 && s == FRGB32 ? dstOver(PRGB32, PRGB32) : |
240 | d == XRGB32 ? dstCopy(d, s) : makeOp(DstOver, d, s); |
241 | } |
242 | |
243 | // SrcIn |
244 | // ----- |
245 | // |
246 | // [SrcIn PRGBxPRGB] |
247 | // Dca' = Sca.Da Dca' = Sca.Da.m + Dca.(1 - m) |
248 | // Da' = Sa .Da Da' = Sa .Da.m + Da .(1 - m) |
249 | // |
250 | // [SrcIn PRGBxXRGB] ~= [SrcIn PRGBxPRGB] |
251 | // Dca' = Sc.Da Dca' = Sc.Da.m + Dca.(1 - m) |
252 | // Da' = 1 .Da Da' = 1 .Da.m + Da .(1 - m) |
253 | // |
254 | // [SrcIn XRGBxPRGB] |
255 | // Dc' = Sca Dc' = Sca.m + Dc.(1 - m) |
256 | // |
257 | // [SrcIn XRGBxXRGB] ~= [SrcCopy XRGBxXRGB] |
258 | // Dc' = Sc Dc' = Sc.m + Dc.(1 - m) |
259 | static constexpr BLCompOpSimplifyInfo srcIn(uint32_t d, uint32_t s) noexcept { |
260 | return d == PRGB32 && s == ZERO32 ? srcIn(PRGB32, PRGB32) : |
261 | d == PRGB32 && s == FRGB32 ? srcIn(PRGB32, PRGB32) : |
262 | d == XRGB32 ? srcCopy(d, s) : makeOp(SrcIn, d, s); |
263 | } |
264 | |
265 | // DstIn |
266 | // ----- |
267 | // |
268 | // [DstIn PRGBxPRGB] |
269 | // Dca' = Dca.Sa Dca' = Dca.Sa.m + Dca.(1 - m) |
270 | // Da' = Da .Sa Da' = Da .Sa.m + Da .(1 - m) |
271 | // |
272 | // [DstIn PRGBxXRGB] ~= [Dst] |
273 | // Dca' = Dca |
274 | // Da' = Da |
275 | // |
276 | // [DstIn XRGBxPRGB] |
277 | // Dc' = Dc.Sa Dc' = Dc.Sa.m + Dc.(1 - m) |
278 | // |
279 | // [DstIn XRGBxXRGB] ~= [Dst] |
280 | // Dc' = Dc |
281 | static constexpr BLCompOpSimplifyInfo dstIn(uint32_t d, uint32_t s) noexcept { |
282 | return d == PRGB32 && s == ZERO32 ? srcCopy(d, s) : |
283 | d == PRGB32 && s == XRGB32 ? dstCopy(d, s) : |
284 | d == PRGB32 && s == FRGB32 ? dstCopy(d, s) : |
285 | d == XRGB32 && s == PRGB32 ? dstIn(PRGB32, PRGB32) : |
286 | d == XRGB32 && s == ZERO32 ? dstIn(PRGB32, FRGB32) : |
287 | d == XRGB32 && s == FRGB32 ? dstCopy(d, s) : |
288 | d == XRGB32 && s == XRGB32 ? dstCopy(d, s) : makeOp(DstIn, d, s); |
289 | } |
290 | |
291 | // SrcOut |
292 | // ------ |
293 | // |
294 | // [SrcOut PRGBxPRGB] |
295 | // Dca' = Sca.(1 - Da) Dca' = Sca.m.(1 - Da) + Dca.(1 - m) |
296 | // Da' = Sa .(1 - Da) Da' = Sa .m.(1 - Da) + Da .(1 - m) |
297 | // |
298 | // [SrcOut PRGBxXRGB] ~= [SrcOut PRGBxPRGB] |
299 | // Dca' = Sc.(1 - Da) Dca' = Sc.m.(1 - Da) + Dca.(1 - m) |
300 | // Da' = 1 .(1 - Da) Da' = 1 .m.(1 - Da) + Da .(1 - m) |
301 | // |
302 | // [SrcOut XRGBxPRGB] ~= [Clear XRGBxPRGB] |
303 | // Dc' = 0 Dc' = Dc.(1 - m) |
304 | // |
305 | // [SrcOut XRGBxXRGB] ~= [Clear XRGBxPRGB] |
306 | // Dc' = 0 Dc' = Dc.(1 - m) |
307 | static constexpr BLCompOpSimplifyInfo srcOut(uint32_t d, uint32_t s) noexcept { |
308 | return d == PRGB32 && s == ZERO32 ? clear(d, s) : |
309 | d == PRGB32 && s == FRGB32 ? srcOut(PRGB32, PRGB32) : |
310 | d == XRGB32 ? clear(d, s) : makeOp(SrcOut, d, s); |
311 | } |
312 | |
313 | // DstOut |
314 | // ------ |
315 | // |
316 | // [DstOut PRGBxPRGB] |
317 | // Dca' = Dca.(1 - Sa) Dca' = Dca.(1 - Sa.m) |
318 | // Da' = Da .(1 - Sa) Da' = Da .(1 - Sa.m) |
319 | // |
320 | // [DstOut PRGBxXRGB] ~= [Clear PRGBxPRGB] |
321 | // Dca' = 0 |
322 | // Da' = 0 |
323 | // |
324 | // [DstOut XRGBxPRGB] |
325 | // Dc' = Dc.(1 - Sa) Dc' = Dc.(1 - Sa.m) |
326 | // |
327 | // [DstOut XRGBxXRGB] ~= [Clear XRGBxPRGB] |
328 | // Dc' = 0 |
329 | static constexpr BLCompOpSimplifyInfo dstOut(uint32_t d, uint32_t s) noexcept { |
330 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
331 | d == PRGB32 && s == FRGB32 ? clear(d, s) : |
332 | d == PRGB32 && s == XRGB32 ? clear(d, s) : |
333 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
334 | d == XRGB32 && s == FRGB32 ? clear(d, s) : |
335 | d == XRGB32 && s == XRGB32 ? clear(d, s) : makeOp(DstOut, d, s); |
336 | } |
337 | |
338 | // SrcAtop |
339 | // ------- |
340 | // |
341 | // [SrcAtop PRGBxPRGB] |
342 | // Dca' = Sca.Da + Dca.(1 - Sa) Dca' = Sca.Da.m + Dca.(1 - Sa.m) |
343 | // Da' = Sa .Da + Da .(1 - Sa) = Da Da' = Sa .Da.m + Da .(1 - Sa.m) = Da |
344 | // |
345 | // [SrcAtop PRGBxXRGB] ~= [SrcIn PRGBxPRGB] |
346 | // Dca' = Sc.Da Dca' = Sc.Da.m + Dca.(1 - m) |
347 | // Da' = 1 .Da Da' = 1 .Da.m + Da .(1 - m) |
348 | // |
349 | // [SrcAtop XRGBxPRGB] ~= [SrcOver PRGBxPRGB] |
350 | // Dc' = Sca + Dc.(1 - Sa) Dc' = Sca.m + Dc.(1 - Sa.m) |
351 | // |
352 | // [SrcAtop XRGBxXRGB] ~= [Src PRGBxPRGB] |
353 | // Dc' = Sc Dc' = Sc.m + Dc.(1 - m) |
354 | static constexpr BLCompOpSimplifyInfo srcAtop(uint32_t d, uint32_t s) noexcept { |
355 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
356 | d == PRGB32 && s == FRGB32 ? srcIn(d, s) : |
357 | d == PRGB32 && s == XRGB32 ? srcIn(d, s) : |
358 | d == XRGB32 && s == PRGB32 ? srcOver(d, s) : |
359 | d == XRGB32 && s == ZERO32 ? srcOver(d, s) : |
360 | d == XRGB32 && s == FRGB32 ? srcCopy(d, s) : |
361 | d == XRGB32 && s == XRGB32 ? srcCopy(d, s) : makeOp(SrcAtop, d, s); |
362 | } |
363 | |
364 | // DstAtop |
365 | // ------- |
366 | // |
367 | // [DstAtop PRGBxPRGB] |
368 | // Dca' = Dca.Sa + Sca.(1 - Da) Dca' = Dca.(1 - m.(1 - Sa)) + Sca.m.(1 - Da) |
369 | // Da' = Da .Sa + Sa .(1 - Da) = Sa Da' = Da .(1 - m.(1 - Sa)) + Sa .m.(1 - Da) |
370 | // |
371 | // [DstAtop PRGBxXRGB] ~= [DstOver PRGBxPRGB] |
372 | // Dca' = Dca + Sc.(1 - Da) Dca' = Dca + Sc.m.(1 - Da) |
373 | // Da' = Da + 1 .(1 - Da) = 1 Da' = Da + 1 .m.(1 - Da) |
374 | // |
375 | // [DstAtop XRGBxPRGB] ~= [DstIn XRGBxPRGB] |
376 | // Dc' = Dc.Sa Dc' = Dc.(1 - m.(1 - Sa)) = Dc.(1 - m) + Dc.Sa.m |
377 | // |
378 | // [DstAtop XRGBxXRGB] ~= [Dst] |
379 | // Dc' = Dc |
380 | static constexpr BLCompOpSimplifyInfo dstAtop(uint32_t d, uint32_t s) noexcept { |
381 | return d == PRGB32 && s == ZERO32 ? clear(d, s) : |
382 | d == PRGB32 && s == FRGB32 ? dstOver(d, s) : |
383 | d == PRGB32 && s == XRGB32 ? dstOver(d, s) : |
384 | d == XRGB32 && s == PRGB32 ? dstIn(d, s) : |
385 | d == XRGB32 && s == ZERO32 ? clear(d, s) : |
386 | d == XRGB32 && s == FRGB32 ? dstCopy(d, s) : |
387 | d == XRGB32 && s == XRGB32 ? dstCopy(d, s) : makeOp(DstAtop, d, s); |
388 | } |
389 | |
390 | // Xor |
391 | // --- |
392 | // |
393 | // [Xor PRGBxPRGB] |
394 | // Dca' = Dca.(1 - Sa) + Sca.(1 - Da) Dca' = Dca.(1 - Sa.m) + Sca.m.(1 - Da) |
395 | // Da' = Da .(1 - Sa) + Sa .(1 - Da) Da' = Da .(1 - Sa.m) + Sa .m.(1 - Da) |
396 | // |
397 | // [Xor PRGBxXRGB] ~= [SrcOut PRGBxPRGB] |
398 | // Dca' = Sca.(1 - Da) Dca' = Sca.m.(1 - Da) + Dca.(1 - m) |
399 | // Da' = 1 .(1 - Da) Da' = 1 .m.(1 - Da) + Da .(1 - m) |
400 | // |
401 | // [Xor XRGBxPRGB] ~= [DstOut XRGBxPRGB] |
402 | // Dc' = Dc.(1 - Sa) Dc' = Dc.(1 - Sa.m) |
403 | // |
404 | // [Xor XRGBxXRGB] ~= [Clear XRGBxPRGB] |
405 | // Dc' = 0 Dc' = Dc.(1 - m) |
406 | static constexpr BLCompOpSimplifyInfo xor_(uint32_t d, uint32_t s) noexcept { |
407 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
408 | d == PRGB32 && s == FRGB32 ? srcOut(d, s) : |
409 | d == PRGB32 && s == XRGB32 ? srcOut(d, s) : |
410 | d == XRGB32 && s == PRGB32 ? dstOut(d, s) : |
411 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
412 | d == XRGB32 && s == FRGB32 ? clear(d, s) : |
413 | d == XRGB32 && s == XRGB32 ? clear(d, s) : makeOp(Xor, d, s); |
414 | } |
415 | |
416 | // Plus |
417 | // ---- |
418 | // |
419 | // [Plus PRGBxPRGB] |
420 | // Dca' = Clamp(Dca + Sca) Dca' = Clamp(Dca + Sca.m) |
421 | // Da' = Clamp(Da + Sa ) Da' = Clamp(Da + Sa .m) |
422 | // |
423 | // [Plus PRGBxXRGB] ~= [Plus PRGBxPRGB] |
424 | // Dca' = Clamp(Dca + Sc) Dca' = Clamp(Dca + Sc.m) |
425 | // Da' = Clamp(Da + 1 ) Da' = Clamp(Da + 1 .m) |
426 | // |
427 | // [Plus XRGBxPRGB] ~= [Plus PRGBxPRGB] |
428 | // Dc' = Clamp(Dc + Sca) Dc' = Clamp(Dc + Sca.m) |
429 | // |
430 | // [Plus XRGBxXRGB] ~= [Plus PRGBxPRGB] |
431 | // Dc' = Clamp(Dc + Sc) Dc' = Clamp(Dc + Sc.m) |
432 | static constexpr BLCompOpSimplifyInfo plus(uint32_t d, uint32_t s) noexcept { |
433 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
434 | d == PRGB32 && s == FRGB32 ? plus(PRGB32, PRGB32) : |
435 | d == XRGB32 && s == PRGB32 ? plus(PRGB32, PRGB32) : |
436 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
437 | d == XRGB32 && s == FRGB32 ? plus(PRGB32, PRGB32) : |
438 | d == XRGB32 && s == XRGB32 ? plus(PRGB32, PRGB32) : makeOp(Plus, d, s); |
439 | } |
440 | |
441 | // Minus |
442 | // ----- |
443 | // |
444 | // [Minus PRGBxPRGB] |
445 | // Dca' = Clamp(Dca - Sca) Dca' = Clamp(Dca - Sca).m + Dca.(1 - m) |
446 | // Da' = Da + Sa.(1 - Da) Da' = Da + Sa.m(1 - Da) |
447 | // |
448 | // [Minus PRGBxXRGB] ~= [Minus PRGBxPRGB] |
449 | // Dca' = Clamp(Dca - Sc) Dca' = Clamp(Dca - Sc).m + Dca.(1 - m) |
450 | // Da' = Da + 1.(1 - Da) = 1 Da' = Da + 1.m(1 - Da) |
451 | // |
452 | // [Minus XRGBxPRGB] |
453 | // Dc' = Clamp(Dc - Sca) Dc' = Clamp(Dc - Sca).m + Dc.(1 - m) |
454 | // |
455 | // [Minus XRGBxXRGB] ~= [Minus XRGBxPRGB] |
456 | // Dc' = Clamp(Dc - Sc) Dc' = Clamp(Dc - Sc).m + Dc.(1 - m) |
457 | // |
458 | // NOTE: |
459 | // `Clamp(a - b)` == `Max(a - b, 0)` == `1 - Min(1 - a + b, 1)` |
460 | static constexpr BLCompOpSimplifyInfo minus(uint32_t d, uint32_t s) noexcept { |
461 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
462 | d == PRGB32 && s == FRGB32 ? minus(PRGB32, PRGB32) : |
463 | d == XRGB32 && s == PRGB32 ? minus(PRGB32, PRGB32) : |
464 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
465 | d == XRGB32 && s == FRGB32 ? minus(PRGB32, PRGB32) : |
466 | d == XRGB32 && s == XRGB32 ? minus(PRGB32, PRGB32) : makeOp(Minus, d, s); |
467 | } |
468 | |
469 | // Multiply |
470 | // -------- |
471 | // |
472 | // [Multiply PRGBxPRGB] |
473 | // Dca' = Dca.(Sca + 1 - Sa) + Sca.(1 - Da) |
474 | // Da' = Da .(Sa + 1 - Sa) + Sa .(1 - Da) = Da + Sa.(1 - Da) |
475 | // |
476 | // Dca' = Dca.(Sca.m + 1 - Sa.m) + Sca.m(1 - Da) |
477 | // Da' = Da .(Sa .m + 1 - Sa.m) + Sa .m(1 - Da) = Da + Sa.m(1 - Da) |
478 | // |
479 | // [Multiply PRGBxXRGB] |
480 | // Dca' = Sc.(Dca + 1 - Da) |
481 | // Da' = 1 .(Da + 1 - Da) = 1 |
482 | // |
483 | // Dca' = Dca.(Sc.m + 1 - 1.m) + Sc.m(1 - Da) |
484 | // Da' = Da .(1 .m + 1 - 1.m) + 1 .m(1 - Da) = Da + Sa.m(1 - Da) |
485 | // |
486 | // [Multiply XRGBxPRGB] |
487 | // Dc' = Dc.(Sca + 1 - Sa ) |
488 | // Dc' = Dc.(Sca.m + 1 - Sa.m) |
489 | // |
490 | // [Multiply XRGBxXRGB] |
491 | // Dc' = Dc.(Sc + 1 - 1 ) |
492 | // Dc' = Dc.(Sc.m + 1 - 1.m) |
493 | static constexpr BLCompOpSimplifyInfo multiply(uint32_t d, uint32_t s) noexcept { |
494 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
495 | d == PRGB32 && s == FRGB32 ? minus(PRGB32, XRGB32) : |
496 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
497 | d == XRGB32 && s == FRGB32 ? minus(XRGB32, XRGB32) : makeOp(Multiply, d, s); |
498 | } |
499 | |
500 | // Screen |
501 | // ------ |
502 | // |
503 | // [Screen PRGBxPRGB] |
504 | // Dca' = Dca + Sca.(1 - Dca) |
505 | // Da' = Da + Sa .(1 - Da ) |
506 | // |
507 | // Dca' = Dca + Sca.m.(1 - Dca) |
508 | // Da' = Da + Sa .m.(1 - Da ) |
509 | // |
510 | // [Screen PRGBxXRGB] ~= [Screen PRGBxPRGB] |
511 | // Dca' = Dca + Sc.(1 - Dca) |
512 | // Da' = Da + 1 .(1 - Da ) |
513 | // |
514 | // Dca' = Dca + Sc.m.(1 - Dca) |
515 | // Da' = Da + 1 .m.(1 - Da ) |
516 | // |
517 | // [Screen XRGBxPRGB] ~= [Screen PRGBxPRGB] |
518 | // Dc' = Dc + Sca .(1 - Dca) |
519 | // Dc' = Dc + Sca.m.(1 - Dca) |
520 | // |
521 | // [Screen PRGBxPRGB] ~= [Screen PRGBxPRGB] |
522 | // Dc' = Dc + Sc .(1 - Dc) |
523 | // Dc' = Dc + Sc.m.(1 - Dc) |
524 | static constexpr BLCompOpSimplifyInfo screen(uint32_t d, uint32_t s) noexcept { |
525 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
526 | d == PRGB32 && s == FRGB32 ? screen(PRGB32, PRGB32) : |
527 | d == XRGB32 && s == PRGB32 ? screen(PRGB32, PRGB32) : |
528 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
529 | d == XRGB32 && s == FRGB32 ? screen(PRGB32, PRGB32) : |
530 | d == XRGB32 && s == XRGB32 ? screen(PRGB32, XRGB32) : makeOp(Screen, d, s); |
531 | } |
532 | |
533 | // Overlay |
534 | // ------- |
535 | // |
536 | // [Overlay PRGBxPRGB] |
537 | // if (2.Dca < Da) |
538 | // Dca' = Dca + Sca - (Dca.Sa + Sca.Da - 2.Sca.Dca) |
539 | // Da' = Da + Sa - Sa.Da |
540 | // else |
541 | // Dca' = Dca + Sca + (Dca.Sa + Sca.Da - 2.Sca.Dca) - Sa.Da |
542 | // Da' = Da + Sa - Sa.Da |
543 | // |
544 | // [Overlay PRGBxXRGB] |
545 | // if (2.Dca - Da < 0) |
546 | // Dca' = Sc.(2.Dca - Da + 1) |
547 | // Da' = 1 |
548 | // else |
549 | // Dca' = 2.Dca - Da - Sc.(1 - (2.Dca - Da)) |
550 | // Da' = 1 |
551 | // |
552 | // [Overlay XRGBxPRGB] |
553 | // if (2.Dca < Da) |
554 | // Dc' = Dc - (Dc.Sa - 2.Sca.Dc) |
555 | // else |
556 | // Dc' = Dc + 2.Sca - Sa + (Dca.Sa - 2.Sca.Dc) |
557 | // |
558 | // [Overlay XRGBxXRGB] |
559 | // if (2.Dc - 1 < 0) |
560 | // Dc' = 2.Dc.Sc |
561 | // else |
562 | // Dc' = 2.(Dc + Sc) - 2.Sc.Dc - 1 |
563 | static constexpr BLCompOpSimplifyInfo overlay(uint32_t d, uint32_t s) noexcept { |
564 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
565 | d == PRGB32 && s == FRGB32 ? overlay(PRGB32, XRGB32) : |
566 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
567 | d == XRGB32 && s == FRGB32 ? overlay(XRGB32, XRGB32) : makeOp(Screen, d, s); |
568 | } |
569 | |
570 | // Darken |
571 | // ------ |
572 | // |
573 | // [Darken PRGBxPRGB] |
574 | // Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) |
575 | // Da' = min(Sa .Da, Da .Sa) + Sa .(1 - Da) + Da .(1 - Sa) |
576 | // = Sa + Da - Sa.Da |
577 | // |
578 | // Dca' = min(Sca.m.Da, Dca.Sa.m) + Sca.m.(1 - Da) + Dca.(1 - Sa.m) |
579 | // Da' = min(Sa .m.Da, Da .Sa.m) + Sa .m.(1 - Da) + Da .(1 - Sa.m) |
580 | // = Sa.m + Da - Sa.m.Da |
581 | // |
582 | // [Darken PRGBxXRGB] |
583 | // Dca' = min(Sc.Da, Dca) + Sc.(1 - Da) |
584 | // Da' = min(1 .Da, Da ) + 1 .(1 - Da) |
585 | // = Sa + Da - Sa.Da |
586 | // |
587 | // Dca' = min(Sc.m.Da, Dca.m) + Sc.m.(1 - Da) + Dca.(1 - 1.m) |
588 | // Da' = min(1 .m.Da, Da .m) + 1 .m.(1 - Da) + Da .(1 - 1.m) |
589 | // = 1.m + Da - 1.m.Da |
590 | // |
591 | // [Darken XRGBxPRGB] |
592 | // Dc' = min(Sca , Dc.Sa ) + Dc.(1 - Sa ) |
593 | // Dc' = min(Sca.m, Dc.Sa.m) + Dc.(1 - Sa.m) |
594 | // |
595 | // [Darken XRGBxXRGB] |
596 | // Dc' = min(Sc, Dc) |
597 | // Dc' = min(Sc, Dc).m + Dc.(1 - m) |
598 | static constexpr BLCompOpSimplifyInfo darken(uint32_t d, uint32_t s) noexcept { |
599 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
600 | d == PRGB32 && s == FRGB32 ? darken(PRGB32, XRGB32) : |
601 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
602 | d == XRGB32 && s == FRGB32 ? darken(XRGB32, XRGB32) : makeOp(Darken, d, s); |
603 | } |
604 | |
605 | // Lighten |
606 | // ------- |
607 | // |
608 | // [Lighten PRGBxPRGB] |
609 | // Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) |
610 | // Da' = max(Sa .Da, Da .Sa) + Sa .(1 - Da) + Da .(1 - Sa) |
611 | // = Sa + Da - Sa.Da |
612 | // |
613 | // Dca' = max(Sca.m.Da, Dca.Sa.m) + Sca.m.(1 - Da) + Dca.(1 - Sa.m) |
614 | // Da' = max(Sa .m.Da, Da .Sa.m) + Sa .m.(1 - Da) + Da .(1 - Sa.m) |
615 | // = Sa.m + Da - Sa.m.Da |
616 | // |
617 | // [Lighten PRGBxXRGB] |
618 | // Dca' = max(Sc.Da, Dca) + Sc.(1 - Da) |
619 | // Da' = max(1 .Da, Da ) + 1 .(1 - Da) |
620 | // = Sa + Da - Sa.Da |
621 | // |
622 | // Dca' = max(Sc.m.Da, Dca.m) + Sc.m.(1 - Da) + Dca.(1 - 1.m) |
623 | // Da' = max(1 .m.Da, Da .m) + 1 .m.(1 - Da) + Da .(1 - 1.m) |
624 | // = 1.m + Da - 1.m.Da |
625 | // |
626 | // [Lighten XRGBxPRGB] |
627 | // Dc' = max(Sca , Dc.Sa ) + Dc.(1 - Sa ) |
628 | // Dc' = max(Sca.m, Dc.Sa.m) + Dc.(1 - Sa.m) |
629 | // |
630 | // [Lighten XRGBxXRGB] |
631 | // Dc' = max(Sc, Dc) |
632 | // Dc' = max(Sc, Dc).m + Dc.(1 - m) |
633 | static constexpr BLCompOpSimplifyInfo lighten(uint32_t d, uint32_t s) noexcept { |
634 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
635 | d == PRGB32 && s == FRGB32 ? lighten(PRGB32, XRGB32) : |
636 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
637 | d == XRGB32 && s == FRGB32 ? lighten(XRGB32, XRGB32) : makeOp(Lighten, d, s); |
638 | } |
639 | |
640 | // ColorDodge |
641 | // ---------- |
642 | // |
643 | // [ColorDodge PRGBxPRGB] |
644 | // Dca' = min(Dca.Sa.Sa / max(Sa - Sca, 0.001), Da.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) |
645 | // Da' = Sa + Da - Sa.Da |
646 | // |
647 | // Dca' = min(Dca.Sa.m.Sa.m / max(Sa.m - Sca.m, 0.001), Da.Sa.m) + Sca.m.(1 - Da) + Dca.(1 - Sa.m) |
648 | // Da' = Sa.m + Da - Sa.m.Da |
649 | // |
650 | // [ColorDodge PRGBxXRGB] |
651 | // Dca' = min(Dca / max(1 - Sc, 0.001), Da) + Sc.(1 - Da) |
652 | // Da' = 1 |
653 | // |
654 | // Dca' = min(Dca.1.m.1.m / max(1.m - Sc.m, 0.001), Da.1.m) + Sc.m.(1 - Da) + Dca.(1 - 1.m) |
655 | // Da' = 1.m + Da - 1.m.Da |
656 | // |
657 | // [ColorDodge XRGBxPRGB] |
658 | // Dc' = min(Dc.Sa .Sa / max(Sa - Sca , 0.001), Sa) + Dc.(1 - Sa) |
659 | // Dc' = min(Dc.Sa.m.Sa.m / max(Sa.m - Sca.m, 0.001), Sa.m) + Dc.(1 - Sa.m) |
660 | // |
661 | // [ColorDodge XRGBxXRGB] |
662 | // Dc' = min(Dc / max(1 - Sc, 0.001), 1) |
663 | // Dc' = min(Dc / max(1 - Sc, 0.001), 1).m + Dc.(1 - m) |
664 | static constexpr BLCompOpSimplifyInfo colorDodge(uint32_t d, uint32_t s) noexcept { |
665 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
666 | d == PRGB32 && s == FRGB32 ? colorDodge(PRGB32, PRGB32) : |
667 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
668 | d == XRGB32 && s == FRGB32 ? colorDodge(XRGB32, XRGB32) : makeOp(ColorDodge, d, s); |
669 | } |
670 | |
671 | // ColorBurn |
672 | // --------- |
673 | // |
674 | // [ColorBurn PRGBxPRGB] |
675 | // Dca' = Sa.Da - min(Sa.Da, (Da - Dca).Sa.Sa / max(Sca, 0.001)) + Sca.(1 - Da) + Dca.(1 - Sa) |
676 | // Da' = Sa + Da - Sa.Da |
677 | // |
678 | // Dca' = Sa.m.Da - min(Sa.m.Da, (Da - Dca).Sa.m.Sa.m / max(Sca.m, 0.001)) + Sca.m.(1 - Da) + Dca.(1 - Sa.m) |
679 | // Da' = Sa.m + Da - Sa.m.Da |
680 | // |
681 | // [ColorBurn PRGBxXRGB] |
682 | // Dca' = 1.Da - min(Da, (Da - Dca) / max(Sc, 0.001)) + Sc.(1 - Da) |
683 | // Da' = 1 |
684 | // |
685 | // Dca' = m.Da - min(1.m.Da, (Da - Dca).1.m.1.m / max(Sc.m, 0.001)) + Sc.m.(1 - Da) + Dca.(1 - 1.m) |
686 | // Da' = 1.m + Da - 1.m.Da |
687 | // |
688 | // [ColorBurn XRGBxPRGB] |
689 | // Dc' = Sa - min(Sa , (1 - Dc).Sa .Sa / max(Sca , 0.001)) + Dc.(1 - Sa) |
690 | // Dc' = Sa.m - min(Sa.m, (1 - Dc).Sa.m.Sa.m / max(Sca.m, 0.001)) + Dc.(1 - Sa.m) |
691 | // |
692 | // [ColorBurn XRGBxXRGB] |
693 | // Dc' = (1 - min(1, (1 - Dc) / max(Sc, 0.001))) |
694 | // Dc' = (1 - min(1, (1 - Dc) / max(Sc, 0.001))).m + Dc.(1 - m) |
695 | static constexpr BLCompOpSimplifyInfo colorBurn(uint32_t d, uint32_t s) noexcept { |
696 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
697 | d == PRGB32 && s == FRGB32 ? colorBurn(PRGB32, XRGB32) : |
698 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
699 | d == XRGB32 && s == FRGB32 ? colorBurn(XRGB32, XRGB32) : makeOp(ColorBurn, d, s); |
700 | } |
701 | |
702 | // LinearBurn |
703 | // ---------- |
704 | // |
705 | // [LinearBurn PRGBxPRGB] |
706 | // Dca' = Clamp(Dca + Sca - Sa.Da) |
707 | // Da' = Da + Sa - Sa.Da |
708 | // |
709 | // Dca' = Clamp(Dca + Sca - Sa.Da).m + Dca.(1 - m) |
710 | // Da' = Sa.m.(1 - Da) + Da |
711 | // |
712 | // [LinearBurn PRGBxXRGB] |
713 | // Dca' = Clamp(Dca + Sc - Da) |
714 | // Da' = 1 |
715 | // |
716 | // Dca' = Clamp(Dca + Sc - Da).m + Dca.(1 - m) |
717 | // Da' = Da + Sa - Sa.Da |
718 | // |
719 | // [LinearBurn XRGBxPRGB] |
720 | // Dc' = Clamp(Dc + Sca - Sa) |
721 | // Dc' = Clamp(Dc + Sca - Sa).m + Dc.(1 - m) |
722 | // |
723 | // [LinearBurn XRGBxXRGB] |
724 | // Dc' = Clamp(Dc + Sc - 1) |
725 | // Dc' = Clamp(Dc + Sc - 1).m + Dc.(1 - m) |
726 | static constexpr BLCompOpSimplifyInfo linearBurn(uint32_t d, uint32_t s) noexcept { |
727 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
728 | d == PRGB32 && s == FRGB32 ? linearBurn(PRGB32, XRGB32) : |
729 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
730 | d == XRGB32 && s == FRGB32 ? linearBurn(XRGB32, XRGB32) : makeOp(LinearBurn, d, s); |
731 | } |
732 | |
733 | // LinearLight |
734 | // ----------- |
735 | // |
736 | // [LinearLight PRGBxPRGB] |
737 | // Dca' = min(max((Dca.Sa + 2.Sca.Da - Sa.Da), 0), Sa.Da) + Sca.(1 - Da) + Dca.(1 - Sa) |
738 | // Da' = Da + Sa - Sa.Da |
739 | // |
740 | // Dca' = min(max((Dca.Sa.m + 2.Sca.m.Da - Sa.m.Da), 0), Sa.m.Da) + Sca.m.(1 - Da) + Dca.(1 - Sa.m) |
741 | // Da' = Da + Sa.m - Sa.m.Da |
742 | // |
743 | // [LinearLight PRGBxXRGB] |
744 | // Dca' = min(max((Dca + 2.Sc.Da - Da), 0), Da) + Sc.(1 - Da) |
745 | // Da' = 1 |
746 | // |
747 | // Dca' = min(max((Dca.1.m + 2.Sc.m.Da - 1.m.Da), 0), 1.m.Da) + Sc.m.(1 - Da) + Dca.(1 - m) |
748 | // Da' = Da + Sa.m - Sa.m.Da |
749 | // |
750 | // [LinearLight XRGBxPRGB] |
751 | // Dca' = min(max((Dc.Sa + 2.Sca - Sa ), 0), Sa ) + Dca.(1 - Sa) |
752 | // Dca' = min(max((Dc.Sa.m + 2.Sca.m - Sa.m), 0), Sa.m) + Dca.(1 - Sa.m) |
753 | // |
754 | // [LinearLight XRGBxXRGB] |
755 | // Dc' = min(max((Dc + 2.Sc - 1), 0), 1) |
756 | // Dc' = min(max((Dc + 2.Sc - 1), 0), 1).m + Dca.(1 - m) |
757 | static constexpr BLCompOpSimplifyInfo linearLight(uint32_t d, uint32_t s) noexcept { |
758 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
759 | d == PRGB32 && s == FRGB32 ? linearLight(PRGB32, XRGB32) : |
760 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
761 | d == XRGB32 && s == FRGB32 ? linearLight(XRGB32, XRGB32) : makeOp(LinearLight, d, s); |
762 | } |
763 | |
764 | // PinLight |
765 | // -------- |
766 | // |
767 | // [PinLight PRGBxPRGB] |
768 | // if 2.Sca <= Sa |
769 | // Dca' = min(Dca.Sa, 2.Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) |
770 | // Da' = Da + Sa.(1 - Da) |
771 | // else |
772 | // Dca' = max(Dca.Sa, 2.Sca.Da - Sa.Da) + Sca.(1 - Da) + Dca.(1 - Sa) |
773 | // Da' = Da + Sa.(1 - Da) |
774 | // |
775 | // if 2.Sca.m <= Sa.m |
776 | // Dca' = min(Dca.Sa.m, 2.Sca.m.Da) + Sca.m.(1 - Da) + Dca.(1 - Sa.m) |
777 | // Da' = Da + Sa.m.(1 - Da) |
778 | // else |
779 | // Dca' = max(Dca.Sa.m, 2.Sca.m.Da - Sa.m.Da) + Sca.m.(1 - Da) + Dca.(1 - Sa.m) |
780 | // Da' = Da + Sa.m.(1 - Da) |
781 | // |
782 | // [PinLight PRGBxXRGB] |
783 | // if 2.Sc <= 1 |
784 | // Dca' = min(Dca, 2.Sc.Da) + Sc.(1 - Da) |
785 | // Da' = 1 |
786 | // else |
787 | // Dca' = max(Dca, 2.Sc.Da - Da) + Sc.(1 - Da) |
788 | // Da' = 1 |
789 | // |
790 | // if 2.Sc.m <= 1.m |
791 | // Dca' = min(Dca.m, 2.Sc.m.Da) + Sc.m.(1 - Da) + Dca.(1 - m) |
792 | // Da' = Da + m.(1 - Da) |
793 | // else |
794 | // Dca' = max(Dca.m, 2.Sc.m.Da - m.Da) + Sc.m.(1 - Da) + Dc.(1 - m) |
795 | // Da' = Da + m.(1 - Da) |
796 | // |
797 | // [PinLight XRGBxPRGB] |
798 | // if 2.Sca <= Sa |
799 | // Dc' = min(Dc.Sa, 2.Sca) + Dc.(1 - Sa) |
800 | // else |
801 | // Dc' = max(Dc.Sa, 2.Sca - Sa) + Dc.(1 - Sa) |
802 | // |
803 | // if 2.Sca.m <= Sa.m |
804 | // Dc' = min(Dc.Sa.m, 2.Sca.m) + Dc.(1 - Sa.m) |
805 | // else |
806 | // Dc' = max(Dc.Sa.m, 2.Sca.m - Sa.m) + Dc.(1 - Sa.m) |
807 | // |
808 | // [PinLight XRGBxXRGB] |
809 | // if 2.Sc <= 1 |
810 | // Dc' = min(Dc, 2.Sc) |
811 | // else |
812 | // Dc' = max(Dc, 2.Sc - 1) |
813 | // |
814 | // if 2.Sca.m <= Sa.m |
815 | // Dc' = min(Dc, 2.Sc).m + Dca.(1 - m) |
816 | // else |
817 | // Dc' = max(Dc, 2.Sc - 1).m + Dca.(1 - m) |
818 | static constexpr BLCompOpSimplifyInfo pinLight(uint32_t d, uint32_t s) noexcept { |
819 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
820 | d == PRGB32 && s == FRGB32 ? pinLight(PRGB32, XRGB32) : |
821 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
822 | d == XRGB32 && s == FRGB32 ? pinLight(XRGB32, XRGB32) : makeOp(PinLight, d, s); |
823 | } |
824 | |
825 | // HardLight |
826 | // --------- |
827 | // |
828 | // [HardLight PRGBxPRGB] |
829 | // if (2.Sca <= Sa) |
830 | // Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) |
831 | // Da' = Sa + Da - Sa.Da |
832 | // else |
833 | // Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) |
834 | // Da' = Sa + Da - Sa.Da |
835 | // |
836 | // if (2.Sca.m <= Sa.m) |
837 | // Dca' = 2.Sca.m.Dca + Sca.m(1 - Da) + Dca.(1 - Sa.m) |
838 | // Da' = Sa.m + Da - Sa.m.Da |
839 | // else |
840 | // Dca' = Sa.m.Da - 2.(Da - Dca).(Sa.m - Sca.m) + Sca.m.(1 - Da) + Dca.(1 - Sa.m) |
841 | // Da' = Sa.m + Da - Sa.m.Da |
842 | // |
843 | // [HardLight PRGBxXRGB] |
844 | // if (2.Sc <= 1) |
845 | // Dca' = 2.Sc.Dca + Sc.(1 - Da) |
846 | // Da' = 1 |
847 | // else |
848 | // Dca' = Da - 2.(Da - Dca).(1 - Sc) + Sc.(1 - Da) |
849 | // Da' = 1 |
850 | // |
851 | // if (2.Sc.m <= m) |
852 | // Dca' = 2.Sc.m.Dca + Sc.m(1 - Da) + Dca.(1 - m) |
853 | // Da' = Da + m.(1 - Da) |
854 | // else |
855 | // Dca' = 1.m.Da - 2.(Da - Dca).((1 - Sc).m) + Sc.m.(1 - Da) + Dca.(1 - m) |
856 | // Da' = Da + m.(1 - Da) |
857 | // |
858 | // [HardLight XRGBxPRGB] |
859 | // if (2.Sca <= Sa) |
860 | // Dc' = 2.Sca.Dc + Dc.(1 - Sa) |
861 | // else |
862 | // Dc' = Sa - 2.(1 - Dc).(Sa - Sca) + Dc.(1 - Sa) |
863 | // |
864 | // if (2.Sca.m <= Sa.m) |
865 | // Dc' = 2.Sca.m.Dc + Dc.(1 - Sa.m) |
866 | // else |
867 | // Dc' = Sa.m - 2.(1 - Dc).(Sa.m - Sca.m) + Dc.(1 - Sa.m) |
868 | // |
869 | // [HardLight XRGBxXRGB] |
870 | // if (2.Sc <= 1) |
871 | // Dc' = 2.Sc.Dc |
872 | // else |
873 | // Dc' = 1 - 2.(1 - Dc).(1 - Sc) |
874 | // |
875 | // if (2.Sc.m <= 1.m) |
876 | // Dc' = 2.Sc.Dc.m + Dc.(1 - m) |
877 | // else |
878 | // Dc' = (1 - 2.(1 - Dc).(1 - Sc)).m - Dc.(1 - m) |
879 | static constexpr BLCompOpSimplifyInfo hardLight(uint32_t d, uint32_t s) noexcept { |
880 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
881 | d == PRGB32 && s == FRGB32 ? hardLight(PRGB32, XRGB32) : |
882 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
883 | d == XRGB32 && s == FRGB32 ? hardLight(XRGB32, XRGB32) : makeOp(HardLight, d, s); |
884 | } |
885 | |
886 | // SoftLight |
887 | // --------- |
888 | // |
889 | // [SoftLight PRGBxPRGB] |
890 | // Dc = Dca/Da |
891 | // if 2.Sca - Sa <= 0 |
892 | // Dca' = Dca + Sca.(1 - Da) + (2.Sca - Sa).Da.[[ Dc.(1 - Dc) ]] |
893 | // Da' = Da + Sa - Sa.Da |
894 | // else if 2.Sca - Sa > 0 and 4.Dc <= 1 |
895 | // Dca' = Dca + Sca.(1 - Da) + (2.Sca - Sa).Da.[[ 4.Dc.(4.Dc.Dc + Dc - 4.Dc + 1) - Dc]] |
896 | // Da' = Da + Sa - Sa.Da |
897 | // else |
898 | // Dca' = Dca + Sca.(1 - Da) + (2.Sca - Sa).Da.[[ sqrt(Dc) - Dc ]] |
899 | // Da' = Da + Sa - Sa.Da |
900 | // |
901 | // [SoftLight XRGBxXRGB] |
902 | // if 2.Sc <= 1 |
903 | // Dc' = Dc + (2.Sc - 1).[[ Dc.(1 - Dc) ]] |
904 | // else if 2.Sc > 1 and 4.Dc <= 1 |
905 | // Dc' = Dc + (2.Sc - 1).[[ 4.Dc.(4.Dc.Dc + Dc - 4.Dc + 1) - Dc]] |
906 | // else |
907 | // Dc' = Dc + (2.Sc - 1).[[ sqrt(Dc) - Dc ]] |
908 | static constexpr BLCompOpSimplifyInfo softLight(uint32_t d, uint32_t s) noexcept { |
909 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
910 | d == PRGB32 && s == FRGB32 ? softLight(PRGB32, XRGB32) : |
911 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
912 | d == XRGB32 && s == FRGB32 ? softLight(XRGB32, XRGB32) : makeOp(SoftLight, d, s); |
913 | } |
914 | |
915 | // Difference |
916 | // ---------- |
917 | // |
918 | // [Difference PRGBxPRGB] |
919 | // Dca' = Dca + Sca - 2.min(Sca.Da, Dca.Sa) |
920 | // Da' = Sa + Da - Sa.Da |
921 | // |
922 | // Dca' = Dca + Sca.m - 2.min(Sca.m.Da, Dca.Sa.m) |
923 | // Da' = Sa.m + Da - Sa.m.Da |
924 | // |
925 | // [Difference PRGBxXRGB] |
926 | // Dca' = Dca + Sc - 2.min(Sc.Da, Dca) |
927 | // Da' = 1 |
928 | // |
929 | // Dca' = Dca + Sc.m - 2.min(Sc.m.Da, Dca) |
930 | // Da' = Da + 1.m - m.Da |
931 | // |
932 | // [Difference XRGBxPRGB] |
933 | // Dc' = Dc + Sca - 2.min(Sca , Dc.Sa) |
934 | // Dc' = Dc + Sca.m - 2.min(Sca.m, Dc.Sa.m) |
935 | // |
936 | // [Difference XRGBxXRGB] |
937 | // Dc' = Dc + Sc - 2.min(Sc , Dc ) |
938 | // Dc' = Dc + Sc.m - 2.min(Sc.m, Dc.m) |
939 | static constexpr BLCompOpSimplifyInfo difference(uint32_t d, uint32_t s) noexcept { |
940 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
941 | d == PRGB32 && s == FRGB32 ? difference(PRGB32, PRGB32) : |
942 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
943 | d == XRGB32 && s == FRGB32 ? difference(XRGB32, PRGB32) : makeOp(Difference, d, s); |
944 | } |
945 | |
946 | // Exclusion |
947 | // --------- |
948 | // |
949 | // [Exclusion PRGBxPRGB] |
950 | // Dca' = Dca + Sca.(Da - 2.Dca) |
951 | // Da' = Da + Sa - Sa.Da |
952 | // |
953 | // Dca' = Dca + Sca.m.(Da - 2.Dca) |
954 | // Da' = Da + Sa.m - Sa.m.Da |
955 | // |
956 | // [Exclusion PRGBxXRGB] ~= [Exclusion PRGBxPRGB] |
957 | // Dca' = Dca + Sc.(Da - 2.Dca) |
958 | // Da' = Da + 1 - 1.Da |
959 | // |
960 | // Dca' = Dca + Sc.m.(Da - 2.Dca) |
961 | // Da' = Da + 1.m - 1.m.Da |
962 | // |
963 | // [Exclusion XRGBxPRGB] |
964 | // Dc' = Dc + Sca .(1 - 2.Dc) |
965 | // Dc' = Dc + Sca.m.(1 - 2.Dc) |
966 | // |
967 | // [Exclusion XRGBxXRGB] ~= [Exclusion XRGBxPRGB] |
968 | // Dc' = Dc + Sc .(1 - 2.Dc) |
969 | // Dc' = Dc + Sc.m.(1 - 2.Dc) |
970 | static constexpr BLCompOpSimplifyInfo exclusion(uint32_t d, uint32_t s) noexcept { |
971 | return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) : |
972 | d == PRGB32 && s == FRGB32 ? exclusion(PRGB32, PRGB32) : |
973 | d == XRGB32 && s == ZERO32 ? dstCopy(d, s) : |
974 | d == XRGB32 && s == FRGB32 ? exclusion(XRGB32, PRGB32) : makeOp(Exclusion, d, s); |
975 | } |
976 | |
977 | // HACK: MSVC has a problem with code that does multiple ternary operations (? :) |
978 | // so we had to split it so Blend2D can compile. So please don't be active |
979 | // here and don't try to join these functions otherwise you break MSVC builds. |
980 | static constexpr BLCompOpSimplifyInfo valueDecomposed_1(uint32_t compOp, uint32_t d, uint32_t s) noexcept { |
981 | return compOp == BL_COMP_OP_SRC_COPY ? srcCopy(d, s) : |
982 | compOp == BL_COMP_OP_SRC_OVER ? srcOver(d, s) : |
983 | compOp == BL_COMP_OP_SRC_IN ? srcIn(d, s) : |
984 | compOp == BL_COMP_OP_SRC_OUT ? srcOut(d, s) : |
985 | compOp == BL_COMP_OP_SRC_ATOP ? srcAtop(d, s) : |
986 | compOp == BL_COMP_OP_DST_COPY ? dstCopy(d, s) : |
987 | compOp == BL_COMP_OP_DST_OVER ? dstOver(d, s) : |
988 | compOp == BL_COMP_OP_DST_IN ? dstIn(d, s) : |
989 | compOp == BL_COMP_OP_DST_OUT ? dstOut(d, s) : |
990 | compOp == BL_COMP_OP_DST_ATOP ? dstAtop(d, s) : dstCopy(d, s); |
991 | } |
992 | |
993 | static constexpr BLCompOpSimplifyInfo valueDecomposed_2(uint32_t compOp, uint32_t d, uint32_t s) noexcept { |
994 | return compOp == BL_COMP_OP_XOR ? xor_(d, s) : |
995 | compOp == BL_COMP_OP_CLEAR ? clear(d, s) : |
996 | compOp == BL_COMP_OP_CLEAR ? clear(d, s) : |
997 | compOp == BL_COMP_OP_PLUS ? plus(d, s) : |
998 | compOp == BL_COMP_OP_MINUS ? minus(d, s) : |
999 | compOp == BL_COMP_OP_MULTIPLY ? multiply(d, s) : |
1000 | compOp == BL_COMP_OP_SCREEN ? screen(d, s) : |
1001 | compOp == BL_COMP_OP_OVERLAY ? overlay(d, s) : |
1002 | compOp == BL_COMP_OP_DARKEN ? darken(d, s) : |
1003 | compOp == BL_COMP_OP_LIGHTEN ? lighten(d, s) : valueDecomposed_1(compOp, d, s); |
1004 | } |
1005 | |
1006 | // Just dispatches to the respective composition operator. |
1007 | static constexpr BLCompOpSimplifyInfo valueDecomposed_3(uint32_t compOp, uint32_t d, uint32_t s) noexcept { |
1008 | return compOp == BL_COMP_OP_COLOR_DODGE ? colorDodge(d, s) : |
1009 | compOp == BL_COMP_OP_COLOR_BURN ? colorBurn(d, s) : |
1010 | compOp == BL_COMP_OP_LINEAR_BURN ? linearBurn(d, s) : |
1011 | compOp == BL_COMP_OP_LINEAR_LIGHT ? linearLight(d, s) : |
1012 | compOp == BL_COMP_OP_PIN_LIGHT ? pinLight(d, s) : |
1013 | compOp == BL_COMP_OP_HARD_LIGHT ? hardLight(d, s) : |
1014 | compOp == BL_COMP_OP_SOFT_LIGHT ? softLight(d, s) : |
1015 | compOp == BL_COMP_OP_DIFFERENCE ? difference(d, s) : |
1016 | compOp == BL_COMP_OP_EXCLUSION ? exclusion(d, s) : valueDecomposed_2(compOp, d, s); |
1017 | } |
1018 | |
1019 | // Function called by the table generator, decompose and continue... |
1020 | static constexpr BLCompOpSimplifyInfo value(size_t index) noexcept { |
1021 | return valueDecomposed_3(uint32_t((index / BL_FORMAT_RESERVED_COUNT) % BL_COMP_OP_INTERNAL_COUNT), |
1022 | uint32_t(index / (BL_COMP_OP_INTERNAL_COUNT * BL_FORMAT_RESERVED_COUNT)), |
1023 | uint32_t(index % BL_FORMAT_RESERVED_COUNT)); |
1024 | } |
1025 | }; |
1026 | |
1027 | template<uint32_t DstFormat> |
1028 | struct BLSimplifyInfoRecordSetGen { |
1029 | // Function called by the table generator, decompose and continue... |
1030 | static constexpr BLCompOpSimplifyInfo value(size_t index) noexcept { |
1031 | return BLCompOpSimplifyInfoGen::valueDecomposed_3(uint32_t(index / BL_FORMAT_RESERVED_COUNT), DstFormat, uint32_t(index % BL_FORMAT_RESERVED_COUNT)); |
1032 | } |
1033 | }; |
1034 | |
1035 | // HACK: MSVC doesn't honor constexpr functions and sometimes outputs initialization |
1036 | // code even when the expression can be calculated at compile time. To fix this |
1037 | // we go throught an additional constexpr to force the compiler to always generate |
1038 | // our lookup tables at compile time. |
1039 | // |
1040 | // Additionally, if there is a mistake leading to recursion the compiler would catch it |
1041 | // at compile-time instead of hitting it at runtime during initialization. |
1042 | static_assert(BL_FORMAT_COUNT == 4, "Don't forget to add new formats to blCompOpSimplifyInfoTable" ); |
1043 | static constexpr const BLCompOpSimplifyInfoTable blCompOpSimplifyInfoTable_ = {{ |
1044 | blLookupTable<BLCompOpSimplifyInfo, BL_COMP_OP_SIMPLIFY_RECORD_SIZE, BLSimplifyInfoRecordSetGen<0>>(), |
1045 | blLookupTable<BLCompOpSimplifyInfo, BL_COMP_OP_SIMPLIFY_RECORD_SIZE, BLSimplifyInfoRecordSetGen<1>>(), |
1046 | blLookupTable<BLCompOpSimplifyInfo, BL_COMP_OP_SIMPLIFY_RECORD_SIZE, BLSimplifyInfoRecordSetGen<2>>(), |
1047 | blLookupTable<BLCompOpSimplifyInfo, BL_COMP_OP_SIMPLIFY_RECORD_SIZE, BLSimplifyInfoRecordSetGen<3>>() |
1048 | }}; |
1049 | const BLCompOpSimplifyInfoTable blCompOpSimplifyInfoTable = blCompOpSimplifyInfoTable_; |
1050 | |