Trilinear scaler overhaul: moving image hotspot processing to tfb_draw/DCQ; proper handling of src and dst alpha surfaces; src and mipmap alignment fixes; code cleanup

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2029 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2005-12-03 09:55:55 +00:00
parent 7089b27835
commit a5673967da
+387 -414
View File
@@ -10,6 +10,7 @@
typedef SDL_Surface *NativeCanvas;
// BYTE x BYTE weight (mult >> 8) table
static Uint8 btable[256][256];
void
@@ -18,7 +19,8 @@ TFB_DrawCanvas_Initialize (void)
int i, j;
for (i = 0; i < 256; ++i)
for (j = 0; j < 256; ++j)
btable[j][i] = (j * i) >> 8;
btable[j][i] = (j * i + 0x80) >> 8;
// need error correction here
}
void
@@ -71,8 +73,6 @@ TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *pale
}
LockMutex (img->mutex);
targetRect.x = x;
targetRect.y = y;
if (palette == 0)
palette = img->Palette;
@@ -100,17 +100,23 @@ TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *pale
srcRect.w = img->extent.width;
srcRect.h = img->extent.height;
pSrcRect = &srcRect;
targetRect.x = x - img->last_scale_hs.x;
targetRect.y = y - img->last_scale_hs.y;
}
else
{
surf = img->NormalImg;
pSrcRect = NULL;
targetRect.x = x - img->NormalHs.x;
targetRect.y = y - img->NormalHs.y;
}
if (surf->format->palette)
SDL_SetColors (surf, (SDL_Color*)palette, 0, 256);
SDL_BlitSurface(surf, pSrcRect, (NativeCanvas) target, &targetRect);
SDL_BlitSurface (surf, pSrcRect, (NativeCanvas) target, &targetRect);
UnlockMutex (img->mutex);
}
@@ -217,9 +223,6 @@ TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, int scale, int r, int
LockMutex (img->mutex);
targetRect.x = x;
targetRect.y = y;
if (scale != 0 && scale != GSCALE_IDENTITY)
{
TFB_DrawImage_FixScaling (img, scale, TFB_SCALE_NEAREST);
@@ -229,11 +232,17 @@ TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, int scale, int r, int
srcRect.w = img->extent.width;
srcRect.h = img->extent.height;
pSrcRect = &srcRect;
targetRect.x = x - img->last_scale_hs.x;
targetRect.y = y - img->last_scale_hs.y;
}
else
{
surf = img->NormalImg;
pSrcRect = NULL;
targetRect.x = x - img->NormalHs.x;
targetRect.y = y - img->NormalHs.y;
}
if (surf->format->palette)
@@ -586,21 +595,26 @@ TFB_DrawCanvas_SetTransparentColor (TFB_Canvas canvas, int r, int g, int b, BOOL
}
void
TFB_DrawCanvas_GetScaledExtent (TFB_Canvas src_canvas, TFB_Canvas src_mipmap, int scale, PEXTENT size)
TFB_DrawCanvas_GetScaledExtent (TFB_Canvas src_canvas, HOT_SPOT src_hs,
TFB_Canvas src_mipmap, HOT_SPOT mm_hs,
int scale, PEXTENT size, HOT_SPOT *hs)
{
SDL_Surface *src = (SDL_Surface *)src_canvas;
if (!src_mipmap)
{
size->width = (int) (src->w * scale / (float)GSCALE_IDENTITY + 0.5);
size->height = (int) (src->h * scale / (float)GSCALE_IDENTITY + 0.5);
size->width = src->w * scale / GSCALE_IDENTITY;
size->height = src->h * scale / GSCALE_IDENTITY;
hs->x = src_hs.x * scale / GSCALE_IDENTITY;
hs->y = src_hs.y * scale / GSCALE_IDENTITY;
}
else
{
// interpolates extents between src and mipmap to get smoother
// transition when surface changes
SDL_Surface *mipmap = (SDL_Surface *)src_mipmap;
float ratio = (scale / (float)GSCALE_IDENTITY) * 2.0f - 1.0f;
if (ratio < 0.0f)
ratio = 0.0f;
@@ -609,6 +623,9 @@ TFB_DrawCanvas_GetScaledExtent (TFB_Canvas src_canvas, TFB_Canvas src_mipmap, in
size->width = (int)((src->w - mipmap->w) * ratio + mipmap->w + 0.5);
size->height = (int)((src->h - mipmap->h) * ratio + mipmap->h + 0.5);
hs->x = (int)((src_hs.x - mm_hs.x) * ratio + mm_hs.x + 0.5);
hs->y = (int)((src_hs.y - mm_hs.y) * ratio + mm_hs.y + 0.5);
}
if (!size->width && src->w)
@@ -650,9 +667,9 @@ TFB_DrawCanvas_Rescale_Nearest (TFB_Canvas src_canvas, TFB_Canvas dest_canvas, E
sx = sy = 0;
if (size.width > 1)
sx = 65536 * (src->w - 1) / (size.width - 1);
sx = ((src->w - 1) << 16) / (size.width - 1);
if (size.height > 1)
sy = 65536 * (src->h - 1) / (size.height - 1);
sy = ((src->h - 1) << 16) / (size.height - 1);
sax = saspace;
say = saspace + size.width;
@@ -737,19 +754,142 @@ TFB_DrawCanvas_Rescale_Nearest (TFB_Canvas src_canvas, TFB_Canvas dest_canvas, E
SDL_UnlockSurface (src);
}
typedef union
{
Uint32 value;
Uint8 chan[4];
struct
{
Uint8 r, g, b, a;
} c;
} pixel_t;
static inline Uint8
dot_product_8_4 (pixel_t* p, int c, Uint8* v)
{ // math expanded for speed
#if 0
return (
(Uint32)p[0].chan[c] * v[0] + (Uint32)p[1].chan[c] * v[1] +
(Uint32)p[2].chan[c] * v[2] + (Uint32)p[3].chan[c] * v[3]
) >> 8;
#else
// mult-table driven version
return
btable[p[0].chan[c]][v[0]] + btable[p[1].chan[c]][v[1]] +
btable[p[2].chan[c]][v[2]] + btable[p[3].chan[c]][v[3]];
#endif
}
static inline Uint8
weight_product_8_4 (pixel_t* p, int c, Uint8* w)
{ // math expanded for speed
return (
(Uint32)p[0].chan[c] * w[0] + (Uint32)p[1].chan[c] * w[1] +
(Uint32)p[2].chan[c] * w[2] + (Uint32)p[3].chan[c] * w[3]
) / (w[0] + w[1] + w[2] + w[3]);
}
static inline Uint8
blend_ratio_2 (Uint8 c1, Uint8 c2, int ratio)
{ // blend 2 color values according to ratio (0..256)
// identical to proper alpha blending
return (((c1 - c2) * ratio) >> 8) + c2;
}
static inline Uint32
tri_get_pixel (void* ppix, SDL_PixelFormat *fmt, SDL_Color *pal,
Uint32 mask, Uint32 key)
{
pixel_t p;
// start off with non-present pixel
p.value = 0;
if (pal)
{ // paletted pixel; mask not used
Uint32 c = *(Uint8 *)ppix;
if (c != key)
{
p.c.r = pal[c].r;
p.c.g = pal[c].g;
p.c.b = pal[c].b;
p.c.a = SDL_ALPHA_OPAQUE;
}
}
else
{ // RGB(A) pixel; (pix & mask) != key
Uint32 c = *(Uint32 *)ppix;
if ((c & mask) != key)
{
#if 0
SDL_GetRGBA (c, fmt, &p.c.r, &p.c.g, &p.c.b, &p.c.a);
#else
p.c.r = (c >> fmt->Rshift) & 0xff;
p.c.g = (c >> fmt->Gshift) & 0xff;
p.c.b = (c >> fmt->Bshift) & 0xff;
if (fmt->Amask)
p.c.a = (c >> fmt->Ashift) & 0xff;
else
p.c.a = SDL_ALPHA_OPAQUE;
}
#endif
}
return p.value;
}
void
TFB_DrawCanvas_Rescale_Trilinear (TFB_Canvas src_canvas, TFB_Canvas dest_canvas, TFB_Canvas src_mipmap, EXTENT size)
TFB_DrawCanvas_Rescale_Trilinear (TFB_Canvas src_canvas,
TFB_Canvas dest_canvas, TFB_Canvas src_mipmap, EXTENT size)
{
SDL_Surface *src = (SDL_Surface *)src_canvas;
SDL_Surface *dst = (SDL_Surface *)dest_canvas;
SDL_Surface *mipmap = (SDL_Surface *)src_mipmap;
SDL_PixelFormat *srcfmt = src->format;
SDL_PixelFormat *mmfmt = mipmap->format;
SDL_PixelFormat *dstfmt = dst->format;
const int dstopaque = dstfmt->Amask;
const int dsttransparent = (dst->flags & SDL_SRCCOLORKEY) ? dstfmt->colorkey : 0;
SDL_Color *srcpal = srcfmt->palette? srcfmt->palette->colors : 0;
SDL_Color *mmpal = mmfmt->palette ? mmfmt->palette->colors : 0;
const int sbpp = srcfmt->BytesPerPixel;
const int mmbpp = mmfmt->BytesPerPixel;
const int slen = src->pitch;
const int mmlen = mipmap->pitch;
const int dst_has_alpha = (dstfmt->Amask != 0);
const int transparent = (dst->flags & SDL_SRCCOLORKEY) ?
dstfmt->colorkey : 0;
const int w = size.width, h = size.height;
const int ALPHA_THRESHOLD = 128;
int ratio = (int)(256.0f * (((float)w / src->w) * 2.0f - 1.0f));
const int alpha_threshold = dst_has_alpha ? 0 : 127;
// src v. mipmap importance factor
int ratio;
// source masks and keys
Uint32 mk0 = 0, ck0 = ~0, mk1 = 0, ck1 = ~0;
// source fractional x and y positions
int sx0, sy0, sx1, sy1;
// source fractional dx and dy increments
int fsx0 = 0, fsy0 = 0, fsx1 = 0, fsy1 = 0;
// source fractional x and y starting points
int ssx0 = 0, ssy0 = 0, ssx1 = 0, ssy1 = 0;
int x, y;
fsx0 = (src->w << 16) / w;
fsy0 = (src->h << 16) / h;
if (w > 1)
fsx1 = ((mipmap->w - 1) << 16) / (w - 1);
if (h > 1)
fsy1 = ((mipmap->h - 1) << 16) / (h - 1);
// give equal importance to both edges
ssx0 = (((src->w - 1) << 16) - fsx0 * (w - 1)) >> 1;
ssy0 = (((src->h - 1) << 16) - fsy0 * (h - 1)) >> 1;
ssx1 = (((mipmap->w - 1) << 16) - fsx1 * (w - 1)) >> 1;
ssy1 = (((mipmap->h - 1) << 16) - fsy1 * (h - 1)) >> 1;
// src v. mipmap importance factor
ratio = (w << 9) / src->w - 256;
if (ratio < 0)
ratio = 0;
if (ratio > 256)
@@ -762,404 +902,237 @@ TFB_DrawCanvas_Rescale_Trilinear (TFB_Canvas src_canvas, TFB_Canvas dest_canvas,
return;
}
if (src->format->BytesPerPixel == 1 && dst->format->BytesPerPixel == 4 &&
mipmap->format->BytesPerPixel == 1)
{
SDL_Color *srcpal = src->format->palette->colors;
SDL_Color *mmpal = mipmap->format->palette->colors;
int fsx0 = (int)(65536.0f * (float)src->w / w);
int fsy0 = (int)(65536.0f * (float)src->h / h);
int fsx1 = (int)(65536.0f * (float)mipmap->w / w);
int fsy1 = (int)(65536.0f * (float)mipmap->h / h);
int sx0 = 0, sy0 = 0, sx1 = 0, sy1 = 0;
int x, y;
Uint32 ck0 = src->format->colorkey;
Uint32 ck1 = mipmap->format->colorkey;
SDL_LockSurface(src);
SDL_LockSurface(dst);
SDL_LockSurface(mipmap);
for (y = 0; y < h; ++y)
{
Uint32 *dst_p = (Uint32 *)dst->pixels + y * dst->w;
Uint8 *src_a0 = (Uint8 *)src->pixels + (sy0 >> 16) * src->pitch;
Uint8 *src_a1 = (Uint8 *)mipmap->pixels + (sy1 >> 16) * mipmap->pitch;
for (x = 0; x < w; ++x)
{
Uint8 u0 = (sx0 >> 8) & 0xff;
Uint8 u1 = (sx1 >> 8) & 0xff;
Uint8 v0 = (sy0 >> 8) & 0xff;
Uint8 v1 = (sy1 >> 8) & 0xff;
Uint8 ul0 = btable[255 - u0][255 - v0];
Uint8 ul1 = btable[255 - u1][255 - v1];
Uint8 ur0 = btable[u0][255 - v0];
Uint8 ur1 = btable[u1][255 - v1];
Uint8 ll0 = btable[255 - u0][v0];
Uint8 ll1 = btable[255 - u1][v1];
Uint8 lr0 = btable[u0][v0];
Uint8 lr1 = btable[u1][v1];
Uint8 r0[5], r1[5], g0[5], g1[5], b0[5], b1[5], a0[5], a1[5];
Uint8 c;
Uint8 *src_p0 = src_a0 + (sx0 >> 16);
Uint8 *src_p1 = src_a1 + (sx1 >> 16);
if ((sx0 >> 16) <= src->w - 2)
{
a0[0] = ((c = *src_p0) == ck0) ? 0 : 255;
r0[0] = srcpal[c].r;
g0[0] = srcpal[c].g;
b0[0] = srcpal[c].b;
a0[1] = ((c = *(src_p0 + 1)) == ck0) ? 0 : 255;
r0[1] = srcpal[c].r;
g0[1] = srcpal[c].g;
b0[1] = srcpal[c].b;
if ((sy0 >> 16) <= src->h - 2)
{
a0[2] = ((c = *(src_p0 + src->pitch)) == ck0) ? 0 : 255;
r0[2] = srcpal[c].r;
g0[2] = srcpal[c].g;
b0[2] = srcpal[c].b;
a0[3] = ((c = *(src_p0 + src->pitch + 1)) == ck0) ? 0 : 255;
r0[3] = srcpal[c].r;
g0[3] = srcpal[c].g;
b0[3] = srcpal[c].b;
}
else
{
a0[2] = a0[0];
r0[2] = r0[0];
g0[2] = g0[0];
b0[2] = b0[0];
a0[3] = a0[1];
r0[3] = r0[1];
g0[3] = g0[1];
b0[3] = b0[1];
}
}
else
{
a0[0] = a0[1] = ((c = *src_p0) == ck0) ? 0 : 255;
r0[0] = r0[1] = srcpal[c].r;
g0[0] = g0[1] = srcpal[c].g;
b0[0] = b0[1] = srcpal[c].b;
if ((sy0 >> 16) <= src->h - 2)
{
a0[2] = a0[3] = ((c = *(src_p0 + src->pitch)) == ck0) ? 0 : 255;
r0[2] = r0[3] = srcpal[c].r;
g0[2] = g0[3] = srcpal[c].g;
b0[2] = b0[3] = srcpal[c].b;
}
else
{
a0[2] = a0[3] = a0[0];
r0[2] = r0[3] = r0[0];
g0[2] = g0[3] = g0[0];
b0[2] = b0[3] = b0[0];
}
}
if ((sx1 >> 16) <= mipmap->w - 2)
{
a1[0] = ((c = *src_p1) == ck1) ? 0 : 255;
r1[0] = mmpal[c].r;
g1[0] = mmpal[c].g;
b1[0] = mmpal[c].b;
a1[1] = ((c = *(src_p1 + 1)) == ck1) ? 0 : 255;
r1[1] = mmpal[c].r;
g1[1] = mmpal[c].g;
b1[1] = mmpal[c].b;
if ((sy1 >> 16) <= mipmap->h - 2)
{
a1[2] = ((c = *(src_p1 + mipmap->pitch)) == ck1) ? 0 : 255;
r1[2] = mmpal[c].r;
g1[2] = mmpal[c].g;
b1[2] = mmpal[c].b;
a1[3] = ((c = *(src_p1 + mipmap->pitch + 1)) == ck1) ? 0 : 255;
r1[3] = mmpal[c].r;
g1[3] = mmpal[c].g;
b1[3] = mmpal[c].b;
}
else
{
a1[2] = a1[0];
r1[2] = r1[0];
g1[2] = g1[0];
b1[2] = b1[0];
a1[3] = a1[1];
r1[3] = r1[1];
g1[3] = g1[1];
b1[3] = b1[1];
}
}
else
{
a1[0] = a1[1] = ((c = *src_p1) == ck1) ? 0 : 255;
r1[0] = r1[1] = mmpal[c].r;
g1[0] = g1[1] = mmpal[c].g;
b1[0] = b1[1] = mmpal[c].b;
if ((sy1 >> 16) <= mipmap->h - 2)
{
a1[2] = a1[3] = ((c = *(src_p1 + mipmap->pitch)) == ck1) ? 0 : 255;
r1[2] = r1[3] = mmpal[c].r;
g1[2] = g1[3] = mmpal[c].g;
b1[2] = b1[3] = mmpal[c].b;
}
else
{
a1[2] = a1[3] = a1[0];
r1[2] = r1[3] = r1[0];
g1[2] = g1[3] = g1[0];
b1[2] = b1[3] = b1[0];
}
}
a0[4] = ((ul0 * a0[0]) >> 8) + ((ur0 * a0[1]) >> 8) + ((ll0 * a0[2]) >> 8) + ((lr0 * a0[3]) >> 8);
a1[4] = ((ul1 * a1[0]) >> 8) + ((ur1 * a1[1]) >> 8) + ((ll1 * a1[2]) >> 8) + ((lr1 * a1[3]) >> 8);
if ((((a0[4] - a1[4]) * ratio) >> 8) + a1[4] > ALPHA_THRESHOLD)
{
r0[4] = ((ul0 * r0[0]) >> 8) + ((ur0 * r0[1]) >> 8) + ((ll0 * r0[2]) >> 8) + ((lr0 * r0[3]) >> 8);
g0[4] = ((ul0 * g0[0]) >> 8) + ((ur0 * g0[1]) >> 8) + ((ll0 * g0[2]) >> 8) + ((lr0 * g0[3]) >> 8);
b0[4] = ((ul0 * b0[0]) >> 8) + ((ur0 * b0[1]) >> 8) + ((ll0 * b0[2]) >> 8) + ((lr0 * b0[3]) >> 8);
r1[4] = ((ul1 * r1[0]) >> 8) + ((ur1 * r1[1]) >> 8) + ((ll1 * r1[2]) >> 8) + ((lr1 * r1[3]) >> 8);
g1[4] = ((ul1 * g1[0]) >> 8) + ((ur1 * g1[1]) >> 8) + ((ll1 * g1[2]) >> 8) + ((lr1 * g1[3]) >> 8);
b1[4] = ((ul1 * b1[0]) >> 8) + ((ur1 * b1[1]) >> 8) + ((ll1 * b1[2]) >> 8) + ((lr1 * b1[3]) >> 8);
*dst_p++ =
(((((r0[4] - r1[4]) * ratio) >> 8) + r1[4]) << dstfmt->Rshift) |
(((((g0[4] - g1[4]) * ratio) >> 8) + g1[4]) << dstfmt->Gshift) |
(((((b0[4] - b1[4]) * ratio) >> 8) + b1[4]) << dstfmt->Bshift) |
dstopaque;
}
else
{
*dst_p++ = dsttransparent;
}
sx0 += fsx0;
sx1 += fsx1;
}
sx0 = sx1 = 0;
sy0 += fsy0;
sy1 += fsy1;
}
SDL_UnlockSurface(mipmap);
SDL_UnlockSurface(dst);
SDL_UnlockSurface(src);
}
else if (src->format->BytesPerPixel == 4 && dst->format->BytesPerPixel == 4 &&
mipmap->format->BytesPerPixel == 4)
{
int fsx0 = (int)(65536.0f * (float)src->w / w);
int fsy0 = (int)(65536.0f * (float)src->h / h);
int fsx1 = (int)(65536.0f * (float)mipmap->w / w);
int fsy1 = (int)(65536.0f * (float)mipmap->h / h);
int sx0 = 0, sy0 = 0, sx1 = 0, sy1 = 0;
int x, y;
Uint32 ck0 = 0; // 0 means alpha=0 too, so it's safe
Uint32 ck1 = 0;
// use colorkeys where appropriate
if (src->flags & SDL_SRCCOLORKEY)
ck0 = src->format->colorkey;
if (mipmap->flags & SDL_SRCCOLORKEY)
ck1 = mipmap->format->colorkey;
SDL_LockSurface(src);
SDL_LockSurface(dst);
SDL_LockSurface(mipmap);
for (y = 0; y < h; ++y)
{
Uint32 *dst_p = (Uint32 *)dst->pixels + y * dst->w;
Uint32 *src_a0 = (Uint32 *)src->pixels + (sy0 >> 16) * src->w;
Uint32 *src_a1 = (Uint32 *)mipmap->pixels + (sy1 >> 16) * mipmap->w;
for (x = 0; x < w; ++x)
{
Uint8 u0 = (sx0 >> 8) & 0xff;
Uint8 u1 = (sx1 >> 8) & 0xff;
Uint8 v0 = (sy0 >> 8) & 0xff;
Uint8 v1 = (sy1 >> 8) & 0xff;
Uint8 ul0 = btable[255 - u0][255 - v0];
Uint8 ul1 = btable[255 - u1][255 - v1];
Uint8 ur0 = btable[u0][255 - v0];
Uint8 ur1 = btable[u1][255 - v1];
Uint8 ll0 = btable[255 - u0][v0];
Uint8 ll1 = btable[255 - u1][v1];
Uint8 lr0 = btable[u0][v0];
Uint8 lr1 = btable[u1][v1];
Uint8 r0[5], r1[5], g0[5], g1[5], b0[5], b1[5], a0[5], a1[5];
Uint32 *src_p0 = src_a0 + (sx0 >> 16);
Uint32 *src_p1 = src_a1 + (sx1 >> 16);
if ((sx0 >> 16) <= src->w - 2)
{
SDL_GetRGBA (*src_p0, src->format, &r0[0], &g0[0], &b0[0], &a0[0]);
SDL_GetRGBA (*(src_p0 + 1), src->format, &r0[1], &g0[1], &b0[1], &a0[1]);
if (src_p0[0] == ck0)
a0[0] = 0;
if (src_p0[1] == ck0)
a0[1] = 0;
if ((sy0 >> 16) <= src->h - 2)
{
SDL_GetRGBA (*(src_p0 + src->w), src->format, &r0[2], &g0[2], &b0[2], &a0[2]);
SDL_GetRGBA (*(src_p0 + src->w + 1), src->format, &r0[3], &g0[3], &b0[3], &a0[3]);
if (src_p0[src->w] == ck0)
a0[2] = 0;
if (src_p0[src->w + 1] == ck0)
a0[3] = 0;
}
else
{
r0[2] = r0[0];
g0[2] = g0[0];
b0[2] = b0[0];
a0[2] = a0[0];
r0[3] = r0[1];
g0[3] = g0[1];
b0[3] = b0[1];
a0[3] = a0[1];
}
}
else
{
SDL_GetRGBA (*src_p0, src->format, &r0[0], &g0[0], &b0[0], &a0[0]);
if (src_p0[0] == ck0)
a0[0] = 0;
r0[1] = r0[0];
g0[1] = g0[0];
b0[1] = b0[0];
a0[1] = a0[0];
if ((sy0 >> 16) <= src->h - 2)
{
SDL_GetRGBA (*(src_p0 + src->w), src->format, &r0[2], &g0[2], &b0[2], &a0[2]);
if (src_p0[src->w] == ck0)
a0[2] = 0;
r0[3] = r0[2];
g0[3] = g0[2];
b0[3] = b0[2];
a0[3] = a0[2];
}
else
{
r0[2] = r0[3] = r0[0];
g0[2] = g0[3] = g0[0];
b0[2] = b0[3] = b0[0];
a0[2] = a0[3] = a0[0];
}
}
if ((sx1 >> 16) <= mipmap->w - 2)
{
SDL_GetRGBA (*src_p1, mipmap->format, &r1[0], &g1[0], &b1[0], &a1[0]);
SDL_GetRGBA (*(src_p1 + 1), mipmap->format, &r1[1], &g1[1], &b1[1], &a1[1]);
if (src_p1[0] == ck1)
a1[0] = 0;
if (src_p1[1] == ck1)
a1[1] = 0;
if ((sy1 >> 16) <= mipmap->h - 2)
{
SDL_GetRGBA (*(src_p1 + mipmap->w) , mipmap->format, &r1[2], &g1[2], &b1[2], &a1[2]);
SDL_GetRGBA (*(src_p1 + mipmap->w + 1), mipmap->format, &r1[3], &g1[3], &b1[3], &a1[3]);
if (src_p1[mipmap->w] == ck1)
a1[2] = 0;
if (src_p1[mipmap->w + 1] == ck1)
a1[3] = 0;
}
else
{
r1[2] = r1[0];
g1[2] = g1[0];
b1[2] = b1[0];
a1[2] = a1[0];
r1[3] = r1[1];
g1[3] = g1[1];
b1[3] = b1[1];
a1[3] = a1[1];
}
}
else
{
SDL_GetRGBA (*src_p1, mipmap->format, &r1[0], &g1[0], &b1[0], &a1[0]);
if (src_p1[0] == ck1)
a1[0] = 0;
r1[1] = r1[0];
g1[1] = g1[0];
b1[1] = b1[0];
a1[1] = a1[0];
if ((sy1 >> 16) <= mipmap->h - 2)
{
SDL_GetRGBA (*(src_p1 + mipmap->w), mipmap->format, &r1[2], &g1[2], &b1[2], &a1[2]);
if (src_p1[mipmap->w] == ck1)
a1[2] = 0;
r1[3] = r1[2];
g1[3] = g1[2];
b1[3] = b1[2];
a1[3] = a1[2];
}
else
{
r1[2] = r1[3] = r1[0];
g1[2] = g1[3] = g1[0];
b1[2] = b1[3] = b1[0];
a1[2] = a1[3] = a1[0];
}
}
a0[4] = ((ul0 * a0[0]) >> 8) + ((ur0 * a0[1]) >> 8) + ((ll0 * a0[2]) >> 8) + ((lr0 * a0[3]) >> 8);
a1[4] = ((ul1 * a1[0]) >> 8) + ((ur1 * a1[1]) >> 8) + ((ll1 * a1[2]) >> 8) + ((lr1 * a1[3]) >> 8);
if ((((a0[4] - a1[4]) * ratio) >> 8) + a1[4] > ALPHA_THRESHOLD)
{
r0[4] = ((ul0 * r0[0]) >> 8) + ((ur0 * r0[1]) >> 8) + ((ll0 * r0[2]) >> 8) + ((lr0 * r0[3]) >> 8);
g0[4] = ((ul0 * g0[0]) >> 8) + ((ur0 * g0[1]) >> 8) + ((ll0 * g0[2]) >> 8) + ((lr0 * g0[3]) >> 8);
b0[4] = ((ul0 * b0[0]) >> 8) + ((ur0 * b0[1]) >> 8) + ((ll0 * b0[2]) >> 8) + ((lr0 * b0[3]) >> 8);
r1[4] = ((ul1 * r1[0]) >> 8) + ((ur1 * r1[1]) >> 8) + ((ll1 * r1[2]) >> 8) + ((lr1 * r1[3]) >> 8);
g1[4] = ((ul1 * g1[0]) >> 8) + ((ur1 * g1[1]) >> 8) + ((ll1 * g1[2]) >> 8) + ((lr1 * g1[3]) >> 8);
b1[4] = ((ul1 * b1[0]) >> 8) + ((ur1 * b1[1]) >> 8) + ((ll1 * b1[2]) >> 8) + ((lr1 * b1[3]) >> 8);
*dst_p++ =
(((((r0[4] - r1[4]) * ratio) >> 8) + r1[4]) << dstfmt->Rshift) |
(((((g0[4] - g1[4]) * ratio) >> 8) + g1[4]) << dstfmt->Gshift) |
(((((b0[4] - b1[4]) * ratio) >> 8) + b1[4]) << dstfmt->Bshift) |
dstopaque;
}
else
{
*dst_p++ = dsttransparent;
}
sx0 += fsx0;
sx1 += fsx1;
}
sx0 = sx1 = 0;
sy0 += fsy0;
sy1 += fsy1;
}
SDL_UnlockSurface(mipmap);
SDL_UnlockSurface(dst);
SDL_UnlockSurface(src);
}
else
if ((srcfmt->BytesPerPixel != 1 && srcfmt->BytesPerPixel != 4) ||
(mmfmt->BytesPerPixel != 1 && mmfmt->BytesPerPixel != 4) ||
(dst->format->BytesPerPixel != 4))
{
fprintf (stderr, "Tried to deal with unknown BPP: %d -> %d, mipmap %d\n",
src->format->BitsPerPixel, dst->format->BitsPerPixel, mipmap->format->BitsPerPixel);
srcfmt->BitsPerPixel, dst->format->BitsPerPixel, mmfmt->BitsPerPixel);
}
// use colorkeys where appropriate
if (srcfmt->Amask)
{ // alpha transparency
mk0 = srcfmt->Amask;
ck0 = 0;
}
else if (src->flags & SDL_SRCCOLORKEY)
{ // colorkey transparency
mk0 = ~srcfmt->Amask;
ck0 = srcfmt->colorkey & mk0;
}
if (mmfmt->Amask)
{ // alpha transparency
mk1 = mmfmt->Amask;
ck1 = 0;
}
else if (mipmap->flags & SDL_SRCCOLORKEY)
{ // colorkey transparency
mk1 = ~mmfmt->Amask;
ck1 = mmfmt->colorkey & mk1;
}
SDL_LockSurface(src);
SDL_LockSurface(dst);
SDL_LockSurface(mipmap);
for (y = 0, sy0 = ssy0, sy1 = ssy1;
y < h;
++y, sy0 += fsy0, sy1 += fsy1)
{
Uint32 *dst_p = (Uint32 *) ((Uint8*)dst->pixels + y * dst->pitch);
Uint8 *src_a0 = (Uint8*)src->pixels + (sy0 >> 16) * slen;
Uint8 *src_a1 = (Uint8*)mipmap->pixels + (sy1 >> 16) * mmlen;
// retrieve the fractional portions of y
const Uint8 v0 = (sy0 >> 8) & 0xff;
const Uint8 v1 = (sy1 >> 8) & 0xff;
Uint8 w0[4], w1[4]; // pixel weight vectors
for (x = 0, sx0 = ssx0, sx1 = ssx1;
x < w;
++x, ++dst_p, sx0 += fsx0, sx1 += fsx1)
{
Uint8 *src_p0 = src_a0 + (sx0 >> 16) * sbpp;
Uint8 *src_p1 = src_a1 + (sx1 >> 16) * mmbpp;
// retrieve the fractional portions of x
const Uint8 u0 = (sx0 >> 8) & 0xff;
const Uint8 u1 = (sx1 >> 8) & 0xff;
// pixels are examined and numbered in pattern
// 0 1
// 2 3
// the ideal pixel (4) is somewhere between these four
// and is calculated from these using weight vector (w)
// with a dot product
pixel_t p0[5], p1[5];
Uint8 res_a;
w0[0] = btable[255 - u0][255 - v0];
w0[1] = btable[u0][255 - v0];
w0[2] = btable[255 - u0][v0];
w0[3] = btable[u0][v0];
w1[0] = btable[255 - u1][255 - v1];
w1[1] = btable[u1][255 - v1];
w1[2] = btable[255 - u1][v1];
w1[3] = btable[u1][v1];
// collect interesting pixels from src image
p0[0].value = tri_get_pixel (src_p0, srcfmt, srcpal, mk0, ck0);
if ((sx0 >> 16) <= src->w - 2)
{
p0[1].value = tri_get_pixel (src_p0 + sbpp,
srcfmt, srcpal, mk0, ck0);
if ((sy0 >> 16) <= src->h - 2)
{
p0[2].value = tri_get_pixel (src_p0 + slen,
srcfmt, srcpal, mk0, ck0);
p0[3].value = tri_get_pixel (src_p0 + slen + sbpp,
srcfmt, srcpal, mk0, ck0);
}
else
{
p0[2].value = p0[0].value;
p0[3].value = p0[1].value;
}
}
else
{
p0[1].value = p0[0].value;
if ((sy0 >> 16) <= src->h - 2)
{
p0[2].value = tri_get_pixel (src_p0 + slen,
srcfmt, srcpal, mk0, ck0);
}
else
{
p0[2].value = p0[0].value;
}
p0[3].value = p0[2].value;
}
// collect interesting pixels from mipmap image
p1[0].value = tri_get_pixel (src_p1, mmfmt, mmpal, mk1, ck1);
if ((sx1 >> 16) <= mipmap->w - 2)
{
p1[1].value = tri_get_pixel (src_p1 + mmbpp,
mmfmt, mmpal, mk1, ck1);
if ((sy1 >> 16) <= mipmap->h - 2)
{
p1[2].value = tri_get_pixel (src_p1 + mmlen,
mmfmt, mmpal, mk1, ck1);
p1[3].value = tri_get_pixel (src_p1 + mmlen + mmbpp,
mmfmt, mmpal, mk1, ck1);
}
else
{
p1[2].value = p1[0].value;
p1[3].value = p1[1].value;
}
}
else
{
p1[1].value = p1[0].value;
if ((sy1 >> 16) <= mipmap->h - 2)
{
p1[2].value = tri_get_pixel (src_p1 + mmlen,
mmfmt, mmpal, mk1, ck1);
}
else
{
p1[2].value = p1[0].value;
}
p1[3].value = p1[2].value;
}
p0[4].c.a = dot_product_8_4 (p0, 3, w0);
p1[4].c.a = dot_product_8_4 (p1, 3, w1);
res_a = blend_ratio_2 (p0[4].c.a, p1[4].c.a, ratio);
if (res_a <= alpha_threshold)
{
*dst_p = transparent;
}
else if (!dst_has_alpha)
{ // RGB surface handling
p0[4].c.r = dot_product_8_4 (p0, 0, w0);
p0[4].c.g = dot_product_8_4 (p0, 1, w0);
p0[4].c.b = dot_product_8_4 (p0, 2, w0);
p1[4].c.r = dot_product_8_4 (p1, 0, w1);
p1[4].c.g = dot_product_8_4 (p1, 1, w1);
p1[4].c.b = dot_product_8_4 (p1, 2, w1);
p0[4].c.r = blend_ratio_2 (p0[4].c.r, p1[4].c.r, ratio);
p0[4].c.g = blend_ratio_2 (p0[4].c.g, p1[4].c.g, ratio);
p0[4].c.b = blend_ratio_2 (p0[4].c.b, p1[4].c.b, ratio);
*dst_p =
(p0[4].c.r << dstfmt->Rshift) |
(p0[4].c.g << dstfmt->Gshift) |
(p0[4].c.b << dstfmt->Bshift);
}
else
{ // RGBA surface handling
// we do not want to blend with non-present pixels
// (pixels that have alpha == 0) as these will
// skew the result and make resulting alpha useless
if (p0[4].c.a != 0)
{
int i;
for (i = 0; i < 4; ++i)
if (p0[i].c.a == 0)
w0[i] = 0;
p0[4].c.r = weight_product_8_4 (p0, 0, w0);
p0[4].c.g = weight_product_8_4 (p0, 1, w0);
p0[4].c.b = weight_product_8_4 (p0, 2, w0);
}
if (p1[4].c.a != 0)
{
int i;
for (i = 0; i < 4; ++i)
if (p1[i].c.a == 0)
w1[i] = 0;
p1[4].c.r = weight_product_8_4 (p1, 0, w1);
p1[4].c.g = weight_product_8_4 (p1, 1, w1);
p1[4].c.b = weight_product_8_4 (p1, 2, w1);
}
if (p0[4].c.a != 0 && p1[4].c.a != 0)
{ // blend if both present
p0[4].c.r = blend_ratio_2 (p0[4].c.r, p1[4].c.r, ratio);
p0[4].c.g = blend_ratio_2 (p0[4].c.g, p1[4].c.g, ratio);
p0[4].c.b = blend_ratio_2 (p0[4].c.b, p1[4].c.b, ratio);
}
else if (p1[4].c.a != 0)
{ // other pixel is present
p0[4].value = p1[4].value;
}
// error-correct alpha to fully opaque to remove
// the often unwanted and unnecessary blending
if (res_a > 0xf8)
res_a = 0xff;
*dst_p =
(p0[4].c.r << dstfmt->Rshift) |
(p0[4].c.g << dstfmt->Gshift) |
(p0[4].c.b << dstfmt->Bshift) |
(res_a << dstfmt->Ashift);
}
}
}
SDL_UnlockSurface(mipmap);
SDL_UnlockSurface(dst);
SDL_UnlockSurface(src);
}
void