mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-24 13:13:58 +00:00
Cleaned up sprite scaling.
svn-id: r13944
This commit is contained in:
parent
29f03f0d9c
commit
c9c56d2f72
@ -153,10 +153,10 @@ private:
|
||||
uint8 getMatch(uint8 r, uint8 g, uint8 b);
|
||||
void fadeServer(void);
|
||||
|
||||
void squashImage(byte *dst, uint16 dstPitch, uint16 dstWidth,
|
||||
void scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth,
|
||||
uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth,
|
||||
uint16 srcHeight, byte *backbuf);
|
||||
void stretchImage(byte *dst, uint16 dstPitch, uint16 dstWidth,
|
||||
uint16 srcHeight);
|
||||
void scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth,
|
||||
uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth,
|
||||
uint16 srcHeight, byte *backbuf);
|
||||
|
||||
|
@ -156,9 +156,9 @@ void Graphics::processMenu(void) {
|
||||
byte *src = _icons[menu][i];
|
||||
|
||||
if (_pocketStatus[menu][i] != MAXMENUANIMS) {
|
||||
squashImage(
|
||||
scaleImageFast(
|
||||
dst, _screenWide, r2.right - r2.left, r2.bottom - r2.top,
|
||||
src, RDMENU_ICONWIDE, RDMENU_ICONWIDE, RDMENU_ICONDEEP, NULL);
|
||||
src, RDMENU_ICONWIDE, RDMENU_ICONWIDE, RDMENU_ICONDEEP);
|
||||
} else {
|
||||
for (j = 0; j < RDMENU_ICONDEEP; j++) {
|
||||
memcpy(dst, src, RDMENU_ICONWIDE);
|
||||
|
@ -77,249 +77,113 @@ void Graphics::blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect *
|
||||
}
|
||||
}
|
||||
|
||||
// I've made the scaling two separate functions because there were cases from
|
||||
// DrawSprite() where it wasn't obvious if the sprite should grow or shrink,
|
||||
// which caused crashes.
|
||||
// There are two different separate functions for scaling the image - one fast
|
||||
// and one good. Or at least that's the theory. I'm sure there are better ways
|
||||
// to scale an image than this. The latter is used at the highest graphics
|
||||
// quality setting. Note that the "good" scaler takes an extra parameter, a
|
||||
// pointer to the area of the screen where the sprite will be drawn.
|
||||
//
|
||||
// Keeping them separate might be a good idea anyway, for readability.
|
||||
//
|
||||
// The code is based on the original DrawSprite() code, so apart from not
|
||||
// knowing if I got it right, I don't know how good the original really is.
|
||||
//
|
||||
// The backbuf parameter points to the buffer where the image will eventually
|
||||
// be drawn. This is only used at the highest graphics detail setting (and not
|
||||
// always even then) and is used to help anti-alias the image.
|
||||
// This code isn't quite like the original DrawSprite(), but should be close
|
||||
// enough.
|
||||
|
||||
void Graphics::squashImage(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight, byte *backbuf) {
|
||||
int32 ince, incne, d;
|
||||
int16 x, y;
|
||||
void Graphics::scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight) {
|
||||
int x, y;
|
||||
|
||||
// Work out the x-scale
|
||||
for (x = 0; x < dstWidth; x++)
|
||||
_xScale[x] = (x * srcWidth) / dstWidth;
|
||||
|
||||
ince = 2 * dstWidth;
|
||||
incne = 2 * (dstWidth - srcWidth);
|
||||
d = 2 * dstWidth - srcWidth;
|
||||
x = y = 0;
|
||||
_xScale[y] = x;
|
||||
for (y = 0; y < dstHeight; y++)
|
||||
_yScale[y] = (y * srcHeight) / dstHeight;
|
||||
|
||||
while (x < srcWidth) {
|
||||
if (d <= 0) {
|
||||
d += ince;
|
||||
x++;
|
||||
} else {
|
||||
d += incne;
|
||||
x++;
|
||||
y++;
|
||||
}
|
||||
_xScale[y] = x;
|
||||
}
|
||||
|
||||
// Work out the y-scale
|
||||
|
||||
ince = 2 * dstHeight;
|
||||
incne = 2 * (dstHeight - srcHeight);
|
||||
d = 2 * dstHeight - srcHeight;
|
||||
x = y = 0;
|
||||
_yScale[y] = x;
|
||||
|
||||
while (x < srcHeight) {
|
||||
if (d <= 0) {
|
||||
d += ince;
|
||||
x++;
|
||||
} else {
|
||||
d += incne;
|
||||
x++;
|
||||
y++;
|
||||
}
|
||||
_yScale[y] = x;
|
||||
}
|
||||
|
||||
// Copy the image (with or without anti-aliasing)
|
||||
|
||||
if (backbuf) {
|
||||
for (y = 0; y < dstHeight; y++) {
|
||||
for (x = 0; x < dstWidth; x++) {
|
||||
uint8 p;
|
||||
uint8 p1 = 0;
|
||||
int count = 0;
|
||||
int spriteCount = 0;
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
int i, j;
|
||||
|
||||
for (j = _yScale[y]; j < _yScale[y + 1]; j++) {
|
||||
for (i = _xScale[x]; i < _xScale[x + 1]; i++) {
|
||||
p = src[j * srcPitch + i];
|
||||
if (p) {
|
||||
red += _palCopy[p][0];
|
||||
green += _palCopy[p][1];
|
||||
blue += _palCopy[p][2];
|
||||
p1 = p;
|
||||
spriteCount++;
|
||||
} else {
|
||||
red += _palCopy[backbuf[x]][0];
|
||||
green += _palCopy[backbuf[x]][1];
|
||||
blue += _palCopy[backbuf[x]][2];
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (spriteCount == 0)
|
||||
dst[x] = 0;
|
||||
else if (spriteCount == 1)
|
||||
dst[x] = p1;
|
||||
else
|
||||
dst[x] = quickMatch((uint8) (red / count), (uint8) (green / count), (uint8) (blue / count));
|
||||
}
|
||||
dst += dstPitch;
|
||||
backbuf += _screenWide;
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < dstHeight; y++) {
|
||||
for (x = 0; x < dstWidth; x++) {
|
||||
dst[x] = src[_yScale[y] * srcPitch + _xScale[x]];
|
||||
}
|
||||
dst += dstPitch;
|
||||
for (y = 0; y < dstHeight; y++) {
|
||||
for (x = 0; x < dstWidth; x++) {
|
||||
dst[x] = src[_yScale[y] * srcPitch + _xScale[x]];
|
||||
}
|
||||
dst += dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::stretchImage(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight, byte *backbuf) {
|
||||
byte *origDst = dst;
|
||||
int32 ince, incne, d;
|
||||
int16 x, y, i, j, k;
|
||||
void Graphics::scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight, byte *backbuf) {
|
||||
for (int y = 0; y < dstHeight; y++) {
|
||||
for (int x = 0; x < dstWidth; x++) {
|
||||
uint8 c1, c2, c3, c4;
|
||||
|
||||
// Work out the x-scale
|
||||
uint32 xPos = (x * srcWidth) / dstWidth;
|
||||
uint32 yPos = (y * srcHeight) / dstHeight;
|
||||
uint32 xFrac = dstWidth - (x * srcWidth) % dstWidth;
|
||||
uint32 yFrac = dstHeight - (y * srcHeight) % dstHeight;
|
||||
|
||||
ince = 2 * srcWidth;
|
||||
incne = 2 * (srcWidth - dstWidth);
|
||||
d = 2 * srcWidth - dstWidth;
|
||||
x = y = 0;
|
||||
_xScale[y] = x;
|
||||
byte *srcPtr = src + yPos * srcPitch + xPos;
|
||||
byte *backPtr = backbuf + y * _screenWide + x;
|
||||
|
||||
while (x < dstWidth) {
|
||||
if (d <= 0) {
|
||||
d += ince;
|
||||
x++;
|
||||
} else {
|
||||
d += incne;
|
||||
x++;
|
||||
y++;
|
||||
_xScale[y] = x;
|
||||
}
|
||||
}
|
||||
bool transparent = true;
|
||||
|
||||
// Work out the y-scale
|
||||
if (*srcPtr) {
|
||||
c1 = *srcPtr;
|
||||
transparent = false;
|
||||
} else
|
||||
c1 = *backPtr;
|
||||
|
||||
ince = 2 * srcHeight;
|
||||
incne = 2 * (srcHeight - dstHeight);
|
||||
d = 2 * srcHeight - dstHeight;
|
||||
x = y = 0;
|
||||
_yScale[y] = x;
|
||||
while (x < dstHeight) {
|
||||
if (d <= 0) {
|
||||
d += ince;
|
||||
x++;
|
||||
} else {
|
||||
d += incne;
|
||||
x++;
|
||||
y++;
|
||||
_yScale[y] = x;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the image
|
||||
|
||||
for (y = 0; y < srcHeight; y++) {
|
||||
for (j = _yScale[y]; j < _yScale[y + 1]; j++) {
|
||||
k = 0;
|
||||
for (x = 0; x < srcWidth; x++) {
|
||||
for (i = _xScale[x]; i < _xScale[x + 1]; i++) {
|
||||
dst[k++] = src[y * srcPitch + x];
|
||||
}
|
||||
}
|
||||
dst += dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Anti-aliasing
|
||||
|
||||
if (backbuf) {
|
||||
byte *newDst = (byte *) malloc(dstWidth * dstHeight);
|
||||
if (!newDst)
|
||||
return;
|
||||
|
||||
memcpy(newDst, origDst, dstWidth);
|
||||
|
||||
for (y = 1; y < dstHeight - 1; y++) {
|
||||
src = origDst + y * dstPitch;
|
||||
dst = newDst + y * dstWidth;
|
||||
*dst++ = *src++;
|
||||
for (x = 1; x < dstWidth - 1; x++) {
|
||||
byte pt[5];
|
||||
byte *p = backbuf + y * 640 + x;
|
||||
int count = 0;
|
||||
|
||||
if (*src) {
|
||||
count++;
|
||||
pt[0] = *src;
|
||||
if (x < dstWidth - 1) {
|
||||
if (*(srcPtr + 1)) {
|
||||
c2 = *(srcPtr + 1);
|
||||
transparent = false;
|
||||
} else
|
||||
pt[0] = *p;
|
||||
c2 = *(backPtr + 1);
|
||||
} else
|
||||
c2 = c1;
|
||||
|
||||
pt[1] = *(src - dstPitch);
|
||||
if (pt[1] == 0)
|
||||
pt[1] = *(p - 640);
|
||||
else
|
||||
count++;
|
||||
|
||||
pt[2] = *(src - 1);
|
||||
if (pt[2] == 0)
|
||||
pt[2] = *(p - 1);
|
||||
else
|
||||
count++;
|
||||
|
||||
pt[3] = *(src + 1);
|
||||
if (pt[3] == 0)
|
||||
pt[3] = *(p + 1);
|
||||
else
|
||||
count++;
|
||||
|
||||
pt[4] = *(src + dstPitch);
|
||||
if (pt[4] == 0)
|
||||
pt[4] = *(p + 640);
|
||||
else
|
||||
count++;
|
||||
|
||||
if (count) {
|
||||
int red = _palCopy[pt[0]][0] << 2;
|
||||
int green = _palCopy[pt[0]][1] << 2;
|
||||
int blue = _palCopy[pt[0]][2] << 2;
|
||||
for (i = 1; i < 5; i++) {
|
||||
red += _palCopy[pt[i]][0];
|
||||
green += _palCopy[pt[i]][1];
|
||||
blue += _palCopy[pt[i]][2];
|
||||
}
|
||||
|
||||
*dst++ = quickMatch((uint8) (red >> 3), (uint8) (green >> 3), (uint8) (blue >> 3));
|
||||
if (y < dstHeight - 1) {
|
||||
if (*(srcPtr + srcPitch)) {
|
||||
c3 = *(srcPtr + srcPitch);
|
||||
transparent = false;
|
||||
} else
|
||||
*dst++ = 0;
|
||||
src++;
|
||||
}
|
||||
*dst++ = *src++;
|
||||
c3 = *(backPtr + _screenWide);
|
||||
} else
|
||||
c3 = c1;
|
||||
|
||||
if (x < dstWidth - 1 && y < dstHeight - 1) {
|
||||
if (*(srcPtr + srcPitch + 1)) {
|
||||
c4 = *(srcPtr + srcPitch + 1);
|
||||
transparent = false;
|
||||
} else
|
||||
c4 = *(backPtr + _screenWide + 1);
|
||||
} else
|
||||
c4 = c3;
|
||||
|
||||
if (!transparent) {
|
||||
uint32 r1 = _palCopy[c1][0];
|
||||
uint32 g1 = _palCopy[c1][1];
|
||||
uint32 b1 = _palCopy[c1][2];
|
||||
|
||||
uint32 r2 = _palCopy[c2][0];
|
||||
uint32 g2 = _palCopy[c2][1];
|
||||
uint32 b2 = _palCopy[c2][2];
|
||||
|
||||
uint32 r3 = _palCopy[c3][0];
|
||||
uint32 g3 = _palCopy[c3][1];
|
||||
uint32 b3 = _palCopy[c3][2];
|
||||
|
||||
uint32 r4 = _palCopy[c4][0];
|
||||
uint32 g4 = _palCopy[c4][1];
|
||||
uint32 b4 = _palCopy[c4][2];
|
||||
|
||||
uint32 r5 = (r1 * xFrac + r2 * (dstWidth - xFrac)) / dstWidth;
|
||||
uint32 g5 = (g1 * xFrac + g2 * (dstWidth - xFrac)) / dstWidth;
|
||||
uint32 b5 = (b1 * xFrac + b2 * (dstWidth - xFrac)) / dstWidth;
|
||||
|
||||
uint32 r6 = (r3 * xFrac + r4 * (dstWidth - xFrac)) / dstWidth;
|
||||
uint32 g6 = (g3 * xFrac + g4 * (dstWidth - xFrac)) / dstWidth;
|
||||
uint32 b6 = (b3 * xFrac + b4 * (dstWidth - xFrac)) / dstWidth;
|
||||
|
||||
uint32 r = (r5 * yFrac + r6 * (dstHeight - yFrac)) / dstHeight;
|
||||
uint32 g = (g5 * yFrac + g6 * (dstHeight - yFrac)) / dstHeight;
|
||||
uint32 b = (b5 * yFrac + b6 * (dstHeight - yFrac)) / dstHeight;
|
||||
|
||||
dst[y * dstWidth + x] = quickMatch(r, g, b);
|
||||
} else
|
||||
dst[y * dstWidth + x] = 0;
|
||||
}
|
||||
memcpy(dst, src, dstWidth);
|
||||
|
||||
src = newDst;
|
||||
dst = origDst;
|
||||
|
||||
for (i = 0; i < dstHeight; i++) {
|
||||
memcpy(dst, src, dstWidth);
|
||||
dst += dstPitch;
|
||||
src += dstWidth;
|
||||
}
|
||||
|
||||
free(newDst);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,12 +355,10 @@ void Graphics::deleteSurface(byte *surface) {
|
||||
int32 Graphics::drawSprite(SpriteInfo *s) {
|
||||
byte *src, *dst;
|
||||
byte *sprite, *newSprite;
|
||||
byte *backbuf = NULL;
|
||||
uint16 scale;
|
||||
int16 i, j;
|
||||
uint16 srcPitch;
|
||||
bool freeSprite = false;
|
||||
bool clipped = false;
|
||||
Common::Rect rd, rs;
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
@ -453,22 +451,18 @@ int32 Graphics::drawSprite(SpriteInfo *s) {
|
||||
if (rd.top < 40) {
|
||||
rs.top = 40 - rd.top;
|
||||
rd.top = 40;
|
||||
clipped = true;
|
||||
}
|
||||
if (rd.bottom > 440) {
|
||||
rd.bottom = 440;
|
||||
rs.bottom = rs.top + (rd.bottom - rd.top);
|
||||
clipped = true;
|
||||
}
|
||||
if (rd.left < 0) {
|
||||
rs.left = -rd.left;
|
||||
rd.left = 0;
|
||||
clipped = true;
|
||||
}
|
||||
if (rd.right > 640) {
|
||||
rd.right = 640;
|
||||
rs.right = rs.left + (rd.right - rd.left);
|
||||
clipped = true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
@ -476,10 +470,6 @@ int32 Graphics::drawSprite(SpriteInfo *s) {
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
if (scale != 256) {
|
||||
if ((_renderCaps & RDBLTFX_EDGEBLEND) && !clipped)
|
||||
backbuf = _buffer + _screenWide * rd.top + rd.left;
|
||||
|
||||
|
||||
if (s->scaledWidth > SCALE_MAXWIDTH || s->scaledHeight > SCALE_MAXHEIGHT) {
|
||||
if (freeSprite)
|
||||
free(sprite);
|
||||
@ -493,16 +483,10 @@ int32 Graphics::drawSprite(SpriteInfo *s) {
|
||||
return RDERR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if (scale < 256) {
|
||||
squashImage(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h, backbuf);
|
||||
} else {
|
||||
if (s->scale > 512) {
|
||||
if (freeSprite)
|
||||
free(sprite);
|
||||
return RDERR_INVALIDSCALING;
|
||||
}
|
||||
stretchImage(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h, backbuf);
|
||||
}
|
||||
if (_renderCaps & RDBLTFX_EDGEBLEND)
|
||||
scaleImageGood(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h, _buffer + _screenWide * rd.top + rd.left);
|
||||
else
|
||||
scaleImageFast(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h);
|
||||
|
||||
if (freeSprite)
|
||||
free(sprite);
|
||||
|
Loading…
x
Reference in New Issue
Block a user