SynGame/allegro/include/allegro5/internal/aintern_blend.h

245 lines
6.6 KiB
C

#ifndef __al_included_allegro5_aintern_blend_h
#define __al_included_allegro5_aintern_blend_h
#include "allegro5/internal/aintern.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __GNUC__
#define _AL_ALWAYS_INLINE inline __attribute__((always_inline))
#else
#define _AL_ALWAYS_INLINE INLINE
#endif
#define _AL_DEST_IS_ZERO \
(dst_mode == ALLEGRO_ZERO && dst_alpha == ALLEGRO_ZERO && \
op != ALLEGRO_DEST_MINUS_SRC && op_alpha != ALLEGRO_DEST_MINUS_SRC)
#define _AL_SRC_NOT_MODIFIED \
(src_mode == ALLEGRO_ONE && src_alpha == ALLEGRO_ONE)
#define _AL_SRC_NOT_MODIFIED_TINT_WHITE \
(_AL_SRC_NOT_MODIFIED && \
tint.r == 1.0f && tint.g == 1.0f && tint.b == 1.0f && tint.a == 1.0f)
#ifndef _AL_NO_BLEND_INLINE_FUNC
/* Only cares about alpha blending modes. */
static _AL_ALWAYS_INLINE float
get_alpha_factor(enum ALLEGRO_BLEND_MODE operation, float src_alpha, float dst_alpha)
{
switch (operation) {
case ALLEGRO_ZERO: return 0;
case ALLEGRO_ONE: return 1;
case ALLEGRO_ALPHA: return src_alpha;
case ALLEGRO_INVERSE_ALPHA: return 1 - src_alpha;
case ALLEGRO_SRC_COLOR: return src_alpha;
case ALLEGRO_DEST_COLOR: return dst_alpha;
case ALLEGRO_INVERSE_SRC_COLOR: return 1 - src_alpha;
case ALLEGRO_INVERSE_DEST_COLOR: return 1 - dst_alpha;
default:
ASSERT(false);
return 0; /* silence warning in release build */
}
}
/* Puts the blending factor in an ALLEGRO_COLOR object. */
static _AL_ALWAYS_INLINE void get_factor(enum ALLEGRO_BLEND_MODE operation,
const ALLEGRO_COLOR *source, const ALLEGRO_COLOR *dest,
ALLEGRO_COLOR *factor)
{
switch (operation) {
case ALLEGRO_ZERO:
factor->r = factor->g = factor->b = factor->a = 0;
break;
case ALLEGRO_ONE:
factor->r = factor->g = factor->b = factor->a = 1;
break;
case ALLEGRO_ALPHA:
factor->r = factor->g = factor->b = factor->a = source->a;
break;
case ALLEGRO_INVERSE_ALPHA:
factor->r = factor->g = factor->b = factor->a = 1 - source->a;
break;
case ALLEGRO_SRC_COLOR:
*factor = *source;
break;
case ALLEGRO_DEST_COLOR:
*factor = *dest;
break;
case ALLEGRO_INVERSE_SRC_COLOR:
factor->r = 1 - source->r;
factor->g = 1 - source->g;
factor->b = 1 - source->b;
factor->a = 1 - source->a;
break;
case ALLEGRO_INVERSE_DEST_COLOR:
factor->r = 1 - dest->r;
factor->g = 1 - dest->g;
factor->b = 1 - dest->b;
factor->a = 1 - dest->a;
break;
default:
ASSERT(false);
factor->r = factor->g = factor->b = factor->a = 0;
break;
}
}
/* Only call this if the blend modes are one of:
* ALLEGRO_ONE, ALLEGRO_ZERO, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA
*/
static _AL_ALWAYS_INLINE
void _al_blend_alpha_inline(
const ALLEGRO_COLOR *scol, const ALLEGRO_COLOR *dcol,
int op, int src_, int dst_, int aop, int asrc_, int adst_,
ALLEGRO_COLOR *result)
{
float asrc, adst;
float src, dst;
result->r = scol->r;
result->g = scol->g;
result->b = scol->b;
result->a = scol->a;
asrc = get_alpha_factor(asrc_, scol->a, dcol->a);
adst = get_alpha_factor(adst_, scol->a, dcol->a);
src = get_alpha_factor(src_, scol->a, dcol->a);
dst = get_alpha_factor(dst_, scol->a, dcol->a);
#define BLEND(c, src, dst) \
result->c = OP(result->c * src, dcol->c * dst);
switch (op) {
case ALLEGRO_ADD:
#define OP(x, y) _ALLEGRO_MIN(1, x + y)
BLEND(r, src, dst)
BLEND(g, src, dst)
BLEND(b, src, dst)
#undef OP
break;
case ALLEGRO_SRC_MINUS_DEST:
#define OP(x, y) _ALLEGRO_MAX(0, x - y)
BLEND(r, src, dst)
BLEND(g, src, dst)
BLEND(b, src, dst)
#undef OP
break;
case ALLEGRO_DEST_MINUS_SRC:
#define OP(x, y) _ALLEGRO_MAX(0, y - x)
BLEND(r, src, dst)
BLEND(g, src, dst)
BLEND(b, src, dst)
#undef OP
break;
}
switch (aop) {
case ALLEGRO_ADD:
#define OP(x, y) _ALLEGRO_MIN(1, x + y)
BLEND(a, asrc, adst)
#undef OP
break;
case ALLEGRO_SRC_MINUS_DEST:
#define OP(x, y) _ALLEGRO_MAX(0, x - y)
BLEND(a, asrc, adst)
#undef OP
break;
case ALLEGRO_DEST_MINUS_SRC:
#define OP(x, y) _ALLEGRO_MAX(0, y - x)
BLEND(a, asrc, adst)
#undef OP
break;
}
#undef BLEND
}
/* call this for general blending. its a little slower than just using alpha */
static _AL_ALWAYS_INLINE
void _al_blend_inline(
const ALLEGRO_COLOR *scol, const ALLEGRO_COLOR *dcol,
int op, int src_, int dst_, int aop, int asrc_, int adst_,
ALLEGRO_COLOR *result)
{
float asrc, adst;
ALLEGRO_COLOR src, dst;
result->r = scol->r;
result->g = scol->g;
result->b = scol->b;
result->a = scol->a;
asrc = get_alpha_factor(asrc_, scol->a, dcol->a);
adst = get_alpha_factor(adst_, scol->a, dcol->a);
get_factor(src_, scol, dcol, &src);
get_factor(dst_, scol, dcol, &dst);
#define BLEND(c, src, dst) \
result->c = OP(result->c * src.c, dcol->c * dst.c);
switch (op) {
case ALLEGRO_ADD:
#define OP(x, y) _ALLEGRO_MIN(1, x + y)
BLEND(r, src, dst)
BLEND(g, src, dst)
BLEND(b, src, dst)
#undef OP
break;
case ALLEGRO_SRC_MINUS_DEST:
#define OP(x, y) _ALLEGRO_MAX(0, x - y)
BLEND(r, src, dst)
BLEND(g, src, dst)
BLEND(b, src, dst)
#undef OP
break;
case ALLEGRO_DEST_MINUS_SRC:
#define OP(x, y) _ALLEGRO_MAX(0, y - x)
BLEND(r, src, dst)
BLEND(g, src, dst)
BLEND(b, src, dst)
#undef OP
break;
}
#undef BLEND
#define BLEND(c, src, dst) \
result->c = OP(result->c * src, dcol->c * dst);
switch (aop) {
case ALLEGRO_ADD:
#define OP(x, y) _ALLEGRO_MIN(1, x + y)
BLEND(a, asrc, adst)
#undef OP
break;
case ALLEGRO_SRC_MINUS_DEST:
#define OP(x, y) _ALLEGRO_MAX(0, x - y)
BLEND(a, asrc, adst)
#undef OP
break;
case ALLEGRO_DEST_MINUS_SRC:
#define OP(x, y) _ALLEGRO_MAX(0, y - x)
BLEND(a, asrc, adst)
#undef OP
break;
}
#undef BLEND
}
#endif
void _al_blend_memory(ALLEGRO_COLOR *src_color, ALLEGRO_BITMAP *dest,
int dx, int dy, ALLEGRO_COLOR *result);
#ifdef __cplusplus
}
#endif
#endif
/* vim: set sts=3 sw=3 et: */