xref: /haiku/src/add-ons/translators/wonderbrush/support/blending.h (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 /*
2  * Copyright 2006, Haiku. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 #ifndef BLENDING_H
10 #define BLENDING_H
11 
12 #include <SupportDefs.h>
13 
14 // faster bit error version:
15 //#define INT_MULT(a, b, t)			((t) = (a) * (b), ((((t) >> 8) + (t)) >> 8))
16 // correct version
17 #define INT_MULT(a, b, t)			((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
18 
19 #define INT_LERP(p, q, a, t)		((p) + INT_MULT(a, ((q) - (p)), t))
20 
21 #define INT_PRELERP(p, q, a, t)		((p) + (q) - INT_MULT(a, p, t))
22 
23 
24 
25 #define GAMMA_BLEND 1
26 
27 #if GAMMA_BLEND
28 
29 extern uint16* kGammaTable;
30 extern uint8* kInverseGammaTable;
31 
32 void init_gamma_blending();
33 void uninit_gamma_blending();
34 
35 // blend
36 inline void
37 blend_gamma(uint16 b1, uint16 b2, uint16 b3, uint8 ba,	// bottom components
38 			uint16 t1, uint16 t2, uint16 t3, uint8 ta,	// top components
39 			uint8* d1, uint8* d2, uint8* d3, uint8* da)	// dest components
40 {
41 	if (ba == 255) {
42 		uint32 destAlpha = 255 - ta;
43 		*d1 = kInverseGammaTable[(b1 * destAlpha + t1 * ta) / 255];
44 		*d2 = kInverseGammaTable[(b2 * destAlpha + t2 * ta) / 255];
45 		*d3 = kInverseGammaTable[(b3 * destAlpha + t3 * ta) / 255];
46 		*da = 255;
47 	} else {
48 		uint8 alphaRest = 255 - ta;
49 		uint32 alphaTemp = (65025 - alphaRest * (255 - ba));
50 		uint32 alphaDest = ba * alphaRest;
51 		uint32 alphaSrc = 255 * ta;
52 		*d1 = kInverseGammaTable[(b1 * alphaDest + t1 * alphaSrc) / alphaTemp];
53 		*d2 = kInverseGammaTable[(b2 * alphaDest + t2 * alphaSrc) / alphaTemp];
54 		*d3 = kInverseGammaTable[(b3 * alphaDest + t3 * alphaSrc) / alphaTemp];
55 		*da = alphaTemp / 255;
56 	}
57 }
58 
59 // blend
60 inline void
61 blend(uint8 b1, uint8 b2, uint8 b3, uint8 ba,		// bottom components
62 	  uint8 t1, uint8 t2, uint8 t3, uint8 ta,		// top components
63 	  uint8* d1, uint8* d2, uint8* d3, uint8* da)	// dest components
64 {
65 	// convert to linear rgb
66 	uint16 gt1 = kGammaTable[t1];
67 	uint16 gt2 = kGammaTable[t2];
68 	uint16 gt3 = kGammaTable[t3];
69 
70 	uint16 gb1 = kGammaTable[b1];
71 	uint16 gb2 = kGammaTable[b2];
72 	uint16 gb3 = kGammaTable[b3];
73 
74 	blend_gamma(gb1, gb2, gb3, ba,
75 				gt1, gt2, gt3, ta,
76 				d1, d2, d3, da);
77 }
78 
79 // convert_to_gamma
80 //
81 // converted value will be gamma corrected in the range [0...2550]
82 // and can be passed on to the other functions that take uint16 components
83 uint16
84 convert_to_gamma(uint8 value);
85 
86 // blend_colors_copy
87 inline void
88 blend_colors_copy(uint8* bottom, uint8 alpha, uint8* dest,
89 				  uint8 c1, uint8 c2, uint8 c3,
90 				  uint16 gc1, uint16 gc2, uint16 gc3)
91 {
92 	if (alpha > 0) {
93 		if (bottom[3] == 0 || alpha == 255) {
94 			dest[0] = c1;
95 			dest[1] = c2;
96 			dest[2] = c3;
97 			dest[3] = alpha;
98 		} else {
99 			// only bottom components need to be gamma corrected
100 			uint16 gb1 = kGammaTable[bottom[0]];
101 			uint16 gb2 = kGammaTable[bottom[1]];
102 			uint16 gb3 = kGammaTable[bottom[2]];
103 
104 			blend_gamma(gb1, gb2, gb3, bottom[3],
105 						gc1, gc2, gc3, alpha,
106 						&dest[0], &dest[1], &dest[2], &dest[3]);
107 		}
108 	} else {
109 		*((uint32*)dest) = *((uint32*)bottom);
110 	}
111 }
112 
113 // blend_colors
114 inline void
115 blend_colors(uint8* bottom, uint8 alpha,
116 			 uint8 c1, uint8 c2, uint8 c3,
117 			 uint16 gc1, uint16 gc2, uint16 gc3)
118 {
119 	if (alpha > 0) {
120 		if (bottom[3] == 0 || alpha == 255) {
121 			bottom[0] = c1;
122 			bottom[1] = c2;
123 			bottom[2] = c3;
124 			bottom[3] = alpha;
125 		} else {
126 			// only bottom components need to be gamma corrected
127 			uint16 gb1 = kGammaTable[bottom[0]];
128 			uint16 gb2 = kGammaTable[bottom[1]];
129 			uint16 gb3 = kGammaTable[bottom[2]];
130 
131 			blend_gamma(gb1, gb2, gb3, bottom[3],
132 						gc1, gc2, gc3, alpha,
133 						&bottom[0], &bottom[1], &bottom[2], &bottom[3]);
134 		}
135 	}
136 }
137 
138 // blend_colors_copy
139 inline void
140 blend_colors_copy(uint8* bottom, uint8 alpha, uint8* dest,
141 				  uint8 c1, uint8 c2, uint8 c3)
142 {
143 	if (alpha > 0) {
144 		if (bottom[3] == 0 || alpha == 255) {
145 			dest[0] = c1;
146 			dest[1] = c2;
147 			dest[2] = c3;
148 			dest[3] = alpha;
149 		} else {
150 			blend(bottom[0], bottom[1], bottom[2], bottom[3],
151 				  c1, c2, c3, alpha,
152 				  &dest[0], &dest[1], &dest[2], &dest[3]);
153 		}
154 	} else {
155 		*((uint32*)dest) = *((uint32*)bottom);
156 	}
157 }
158 
159 // blend_colors
160 inline void
161 blend_colors(uint8* bottom, uint8 alpha, uint8 c1, uint8 c2, uint8 c3)
162 {
163 	if (alpha > 0) {
164 		if (bottom[3] == 0 || alpha == 255) {
165 			bottom[0] = c1;
166 			bottom[1] = c2;
167 			bottom[2] = c3;
168 			bottom[3] = alpha;
169 		} else {
170 			blend(bottom[0], bottom[1], bottom[2], bottom[3],
171 				  c1, c2, c3, alpha,
172 				  &bottom[0], &bottom[1], &bottom[2], &bottom[3]);
173 		}
174 	}
175 }
176 
177 // blend_colors
178 inline void
179 blend_colors(uint8* bottom, uint8* source, uint8 alphaOverride)
180 {
181 	uint8 alpha = (source[3] * alphaOverride) / 255;
182 	if (alpha > 0) {
183 		if (bottom[3] == 0 || alpha == 255) {
184 			bottom[0] = source[0];
185 			bottom[1] = source[1];
186 			bottom[2] = source[2];
187 			bottom[3] = alpha;
188 		} else {
189 			blend(bottom[0], bottom[1], bottom[2], bottom[3],
190 				  source[0], source[1], source[2], alpha,
191 				  &bottom[0], &bottom[1], &bottom[2], &bottom[3]);
192 		}
193 	}
194 }
195 
196 // blend_colors
197 inline void
198 blend_colors(uint8* bottom, uint8* source)
199 {
200 	if (source[3] > 0) {
201 		if (bottom[3] == 0 || source[3] == 255) {
202 			bottom[0] = source[0];
203 			bottom[1] = source[1];
204 			bottom[2] = source[2];
205 			bottom[3] = source[3];
206 		} else {
207 			blend(bottom[0], bottom[1], bottom[2], bottom[3],
208 				  source[0], source[1], source[2], source[3],
209 				  &bottom[0], &bottom[1], &bottom[2], &bottom[3]);
210 		}
211 	}
212 }
213 
214 // blend_colors_copy
215 inline void
216 blend_colors_copy(uint8* dest, uint8* bottom, uint8* top)
217 {
218 	if (bottom[3] == 0 || top[3] == 255) {
219 		dest[0] = top[0];
220 		dest[1] = top[1];
221 		dest[2] = top[2];
222 		dest[3] = top[3];
223 	} else {
224 			blend(bottom[0], bottom[1], bottom[2], bottom[3],
225 				  top[0], top[1], top[2], top[3],
226 				  &dest[0], &dest[1], &dest[2], &dest[3]);
227 	}
228 }
229 
230 // blend_pixels
231 inline void
232 blend_pixels(uint8* bottom, uint8* top, uint8 alpha)
233 {
234 	if (alpha > 0) {
235 		if (alpha == 255) {
236 			bottom[0] = top[0];
237 			bottom[1] = top[1];
238 			bottom[2] = top[2];
239 			bottom[3] = top[3];
240 		} else {
241 			// convert to linear rgb
242 			uint16 t1 = kGammaTable[top[0]];
243 			uint16 t2 = kGammaTable[top[1]];
244 			uint16 t3 = kGammaTable[top[2]];
245 			uint16 b1 = kGammaTable[bottom[0]];
246 			uint16 b2 = kGammaTable[bottom[1]];
247 			uint16 b3 = kGammaTable[bottom[2]];
248 
249 			uint8 mergeAlpha = bottom[3] ? (top[3] * alpha) / 255 : 255;
250 			uint8 invAlpha = 255 - mergeAlpha;
251 			bottom[0] = kInverseGammaTable[(b1 * invAlpha + t1 * mergeAlpha) / 255];
252 			bottom[1] = kInverseGammaTable[(b2 * invAlpha + t2 * mergeAlpha) / 255];
253 			bottom[2] = kInverseGammaTable[(b3 * invAlpha + t3 * mergeAlpha) / 255];
254 			bottom[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
255 		}
256 	}
257 }
258 
259 // blend_pixels_copy
260 inline void
261 blend_pixels_copy(uint8* bottom, uint8* top, uint8* dest, uint8 alpha)
262 {
263 	if (alpha > 0) {
264 		if (alpha == 255) {
265 			dest[0] = top[0];
266 			dest[1] = top[1];
267 			dest[2] = top[2];
268 			dest[3] = top[3];
269 		} else {
270 			// convert to linear rgb
271 			uint16 t1 = kGammaTable[top[0]];
272 			uint16 t2 = kGammaTable[top[1]];
273 			uint16 t3 = kGammaTable[top[2]];
274 			uint16 b1 = kGammaTable[bottom[0]];
275 			uint16 b2 = kGammaTable[bottom[1]];
276 			uint16 b3 = kGammaTable[bottom[2]];
277 
278 			uint8 mergeAlpha = bottom[3] ? (top[3] * alpha) / 255 : 255;
279 			uint8 invAlpha = 255 - mergeAlpha;
280 			dest[0] = kInverseGammaTable[(b1 * invAlpha + t1 * mergeAlpha) / 255];
281 			dest[1] = kInverseGammaTable[(b2 * invAlpha + t2 * mergeAlpha) / 255];
282 			dest[2] = kInverseGammaTable[(b3 * invAlpha + t3 * mergeAlpha) / 255];
283 			dest[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
284 		}
285 	} else {
286 		dest[0] = bottom[0];
287 		dest[1] = bottom[1];
288 		dest[2] = bottom[2];
289 		dest[3] = bottom[3];
290 	}
291 }
292 
293 // blend_pixels_overlay
294 inline void
295 blend_pixels_overlay(uint8* bottom, uint8* top, uint8 alphaOverride)
296 {
297 	uint8 alpha = (top[3] * alphaOverride) / 255;
298 	if (alpha > 0) {
299 		if (alpha == 255) {
300 			bottom[0] = top[0];
301 			bottom[1] = top[1];
302 			bottom[2] = top[2];
303 			bottom[3] = top[3];
304 		} else {
305 			// convert to linear rgb
306 			uint16 t1 = kGammaTable[top[0]];
307 			uint16 t2 = kGammaTable[top[1]];
308 			uint16 t3 = kGammaTable[top[2]];
309 			uint16 b1 = kGammaTable[bottom[0]];
310 			uint16 b2 = kGammaTable[bottom[1]];
311 			uint16 b3 = kGammaTable[bottom[2]];
312 
313 			uint8 mergeAlpha = bottom[3] ? alpha : 255;
314 			uint8 invAlpha = 255 - mergeAlpha;
315 			bottom[0] = kInverseGammaTable[(b1 * invAlpha + t1 * mergeAlpha) / 255];
316 			bottom[1] = kInverseGammaTable[(b2 * invAlpha + t2 * mergeAlpha) / 255];
317 			bottom[2] = kInverseGammaTable[(b3 * invAlpha + t3 * mergeAlpha) / 255];
318 			bottom[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
319 		}
320 	}
321 }
322 
323 // blend_pixels_overlay_copy
324 inline void
325 blend_pixels_overlay_copy(uint8* bottom, uint8* top, uint8* dest, uint8 alphaOverride)
326 {
327 	uint8 alpha = (top[3] * alphaOverride) / 255;
328 	if (alpha > 0) {
329 		if (alpha == 255) {
330 			dest[0] = top[0];
331 			dest[1] = top[1];
332 			dest[2] = top[2];
333 			dest[3] = top[3];
334 		} else {
335 			// convert to linear rgb
336 			uint16 t1 = kGammaTable[top[0]];
337 			uint16 t2 = kGammaTable[top[1]];
338 			uint16 t3 = kGammaTable[top[2]];
339 			uint16 b1 = kGammaTable[bottom[0]];
340 			uint16 b2 = kGammaTable[bottom[1]];
341 			uint16 b3 = kGammaTable[bottom[2]];
342 
343 			uint8 mergeAlpha = bottom[3] ? alpha : 255;
344 			uint8 invAlpha = 255 - mergeAlpha;
345 			dest[0] = kInverseGammaTable[(b1 * invAlpha + t1 * mergeAlpha) / 255];
346 			dest[1] = kInverseGammaTable[(b2 * invAlpha + t2 * mergeAlpha) / 255];
347 			dest[2] = kInverseGammaTable[(b3 * invAlpha + t3 * mergeAlpha) / 255];
348 			dest[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
349 		}
350 	} else {
351 		dest[0] = bottom[0];
352 		dest[1] = bottom[1];
353 		dest[2] = bottom[2];
354 		dest[3] = bottom[3];
355 	}
356 }
357 
358 ///////////////////////////////////////////////////////////////////////////////////////////////////////
359 #else // GAMMA_BLEND
360 
361 // blend_colors_copy
362 inline void
363 blend_colors_copy(uint8* bottom, uint8 alpha, uint8* dest,
364 				  uint8 c1, uint8 c2, uint8 c3)
365 {
366 	if (alpha > 0) {
367 		if (bottom[3] == 0 || alpha == 255) {
368 			dest[0] = c1;
369 			dest[1] = c2;
370 			dest[2] = c3;
371 			dest[3] = alpha;
372 		} else {
373 			if (bottom[3] == 255) {
374 				uint32 destAlpha = 255 - alpha;
375 				dest[0] = (uint8)((bottom[0] * destAlpha + c1 * alpha) / 255);
376 				dest[1] = (uint8)((bottom[1] * destAlpha + c2 * alpha) / 255);
377 				dest[2] = (uint8)((bottom[2] * destAlpha + c3 * alpha) / 255);
378 				dest[3] = 255;
379 			} else {
380 				uint8 alphaRest = 255 - alpha;
381 				uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
382 				uint32 alphaDest = bottom[3] * alphaRest;
383 				uint32 alphaSrc = 255 * alpha;
384 				dest[0] = (bottom[0] * alphaDest + c1 * alphaSrc) / alphaTemp;
385 				dest[1] = (bottom[1] * alphaDest + c2 * alphaSrc) / alphaTemp;
386 				dest[2] = (bottom[2] * alphaDest + c3 * alphaSrc) / alphaTemp;
387 				dest[3] = alphaTemp / 255;
388 			}
389 		}
390 	} else {
391 		*((uint32*)dest) = *((uint32*)bottom);
392 	}
393 }
394 
395 // blend_colors
396 inline void
397 blend_colors(uint8* bottom, uint8 alpha, uint8 c1, uint8 c2, uint8 c3)
398 {
399 	if (alpha > 0) {
400 		if (bottom[3] == 0 || alpha == 255) {
401 			bottom[0] = c1;
402 			bottom[1] = c2;
403 			bottom[2] = c3;
404 			bottom[3] = alpha;
405 		} else {
406 			if (bottom[3] == 255) {
407 				uint32 destAlpha = 255 - alpha;
408 				bottom[0] = (uint8)((bottom[0] * destAlpha + c1 * alpha) / 255);
409 				bottom[1] = (uint8)((bottom[1] * destAlpha + c2 * alpha) / 255);
410 				bottom[2] = (uint8)((bottom[2] * destAlpha + c3 * alpha) / 255);
411 			} else {
412 				uint8 alphaRest = 255 - alpha;
413 				uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
414 				uint32 alphaDest = bottom[3] * alphaRest;
415 				uint32 alphaSrc = 255 * alpha;
416 				bottom[0] = (bottom[0] * alphaDest + c1 * alphaSrc) / alphaTemp;
417 				bottom[1] = (bottom[1] * alphaDest + c2 * alphaSrc) / alphaTemp;
418 				bottom[2] = (bottom[2] * alphaDest + c3 * alphaSrc) / alphaTemp;
419 				bottom[3] = alphaTemp / 255;
420 			}
421 		}
422 	}
423 }
424 
425 // blend_colors
426 inline void
427 blend_colors(uint8* bottom, uint8* source, uint8 alphaOverride)
428 {
429 	uint8 alpha = (source[3] * alphaOverride) / 255;
430 	if (alpha > 0) {
431 		if (bottom[3] == 0 || alpha == 255) {
432 			bottom[0] = source[0];
433 			bottom[1] = source[1];
434 			bottom[2] = source[2];
435 			bottom[3] = alpha;
436 		} else {
437 			if (bottom[3] == 255) {
438 				uint32 destAlpha = 255 - alpha;
439 				bottom[0] = (uint8)((bottom[0] * destAlpha + source[0] * alpha) / 255);
440 				bottom[1] = (uint8)((bottom[1] * destAlpha + source[1] * alpha) / 255);
441 				bottom[2] = (uint8)((bottom[2] * destAlpha + source[2] * alpha) / 255);
442 			} else {
443 				uint8 alphaRest = 255 - alpha;
444 				uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
445 				uint32 alphaDest = bottom[3] * alphaRest;
446 				uint32 alphaSrc = 255 * alpha;
447 				bottom[0] = (bottom[0] * alphaDest + source[0] * alphaSrc) / alphaTemp;
448 				bottom[1] = (bottom[1] * alphaDest + source[1] * alphaSrc) / alphaTemp;
449 				bottom[2] = (bottom[2] * alphaDest + source[2] * alphaSrc) / alphaTemp;
450 				bottom[3] = alphaTemp / 255;
451 			}
452 		}
453 	}
454 }
455 
456 // blend_colors
457 inline void
458 blend_colors(uint8* bottom, uint8* source)
459 {
460 	if (source[3] > 0) {
461 		if (bottom[3] == 0 || source[3] == 255) {
462 			bottom[0] = source[0];
463 			bottom[1] = source[1];
464 			bottom[2] = source[2];
465 			bottom[3] = source[3];
466 		} else {
467 			if (bottom[3] == 255) {
468 				uint32 destAlpha = 255 - source[3];
469 				bottom[0] = (uint8)((bottom[0] * destAlpha + source[0] * source[3]) / 255);
470 				bottom[1] = (uint8)((bottom[1] * destAlpha + source[1] * source[3]) / 255);
471 				bottom[2] = (uint8)((bottom[2] * destAlpha + source[2] * source[3]) / 255);
472 			} else {
473 				uint8 alphaRest = 255 - source[3];
474 				uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
475 				uint32 alphaDest = bottom[3] * alphaRest;
476 				uint32 alphaSrc = 255 * source[3];
477 				bottom[0] = (bottom[0] * alphaDest + source[0] * alphaSrc) / alphaTemp;
478 				bottom[1] = (bottom[1] * alphaDest + source[1] * alphaSrc) / alphaTemp;
479 				bottom[2] = (bottom[2] * alphaDest + source[2] * alphaSrc) / alphaTemp;
480 				bottom[3] = alphaTemp / 255;
481 			}
482 		}
483 	}
484 }
485 
486 // blend_colors_copy
487 inline void
488 blend_colors_copy(uint8* dest, uint8* bottom, uint8* top)
489 {
490 	if (bottom[3] == 0 || top[3] == 255) {
491 		dest[0] = top[0];
492 		dest[1] = top[1];
493 		dest[2] = top[2];
494 		dest[3] = top[3];
495 	} else {
496 		if (bottom[3] == 255) {
497 			uint32 destAlpha = 255 - top[3];
498 			dest[0] = (uint8)((bottom[0] * destAlpha + top[0] * top[3]) / 255);
499 			dest[1] = (uint8)((bottom[1] * destAlpha + top[1] * top[3]) / 255);
500 			dest[2] = (uint8)((bottom[2] * destAlpha + top[2] * top[3]) / 255);
501 			dest[3] = 255;
502 		} else {
503 			uint8 alphaRest = 255 - top[3];
504 			uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
505 			uint32 alphaDest = bottom[3] * alphaRest;
506 			uint32 alphaSrc = 255 * top[3];
507 			dest[0] = (bottom[0] * alphaDest + top[0] * alphaSrc) / alphaTemp;
508 			dest[1] = (bottom[1] * alphaDest + top[1] * alphaSrc) / alphaTemp;
509 			dest[2] = (bottom[2] * alphaDest + top[2] * alphaSrc) / alphaTemp;
510 			dest[3] = alphaTemp / 255;
511 		}
512 	}
513 }
514 
515 // blend_pixels
516 inline void
517 blend_pixels(uint8* bottom, uint8* top, uint8 alpha)
518 {
519 	if (alpha > 0) {
520 		if (alpha == 255) {
521 			bottom[0] = top[0];
522 			bottom[1] = top[1];
523 			bottom[2] = top[2];
524 			bottom[3] = top[3];
525 		} else {
526 			uint8 mergeAlpha = bottom[3] ? (top[3] * alpha) / 255 : 255;
527 			uint8 invAlpha = 255 - mergeAlpha;
528 			bottom[0] = (bottom[0] * invAlpha + top[0] * mergeAlpha) / 255;
529 			bottom[1] = (bottom[1] * invAlpha + top[1] * mergeAlpha) / 255;
530 			bottom[2] = (bottom[2] * invAlpha + top[2] * mergeAlpha) / 255;
531 			bottom[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
532 		}
533 	}
534 }
535 
536 // blend_pixels_copy
537 inline void
538 blend_pixels_copy(uint8* bottom, uint8* top, uint8* dest, uint8 alpha)
539 {
540 	if (alpha > 0) {
541 		if (alpha == 255) {
542 			dest[0] = top[0];
543 			dest[1] = top[1];
544 			dest[2] = top[2];
545 			dest[3] = top[3];
546 		} else {
547 			uint8 mergeAlpha = bottom[3] ? (top[3] * alpha) / 255 : 255;
548 			uint8 invAlpha = 255 - mergeAlpha;
549 			dest[0] = (bottom[0] * invAlpha + top[0] * mergeAlpha) / 255;
550 			dest[1] = (bottom[1] * invAlpha + top[1] * mergeAlpha) / 255;
551 			dest[2] = (bottom[2] * invAlpha + top[2] * mergeAlpha) / 255;
552 			dest[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
553 		}
554 	} else {
555 		dest[0] = bottom[0];
556 		dest[1] = bottom[1];
557 		dest[2] = bottom[2];
558 		dest[3] = bottom[3];
559 	}
560 }
561 
562 // blend_pixels_overlay
563 inline void
564 blend_pixels_overlay(uint8* bottom, uint8* top, uint8 alphaOverride)
565 {
566 	uint8 alpha = (top[3] * alphaOverride) / 255;
567 	if (alpha > 0) {
568 		if (alpha == 255) {
569 			bottom[0] = top[0];
570 			bottom[1] = top[1];
571 			bottom[2] = top[2];
572 			bottom[3] = top[3];
573 		} else {
574 			uint8 mergeAlpha = bottom[3] ? alpha : 255;
575 			uint8 invAlpha = 255 - mergeAlpha;
576 			bottom[0] = (bottom[0] * invAlpha + top[0] * mergeAlpha) / 255;
577 			bottom[1] = (bottom[1] * invAlpha + top[1] * mergeAlpha) / 255;
578 			bottom[2] = (bottom[2] * invAlpha + top[2] * mergeAlpha) / 255;
579 			bottom[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
580 		}
581 	}
582 }
583 
584 // blend_pixels_overlay_copy
585 inline void
586 blend_pixels_overlay_copy(uint8* bottom, uint8* top, uint8* dest, uint8 alphaOverride)
587 {
588 	uint8 alpha = (top[3] * alphaOverride) / 255;
589 	if (alpha > 0) {
590 		if (alpha == 255) {
591 			dest[0] = top[0];
592 			dest[1] = top[1];
593 			dest[2] = top[2];
594 			dest[3] = top[3];
595 		} else {
596 			uint8 mergeAlpha = bottom[3] ? alpha : 255;
597 			uint8 invAlpha = 255 - mergeAlpha;
598 			dest[0] = (bottom[0] * invAlpha + top[0] * mergeAlpha) / 255;
599 			dest[1] = (bottom[1] * invAlpha + top[1] * mergeAlpha) / 255;
600 			dest[2] = (bottom[2] * invAlpha + top[2] * mergeAlpha) / 255;
601 			dest[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
602 		}
603 	} else {
604 		dest[0] = bottom[0];
605 		dest[1] = bottom[1];
606 		dest[2] = bottom[2];
607 		dest[3] = bottom[3];
608 	}
609 }
610 
611 #endif	// GAMMA_BLEND
612 
613 #endif // BLENDING_H
614