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
29extern uint16* kGammaTable;
30extern uint8* kInverseGammaTable;
31
32void init_gamma_blending();
33void uninit_gamma_blending();
34
35// blend
36inline void
37blend_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
60inline void
61blend(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
83uint16
84convert_to_gamma(uint8 value);
85
86// blend_colors_copy
87inline void
88blend_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
114inline void
115blend_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
139inline void
140blend_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
160inline void
161blend_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
178inline void
179blend_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
197inline void
198blend_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
215inline void
216blend_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
231inline void
232blend_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
260inline void
261blend_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
294inline void
295blend_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
324inline void
325blend_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
362inline void
363blend_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
396inline void
397blend_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
426inline void
427blend_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
457inline void
458blend_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
487inline void
488blend_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
516inline void
517blend_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
537inline void
538blend_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
563inline void
564blend_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
585inline void
586blend_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