From c9c56d2f7242b02e9b23217dfcd1c657f9811ea0 Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Sun, 6 Jun 2004 15:40:31 +0000 Subject: Cleaned up sprite scaling. svn-id: r13944 --- sword2/driver/d_draw.h | 6 +- sword2/driver/menu.cpp | 4 +- sword2/driver/render.cpp | 316 ++++++++++++++--------------------------------- sword2/driver/sprite.cpp | 24 +--- 4 files changed, 99 insertions(+), 251 deletions(-) diff --git a/sword2/driver/d_draw.h b/sword2/driver/d_draw.h index 1177b3e6b7..2d8eb83412 100644 --- a/sword2/driver/d_draw.h +++ b/sword2/driver/d_draw.h @@ -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); diff --git a/sword2/driver/menu.cpp b/sword2/driver/menu.cpp index 28ab6b955e..8fa68791db 100644 --- a/sword2/driver/menu.cpp +++ b/sword2/driver/menu.cpp @@ -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); diff --git a/sword2/driver/render.cpp b/sword2/driver/render.cpp index e76bdf7369..c6e9f745b2 100644 --- a/sword2/driver/render.cpp +++ b/sword2/driver/render.cpp @@ -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. - -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; +// This code isn't quite like the original DrawSprite(), but should be close +// enough. - // Work out the x-scale - - ince = 2 * dstWidth; - incne = 2 * (dstWidth - srcWidth); - d = 2 * dstWidth - srcWidth; - x = y = 0; - _xScale[y] = x; - - while (x < srcWidth) { - if (d <= 0) { - d += ince; - x++; - } else { - d += incne; - x++; - y++; - } - _xScale[y] = x; - } +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 y-scale + for (x = 0; x < dstWidth; x++) + _xScale[x] = (x * srcWidth) / dstWidth; - ince = 2 * dstHeight; - incne = 2 * (dstHeight - srcHeight); - d = 2 * dstHeight - srcHeight; - x = y = 0; - _yScale[y] = x; + for (y = 0; y < dstHeight; y++) + _yScale[y] = (y * srcHeight) / dstHeight; - 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; - - // Work out the x-scale - - ince = 2 * srcWidth; - incne = 2 * (srcWidth - dstWidth); - d = 2 * srcWidth - dstWidth; - x = y = 0; - _xScale[y] = x; - - while (x < dstWidth) { - if (d <= 0) { - d += ince; - x++; - } else { - d += incne; - x++; - y++; - _xScale[y] = x; - } - } - - // Work out the y-scale - - 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; - } - } +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; - // Copy the image + uint32 xPos = (x * srcWidth) / dstWidth; + uint32 yPos = (y * srcHeight) / dstHeight; + uint32 xFrac = dstWidth - (x * srcWidth) % dstWidth; + uint32 yFrac = dstHeight - (y * srcHeight) % dstHeight; - 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 + byte *srcPtr = src + yPos * srcPitch + xPos; + byte *backPtr = backbuf + y * _screenWide + x; - if (backbuf) { - byte *newDst = (byte *) malloc(dstWidth * dstHeight); - if (!newDst) - return; + bool transparent = true; - memcpy(newDst, origDst, dstWidth); + if (*srcPtr) { + c1 = *srcPtr; + transparent = false; + } else + c1 = *backPtr; - 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; - - 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)); + c2 = *(backPtr + 1); + } else + c2 = c1; + + if (y < dstHeight - 1) { + if (*(srcPtr + srcPitch)) { + c3 = *(srcPtr + srcPitch); + transparent = false; } else - *dst++ = 0; - src++; - } - *dst++ = *src++; - } - memcpy(dst, src, dstWidth); - - src = newDst; - dst = origDst; - - for (i = 0; i < dstHeight; i++) { - memcpy(dst, src, dstWidth); - dst += dstPitch; - src += dstWidth; + 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; } - - free(newDst); } } diff --git a/sword2/driver/sprite.cpp b/sword2/driver/sprite.cpp index 776c1d9d55..601e003f5b 100644 --- a/sword2/driver/sprite.cpp +++ b/sword2/driver/sprite.cpp @@ -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); -- cgit v1.2.3