#include "glheader.h"
#include "context.h"
#include "colormac.h"
#include "macros.h"
#include "s_blend.h"
#include "s_context.h"
#include "s_span.h"
#if defined(USE_MMX_ASM)
#include "x86/mmx.h"
#include "x86/common_x86_asm.h"
#define _BLENDAPI _ASMAPI
#else
#define _BLENDAPI
#endif
#define DIV255(X) (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
static void _BLENDAPI
blend_noop(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLint bytes;
ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendSrcRGB == GL_ZERO);
ASSERT(ctx->Color.BlendDstRGB == GL_ONE);
(void) ctx;
if (chanType == GL_UNSIGNED_BYTE)
bytes = 4 * n * sizeof(GLubyte);
else if (chanType == GL_UNSIGNED_SHORT)
bytes = 4 * n * sizeof(GLushort);
else
bytes = 4 * n * sizeof(GLfloat);
_mesa_memcpy(src, dst, bytes);
}
static void _BLENDAPI
blend_replace(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendSrcRGB == GL_ONE);
ASSERT(ctx->Color.BlendDstRGB == GL_ZERO);
(void) ctx;
(void) n;
(void) mask;
(void) src;
(void) dst;
}
static void _BLENDAPI
blend_transparency_ubyte(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
GLuint i;
ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendSrcRGB == GL_SRC_ALPHA);
ASSERT(ctx->Color.BlendSrcA == GL_SRC_ALPHA);
ASSERT(ctx->Color.BlendDstRGB == GL_ONE_MINUS_SRC_ALPHA);
ASSERT(ctx->Color.BlendDstA == GL_ONE_MINUS_SRC_ALPHA);
ASSERT(chanType == GL_UNSIGNED_BYTE);
(void) ctx;
for (i = 0; i < n; i++) {
if (mask[i]) {
const GLint t = rgba[i][ACOMP];
if (t == 0) {
COPY_4UBV(rgba[i], dest[i]);
}
else if (t != 255) {
GLint divtemp;
const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
ASSERT(r <= 255);
ASSERT(g <= 255);
ASSERT(b <= 255);
ASSERT(a <= 255);
rgba[i][RCOMP] = (GLubyte) r;
rgba[i][GCOMP] = (GLubyte) g;
rgba[i][BCOMP] = (GLubyte) b;
rgba[i][ACOMP] = (GLubyte) a;
}
}
}
}
static void _BLENDAPI
blend_transparency_ushort(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
GLuint i;
ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendSrcRGB == GL_SRC_ALPHA);
ASSERT(ctx->Color.BlendSrcA == GL_SRC_ALPHA);
ASSERT(ctx->Color.BlendDstRGB == GL_ONE_MINUS_SRC_ALPHA);
ASSERT(ctx->Color.BlendDstA == GL_ONE_MINUS_SRC_ALPHA);
ASSERT(chanType == GL_UNSIGNED_SHORT);
(void) ctx;
for (i = 0; i < n; i++) {
if (mask[i]) {
const GLint t = rgba[i][ACOMP];
if (t == 0) {
COPY_4V(rgba[i], dest[i]);
}
else if (t != 65535) {
const GLfloat tt = (GLfloat) t / 65535.0F;
GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
ASSIGN_4V(rgba[i], r, g, b, a);
}
}
}
}
static void _BLENDAPI
blend_transparency_float(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
GLuint i;
ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendSrcRGB == GL_SRC_ALPHA);
ASSERT(ctx->Color.BlendSrcA == GL_SRC_ALPHA);
ASSERT(ctx->Color.BlendDstRGB == GL_ONE_MINUS_SRC_ALPHA);
ASSERT(ctx->Color.BlendDstA == GL_ONE_MINUS_SRC_ALPHA);
ASSERT(chanType == GL_FLOAT);
(void) ctx;
for (i = 0; i < n; i++) {
if (mask[i]) {
const GLfloat t = rgba[i][ACOMP];
if (t == 0.0F) {
COPY_4V(rgba[i], dest[i]);
}
else if (t != 1.0F) {
GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP];
GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP];
GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP];
GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP];
ASSIGN_4V(rgba[i], r, g, b, a);
}
}
}
}
static void _BLENDAPI
blend_add(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLuint i;
ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
ASSERT(ctx->Color.BlendSrcRGB == GL_ONE);
ASSERT(ctx->Color.BlendDstRGB == GL_ONE);
(void) ctx;
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
rgba[i][RCOMP] = (GLubyte) MIN2( r, 255 );
rgba[i][GCOMP] = (GLubyte) MIN2( g, 255 );
rgba[i][BCOMP] = (GLubyte) MIN2( b, 255 );
rgba[i][ACOMP] = (GLubyte) MIN2( a, 255 );
}
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
rgba[i][RCOMP] = (GLshort) MIN2( r, 255 );
rgba[i][GCOMP] = (GLshort) MIN2( g, 255 );
rgba[i][BCOMP] = (GLshort) MIN2( b, 255 );
rgba[i][ACOMP] = (GLshort) MIN2( a, 255 );
}
}
}
else {
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
ASSERT(chanType == GL_FLOAT);
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] += dest[i][RCOMP];
rgba[i][GCOMP] += dest[i][GCOMP];
rgba[i][BCOMP] += dest[i][BCOMP];
rgba[i][ACOMP] += dest[i][ACOMP];
}
}
}
}
static void _BLENDAPI
blend_min(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLuint i;
ASSERT(ctx->Color.BlendEquationRGB == GL_MIN);
ASSERT(ctx->Color.BlendEquationA == GL_MIN);
(void) ctx;
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
else {
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
ASSERT(chanType == GL_FLOAT);
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
}
static void _BLENDAPI
blend_max(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLuint i;
ASSERT(ctx->Color.BlendEquationRGB == GL_MAX);
ASSERT(ctx->Color.BlendEquationA == GL_MAX);
(void) ctx;
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
else {
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
ASSERT(chanType == GL_FLOAT);
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
}
static void _BLENDAPI
blend_modulate(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLuint i;
(void) ctx;
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
GLint divtemp;
rgba[i][RCOMP] = DIV255(rgba[i][RCOMP] * dest[i][RCOMP]);
rgba[i][GCOMP] = DIV255(rgba[i][GCOMP] * dest[i][GCOMP]);
rgba[i][BCOMP] = DIV255(rgba[i][BCOMP] * dest[i][BCOMP]);
rgba[i][ACOMP] = DIV255(rgba[i][ACOMP] * dest[i][ACOMP]);
}
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
rgba[i][GCOMP] = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
rgba[i][BCOMP] = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
rgba[i][ACOMP] = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
}
}
}
else {
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
ASSERT(chanType == GL_FLOAT);
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
}
}
}
}
static void
blend_general_float(GLcontext *ctx, GLuint n, const GLubyte mask[],
GLfloat rgba[][4], GLfloat dest[][4],
GLenum chanType)
{
GLuint i;
for (i = 0; i < n; i++) {
if (mask[i]) {
const GLfloat Rs = rgba[i][RCOMP];
const GLfloat Gs = rgba[i][GCOMP];
const GLfloat Bs = rgba[i][BCOMP];
const GLfloat As = rgba[i][ACOMP];
const GLfloat Rd = dest[i][RCOMP];
const GLfloat Gd = dest[i][GCOMP];
const GLfloat Bd = dest[i][BCOMP];
const GLfloat Ad = dest[i][ACOMP];
GLfloat sR, sG, sB, sA;
GLfloat dR, dG, dB, dA;
GLfloat r, g, b, a;
switch (ctx->Color.BlendSrcRGB) {
case GL_ZERO:
sR = sG = sB = 0.0F;
break;
case GL_ONE:
sR = sG = sB = 1.0F;
break;
case GL_DST_COLOR:
sR = Rd;
sG = Gd;
sB = Bd;
break;
case GL_ONE_MINUS_DST_COLOR:
sR = 1.0F - Rd;
sG = 1.0F - Gd;
sB = 1.0F - Bd;
break;
case GL_SRC_ALPHA:
sR = sG = sB = As;
break;
case GL_ONE_MINUS_SRC_ALPHA:
sR = sG = sB = 1.0F - As;
break;
case GL_DST_ALPHA:
sR = sG = sB = Ad;
break;
case GL_ONE_MINUS_DST_ALPHA:
sR = sG = sB = 1.0F - Ad;
break;
case GL_SRC_ALPHA_SATURATE:
if (As < 1.0F - Ad) {
sR = sG = sB = As;
}
else {
sR = sG = sB = 1.0F - Ad;
}
break;
case GL_CONSTANT_COLOR:
sR = ctx->Color.BlendColor[0];
sG = ctx->Color.BlendColor[1];
sB = ctx->Color.BlendColor[2];
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
sR = 1.0F - ctx->Color.BlendColor[0];
sG = 1.0F - ctx->Color.BlendColor[1];
sB = 1.0F - ctx->Color.BlendColor[2];
break;
case GL_CONSTANT_ALPHA:
sR = sG = sB = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_ALPHA:
sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_SRC_COLOR:
sR = Rs;
sG = Gs;
sB = Bs;
break;
case GL_ONE_MINUS_SRC_COLOR:
sR = 1.0F - Rs;
sG = 1.0F - Gs;
sB = 1.0F - Bs;
break;
default:
_mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float");
return;
}
switch (ctx->Color.BlendSrcA) {
case GL_ZERO:
sA = 0.0F;
break;
case GL_ONE:
sA = 1.0F;
break;
case GL_DST_COLOR:
sA = Ad;
break;
case GL_ONE_MINUS_DST_COLOR:
sA = 1.0F - Ad;
break;
case GL_SRC_ALPHA:
sA = As;
break;
case GL_ONE_MINUS_SRC_ALPHA:
sA = 1.0F - As;
break;
case GL_DST_ALPHA:
sA = Ad;
break;
case GL_ONE_MINUS_DST_ALPHA:
sA = 1.0F - Ad;
break;
case GL_SRC_ALPHA_SATURATE:
sA = 1.0;
break;
case GL_CONSTANT_COLOR:
sA = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
sA = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_CONSTANT_ALPHA:
sA = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_ALPHA:
sA = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_SRC_COLOR:
sA = As;
break;
case GL_ONE_MINUS_SRC_COLOR:
sA = 1.0F - As;
break;
default:
sA = 0.0F;
_mesa_problem(ctx, "Bad blend source A factor in blend_general_float");
return;
}
switch (ctx->Color.BlendDstRGB) {
case GL_ZERO:
dR = dG = dB = 0.0F;
break;
case GL_ONE:
dR = dG = dB = 1.0F;
break;
case GL_SRC_COLOR:
dR = Rs;
dG = Gs;
dB = Bs;
break;
case GL_ONE_MINUS_SRC_COLOR:
dR = 1.0F - Rs;
dG = 1.0F - Gs;
dB = 1.0F - Bs;
break;
case GL_SRC_ALPHA:
dR = dG = dB = As;
break;
case GL_ONE_MINUS_SRC_ALPHA:
dR = dG = dB = 1.0F - As;
break;
case GL_DST_ALPHA:
dR = dG = dB = Ad;
break;
case GL_ONE_MINUS_DST_ALPHA:
dR = dG = dB = 1.0F - Ad;
break;
case GL_CONSTANT_COLOR:
dR = ctx->Color.BlendColor[0];
dG = ctx->Color.BlendColor[1];
dB = ctx->Color.BlendColor[2];
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
dR = 1.0F - ctx->Color.BlendColor[0];
dG = 1.0F - ctx->Color.BlendColor[1];
dB = 1.0F - ctx->Color.BlendColor[2];
break;
case GL_CONSTANT_ALPHA:
dR = dG = dB = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_ALPHA:
dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_DST_COLOR:
dR = Rd;
dG = Gd;
dB = Bd;
break;
case GL_ONE_MINUS_DST_COLOR:
dR = 1.0F - Rd;
dG = 1.0F - Gd;
dB = 1.0F - Bd;
break;
default:
dR = dG = dB = 0.0F;
_mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float");
return;
}
switch (ctx->Color.BlendDstA) {
case GL_ZERO:
dA = 0.0F;
break;
case GL_ONE:
dA = 1.0F;
break;
case GL_SRC_COLOR:
dA = As;
break;
case GL_ONE_MINUS_SRC_COLOR:
dA = 1.0F - As;
break;
case GL_SRC_ALPHA:
dA = As;
break;
case GL_ONE_MINUS_SRC_ALPHA:
dA = 1.0F - As;
break;
case GL_DST_ALPHA:
dA = Ad;
break;
case GL_ONE_MINUS_DST_ALPHA:
dA = 1.0F - Ad;
break;
case GL_CONSTANT_COLOR:
dA = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
dA = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_CONSTANT_ALPHA:
dA = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_ALPHA:
dA = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_DST_COLOR:
dA = Ad;
break;
case GL_ONE_MINUS_DST_COLOR:
dA = 1.0F - Ad;
break;
default:
dA = 0.0F;
_mesa_problem(ctx, "Bad blend dest A factor in blend_general_float");
return;
}
switch (ctx->Color.BlendEquationRGB) {
case GL_FUNC_ADD:
r = Rs * sR + Rd * dR;
g = Gs * sG + Gd * dG;
b = Bs * sB + Bd * dB;
a = As * sA + Ad * dA;
break;
case GL_FUNC_SUBTRACT:
r = Rs * sR - Rd * dR;
g = Gs * sG - Gd * dG;
b = Bs * sB - Bd * dB;
a = As * sA - Ad * dA;
break;
case GL_FUNC_REVERSE_SUBTRACT:
r = Rd * dR - Rs * sR;
g = Gd * dG - Gs * sG;
b = Bd * dB - Bs * sB;
a = Ad * dA - As * sA;
break;
case GL_MIN:
r = MIN2( Rd, Rs );
g = MIN2( Gd, Gs );
b = MIN2( Bd, Bs );
break;
case GL_MAX:
r = MAX2( Rd, Rs );
g = MAX2( Gd, Gs );
b = MAX2( Bd, Bs );
break;
default:
r = g = b = 0.0F;
_mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
return;
}
switch (ctx->Color.BlendEquationA) {
case GL_FUNC_ADD:
a = As * sA + Ad * dA;
break;
case GL_FUNC_SUBTRACT:
a = As * sA - Ad * dA;
break;
case GL_FUNC_REVERSE_SUBTRACT:
a = Ad * dA - As * sA;
break;
case GL_MIN:
a = MIN2( Ad, As );
break;
case GL_MAX:
a = MAX2( Ad, As );
break;
default:
a = 0.0F;
_mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
return;
}
#if 0
rgba[i][RCOMP] = MAX2( r, 0.0F );
rgba[i][GCOMP] = MAX2( g, 0.0F );
rgba[i][BCOMP] = MAX2( b, 0.0F );
rgba[i][ACOMP] = CLAMP( a, 0.0F, 1.0F );
#else
ASSIGN_4V(rgba[i], r, g, b, a);
#endif
}
}
}
static void
blend_general(GLcontext *ctx, GLuint n, const GLubyte mask[],
void *src, const void *dst, GLenum chanType)
{
GLfloat rgbaF[MAX_WIDTH][4], destF[MAX_WIDTH][4];
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
GLuint i;
for (i = 0; i < n; i++) {
if (mask[i]) {
rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]);
rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]);
rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]);
rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]);
destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]);
destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]);
destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]);
destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]);
}
}
blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
for (i = 0; i < n; i++) {
if (mask[i]) {
UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][RCOMP], rgbaF[i][RCOMP]);
UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][GCOMP], rgbaF[i][GCOMP]);
UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][BCOMP], rgbaF[i][BCOMP]);
UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][ACOMP], rgbaF[i][ACOMP]);
}
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
GLuint i;
for (i = 0; i < n; i++) {
if (mask[i]) {
rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]);
rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]);
rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]);
rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]);
destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]);
destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]);
destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]);
destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]);
}
}
blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
for (i = 0; i < n; i++) {
if (mask[i]) {
UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]);
UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]);
UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]);
UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]);
}
}
}
else {
blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
}
}
void
_swrast_choose_blend_func(GLcontext *ctx, GLenum chanType)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
const GLenum eq = ctx->Color.BlendEquationRGB;
const GLenum srcRGB = ctx->Color.BlendSrcRGB;
const GLenum dstRGB = ctx->Color.BlendDstRGB;
const GLenum srcA = ctx->Color.BlendSrcA;
const GLenum dstA = ctx->Color.BlendDstA;
if (ctx->Color.BlendEquationRGB != ctx->Color.BlendEquationA) {
swrast->BlendFunc = blend_general;
}
else if (eq == GL_MIN) {
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_min;
}
else
#endif
swrast->BlendFunc = blend_min;
}
else if (eq == GL_MAX) {
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_max;
}
else
#endif
swrast->BlendFunc = blend_max;
}
else if (srcRGB != srcA || dstRGB != dstA) {
swrast->BlendFunc = blend_general;
}
else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA
&& dstRGB == GL_ONE_MINUS_SRC_ALPHA) {
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_transparency;
}
else
#endif
{
if (chanType == GL_UNSIGNED_BYTE)
swrast->BlendFunc = blend_transparency_ubyte;
else if (chanType == GL_UNSIGNED_SHORT)
swrast->BlendFunc = blend_transparency_ushort;
else
swrast->BlendFunc = blend_transparency_float;
}
}
else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) {
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_add;
}
else
#endif
swrast->BlendFunc = blend_add;
}
else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT)
&& (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR))
||
((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT)
&& (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) {
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_modulate;
}
else
#endif
swrast->BlendFunc = blend_modulate;
}
else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
swrast->BlendFunc = blend_noop;
}
else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
swrast->BlendFunc = blend_replace;
}
else {
swrast->BlendFunc = blend_general;
}
}
void
_swrast_blend_span(GLcontext *ctx, struct gl_renderbuffer *rb, SWspan *span)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
void *rbPixels;
ASSERT(span->end <= MAX_WIDTH);
ASSERT(span->arrayMask & SPAN_RGBA);
ASSERT(rb->DataType == span->array->ChanType);
ASSERT(!ctx->Color._LogicOpEnabled);
rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
swrast->BlendFunc(ctx, span->end, span->array->mask,
span->array->rgba, rbPixels, span->array->ChanType);
}