support texture wrap modes

This commit is contained in:
David Rose 2009-01-21 22:38:42 +00:00
parent e8543823a6
commit 8d96071d4b
10 changed files with 495 additions and 286 deletions

View File

@ -84,6 +84,12 @@ ConfigVariableBool td_ignore_mipmaps
PRC_DESC("Configure this true to disable use of mipmaps on the "
"tinydisplay software renderer."));
ConfigVariableBool td_ignore_clamp
("td-ignore-clamp", false,
PRC_DESC("Configure this true to disable texture clamp mode and other "
"wrap modes other than repeat (all textures will repeat, which "
"is a little cheaper)."));
ConfigVariableBool td_perspective_textures
("td-perspective-textures", true,
PRC_DESC("Configure this false to disable use of perspective-correct "

View File

@ -36,6 +36,7 @@ extern ConfigVariableInt osx_mouse_wheel_scale;
extern ConfigVariableInt td_texture_ram;
extern ConfigVariableBool td_ignore_mipmaps;
extern ConfigVariableBool td_ignore_clamp;
extern ConfigVariableBool td_perspective_textures;
#endif

View File

@ -1371,6 +1371,10 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), 1)) {
return false;
}
gltex->border_color.v[0] = 0.0f;
gltex->border_color.v[1] = 0.0f;
gltex->border_color.v[2] = 0.0f;
gltex->border_color.v[3] = 0.0f;
PIXEL *ip = gltex->levels[0].pixmap + gltex->xsize * gltex->ysize;
PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB;
@ -1683,7 +1687,22 @@ update_texture(TextureContext *tc, bool force, int stage_index) {
GLTexture *gltex = &gtc->_gltex;
_c->current_textures[stage_index] = gltex;
_c->zb->current_textures[stage_index] = gltex->levels;
ZTextureDef *texture_def = &_c->zb->current_textures[stage_index];
texture_def->levels = gltex->levels;
texture_def->s_max = gltex->s_max;
texture_def->t_max = gltex->t_max;
const V4 &bc = gltex->border_color;
int r = (int)(bc.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN)
+ ZB_POINT_RED_MIN);
int g = (int)(bc.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN)
+ ZB_POINT_GREEN_MIN);
int b = (int)(bc.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN)
+ ZB_POINT_BLUE_MIN);
int a = (int)(bc.v[3] * (ZB_POINT_ALPHA_MAX - ZB_POINT_ALPHA_MIN)
+ ZB_POINT_ALPHA_MIN);
texture_def->border_color = RGBA_TO_PIXEL(r, g, b, a);
return true;
}
@ -2159,11 +2178,12 @@ do_issue_texture() {
}
nassertv(num_stages <= MAX_TEXTURE_STAGES);
Texture::QualityLevel quality_level = _texture_quality_override;
Texture::FilterType minfilter = Texture::FT_nearest;
Texture::FilterType magfilter = Texture::FT_nearest;
bool all_use_mipmaps = true;
bool all_replace = true;
bool all_nearest = true;
bool all_mipmap_nearest = true;
bool any_mipmap = false;
bool needs_general = false;
Texture::QualityLevel best_quality_level = Texture::QL_default;
for (int si = 0; si < num_stages; ++si) {
TextureStage *stage = _target_texture->get_on_ff_stage(si);
@ -2187,17 +2207,100 @@ do_issue_texture() {
all_replace = false;
}
if (quality_level < texture->get_quality_level()) {
Texture::QualityLevel quality_level = _texture_quality_override;
if (quality_level == Texture::QL_default) {
quality_level = texture->get_quality_level();
}
if (minfilter < texture->get_minfilter()) {
minfilter = texture->get_minfilter();
if (quality_level == Texture::QL_default) {
quality_level = texture_quality_level;
}
if (magfilter < texture->get_magfilter()) {
magfilter = texture->get_magfilter();
best_quality_level = max(best_quality_level, quality_level);
ZTextureDef *texture_def = &_c->zb->current_textures[si];
// Fill in the filter func pointers. These may not actually get
// called, if we decide below we can inline the filters.
Texture::FilterType minfilter = texture->get_minfilter();
Texture::FilterType magfilter = texture->get_magfilter();
if (td_ignore_mipmaps && Texture::is_mipmap(minfilter)) {
// Downgrade mipmaps.
if (minfilter == Texture::FT_nearest_mipmap_nearest) {
minfilter = Texture::FT_nearest;
} else {
minfilter = Texture::FT_linear;
}
}
if (!texture->uses_mipmaps()) {
all_use_mipmaps = false;
// Depending on this particular texture's quality level, we may
// downgrade the requested filters.
if (quality_level == Texture::QL_fastest) {
minfilter = Texture::FT_nearest;
magfilter = Texture::FT_nearest;
} else if (quality_level == Texture::QL_normal) {
if (Texture::is_mipmap(minfilter)) {
minfilter = Texture::FT_nearest_mipmap_nearest;
} else {
minfilter = Texture::FT_nearest;
}
magfilter = Texture::FT_nearest;
}
texture_def->tex_minfilter_func = get_tex_filter_func(minfilter);
texture_def->tex_magfilter_func = get_tex_filter_func(magfilter);
Texture::WrapMode wrap_u = texture->get_wrap_u();
Texture::WrapMode wrap_v = texture->get_wrap_v();
if (td_ignore_clamp) {
wrap_u = Texture::WM_repeat;
wrap_v = Texture::WM_repeat;
}
if (wrap_u != Texture::WM_repeat || wrap_v != Texture::WM_repeat) {
// We have some nonstandard wrap mode. This will force the use
// of the general texfilter mode.
needs_general = true;
// We need another level of indirection to implement the
// different texcoord wrap modes. This means we will be using
// the _impl function pointers, which are called by the toplevel
// function.
texture_def->tex_minfilter_func_impl = texture_def->tex_minfilter_func;
texture_def->tex_magfilter_func_impl = texture_def->tex_magfilter_func;
// Now assign the toplevel function pointer to do the
// appropriate texture coordinate wrapping/clamping.
texture_def->tex_minfilter_func = apply_wrap_general_minfilter;
texture_def->tex_magfilter_func = apply_wrap_general_magfilter;
texture_def->tex_wrap_u_func = get_tex_wrap_func(wrap_u);
texture_def->tex_wrap_v_func = get_tex_wrap_func(wrap_v);
// The following special cases are handled inline, rather than
// relying on the above wrap function pointers.
if (wrap_u && Texture::WM_border_color && wrap_v == Texture::WM_border_color) {
texture_def->tex_minfilter_func = apply_wrap_border_color_minfilter;
texture_def->tex_magfilter_func = apply_wrap_border_color_magfilter;
} else if (wrap_u && Texture::WM_clamp && wrap_v == Texture::WM_clamp) {
texture_def->tex_minfilter_func = apply_wrap_clamp_minfilter;
texture_def->tex_magfilter_func = apply_wrap_clamp_magfilter;
}
}
if (minfilter != Texture::FT_nearest || magfilter != Texture::FT_nearest) {
all_nearest = false;
}
if (minfilter != Texture::FT_nearest_mipmap_nearest ||
magfilter != Texture::FT_nearest) {
all_mipmap_nearest = false;
}
if (Texture::is_mipmap(minfilter)) {
any_mipmap = true;
}
}
@ -2214,33 +2317,21 @@ do_issue_texture() {
_texturing_state = 1; // textured (not perspective correct)
}
if (quality_level == Texture::QL_default) {
quality_level = texture_quality_level;
}
if (quality_level == Texture::QL_best) {
if (best_quality_level == Texture::QL_best) {
// This is the most generic texture filter. Slow, but pretty.
_texfilter_state = 2; // tgeneral
if (!all_use_mipmaps && Texture::is_mipmap(minfilter)) {
// We can't enable mipmaps unless all the textures in the stack
// enable mipmaps.
minfilter = Texture::FT_linear;
if (!needs_general) {
if (all_nearest) {
// This case is inlined.
_texfilter_state = 0; // tnearest
} else if (all_mipmap_nearest) {
// So is this case.
_texfilter_state = 1; // tmipmap
}
}
_c->zb->tex_minfilter_func = get_tex_filter_func(minfilter);
_c->zb->tex_magfilter_func = get_tex_filter_func(magfilter);
if (minfilter == Texture::FT_nearest && magfilter == Texture::FT_nearest) {
// This case is inlined.
_texfilter_state = 0; // tnearest
} else if (minfilter == Texture::FT_nearest_mipmap_nearest &&
magfilter == Texture::FT_nearest) {
// So is this case.
_texfilter_state = 1; // tmipmap
}
} else if (quality_level == Texture::QL_fastest) {
} else if (best_quality_level == Texture::QL_fastest) {
// This is the cheapest texture filter. We disallow mipmaps and
// perspective correctness.
_texfilter_state = 0; // tnearest
@ -2251,9 +2342,15 @@ do_issue_texture() {
// there are no mipmaps, and mipmap_nearest if there are any
// mipmaps--these are the two inlined filters.
_texfilter_state = 0; // tnearest
if (all_use_mipmaps && !td_ignore_mipmaps) {
if (any_mipmap) {
_texfilter_state = 1; // tmipmap
}
if (needs_general) {
// To support nonstandard texcoord wrapping etc, we need to
// force the general texfilter mode.
_texfilter_state = 2; // tgeneral
}
}
}
@ -2365,6 +2462,11 @@ upload_texture(TinyTextureContext *gtc, bool force) {
if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), num_levels)) {
return false;
}
Colorf border_color = tex->get_border_color();
gltex->border_color.v[0] = border_color[0];
gltex->border_color.v[1] = border_color[1];
gltex->border_color.v[2] = border_color[2];
gltex->border_color.v[3] = border_color[3];
int bytecount = 0;
int xsize = gltex->xsize;
@ -2470,6 +2572,11 @@ upload_simple_texture(TinyTextureContext *gtc) {
if (!setup_gltex(gltex, width, height, 1)) {
return false;
}
Colorf border_color = tex->get_border_color();
gltex->border_color.v[0] = border_color[0];
gltex->border_color.v[1] = border_color[1];
gltex->border_color.v[2] = border_color[2];
gltex->border_color.v[3] = border_color[3];
ZTextureLevel *dest = &gltex->levels[0];
memcpy(dest->pixmap, image_ptr, image_size);
@ -2546,9 +2653,10 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
next_buffer += bytecount;
nassertr(next_buffer <= end_of_buffer, false);
dest->s_mask = (1 << (s_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS);
dest->t_mask = (1 << (t_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS);
dest->t_shift = (ZB_POINT_ST_FRAC_BITS - s_bits);
dest->s_mask = ((1 << (s_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
dest->t_mask = ((1 << (t_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
dest->s_shift = (ZB_POINT_ST_FRAC_BITS + level);
dest->t_shift = (ZB_POINT_ST_FRAC_BITS - s_bits + level);
x_size = max((x_size >> 1), 1);
y_size = max((y_size >> 1), 1);
@ -2982,33 +3090,48 @@ get_tex_filter_func(Texture::FilterType filter) {
return &lookup_texture_bilinear;
case Texture::FT_nearest_mipmap_nearest:
if (td_ignore_mipmaps) {
return &lookup_texture_nearest;
}
return &lookup_texture_mipmap_nearest;
case Texture::FT_nearest_mipmap_linear:
if (td_ignore_mipmaps) {
return &lookup_texture_nearest;
}
return &lookup_texture_mipmap_linear;
case Texture::FT_linear_mipmap_nearest:
if (td_ignore_mipmaps) {
return &lookup_texture_bilinear;
}
return &lookup_texture_mipmap_bilinear;
case Texture::FT_linear_mipmap_linear:
if (td_ignore_mipmaps) {
return &lookup_texture_bilinear;
}
return &lookup_texture_mipmap_trilinear;
default:
return &lookup_texture_nearest;
}
}
////////////////////////////////////////////////////////////////////
// Function: TinyGraphicsStateGuardian::get_tex_wrap_func
// Access: Private, Static
// Description: Returns the pointer to the appropriate wrap
// function according to the texture's wrap mode.
////////////////////////////////////////////////////////////////////
ZB_texWrapFunc TinyGraphicsStateGuardian::
get_tex_wrap_func(Texture::WrapMode wrap_mode) {
switch (wrap_mode) {
case Texture::WM_clamp:
case Texture::WM_border_color: // border_color is handled later.
return &texcoord_clamp;
case Texture::WM_repeat:
case Texture::WM_invalid:
return &texcoord_repeat;
case Texture::WM_mirror:
return &texcoord_mirror;
case Texture::WM_mirror_once:
return &texcoord_mirror_once;
}
return &texcoord_repeat;
}
////////////////////////////////////////////////////////////////////
// Function: TinyGraphicsStateGuardian::texgen_null

View File

@ -125,6 +125,7 @@ private:
static void load_matrix(M4 *matrix, const TransformState *transform);
static int get_color_blend_op(ColorBlendAttrib::Operand operand);
static ZB_lookupTextureFunc get_tex_filter_func(Texture::FilterType filter);
static ZB_texWrapFunc get_tex_wrap_func(Texture::WrapMode wrap_mode);
INLINE void clear_light_state();

View File

@ -36,6 +36,7 @@ ZBuffer *ZB_open(int xsize, int ysize, int mode,
zb = (ZBuffer *)gl_malloc(sizeof(ZBuffer));
if (zb == NULL)
return NULL;
memset(zb, 0, sizeof(ZBuffer));
/* xsize must be a multiple of 4 */
xsize = (xsize + 3) & ~3;
@ -82,9 +83,6 @@ ZBuffer *ZB_open(int xsize, int ysize, int mode,
zb->pbuf = (PIXEL *)frame_buffer;
}
zb->current_textures[0] = NULL;
zb->current_textures[1] = NULL;
return zb;
error:
gl_free(zb);
@ -375,25 +373,24 @@ void ZB_clear_viewport(ZBuffer * zb, int clear_z, ZPOINT z,
// Grab the nearest texel from the base level. This is also
// implemented inline as ZB_LOOKUP_TEXTURE_NEAREST.
PIXEL lookup_texture_nearest(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
PIXEL lookup_texture_nearest(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx)
{
return ZB_LOOKUP_TEXTURE_NEAREST(texture_levels, s, t);
return ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s, t);
}
// Bilinear filter four texels in the base level.
PIXEL lookup_texture_bilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
PIXEL lookup_texture_bilinear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx)
{
ZTextureLevel *base_level = texture_levels;
PIXEL p1, p2, p3, p4;
int sf, tf;
int r, g, b, a;
p1 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH);
p2 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s, t - ZB_ST_FRAC_HIGH);
p1 = ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH);
p2 = ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH);
sf = s & ZB_ST_FRAC_MASK;
p3 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s - ZB_ST_FRAC_HIGH, t);
p4 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s, t);
p3 = ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t);
p4 = ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s, t);
tf = t & ZB_ST_FRAC_MASK;
r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
@ -406,19 +403,19 @@ PIXEL lookup_texture_bilinear(ZTextureLevel *texture_levels, int s, int t, unsig
// Grab the nearest texel from the nearest mipmap level. This is also
// implemented inline as ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST.
PIXEL lookup_texture_mipmap_nearest(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
PIXEL lookup_texture_mipmap_nearest(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx)
{
return ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_levels, s, t, level);
return ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
}
// Linear filter the two texels from the two nearest mipmap levels.
PIXEL lookup_texture_mipmap_linear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
PIXEL lookup_texture_mipmap_linear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx)
{
PIXEL p1, p2;
int r, g, b, a;
p1 = ZB_LOOKUP_TEXTURE_NEAREST(texture_levels + level - 1, s >> (level - 1), t >> (level - 1));
p2 = ZB_LOOKUP_TEXTURE_NEAREST(texture_levels + level, s >> level, t >> level);
p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level - 1);
p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
unsigned int bitsize = (level - 1) + ZB_POINT_ST_FRAC_BITS;
r = LINEAR_FILTER_BITSIZE(PIXEL_R(p1), PIXEL_R(p2), level_dx, bitsize);
@ -430,23 +427,19 @@ PIXEL lookup_texture_mipmap_linear(ZTextureLevel *texture_levels, int s, int t,
}
// Bilinear filter four texels in the nearest mipmap level.
PIXEL lookup_texture_mipmap_bilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
PIXEL lookup_texture_mipmap_bilinear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx)
{
ZTextureLevel *base_level = texture_levels + level;
s >>= level;
t >>= level;
PIXEL p1, p2, p3, p4;
int sf, tf;
int r, g, b, a;
p1 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH);
p2 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s, t - ZB_ST_FRAC_HIGH);
sf = s & ZB_ST_FRAC_MASK;
p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH, level);
p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH, level);
sf = (s >> level) & ZB_ST_FRAC_MASK;
p3 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s - ZB_ST_FRAC_HIGH, t);
p4 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s, t);
tf = t & ZB_ST_FRAC_MASK;
p3 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t, level);
p4 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
tf = (t >> level) & ZB_ST_FRAC_MASK;
r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
@ -458,26 +451,22 @@ PIXEL lookup_texture_mipmap_bilinear(ZTextureLevel *texture_levels, int s, int t
// Bilinear filter four texels in each of the nearest two mipmap
// levels, then linear filter them together.
PIXEL lookup_texture_mipmap_trilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
PIXEL lookup_texture_mipmap_trilinear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx)
{
PIXEL p1a, p2a;
{
ZTextureLevel *base_level = texture_levels + level - 1;
int sl = s >> (level - 1);
int tl = t >> (level - 1);
PIXEL p1, p2, p3, p4;
int sf, tf;
int r, g, b, a;
p1 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl - ZB_ST_FRAC_HIGH, tl - ZB_ST_FRAC_HIGH);
p2 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl, tl - ZB_ST_FRAC_HIGH);
sf = sl & ZB_ST_FRAC_MASK;
p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH, level - 1);
p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH, level - 1);
sf = (s >> (level - 1)) & ZB_ST_FRAC_MASK;
p3 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl - ZB_ST_FRAC_HIGH, tl);
p4 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl, tl);
tf = tl & ZB_ST_FRAC_MASK;
p3 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t, level - 1);
p4 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level - 1);
tf = (t >> (level - 1)) & ZB_ST_FRAC_MASK;
r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
@ -487,21 +476,17 @@ PIXEL lookup_texture_mipmap_trilinear(ZTextureLevel *texture_levels, int s, int
}
{
ZTextureLevel *base_level = texture_levels + level;
int sl = s >> level;
int tl = t >> level;
PIXEL p1, p2, p3, p4;
int sf, tf;
int r, g, b, a;
p1 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl - ZB_ST_FRAC_HIGH, tl - ZB_ST_FRAC_HIGH);
p2 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl, tl - ZB_ST_FRAC_HIGH);
sf = sl & ZB_ST_FRAC_MASK;
p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH, level);
p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH, level);
sf = (s >> level) & ZB_ST_FRAC_MASK;
p3 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl - ZB_ST_FRAC_HIGH, tl);
p4 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl, tl);
tf = tl & ZB_ST_FRAC_MASK;
p3 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t, level);
p4 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
tf = (t >> level) & ZB_ST_FRAC_MASK;
r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
@ -519,3 +504,68 @@ PIXEL lookup_texture_mipmap_trilinear(ZTextureLevel *texture_levels, int s, int
return RGBA_TO_PIXEL(r, g, b, a);
}
// Apply the wrap mode to s and t coordinates by calling the generic
// wrap mode function.
PIXEL apply_wrap_general_minfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
s = (*texture_def->tex_wrap_u_func)(s, texture_def->s_max);
t = (*texture_def->tex_wrap_v_func)(t, texture_def->t_max);
return (*texture_def->tex_minfilter_func_impl)(texture_def, s, t, level, level_dx);
}
PIXEL apply_wrap_general_magfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
s = (*texture_def->tex_wrap_u_func)(s, texture_def->s_max);
t = (*texture_def->tex_wrap_v_func)(t, texture_def->t_max);
return (*texture_def->tex_magfilter_func_impl)(texture_def, s, t, level, level_dx);
}
// Outside the legal range of s and t, return just the texture's
// border color.
PIXEL apply_wrap_border_color_minfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
if (s < 0 || t < 0 || s > texture_def->s_max || t > texture_def->t_max) {
return texture_def->border_color;
}
return (*texture_def->tex_minfilter_func_impl)(texture_def, s, t, level, level_dx);
}
PIXEL apply_wrap_border_color_magfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
if (s < 0 || t < 0 || s > texture_def->s_max || t > texture_def->t_max) {
return texture_def->border_color;
}
return (*texture_def->tex_magfilter_func_impl)(texture_def, s, t, level, level_dx);
}
// Outside the legal range of s and t, clamp s and t to the edge.
// This is also duplicated by texcoord_clamp(), but using these
// functions instead saves two additional function calls per pixel.
PIXEL apply_wrap_clamp_minfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
s = min(max(s, 0), texture_def->s_max);
t = min(max(t, 0), texture_def->t_max);
return (*texture_def->tex_minfilter_func_impl)(texture_def, s, t, level, level_dx);
}
PIXEL apply_wrap_clamp_magfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
s = min(max(s, 0), texture_def->s_max);
t = min(max(t, 0), texture_def->t_max);
return (*texture_def->tex_magfilter_func_impl)(texture_def, s, t, level, level_dx);
}
int texcoord_clamp(int coord, int max_coord) {
return min(max(coord, 0), max_coord);
}
int texcoord_repeat(int coord, int max_coord) {
return coord;
}
int texcoord_mirror(int coord, int max_coord) {
if ((coord & ((max_coord << 1) - 1)) > max_coord) {
coord = (max_coord << 1) - coord;
}
return coord;
}
int texcoord_mirror_once(int coord, int max_coord) {
if (coord > max_coord) {
coord = (max_coord << 1) - coord;
}
return max(coord, 0);
}

View File

@ -26,15 +26,15 @@ typedef unsigned int ZPOINT;
#define MAX_MIPMAP_LEVELS (32 - ZB_POINT_ST_FRAC_BITS + 1)
/* Returns the index within a texture level for the given (s, t) texel. */
#define ZB_TEXEL(level, s, t) \
((((t) & (level)->t_mask) >> (level)->t_shift) | \
(((s) & (level)->s_mask) >> ZB_POINT_ST_FRAC_BITS))
#define ZB_TEXEL(texture_level, s, t) \
((((t) & (texture_level).t_mask) >> (texture_level).t_shift) | \
(((s) & (texture_level).s_mask) >> (texture_level).s_shift))
#define ZB_LOOKUP_TEXTURE_NEAREST(texture_levels, s, t) \
(texture_levels)->pixmap[ZB_TEXEL(texture_levels, s, t)]
#define ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s, t) \
(texture_def)->levels[0].pixmap[ZB_TEXEL((texture_def)->levels[0], s, t)]
#define ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_levels, s, t, level) \
ZB_LOOKUP_TEXTURE_NEAREST((texture_levels) + (level), (s) >> (level), (t) >> (level))
#define ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level) \
(texture_def)->levels[(level)].pixmap[ZB_TEXEL((texture_def)->levels[(level)], s, t)]
/* A special abs() function which doesn't require any branching
instructions. Might not work on some exotic hardware. */
@ -105,18 +105,33 @@ typedef unsigned int PIXEL;
typedef struct {
PIXEL *pixmap;
unsigned int s_mask, t_mask, t_shift;
unsigned int s_mask, s_shift, t_mask, t_shift;
} ZTextureLevel;
typedef struct ZBuffer ZBuffer;
typedef struct ZBufferPoint ZBufferPoint;
typedef struct ZTextureDef ZTextureDef;
typedef void (*ZB_fillTriangleFunc)(ZBuffer *,
ZBufferPoint *,ZBufferPoint *,ZBufferPoint *);
typedef void (*ZB_storePixelFunc)(ZBuffer *zb, PIXEL &result, int r, int g, int b, int a);
typedef PIXEL (*ZB_lookupTextureFunc)(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
typedef PIXEL (*ZB_lookupTextureFunc)(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
typedef int (*ZB_texWrapFunc)(int coord, int max_coord);
struct ZTextureDef {
ZTextureLevel *levels;
ZB_lookupTextureFunc tex_minfilter_func;
ZB_lookupTextureFunc tex_magfilter_func;
ZB_lookupTextureFunc tex_minfilter_func_impl;
ZB_lookupTextureFunc tex_magfilter_func_impl;
ZB_texWrapFunc tex_wrap_u_func;
ZB_texWrapFunc tex_wrap_v_func;
int s_max, t_max;
PIXEL border_color;
};
struct ZBuffer {
int xsize,ysize;
@ -130,12 +145,10 @@ struct ZBuffer {
int nb_colors;
unsigned char *dctable;
int *ctable;
ZTextureLevel *current_textures[MAX_TEXTURE_STAGES]; // This is actually an array of texture levels for each stage.
ZTextureDef current_textures[MAX_TEXTURE_STAGES];
int reference_alpha;
int blend_r, blend_g, blend_b, blend_a;
ZB_storePixelFunc store_pix_func;
ZB_lookupTextureFunc tex_minfilter_func;
ZB_lookupTextureFunc tex_magfilter_func;
};
struct ZBufferPoint {
@ -192,12 +205,26 @@ void ZB_clear_viewport(ZBuffer * zb, int clear_z, ZPOINT z,
int clear_color, unsigned int r, unsigned int g, unsigned int b, unsigned int a,
int xmin, int ymin, int xsize, int ysize);
PIXEL lookup_texture_nearest(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_bilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_mipmap_nearest(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_mipmap_linear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_mipmap_bilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_mipmap_trilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_nearest(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_bilinear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_mipmap_nearest(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_mipmap_linear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_mipmap_bilinear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL lookup_texture_mipmap_trilinear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL apply_wrap_general_minfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL apply_wrap_general_magfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL apply_wrap_border_color_minfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL apply_wrap_border_color_magfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL apply_wrap_clamp_minfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
PIXEL apply_wrap_clamp_magfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx);
int texcoord_clamp(int coord, int max_coord);
int texcoord_repeat(int coord, int max_coord);
int texcoord_mirror(int coord, int max_coord);
int texcoord_mirror_once(int coord, int max_coord);
/* linesize is in BYTES */
void ZB_copyFrameBuffer(ZBuffer *zb,void *buf,int linesize);

View File

@ -123,6 +123,7 @@ typedef struct GLTexture {
int num_levels;
int xsize, ysize;
int s_max, t_max;
V4 border_color;
void *allocated_buffer;
int total_bytecount;

View File

@ -60,9 +60,9 @@ CodeTable = {
'zless' : '#define ZCMP(zpix, z) ((ZPOINT)(zpix) < (ZPOINT)(z))',
# texture filters
'tnearest' : '#define CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx)\n#define ZB_LOOKUP_TEXTURE(texture_levels, s, t, level, level_dx) ZB_LOOKUP_TEXTURE_NEAREST(texture_levels, s, t)',
'tmipmap' : '#define CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx) DO_CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx)\n#define INTERP_MIPMAP\n#define ZB_LOOKUP_TEXTURE(texture_levels, s, t, level, level_dx) ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_levels, s, t, level)',
'tgeneral' : '#define CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx) DO_CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx)\n#define INTERP_MIPMAP\n#define ZB_LOOKUP_TEXTURE(texture_levels, s, t, level, level_dx) ((level == 0) ? zb->tex_magfilter_func(texture_levels, s, t, level, level_dx) : zb->tex_minfilter_func(texture_levels, s, t, level, level_dx))',
'tnearest' : '#define CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx)\n#define ZB_LOOKUP_TEXTURE(texture_def, s, t, level, level_dx) ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s, t)',
'tmipmap' : '#define CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx) DO_CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx)\n#define INTERP_MIPMAP\n#define ZB_LOOKUP_TEXTURE(texture_def, s, t, level, level_dx) ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level)',
'tgeneral' : '#define CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx) DO_CALC_MIPMAP_LEVEL(mipmap_level, mipmap_dx, dsdx, dtdx)\n#define INTERP_MIPMAP\n#define ZB_LOOKUP_TEXTURE(texture_def, s, t, level, level_dx) ((level == 0) ? (texture_def)->tex_magfilter_func(texture_def, s, t, level, level_dx) : (texture_def)->tex_minfilter_func(texture_def, s, t, level, level_dx))',
}
ops = [0] * len(Options)

File diff suppressed because it is too large Load Diff

View File

@ -117,7 +117,7 @@ static void FNAME(smooth_untextured) (ZBuffer *zb,
static void FNAME(white_textured) (ZBuffer *zb,
ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
{
ZTextureLevel *texture_levels;
ZTextureDef *texture_def;
#define INTERP_Z
#define INTERP_ST
@ -128,14 +128,14 @@ static void FNAME(white_textured) (ZBuffer *zb,
#define DRAW_INIT() \
{ \
texture_levels = zb->current_textures[0]; \
texture_def = &zb->current_textures[0]; \
}
#define PUT_PIXEL(_a) \
{ \
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
tmp = ZB_LOOKUP_TEXTURE(texture_def, s, t, mipmap_level, mipmap_dx); \
if (ACMP(zb, PIXEL_A(tmp))) { \
STORE_PIX(pp[_a], tmp, PIXEL_R(tmp), PIXEL_G(tmp), PIXEL_B(tmp), PIXEL_A(tmp)); \
STORE_Z(pz[_a], zz); \
@ -154,7 +154,7 @@ static void FNAME(white_textured) (ZBuffer *zb,
static void FNAME(flat_textured) (ZBuffer *zb,
ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
{
ZTextureLevel *texture_levels;
ZTextureDef *texture_def;
int or0, og0, ob0, oa0;
#define INTERP_Z
@ -170,7 +170,7 @@ static void FNAME(flat_textured) (ZBuffer *zb,
/* This alpha is zero, and we'll never get other than 0. */ \
return; \
} \
texture_levels = zb->current_textures[0]; \
texture_def = &zb->current_textures[0]; \
or0 = p2->r; \
og0 = p2->g; \
ob0 = p2->b; \
@ -181,7 +181,7 @@ static void FNAME(flat_textured) (ZBuffer *zb,
{ \
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
tmp = ZB_LOOKUP_TEXTURE(texture_def, s, t, mipmap_level, mipmap_dx); \
int a = PALPHA_MULT(oa0, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
STORE_PIX(pp[_a], \
@ -209,7 +209,7 @@ static void FNAME(flat_textured) (ZBuffer *zb,
static void FNAME(smooth_textured) (ZBuffer *zb,
ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
{
ZTextureLevel *texture_levels;
ZTextureDef *texture_def;
#define INTERP_Z
#define INTERP_ST
@ -235,14 +235,14 @@ static void FNAME(smooth_textured) (ZBuffer *zb,
#define DRAW_INIT() \
{ \
texture_levels = zb->current_textures[0]; \
texture_def = &zb->current_textures[0]; \
}
#define PUT_PIXEL(_a) \
{ \
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
tmp = ZB_LOOKUP_TEXTURE(texture_def, s, t, mipmap_level, mipmap_dx); \
int a = PALPHA_MULT(oa1, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
STORE_PIX(pp[_a], \
@ -279,7 +279,7 @@ static void FNAME(smooth_textured) (ZBuffer *zb,
static void FNAME(white_perspective) (ZBuffer *zb,
ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
{
ZTextureLevel *texture_levels;
ZTextureDef *texture_def;
float fdzdx,fndzdx,ndszdx,ndtzdx;
#define INTERP_Z
@ -293,7 +293,7 @@ static void FNAME(white_perspective) (ZBuffer *zb,
#define DRAW_INIT() \
{ \
texture_levels = zb->current_textures[0]; \
texture_def = &zb->current_textures[0]; \
fdzdx=(float)dzdx; \
fndzdx=NB_INTERP * fdzdx; \
ndszdx=NB_INTERP * dszdx; \
@ -305,7 +305,7 @@ static void FNAME(white_perspective) (ZBuffer *zb,
{ \
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
tmp = ZB_LOOKUP_TEXTURE(texture_def, s, t, mipmap_level, mipmap_dx); \
if (ACMP(zb, PIXEL_A(tmp))) { \
STORE_PIX(pp[_a], tmp, PIXEL_R(tmp), PIXEL_G(tmp), PIXEL_B(tmp), PIXEL_A(tmp)); \
STORE_Z(pz[_a], zz); \
@ -388,7 +388,7 @@ static void FNAME(white_perspective) (ZBuffer *zb,
static void FNAME(flat_perspective) (ZBuffer *zb,
ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
{
ZTextureLevel *texture_levels;
ZTextureDef *texture_def;
float fdzdx,fndzdx,ndszdx,ndtzdx;
int or0, og0, ob0, oa0;
@ -406,7 +406,7 @@ static void FNAME(flat_perspective) (ZBuffer *zb,
/* This alpha is zero, and we'll never get other than 0. */ \
return; \
} \
texture_levels = zb->current_textures[0]; \
texture_def = &zb->current_textures[0]; \
fdzdx=(float)dzdx; \
fndzdx=NB_INTERP * fdzdx; \
ndszdx=NB_INTERP * dszdx; \
@ -421,7 +421,7 @@ static void FNAME(flat_perspective) (ZBuffer *zb,
{ \
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
tmp = ZB_LOOKUP_TEXTURE(texture_def, s, t, mipmap_level, mipmap_dx); \
int a = PALPHA_MULT(oa0, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
STORE_PIX(pp[_a], \
@ -518,7 +518,7 @@ static void FNAME(flat_perspective) (ZBuffer *zb,
static void FNAME(smooth_perspective) (ZBuffer *zb,
ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
{
ZTextureLevel *texture_levels;
ZTextureDef *texture_def;
float fdzdx,fndzdx,ndszdx,ndtzdx;
#define INTERP_Z
@ -545,7 +545,7 @@ static void FNAME(smooth_perspective) (ZBuffer *zb,
#define DRAW_INIT() \
{ \
texture_levels = zb->current_textures[0]; \
texture_def = &zb->current_textures[0]; \
fdzdx=(float)dzdx; \
fndzdx=NB_INTERP * fdzdx; \
ndszdx=NB_INTERP * dszdx; \
@ -556,7 +556,7 @@ static void FNAME(smooth_perspective) (ZBuffer *zb,
{ \
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
tmp = ZB_LOOKUP_TEXTURE(texture_def, s, t, mipmap_level, mipmap_dx); \
int a = PALPHA_MULT(oa1, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
STORE_PIX(pp[_a], \
@ -683,10 +683,10 @@ static void FNAME(smooth_multitex2) (ZBuffer *zb,
{ \
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(zb->current_textures[0], s, t, mipmap_level, mipmap_dx); \
tmp = ZB_LOOKUP_TEXTURE(&zb->current_textures[0], s, t, mipmap_level, mipmap_dx); \
int a = PALPHA_MULT(oa1, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
int tmpa = ZB_LOOKUP_TEXTURE(zb->current_textures[1], sa, ta, mipmap_levela, mipmap_dxa); \
int tmpa = ZB_LOOKUP_TEXTURE(&zb->current_textures[1], sa, ta, mipmap_levela, mipmap_dxa); \
STORE_PIX(pp[_a], \
RGBA_TO_PIXEL(PCOMPONENT_MULT3(or1, PIXEL_R(tmp), PIXEL_R(tmpa)), \
PCOMPONENT_MULT3(og1, PIXEL_G(tmp), PIXEL_G(tmpa)), \
@ -840,11 +840,11 @@ static void FNAME(smooth_multitex3) (ZBuffer *zb,
{ \
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(zb->current_textures[0], s, t, mipmap_level, mipmap_dx); \
tmp = ZB_LOOKUP_TEXTURE(&zb->current_textures[0], s, t, mipmap_level, mipmap_dx); \
int a = PALPHA_MULT(oa1, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
int tmpa = ZB_LOOKUP_TEXTURE(zb->current_textures[1], sa, ta, mipmap_levela, mipmap_dxa); \
int tmpb = ZB_LOOKUP_TEXTURE(zb->current_textures[2], sb, tb, mipmap_levelb, mipmap_dxb); \
int tmpa = ZB_LOOKUP_TEXTURE(&zb->current_textures[1], sa, ta, mipmap_levela, mipmap_dxa); \
int tmpb = ZB_LOOKUP_TEXTURE(&zb->current_textures[2], sb, tb, mipmap_levelb, mipmap_dxb); \
STORE_PIX(pp[_a], \
RGBA_TO_PIXEL(PCOMPONENT_MULT4(or1, PIXEL_R(tmp), PIXEL_R(tmpa), PIXEL_R(tmpb)), \
PCOMPONENT_MULT4(og1, PIXEL_G(tmp), PIXEL_G(tmpa), PIXEL_G(tmpb)), \