aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorbjörn Andersson2003-08-20 06:51:35 +0000
committerTorbjörn Andersson2003-08-20 06:51:35 +0000
commit1100a46242d9be6cde0d948739be24ce66a8f391 (patch)
treec1d28d552c57648ed6c046e373a680d7cd1ba32f
parentc2df1277a61d224663d17dbd52ab18863dd36bdc (diff)
downloadscummvm-rg350-1100a46242d9be6cde0d948739be24ce66a8f391.tar.gz
scummvm-rg350-1100a46242d9be6cde0d948739be24ce66a8f391.tar.bz2
scummvm-rg350-1100a46242d9be6cde0d948739be24ce66a8f391.zip
Cleaned up DrawSprite() and added scaling, based on the "line doubling"
method in the original code. There are still a few minor things missing, but it should work well enough for now. svn-id: r9788
-rw-r--r--sword2/driver/sprite.cpp442
1 files changed, 269 insertions, 173 deletions
diff --git a/sword2/driver/sprite.cpp b/sword2/driver/sprite.cpp
index b4fab6a562..f7e15eea03 100644
--- a/sword2/driver/sprite.cpp
+++ b/sword2/driver/sprite.cpp
@@ -1457,255 +1457,351 @@ int32 DeleteSurface(uint32 surface)
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
#define SCALE_MAXWIDTH 512
#define SCALE_MAXHEIGHT 512
uint16 xScale[SCALE_MAXWIDTH];
uint16 yScale[SCALE_MAXHEIGHT];
-
-int32 DrawSprite(_spriteInfo *s)
-
-{
- //warning("stub DrawSprite");
- debug(2, "semi-stub DrawSprite");
-
+int32 DrawSprite(_spriteInfo *s) {
uint8 *src, *dst;
uint8 *sprite, *newSprite;
uint8 pixel, red, green, blue;
+ uint16 scale;
int16 i, j;
- int16 freeSprite = 0;
+ uint16 srcPitch;
+ bool freeSprite = false;
ScummVM::Rect rd, rs;
- if (!(s->type & RDSPR_DISPLAYALIGN)) {
- s->x += parallaxScrollx;
- s->y += parallaxScrolly;
- }
-
- // The topmost 40 pixels are reserved by the GUI.
+ // FIXME: There are still a few minor details that I think the
+ // original did:
+ //
+ // * Anti-aliasing sprites when upscaling them.
+ // * The light mask. If a room has one the sprite should be colored
+ // by it, simulating light sources in the room.
+ // * We don't implement the various graphics quality settings at all.
+ //
+ // But it should be good enough for now.
- s->y += 40;
+ // -----------------------------------------------------------------
+ // Decompression and mirroring
+ // -----------------------------------------------------------------
if (s->type & RDSPR_NOCOMPRESSION)
sprite = s->data;
else {
sprite = (uint8 *) malloc(s->w * s->h);
+ freeSprite = true;
if (!sprite)
return RDERR_OUTOFMEMORY;
- freeSprite = 1;
if (s->type >> 8 == RDSPR_RLE16 >> 8) {
- if (DecompressRLE16(sprite, s->data, s->w * s->h, s->colourTable))
+ if (DecompressRLE16(sprite, s->data, s->w * s->h, s->colourTable)) {
+ free(sprite);
return RDERR_DECOMPRESSION;
+ }
} else {
- if (DecompressRLE256(sprite, s->data, s->w * s->h))
+ if (DecompressRLE256(sprite, s->data, s->w * s->h)) {
+ free(sprite);
return RDERR_DECOMPRESSION;
+ }
}
+ }
- if (s->type & RDSPR_FLIP) {
- newSprite = (uint8 *) malloc(s->w * s->h);
- if (newSprite == NULL) {
+ if (s->type & RDSPR_FLIP) {
+ newSprite = (uint8 *) malloc(s->w * s->h);
+ if (newSprite == NULL) {
+ if (freeSprite)
free(sprite);
- return RDERR_OUTOFMEMORY;
- }
- MirrorSprite(newSprite, sprite, s->w, s->h);
- free(sprite);
- sprite = newSprite;
+ return RDERR_OUTOFMEMORY;
}
+ MirrorSprite(newSprite, sprite, s->w, s->h);
+ if (freeSprite)
+ free(sprite);
+ sprite = newSprite;
+ freeSprite = true;
}
+ // -----------------------------------------------------------------
+ // Positioning and clipping.
+ // -----------------------------------------------------------------
- if (s->type & RDSPR_BLEND) {
- // We want to blend the sprite FROM the RECT rs.
- // We want to blend the sprite TO the RECT rd.
- rd.left = s->x - scrollx;
- rd.right = rd.left + s->w;
- rd.top = s->y - scrolly;
- rd.bottom = rd.top + s->h;
+ if (!(s->type & RDSPR_DISPLAYALIGN)) {
+ s->x += parallaxScrollx;
+ s->y += parallaxScrolly;
+ }
- rs.top = 0;
- rs.bottom = s->h;
- rs.left = 0;
+ s->y += 40;
+
+ // A scale factor 0 or 256 means don't scale. Why do they use two
+ // different values to mean the same thing? Normalize it here for
+ // convenience.
+
+ scale = (s->scale == 0) ? 256 : s->scale;
+
+ rs.top = 0;
+ rs.left = 0;
+
+ if (scale != 256) {
+ rs.right = s->scaledWidth;
+ rs.bottom = s->scaledHeight;
+ srcPitch = s->scaledWidth;
+ } else {
rs.right = s->w;
+ rs.bottom = s->h;
+ srcPitch = s->w;
+ }
- //Now do the clipping - top
- if (rd.top < 40) {
- rs.top = (40 - rd.top);
- rd.top = 40;
- }
- //Clip the bottom
- if (rd.bottom > RENDERDEEP) {
- rs.bottom -= (rd.bottom - RENDERDEEP);
- rd.bottom = RENDERDEEP;
+ rd.top = s->y;
+ rd.left = s->x;
+
+ if (!(s->type & RDSPR_DISPLAYALIGN)) {
+ rd.top -= scrolly;
+ rd.left -= scrollx;
+ }
+
+ rd.right = rd.left + rs.right;
+ rd.bottom = rd.top + rs.bottom;
+
+ if (rd.top < 40) {
+ rs.top = (40 - rd.top) * 256 / scale;
+ rd.top = 40;
+ }
+ if (rd.bottom > 440) {
+ rs.bottom -= ((rd.bottom - 440) * 256 / scale);
+ rd.bottom = 440;
+ }
+ if (rd.left < 0) {
+ rs.left = (0 - rd.left) * 256 / scale;
+ rd.left = 0;
+ }
+ if (rd.right > 640) {
+ rs.right -= ((rd.right - 640) * 256 / scale);
+ rd.right = 640;
+ }
+
+ // -----------------------------------------------------------------
+ // Scaling
+ // -----------------------------------------------------------------
+
+ if (scale != 256) {
+ int32 dx, dy, ince, incne, d;
+ int16 x, y;
+
+ if (s->scaledWidth > SCALE_MAXWIDTH || s->scaledHeight > SCALE_MAXHEIGHT) {
+ if (freeSprite)
+ free(sprite);
+ return RDERR_NOTIMPLEMENTED;
}
- //Clip the left
- if (rd.left < 0) {
- rs.left -= rd.left;
- rd.left = 0;
+
+ newSprite = (uint8 *) malloc(s->scaledWidth * s->scaledHeight);
+ if (newSprite == NULL) {
+ if (freeSprite)
+ free(sprite);
+ return RDERR_OUTOFMEMORY;
}
- //Clip the right
- if (rd.right > RENDERWIDE) {
- rs.right -= (rd.right - RENDERWIDE);
- rd.right = RENDERWIDE;
+
+ // This is based on the "line doubling" scaler in the original
+ // code.
+
+ if (scale < 256) {
+ // Work out the x-scale
+
+ dx = s->w;
+ dy = s->scaledWidth;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ xScale[y] = x;
+
+ while (x < s->w) {
+ if (d <= 0) {
+ d += ince;
+ x++;
+ } else {
+ d += incne;
+ x++;
+ y++;
+ }
+ xScale[y] = x;
+ }
+
+ // Work out the y-scale
+
+ dx = s->h;
+ dy = s->scaledHeight;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ yScale[y] = x;
+
+ while (x < s->h) {
+ if (d <= 0) {
+ d += ince;
+ x++;
+ } else {
+ d += incne;
+ x++;
+ y++;
+ }
+ yScale[y] = x;
+ }
+
+ // Copy the sprite
+
+ dst = newSprite;
+
+ for (y = 0; y < s->scaledHeight; y++) {
+ for (x = 0; x < s->scaledWidth; x++) {
+ *dst++ = *(sprite + yScale[y] * s->w + xScale[x]);
+ }
+ }
+ } else {
+ if (s->scale > 512) {
+ if (freeSprite)
+ free(sprite);
+ return RDERR_INVALIDSCALING;
+ }
+
+ // Work out the x-scale
+
+ dy = s->w;
+ dx = s->scaledWidth;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ xScale[y] = x;
+ while (x < s->scaledWidth) {
+ if (d <= 0) {
+ d += ince;
+ x++;
+ } else {
+ d += incne;
+ x++;
+ y++;
+ xScale[y] = x;
+ }
+ }
+
+ // Work out the y-scale
+
+ dy = s->h;
+ dx = s->scaledHeight;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ yScale[y] = x;
+ while (x < s->scaledHeight) {
+ if (d <= 0) {
+ d += ince;
+ x++;
+ } else {
+ d += incne;
+ x++;
+ y++;
+ yScale[y] = x;
+ }
+ }
+
+ // Copy the sprite
+
+ dst = newSprite;
+
+ for (y = 0; y <s->h; y++) {
+ for (j = yScale[y]; j < yScale[y + 1]; j++) {
+ for (x = 0; x < s->w; x++) {
+ for (i = xScale[x]; i < xScale[x + 1]; i++) {
+ *dst++ = *(sprite + y * s->w + x);
+ }
+ }
+ }
+ }
}
+ if (freeSprite)
+ free(sprite);
+ sprite = newSprite;
+ freeSprite = true;
+ }
+
+ // -----------------------------------------------------------------
+ // Drawing
+ // -----------------------------------------------------------------
+
+ src = sprite + rs.top * s->w + rs.left;
+ dst = (uint8 *) lpBackBuffer->_pixels + lpBackBuffer->_width * rd.top + rd.left;
+
+ if (s->type & RDSPR_BLEND) {
if (s->blend & 0x01) {
red = s->blend >> 8;
for (i = 0; i < rs.bottom - rs.top; i++) {
- src = sprite + (rs.top + i) * s->w + rs.left;
- dst = (uint8 *) lpBackBuffer->_pixels + lpBackBuffer->_width * (rd.top + i) + rd.left;
for (j = 0; j < rs.right - rs.left; j++) {
- if (*src) {
- pixel = *dst;
- *dst = paletteMatch[(((palCopy[*src][0] * red + palCopy[pixel][0] * (8 - red)) >> 5) << 12) +
- (((palCopy[*src][1] * red + palCopy[pixel][1] * (8 - red)) >> 5) << 6) +
- (((palCopy[*src][2] * red + palCopy[pixel][2] * (8 - red)) >> 5))];
+ if (src[j]) {
+ pixel = dst[j];
+ dst[j] = paletteMatch[(((palCopy[src[j]][0] * red + palCopy[pixel][0] * (8 - red)) >> 5) << 12) +
+ (((palCopy[src[j]][1] * red + palCopy[pixel][1] * (8 - red)) >> 5) << 6) +
+ (((palCopy[src[j]][2] * red + palCopy[pixel][2] * (8 - red)) >> 5))];
}
- src++;
- dst++;
}
+ src += srcPitch;
+ dst += lpBackBuffer->_width;
}
} else if (s->blend & 0x02) {
red = palCopy[s->blend >> 8][0];
green = palCopy[s->blend >> 8][0];
blue = palCopy[s->blend >> 8][0];
for (i = 0; i < rs.bottom - rs.top; i++) {
- src = sprite + (rs.top + i) * s->w + rs.left;
- dst = (uint8 *) lpBackBuffer->_pixels + lpBackBuffer->_width * (rd.top + i) + rd.left;
for (j = 0; j < rs.right - rs.left; j++) {
- if (*src) {
- pixel = *dst;
- *dst = paletteMatch[((((*src * red + (16 - *src) * palCopy[pixel][0]) >> 4) >> 2) << 12) +
- ((((*src * green + (16 - *src) * palCopy[pixel][1]) >> 4) >> 2) << 6) +
- (((*src * blue + (16 - *src) * palCopy[pixel][2]) >> 4) >> 2)];
+ if (src[j]) {
+ pixel = dst[j];
+ dst[j] = paletteMatch[((((src[j] * red + (16 - src[j]) * palCopy[pixel][0]) >> 4) >> 2) << 12) +
+ ((((src[j] * green + (16 - src[j]) * palCopy[pixel][1]) >> 4) >> 2) << 6) +
+ (((src[j] * blue + (16 - src[j]) * palCopy[pixel][2]) >> 4) >> 2)];
}
- src++;
- dst++;
}
+ src += srcPitch;
+ dst += lpBackBuffer->_width;
}
} else {
+ warning("DrawSprite: Invalid blended sprite");
if (freeSprite)
free(sprite);
- warning("DrawSprite: Invalid blended sprite");
return RDERR_UNKNOWNTYPE;
}
-
- // Upload the sprite area to the backend.
- lpBackBuffer->upload(&rd);
} else {
- // Set startx and starty for the screen buffer
-
- if (s->type & RDSPR_DISPLAYALIGN)
- rd.top = s->y;
- else
- rd.top = s->y - scrolly;
-
- if (s->type & RDSPR_DISPLAYALIGN)
- rd.left = s->x;
- else
- rd.left = s->x - scrollx;
-
- rs.left = 0;
- rs.right = s->w;
- rs.top = 0;
- rs.bottom = s->h;
-
- if (s->scale & 0xFF) {
- // FIXME: For now, turn scaling off.
- warning("FIXME: DrawSprite: Implement scaling");
- s->scale &= ~0xFF;
- }
-
- if (s->scale & 0xff) {
- rd.right = rd.left + s->scaledWidth;
- rd.bottom = rd.top + s->scaledHeight;
- // Do clipping
- if (rd.top < 40) {
- rs.top = (40 - rd.top) * 256 / s->scale;
- rd.top = 40;
- }
- if (rd.bottom > 440) {
- rs.bottom -= ((rd.bottom - 440) * 256 / s->scale);
- rd.bottom = 440;
- }
- if (rd.left < 0) {
- rs.left = (0 - rd.left) * 256 / s->scale;
- rd.left = 0;
- }
- if (rd.right > 640) {
- rs.right -= ((rd.right - 640) * 256 / s->scale);
- rd.right = 640;
- }
- } else {
- rd.right = rd.left + s->w;
- rd.bottom = rd.top + s->h;
-
- // Do clipping
- if (rd.top < 40) {
- rs.top = 40 - rd.top;
- rd.top = 40;
- }
- if (rd.bottom > 440) {
- rs.bottom -= (rd.bottom - 440);
- rd.bottom = 440;
- }
- if (rd.left < 0) {
- rs.left = 0 - rd.left;
- rd.left = 0;
- }
- if (rd.right > 640) {
- rs.right -= (rd.right - 640);
- rd.right = 640;
- }
- }
-
- src = sprite + rs.top * s->w + rs.left;
- dst = (uint8 *) lpBackBuffer->_pixels + lpBackBuffer->_width * rd.top + rd.left;
if (s->type & RDSPR_TRANS) {
for (i = 0; i < rs.bottom - rs.top; i++) {
for (j = 0; j < rs.right - rs.left; j++) {
if (src[j])
dst[j] = src[j];
}
- src += s->w;
+ src += srcPitch;
dst += lpBackBuffer->_width;
}
} else {
for (i = 0; i < rs.bottom - rs.top; i++) {
memcpy(dst, src, rs.right - rs.left);
- src += s->w;
+ src += srcPitch;
dst += lpBackBuffer->_width;
}
}
-
- lpBackBuffer->upload(&rd);
-
- if (freeSprite)
- free(sprite);
}
- // I'm guessing that the rest of the original code is simply to draw
- // the sprite in "software mode" at different quality setting. If so,
- // we should probably adapt some of it. Later.
+ if (freeSprite)
+ free(sprite);
+
+ lpBackBuffer->upload(&rd);
/*