tinydisplay: Reimplement color blending, supporting more options
Separate blend modes/operands for rgb/alpha are now supported, and min/max blend modes are supported too. To avoid code bloat, the operands are now no longer implemented as separate permutations in the table, but using a small table and a mask. I haven't tested performance but it shouldn't be much worse (and this is the "general" fallback case anyway, which should prioritize correctness) and the number of functions is significantly reduced. A bug was fixed regarding sRGB behavior when only the blue channel is enabled. M_subtract and M_inv_subtract are still left unimplemented.
This commit is contained in:
parent
b7ffef7338
commit
dbe05e079b
|
|
@ -24,10 +24,50 @@ FNAME(store_pixel) (ZBuffer *zb, PIXEL &result, int r, int g, int b, int a) {
|
|||
unsigned int fb = PIXEL_B(result);
|
||||
unsigned int fa = PIXEL_A(result);
|
||||
|
||||
r = STORE_PIXEL_0(fr, ((unsigned int)r * OP_A(fr, r) >> 16) + ((unsigned int)fr * OP_B(fr, r) >> 16));
|
||||
g = STORE_PIXEL_1(fg, ((unsigned int)g * OP_A(fg, g) >> 16) + ((unsigned int)fg * OP_B(fg, g) >> 16));
|
||||
b = STORE_PIXEL_2(fb, ((unsigned int)b * OP_A(fb, b) >> 16) + ((unsigned int)fb * OP_B(fb, b) >> 16));
|
||||
a = STORE_PIXEL_3(fa, ((unsigned int)a * OP_A(fa, a) >> 16) + ((unsigned int)fa * OP_B(fa, a) >> 16));
|
||||
#if HAVE_R
|
||||
unsigned int r_ops[] = {0, (unsigned int)r, fr, (unsigned int)a, fa};
|
||||
unsigned int r_opa = r_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_r;
|
||||
unsigned int r_opb = r_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_r;
|
||||
(void)r_opa;
|
||||
(void)r_opb;
|
||||
r = MODE_RGB(r, r_opa, fr, r_opb);
|
||||
#else
|
||||
r = fr;
|
||||
#endif
|
||||
|
||||
#if HAVE_G
|
||||
unsigned int g_ops[] = {0, (unsigned int)g, fg, (unsigned int)a, fa};
|
||||
unsigned int g_opa = g_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_g;
|
||||
unsigned int g_opb = g_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_g;
|
||||
(void)g_opa;
|
||||
(void)g_opb;
|
||||
g = MODE_RGB(g, g_opa, fg, g_opb);
|
||||
#else
|
||||
g = fg;
|
||||
#endif
|
||||
|
||||
#if HAVE_B
|
||||
unsigned int b_ops[] = {0, (unsigned int)b, fb, (unsigned int)a, fa};
|
||||
unsigned int b_opa = b_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_b;
|
||||
unsigned int b_opb = b_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_b;
|
||||
(void)b_opa;
|
||||
(void)b_opb;
|
||||
b = MODE_RGB(b, b_opa, fb, b_opb);
|
||||
#else
|
||||
b = fb;
|
||||
#endif
|
||||
|
||||
#if HAVE_A
|
||||
unsigned int a_ops[] = {0, (unsigned int)a, fa, (unsigned int)a, fa};
|
||||
unsigned int a_opa = a_ops[zb->blenda.op_alpha] ^ zb->blenda.xor_a;
|
||||
unsigned int a_opb = a_ops[zb->blendb.op_alpha] ^ zb->blendb.xor_a;
|
||||
(void)a_opa;
|
||||
(void)a_opb;
|
||||
a = MODE_ALPHA(a, a_opa, fa, a_opb);
|
||||
#else
|
||||
a = fa;
|
||||
#endif
|
||||
|
||||
result = RGBA_TO_PIXEL(r, g, b, a);
|
||||
}
|
||||
|
||||
|
|
@ -36,25 +76,67 @@ FNAME(store_pixel) (ZBuffer *zb, PIXEL &result, int r, int g, int b, int a) {
|
|||
|
||||
static void
|
||||
FNAME_S(store_pixel) (ZBuffer *zb, PIXEL &result, int r, int g, int b, int a) {
|
||||
#if HAVE_R || HAVE_G || HAVE_B || HAVE_A
|
||||
unsigned int fr = PIXEL_SR(result);
|
||||
unsigned int fg = PIXEL_SG(result);
|
||||
unsigned int fb = PIXEL_SB(result);
|
||||
unsigned int fa = PIXEL_A(result);
|
||||
|
||||
r = STORE_PIXEL_0(fr, ((unsigned int)r * OP_A(fr, r) >> 16) + ((unsigned int)fr * OP_B(fr, r) >> 16));
|
||||
g = STORE_PIXEL_1(fg, ((unsigned int)g * OP_A(fg, g) >> 16) + ((unsigned int)fg * OP_B(fg, g) >> 16));
|
||||
b = STORE_PIXEL_2(fb, ((unsigned int)b * OP_A(fb, b) >> 16) + ((unsigned int)fb * OP_B(fb, b) >> 16));
|
||||
a = STORE_PIXEL_3(fa, ((unsigned int)a * OP_A(fa, a) >> 16) + ((unsigned int)fa * OP_B(fa, a) >> 16));
|
||||
#if HAVE_R
|
||||
unsigned int r_ops[] = {0, (unsigned int)r, fr, (unsigned int)a, fa};
|
||||
unsigned int r_opa = r_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_r;
|
||||
unsigned int r_opb = r_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_r;
|
||||
(void)r_opa;
|
||||
(void)r_opb;
|
||||
r = MODE_RGB(r, r_opa, fr, r_opb);
|
||||
#else
|
||||
r = fr;
|
||||
#endif
|
||||
|
||||
#if HAVE_G
|
||||
unsigned int g_ops[] = {0, (unsigned int)g, fg, (unsigned int)a, fa};
|
||||
unsigned int g_opa = g_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_g;
|
||||
unsigned int g_opb = g_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_g;
|
||||
(void)g_opa;
|
||||
(void)g_opb;
|
||||
g = MODE_RGB(g, g_opa, fg, g_opb);
|
||||
#else
|
||||
g = fg;
|
||||
#endif
|
||||
|
||||
#if HAVE_B
|
||||
unsigned int b_ops[] = {0, (unsigned int)b, fb, (unsigned int)a, fa};
|
||||
unsigned int b_opa = b_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_b;
|
||||
unsigned int b_opb = b_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_b;
|
||||
(void)b_opa;
|
||||
(void)b_opb;
|
||||
b = MODE_RGB(b, b_opa, fb, b_opb);
|
||||
#else
|
||||
b = fb;
|
||||
#endif
|
||||
|
||||
#if HAVE_A
|
||||
unsigned int a_ops[] = {0, (unsigned int)a, fa, (unsigned int)a, fa};
|
||||
unsigned int a_opa = a_ops[zb->blenda.op_alpha] ^ zb->blenda.xor_a;
|
||||
unsigned int a_opb = a_ops[zb->blendb.op_alpha] ^ zb->blendb.xor_a;
|
||||
(void)a_opa;
|
||||
(void)a_opb;
|
||||
a = MODE_ALPHA(a, a_opa, fa, a_opb);
|
||||
#else
|
||||
a = fa;
|
||||
#endif
|
||||
|
||||
result = SRGBA_TO_PIXEL(r, g, b, a);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef FNAME_S
|
||||
#endif
|
||||
|
||||
#undef FNAME
|
||||
#undef OP_A
|
||||
#undef OP_B
|
||||
#undef STORE_PIXEL_0
|
||||
#undef STORE_PIXEL_1
|
||||
#undef STORE_PIXEL_2
|
||||
#undef STORE_PIXEL_3
|
||||
#undef MODE_RGB
|
||||
#undef MODE_ALPHA
|
||||
#undef HAVE_R
|
||||
#undef HAVE_G
|
||||
#undef HAVE_B
|
||||
#undef HAVE_A
|
||||
|
|
|
|||
|
|
@ -7,44 +7,32 @@ Each different combination of options is compiled to a different
|
|||
inner-loop store function. The code in tinyGraphicsStateGuardian.cxx
|
||||
will select the appropriate function pointer at draw time. """
|
||||
|
||||
Operands = [
|
||||
'zero', 'one',
|
||||
'icolor', 'micolor',
|
||||
'fcolor', 'mfcolor',
|
||||
'ialpha', 'mialpha',
|
||||
'falpha', 'mfalpha',
|
||||
'ccolor', 'mccolor',
|
||||
'calpha', 'mcalpha',
|
||||
Modes = [
|
||||
'add',
|
||||
'min',
|
||||
'max',
|
||||
]
|
||||
|
||||
CodeTable = {
|
||||
'zero' : '0',
|
||||
'one' : '0x10000',
|
||||
'icolor' : 'i',
|
||||
'micolor' : '0xffff - i',
|
||||
'fcolor' : 'f',
|
||||
'mfcolor' : '0xffff - f',
|
||||
'ialpha' : 'a',
|
||||
'mialpha' : '0xffff - a',
|
||||
'falpha' : 'fa',
|
||||
'mfalpha' : '0xffff - fa',
|
||||
'ccolor' : 'zb->blend_ ## i',
|
||||
'mccolor' : '0xffff - zb->blend_ ## i',
|
||||
'calpha' : 'zb->blend_a',
|
||||
'mcalpha' : '0xffff - zb->blend_a',
|
||||
}
|
||||
# We handle alpha write as a special "off" mode, reducing redundancy.
|
||||
AlphaModes = Modes + ['off']
|
||||
|
||||
CodeTable = {
|
||||
'add': 'STORE_PIX_CLAMP(((unsigned int)c * c_opa >> 16) + ((unsigned int)fc * c_opb >> 16))',
|
||||
'min': 'std::min((unsigned int)c, (unsigned int)fc)',
|
||||
'max': 'std::max((unsigned int)c, (unsigned int)fc)',
|
||||
'off': '(unsigned int)fc',
|
||||
}
|
||||
|
||||
bitnames = 'rgba'
|
||||
|
||||
def getFname(op_a, op_b, mask):
|
||||
def get_fname(rgb_mode, alpha_mode, mask):
|
||||
maskname = ''
|
||||
for b in range(4):
|
||||
for b in range(3):
|
||||
if (mask & (1 << b)):
|
||||
maskname += bitnames[b]
|
||||
else:
|
||||
maskname += '0'
|
||||
return 'store_pixel_%s_%s_%s' % (op_a, op_b, maskname)
|
||||
return 'store_pixel_%s_%s_%s' % (rgb_mode, alpha_mode, maskname)
|
||||
|
||||
# We write the code that actually instantiates the various
|
||||
# pixel-storing functions to store_pixel_code.h.
|
||||
|
|
@ -58,58 +46,44 @@ table = open('store_pixel_table.h', 'w')
|
|||
print('/* This file is generated code--do not edit. See store_pixel.py. */', file=table)
|
||||
print('', file=table)
|
||||
|
||||
for op_a in Operands:
|
||||
for op_b in Operands:
|
||||
for mask in range(0, 16):
|
||||
fname = getFname(op_a, op_b, mask)
|
||||
for rgb_mode in Modes:
|
||||
for alpha_mode in AlphaModes:
|
||||
for mask in range(0, 8):
|
||||
fname = get_fname(rgb_mode, alpha_mode, mask)
|
||||
print('#define FNAME(name) %s' % (fname), file=code)
|
||||
if mask & (1 | 2 | 3):
|
||||
if mask != 0:
|
||||
print('#define FNAME_S(name) %s_s' % (fname), file=code)
|
||||
|
||||
print('#define OP_A(f, i) ((unsigned int)(%s))' % (CodeTable[op_a]), file=code)
|
||||
print('#define OP_B(f, i) ((unsigned int)(%s))' % (CodeTable[op_b]), file=code)
|
||||
for b in range(0, 4):
|
||||
print('#define MODE_RGB(c, c_opa, fc, c_opb) %s' % (CodeTable[rgb_mode]), file=code)
|
||||
print('#define MODE_ALPHA(c, c_opa, fc, c_opb) %s' % (CodeTable[alpha_mode]), file=code)
|
||||
for b in range(0, 3):
|
||||
if (mask & (1 << b)):
|
||||
print("#define STORE_PIXEL_%s(fr, r) STORE_PIX_CLAMP(r)" % (b), file=code)
|
||||
else:
|
||||
print("#define STORE_PIXEL_%s(fr, r) (fr)" % (b), file=code)
|
||||
print("#define HAVE_%s 1" % (bitnames[b].upper()), file=code)
|
||||
if alpha_mode != 'off':
|
||||
print("#define HAVE_A 1", file=code)
|
||||
print('#include "store_pixel.h"', file=code)
|
||||
print('', file=code)
|
||||
|
||||
|
||||
# Now, generate the table of function pointers.
|
||||
arraySize = '[%s][%s][16]' % (len(Operands), len(Operands))
|
||||
arraySize = '[%s][%s][8][2]' % (len(Modes), len(AlphaModes))
|
||||
|
||||
print('extern const ZB_storePixelFunc store_pixel_funcs%s;' % (arraySize), file=table)
|
||||
print('const ZB_storePixelFunc store_pixel_funcs%s = {' % (arraySize), file=code)
|
||||
|
||||
for op_a in Operands:
|
||||
for rgb_mode in Modes:
|
||||
print(' {', file=code)
|
||||
for op_b in Operands:
|
||||
for alpha_mode in AlphaModes:
|
||||
print(' {', file=code)
|
||||
for mask in range(0, 16):
|
||||
fname = getFname(op_a, op_b, mask)
|
||||
print(' %s,' % (fname), file=code)
|
||||
for mask in range(0, 8):
|
||||
fname = get_fname(rgb_mode, alpha_mode, mask)
|
||||
if mask != 0:
|
||||
fname_s = fname + '_s'
|
||||
else:
|
||||
fname_s = fname
|
||||
print(' {%s, %s},' % (fname, fname_s), file=code)
|
||||
print(' },', file=code)
|
||||
print(' },', file=code)
|
||||
print('};', file=code)
|
||||
|
||||
print('', file=code)
|
||||
|
||||
# Now do this again, but for the sRGB function pointers.
|
||||
print('extern const ZB_storePixelFunc store_pixel_funcs_sRGB%s;' % (arraySize), file=table)
|
||||
print('const ZB_storePixelFunc store_pixel_funcs_sRGB%s = {' % (arraySize), file=code)
|
||||
|
||||
for op_a in Operands:
|
||||
print(' {', file=code)
|
||||
for op_b in Operands:
|
||||
print(' {', file=code)
|
||||
for mask in range(0, 16):
|
||||
fname = getFname(op_a, op_b, mask)
|
||||
if mask & (1 | 2 | 3):
|
||||
print(' %s_s,' % (fname), file=code)
|
||||
else:
|
||||
print(' %s,' % (fname), file=code)
|
||||
print(' },', file=code)
|
||||
print(' },', file=code)
|
||||
print('};', file=code)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,4 +1,3 @@
|
|||
/* This file is generated code--do not edit. See store_pixel.py. */
|
||||
|
||||
extern const ZB_storePixelFunc store_pixel_funcs[14][14][16];
|
||||
extern const ZB_storePixelFunc store_pixel_funcs_sRGB[14][14][16];
|
||||
extern const ZB_storePixelFunc store_pixel_funcs[3][4][8][2];
|
||||
|
|
|
|||
|
|
@ -770,96 +770,100 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
|
|||
|
||||
int color_write_state = 0; // cstore
|
||||
|
||||
const ColorWriteAttrib *target_color_write = DCAST(ColorWriteAttrib, _target_rs->get_attrib_def(ColorWriteAttrib::get_class_slot()));
|
||||
const ColorWriteAttrib *target_color_write;
|
||||
_target_rs->get_attrib_def(target_color_write);
|
||||
unsigned int color_channels =
|
||||
target_color_write->get_channels() & _color_write_mask;
|
||||
unsigned int rgb_channels = color_channels & ColorWriteAttrib::C_rgb;
|
||||
|
||||
if (color_channels == ColorWriteAttrib::C_all) {
|
||||
if (srgb_blend) {
|
||||
color_write_state = 4; // csstore
|
||||
} else {
|
||||
color_write_state = 0; // cstore
|
||||
}
|
||||
} else {
|
||||
// Implement a color mask.
|
||||
int op_a = get_color_blend_op(ColorBlendAttrib::O_one);
|
||||
int op_b = get_color_blend_op(ColorBlendAttrib::O_zero);
|
||||
|
||||
if (srgb_blend) {
|
||||
_c->zb->store_pix_func = store_pixel_funcs_sRGB[op_a][op_b][color_channels];
|
||||
} else {
|
||||
_c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
|
||||
}
|
||||
color_write_state = 2; // cgeneral
|
||||
}
|
||||
|
||||
const TransparencyAttrib *target_transparency = DCAST(TransparencyAttrib, _target_rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
|
||||
switch (target_transparency->get_mode()) {
|
||||
case TransparencyAttrib::M_alpha:
|
||||
case TransparencyAttrib::M_dual:
|
||||
if (color_channels == ColorWriteAttrib::C_all) {
|
||||
if (srgb_blend) {
|
||||
color_write_state = 5; // csblend
|
||||
} else {
|
||||
color_write_state = 1; // cblend
|
||||
}
|
||||
} else {
|
||||
// Implement a color mask, with alpha blending.
|
||||
int op_a = get_color_blend_op(ColorBlendAttrib::O_incoming_alpha);
|
||||
int op_b = get_color_blend_op(ColorBlendAttrib::O_one_minus_incoming_alpha);
|
||||
|
||||
if (srgb_blend) {
|
||||
_c->zb->store_pix_func = store_pixel_funcs_sRGB[op_a][op_b][color_channels];
|
||||
} else {
|
||||
_c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
|
||||
}
|
||||
color_write_state = 2; // cgeneral
|
||||
}
|
||||
break;
|
||||
|
||||
case TransparencyAttrib::M_premultiplied_alpha:
|
||||
{
|
||||
// Implement a color mask, with pre-multiplied alpha blending.
|
||||
int op_a = get_color_blend_op(ColorBlendAttrib::O_one);
|
||||
int op_b = get_color_blend_op(ColorBlendAttrib::O_one_minus_incoming_alpha);
|
||||
|
||||
if (srgb_blend) {
|
||||
_c->zb->store_pix_func = store_pixel_funcs_sRGB[op_a][op_b][color_channels];
|
||||
} else {
|
||||
_c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
|
||||
}
|
||||
color_write_state = 2; // cgeneral
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const ColorBlendAttrib *target_color_blend = DCAST(ColorBlendAttrib, _target_rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
|
||||
if (target_color_blend->get_mode() == ColorBlendAttrib::M_add) {
|
||||
// If we have a color blend set that we can support, it overrides the
|
||||
// transparency set.
|
||||
LColor c = target_color_blend->get_color();
|
||||
_c->zb->blend_r = (int)(c[0] * ZB_POINT_RED_MAX);
|
||||
_c->zb->blend_g = (int)(c[1] * ZB_POINT_GREEN_MAX);
|
||||
_c->zb->blend_b = (int)(c[2] * ZB_POINT_BLUE_MAX);
|
||||
_c->zb->blend_a = (int)(c[3] * ZB_POINT_ALPHA_MAX);
|
||||
|
||||
int op_a = get_color_blend_op(target_color_blend->get_operand_a());
|
||||
int op_b = get_color_blend_op(target_color_blend->get_operand_b());
|
||||
|
||||
if (srgb_blend) {
|
||||
_c->zb->store_pix_func = store_pixel_funcs_sRGB[op_a][op_b][color_channels];
|
||||
} else {
|
||||
_c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
|
||||
}
|
||||
color_write_state = 2; // cgeneral
|
||||
}
|
||||
const ColorBlendAttrib *target_color_blend;
|
||||
_target_rs->get_attrib_def(target_color_blend);
|
||||
|
||||
if (color_channels == ColorWriteAttrib::C_off) {
|
||||
color_write_state = 3; // coff
|
||||
}
|
||||
else if (target_color_blend->get_mode() != ColorBlendAttrib::M_none) {
|
||||
// If we have a color blend set that we can support, it overrides the
|
||||
// transparency set.
|
||||
|
||||
int rgb_mode = get_color_blend_mode(target_color_blend->get_mode());
|
||||
int alpha_mode;
|
||||
if (color_channels & ColorWriteAttrib::C_alpha) {
|
||||
alpha_mode = get_color_blend_mode(target_color_blend->get_alpha_mode());
|
||||
} else {
|
||||
// Disabled alpha write is encoded as a separate alpha mode, to cut down
|
||||
// on redundancy in the store_pixel table.
|
||||
alpha_mode = 3;
|
||||
}
|
||||
|
||||
LColor c = target_color_blend->get_color();
|
||||
unsigned int cr = (int)(c[0] * ZB_POINT_RED_MAX);
|
||||
unsigned int cg = (int)(c[1] * ZB_POINT_GREEN_MAX);
|
||||
unsigned int cb = (int)(c[2] * ZB_POINT_BLUE_MAX);
|
||||
unsigned int ca = (int)(c[3] * ZB_POINT_ALPHA_MAX);
|
||||
|
||||
setup_color_blend(_c->zb->blenda, target_color_blend->get_operand_a(),
|
||||
target_color_blend->get_alpha_operand_a(),
|
||||
cr, cg, cb, ca);
|
||||
setup_color_blend(_c->zb->blendb, target_color_blend->get_operand_b(),
|
||||
target_color_blend->get_alpha_operand_b(),
|
||||
cr, cg, cb, ca);
|
||||
|
||||
_c->zb->store_pix_func = store_pixel_funcs[rgb_mode][alpha_mode][rgb_channels][srgb_blend];
|
||||
color_write_state = 2; // cgeneral
|
||||
}
|
||||
else {
|
||||
const TransparencyAttrib *target_transparency;
|
||||
_target_rs->get_attrib_def(target_transparency);
|
||||
|
||||
switch (target_transparency->get_mode()) {
|
||||
case TransparencyAttrib::M_alpha:
|
||||
case TransparencyAttrib::M_dual:
|
||||
if (color_channels == ColorWriteAttrib::C_all) {
|
||||
if (srgb_blend) {
|
||||
color_write_state = 5; // csblend
|
||||
} else {
|
||||
color_write_state = 1; // cblend
|
||||
}
|
||||
} else {
|
||||
// Implement a color mask, with alpha blending.
|
||||
setup_color_blend(_c->zb->blenda, ColorBlendAttrib::O_incoming_alpha, ColorBlendAttrib::O_one);
|
||||
setup_color_blend(_c->zb->blendb, ColorBlendAttrib::O_one_minus_incoming_alpha, ColorBlendAttrib::O_one_minus_incoming_alpha);
|
||||
int alpha_mode = (color_channels & ColorWriteAttrib::C_alpha) ? 0 : 3;
|
||||
_c->zb->store_pix_func = store_pixel_funcs[0][alpha_mode][rgb_channels][srgb_blend];
|
||||
color_write_state = 2; // cgeneral
|
||||
}
|
||||
break;
|
||||
|
||||
case TransparencyAttrib::M_premultiplied_alpha:
|
||||
{
|
||||
// Implement a color mask, with pre-multiplied alpha blending.
|
||||
setup_color_blend(_c->zb->blenda, ColorBlendAttrib::O_one, ColorBlendAttrib::O_one);
|
||||
setup_color_blend(_c->zb->blendb, ColorBlendAttrib::O_one_minus_incoming_alpha, ColorBlendAttrib::O_one_minus_incoming_alpha);
|
||||
int alpha_mode = (color_channels & ColorWriteAttrib::C_alpha) ? 0 : 3;
|
||||
_c->zb->store_pix_func = store_pixel_funcs[0][alpha_mode][rgb_channels][srgb_blend];
|
||||
color_write_state = 2; // cgeneral
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (color_channels == ColorWriteAttrib::C_all) {
|
||||
if (srgb_blend) {
|
||||
color_write_state = 4; // csstore
|
||||
} else {
|
||||
color_write_state = 0; // cstore
|
||||
}
|
||||
} else {
|
||||
// Implement a color mask.
|
||||
setup_color_blend(_c->zb->blenda, ColorBlendAttrib::O_one, ColorBlendAttrib::O_one);
|
||||
setup_color_blend(_c->zb->blendb, ColorBlendAttrib::O_zero, ColorBlendAttrib::O_zero);
|
||||
int alpha_mode = (color_channels & ColorWriteAttrib::C_alpha) ? 0 : 3;
|
||||
_c->zb->store_pix_func = store_pixel_funcs[0][alpha_mode][rgb_channels][srgb_blend];
|
||||
color_write_state = 2; // cgeneral
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int alpha_test_state = 0; // anone
|
||||
const AlphaTestAttrib *target_alpha_test = DCAST(AlphaTestAttrib, _target_rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
|
||||
|
|
@ -3098,66 +3102,141 @@ load_matrix(M4 *matrix, const TransformState *transform) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the integer element of store_pixel_funcs (as defined by
|
||||
* store_pixel.py) that corresponds to the indicated ColorBlendAttrib operand
|
||||
* code.
|
||||
* Returns the integer index into the array of store_pixel functions
|
||||
* corresponding to the given blend mode.
|
||||
*/
|
||||
int TinyGraphicsStateGuardian::
|
||||
get_color_blend_mode(ColorBlendAttrib::Mode mode) {
|
||||
switch (mode) {
|
||||
case ColorBlendAttrib::M_none:
|
||||
case ColorBlendAttrib::M_add:
|
||||
case ColorBlendAttrib::M_subtract:
|
||||
case ColorBlendAttrib::M_inv_subtract:
|
||||
return 0;
|
||||
case ColorBlendAttrib::M_min:
|
||||
return 1;
|
||||
case ColorBlendAttrib::M_max:
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer index into the array of operands computed by store_pixel
|
||||
* that corresponds to the indicated ColorBlendAttrib operand code.
|
||||
*/
|
||||
int TinyGraphicsStateGuardian::
|
||||
get_color_blend_op(ColorBlendAttrib::Operand operand) {
|
||||
switch (operand) {
|
||||
case ColorBlendAttrib::O_zero:
|
||||
return 0;
|
||||
case ColorBlendAttrib::O_one:
|
||||
return 1;
|
||||
case ColorBlendAttrib::O_incoming_color:
|
||||
return 2;
|
||||
case ColorBlendAttrib::O_one_minus_incoming_color:
|
||||
return 3;
|
||||
case ColorBlendAttrib::O_fbuffer_color:
|
||||
return 4;
|
||||
case ColorBlendAttrib::O_one_minus_fbuffer_color:
|
||||
return 5;
|
||||
case ColorBlendAttrib::O_incoming_alpha:
|
||||
return 6;
|
||||
case ColorBlendAttrib::O_one_minus_incoming_alpha:
|
||||
return 7;
|
||||
case ColorBlendAttrib::O_fbuffer_alpha:
|
||||
return 8;
|
||||
case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
|
||||
return 9;
|
||||
case ColorBlendAttrib::O_constant_color:
|
||||
return 10;
|
||||
case ColorBlendAttrib::O_one_minus_constant_color:
|
||||
return 11;
|
||||
case ColorBlendAttrib::O_constant_alpha:
|
||||
return 12;
|
||||
case ColorBlendAttrib::O_one_minus_constant_alpha:
|
||||
return 13;
|
||||
|
||||
case ColorBlendAttrib::O_incoming_color_saturate:
|
||||
return 1;
|
||||
|
||||
case ColorBlendAttrib::O_incoming1_color:
|
||||
return 1;
|
||||
case ColorBlendAttrib::O_one_minus_incoming1_color:
|
||||
return 0;
|
||||
case ColorBlendAttrib::O_incoming1_alpha:
|
||||
return 1;
|
||||
case ColorBlendAttrib::O_one_minus_incoming1_alpha:
|
||||
return 0;
|
||||
|
||||
case ColorBlendAttrib::O_color_scale:
|
||||
return 10;
|
||||
case ColorBlendAttrib::O_one_minus_color_scale:
|
||||
return 11;
|
||||
case ColorBlendAttrib::O_alpha_scale:
|
||||
return 12;
|
||||
case ColorBlendAttrib::O_one_minus_alpha_scale:
|
||||
return 13;
|
||||
return 0;
|
||||
case ColorBlendAttrib::O_incoming_color:
|
||||
case ColorBlendAttrib::O_one_minus_incoming_color:
|
||||
case ColorBlendAttrib::O_incoming_color_saturate:
|
||||
case ColorBlendAttrib::O_incoming1_color:
|
||||
case ColorBlendAttrib::O_one_minus_incoming1_color:
|
||||
case ColorBlendAttrib::O_incoming1_alpha:
|
||||
case ColorBlendAttrib::O_one_minus_incoming1_alpha:
|
||||
return 1;
|
||||
case ColorBlendAttrib::O_fbuffer_color:
|
||||
case ColorBlendAttrib::O_one_minus_fbuffer_color:
|
||||
return 2;
|
||||
case ColorBlendAttrib::O_incoming_alpha:
|
||||
case ColorBlendAttrib::O_one_minus_incoming_alpha:
|
||||
return 3;
|
||||
case ColorBlendAttrib::O_fbuffer_alpha:
|
||||
case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the color blend operand should be inverted.
|
||||
*/
|
||||
bool TinyGraphicsStateGuardian::
|
||||
is_color_blend_op_inverted(ColorBlendAttrib::Operand operand) {
|
||||
switch (operand) {
|
||||
case ColorBlendAttrib::O_zero:
|
||||
case ColorBlendAttrib::O_constant_color:
|
||||
case ColorBlendAttrib::O_constant_alpha:
|
||||
case ColorBlendAttrib::O_color_scale:
|
||||
case ColorBlendAttrib::O_alpha_scale:
|
||||
case ColorBlendAttrib::O_incoming_color:
|
||||
case ColorBlendAttrib::O_incoming_color_saturate:
|
||||
case ColorBlendAttrib::O_incoming1_color:
|
||||
case ColorBlendAttrib::O_incoming1_alpha:
|
||||
case ColorBlendAttrib::O_fbuffer_color:
|
||||
case ColorBlendAttrib::O_incoming_alpha:
|
||||
case ColorBlendAttrib::O_fbuffer_alpha:
|
||||
return false;
|
||||
case ColorBlendAttrib::O_one:
|
||||
case ColorBlendAttrib::O_one_minus_constant_color:
|
||||
case ColorBlendAttrib::O_one_minus_constant_alpha:
|
||||
case ColorBlendAttrib::O_one_minus_color_scale:
|
||||
case ColorBlendAttrib::O_one_minus_alpha_scale:
|
||||
case ColorBlendAttrib::O_one_minus_incoming_color:
|
||||
case ColorBlendAttrib::O_one_minus_incoming1_color:
|
||||
case ColorBlendAttrib::O_one_minus_incoming1_alpha:
|
||||
case ColorBlendAttrib::O_one_minus_fbuffer_color:
|
||||
case ColorBlendAttrib::O_one_minus_incoming_alpha:
|
||||
case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the color blending state for the given blend operand.
|
||||
*/
|
||||
void TinyGraphicsStateGuardian::
|
||||
setup_color_blend(ZBlend &blend, ColorBlendAttrib::Operand op_rgb,
|
||||
ColorBlendAttrib::Operand op_alpha,
|
||||
int cr, int cg, int cb, int ca) {
|
||||
|
||||
blend.op_rgb = get_color_blend_op(op_rgb);
|
||||
blend.op_alpha = get_color_blend_op(op_alpha);
|
||||
|
||||
// If it's inverted (one minus), we xor the value with 0xffff
|
||||
unsigned int mask_rgb = is_color_blend_op_inverted(op_rgb) ? 0xffff : 0x0;
|
||||
unsigned int mask_alpha = is_color_blend_op_inverted(op_alpha) ? 0xffff : 0x0;
|
||||
|
||||
blend.xor_r = mask_rgb;
|
||||
blend.xor_g = mask_rgb;
|
||||
blend.xor_b = mask_rgb;
|
||||
blend.xor_a = mask_alpha;
|
||||
|
||||
// A constant factor is implemented by doing effectively O_zero ^ constant,
|
||||
// so we can conveniently reuse the xor mask field to store it!
|
||||
if (op_rgb == ColorBlendAttrib::O_constant_color ||
|
||||
op_rgb == ColorBlendAttrib::O_one_minus_constant_color) {
|
||||
blend.xor_r ^= cr;
|
||||
blend.xor_g ^= cg;
|
||||
blend.xor_b ^= cb;
|
||||
}
|
||||
if (op_rgb == ColorBlendAttrib::O_constant_alpha ||
|
||||
op_rgb == ColorBlendAttrib::O_one_minus_constant_alpha) {
|
||||
blend.xor_r ^= ca;
|
||||
blend.xor_g ^= ca;
|
||||
blend.xor_b ^= ca;
|
||||
}
|
||||
if (op_alpha == ColorBlendAttrib::O_constant_color ||
|
||||
op_alpha == ColorBlendAttrib::O_constant_alpha ||
|
||||
op_alpha == ColorBlendAttrib::O_one_minus_constant_color ||
|
||||
op_alpha == ColorBlendAttrib::O_one_minus_constant_alpha) {
|
||||
blend.xor_a ^= ca;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pointer to the appropriate filter function according to the
|
||||
* texture's filter type.
|
||||
|
|
|
|||
|
|
@ -125,7 +125,13 @@ private:
|
|||
void setup_material(GLMaterial *gl_material, const Material *material);
|
||||
void do_auto_rescale_normal();
|
||||
static void load_matrix(M4 *matrix, const TransformState *transform);
|
||||
static int get_color_blend_mode(ColorBlendAttrib::Mode mode);
|
||||
static int get_color_blend_op(ColorBlendAttrib::Operand operand);
|
||||
static bool is_color_blend_op_inverted(ColorBlendAttrib::Operand operand);
|
||||
static void setup_color_blend(ZBlend &blend,
|
||||
ColorBlendAttrib::Operand op_rgb,
|
||||
ColorBlendAttrib::Operand op_alpha,
|
||||
int cr=0, int cg=0, int cb=0, int ca=0);
|
||||
static ZB_lookupTextureFunc get_tex_filter_func(SamplerState::FilterType filter);
|
||||
static ZB_texWrapFunc get_tex_wrap_func(SamplerState::WrapMode wrap_mode);
|
||||
|
||||
|
|
|
|||
|
|
@ -158,6 +158,15 @@ struct ZTextureDef {
|
|||
PIXEL border_color;
|
||||
};
|
||||
|
||||
struct ZBlend {
|
||||
int op_rgb;
|
||||
int op_alpha;
|
||||
unsigned int xor_r;
|
||||
unsigned int xor_g;
|
||||
unsigned int xor_b;
|
||||
unsigned int xor_a;
|
||||
};
|
||||
|
||||
struct ZBuffer {
|
||||
int xsize,ysize;
|
||||
int linesize; /* line size, in bytes */
|
||||
|
|
@ -172,7 +181,8 @@ struct ZBuffer {
|
|||
int *ctable;
|
||||
ZTextureDef current_textures[MAX_TEXTURE_STAGES];
|
||||
int reference_alpha;
|
||||
int blend_r, blend_g, blend_b, blend_a;
|
||||
ZBlend blenda;
|
||||
ZBlend blendb;
|
||||
ZB_storePixelFunc store_pix_func;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue