aboutsummaryrefslogtreecommitdiff
path: root/sword2/driver
diff options
context:
space:
mode:
authorTorbjörn Andersson2003-08-26 06:53:00 +0000
committerTorbjörn Andersson2003-08-26 06:53:00 +0000
commit8277c6cb798552de5ef315311db18f91a25e42fc (patch)
tree18606d41b4db06dda28acc075af1141c750fbcff /sword2/driver
parentf3675261a970ca1c76870f3ebbf3774771d22270 (diff)
downloadscummvm-rg350-8277c6cb798552de5ef315311db18f91a25e42fc.tar.gz
scummvm-rg350-8277c6cb798552de5ef315311db18f91a25e42fc.tar.bz2
scummvm-rg350-8277c6cb798552de5ef315311db18f91a25e42fc.zip
The graphics detail settings partially work now. They only affect how
sprites are drawn, but I think that's how it should be. 1: No bells or whistles. 2: This setting adds sprite blending, e.g. the smoke at the docks or the display cases at the Glease Gallery. 3: This setting adds light map support, e.g. when walking under the shack at the docks. 4: This setting adds better scaling algorithms. The first three settings should work fine now. In fact, the third setting is what we used to implement. The fourth setting still needs work and testing. I've added code for downscaling case, but frankly I'm not convinced the result is any better than with the simpler scaler. I usually can't even tell the difference. Of course, my translation of the original code could very well be buggy. svn-id: r9867
Diffstat (limited to 'sword2/driver')
-rw-r--r--sword2/driver/d_draw.cpp33
-rw-r--r--sword2/driver/driver96.h10
-rw-r--r--sword2/driver/menu.cpp2
-rw-r--r--sword2/driver/render.cpp64
-rw-r--r--sword2/driver/render.h4
-rw-r--r--sword2/driver/sprite.cpp196
6 files changed, 166 insertions, 143 deletions
diff --git a/sword2/driver/d_draw.cpp b/sword2/driver/d_draw.cpp
index 68dc133c0c..752a06f304 100644
--- a/sword2/driver/d_draw.cpp
+++ b/sword2/driver/d_draw.cpp
@@ -123,24 +123,35 @@ int32 InitialiseDisplay(int16 width, int16 height, int16 colourDepth, int32 wind
return(RD_OK);
}
-int32 SetBltFx(void) {
- renderCaps |= RDBLTFX_EDGEBLEND + RDBLTFX_ARITHMETICSTRETCH;
- return(RD_OK);
+// FIXME: Clean up this mess. I don't want to add any new flags, but some of
+// them should be renamed. Or maybe we should abandon the whole renderCaps
+// thing and simply check the numeric value of the graphics quality setting
+// instead.
+
+// Note that SetTransFx() actually clears a bit. That's intentional.
+
+void SetTransFx(void) {
+ renderCaps &= ~RDBLTFX_ALLHARDWARE;
}
-int32 ClearBltFx(void) {
- renderCaps &= (0xffffffff - RDBLTFX_EDGEBLEND - RDBLTFX_ARITHMETICSTRETCH);
- return(RD_OK);
+void ClearTransFx(void) {
+ renderCaps |= RDBLTFX_ALLHARDWARE;
}
-int32 ClearShadowFx(void) {
- renderCaps &= (0xffffffff - RDBLTFX_SHADOWBLEND);
- return(RD_OK);
+void SetBltFx(void) {
+ renderCaps |= (RDBLTFX_EDGEBLEND | RDBLTFX_ARITHMETICSTRETCH);
}
-int32 SetShadowFx(void) {
+void ClearBltFx(void) {
+ renderCaps &= ~(RDBLTFX_EDGEBLEND | RDBLTFX_ARITHMETICSTRETCH);
+}
+
+void SetShadowFx(void) {
renderCaps |= RDBLTFX_SHADOWBLEND;
- return RD_OK;
+}
+
+void ClearShadowFx(void) {
+ renderCaps &= ~RDBLTFX_SHADOWBLEND;
}
int32 GetRenderType(void)
diff --git a/sword2/driver/driver96.h b/sword2/driver/driver96.h
index 9255566165..8f8a304aa9 100644
--- a/sword2/driver/driver96.h
+++ b/sword2/driver/driver96.h
@@ -1476,10 +1476,12 @@ typedef struct {
extern int32 InitialiseDisplay(int16 width, int16 height, int16 colourDepth, int32 windowType);
extern int32 WaitForVbl(void);
extern int32 EraseBackBuffer(void);
-extern int32 SetBltFx(void);
-extern int32 ClearBltFx(void);
-extern int32 ClearShadowFx(void);
-extern int32 SetShadowFx(void);
+extern void SetTransFx(void);
+extern void ClearTransFx(void);
+extern void SetBltFx(void);
+extern void ClearBltFx(void);
+extern void ClearShadowFx(void);
+extern void SetShadowFx(void);
extern int32 GetRenderType(void);
extern int32 PlaySmacker(char *filename, _movieTextObject *textObjects[], uint8 *musicOut);
extern void GetDrawStatus(_drvDrawStatus *s);
diff --git a/sword2/driver/menu.cpp b/sword2/driver/menu.cpp
index 241866e8f8..2f6d1d6314 100644
--- a/sword2/driver/menu.cpp
+++ b/sword2/driver/menu.cpp
@@ -238,7 +238,7 @@ int32 ProcessMenu(void) {
if (pocketStatus[menu][i] != MAXMENUANIMS) {
SquashImage(
dst, lpBackBuffer->_width, r.right - r.left, r.bottom - r.top,
- src, RDMENU_ICONWIDE, RDMENU_ICONWIDE, RDMENU_ICONDEEP);
+ src, RDMENU_ICONWIDE, RDMENU_ICONWIDE, RDMENU_ICONDEEP, NULL);
} else {
for (int j = 0; j < RDMENU_ICONDEEP; j++) {
memcpy(dst, src, RDMENU_ICONWIDE);
diff --git a/sword2/driver/render.cpp b/sword2/driver/render.cpp
index 1d9749e3f8..3bdc306f97 100644
--- a/sword2/driver/render.cpp
+++ b/sword2/driver/render.cpp
@@ -349,15 +349,16 @@ void UploadRect(ScummVM::Rect *r) {
static uint16 xScale[SCALE_MAXWIDTH];
static uint16 yScale[SCALE_MAXHEIGHT];
-// This is based on the "line doubling" scaler in the original sprite renderer.
-// I've made it into two separate functions because there were cases from
+// 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.
//
-// The functions can probably be merged later, if/when we implement a better
-// scale function for it.
+// Maybe the functions can be merged later?
+//
+// 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.
-void SquashImage(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight,byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight) {
+void 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;
@@ -403,15 +404,56 @@ void SquashImage(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight,b
// Copy the image
- for (y = 0; y < dstHeight; y++) {
- for (x = 0; x < dstWidth; x++) {
- dst[x] = src[yScale[y] * srcPitch + xScale[x]];
+ 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 += lpBackBuffer->_width;
+ }
+ } else {
+ for (y = 0; y < dstHeight; y++) {
+ for (x = 0; x < dstWidth; x++) {
+ dst[x] = src[yScale[y] * srcPitch + xScale[x]];
+ }
+ dst += dstPitch;
}
- dst += dstPitch;
}
}
-void StretchImage(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight,byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight) {
+void StretchImage(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, i, j, k;
@@ -456,6 +498,8 @@ void StretchImage(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight,
// Copy the image
+ // FIXME: If backbuf != NULL the image should be anti-aliased
+
for (y = 0; y < srcHeight; y++) {
for (j = yScale[y]; j < yScale[y + 1]; j++) {
k = 0;
diff --git a/sword2/driver/render.h b/sword2/driver/render.h
index d49d64ee11..afae35874d 100644
--- a/sword2/driver/render.h
+++ b/sword2/driver/render.h
@@ -88,8 +88,8 @@ extern int16 locationDeep;
// extern uint8 myScreenBuffer[RENDERWIDE * RENDERDEEP];
-void SquashImage(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight);
-void StretchImage(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight);
+void SquashImage(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 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight, byte *backbuf);
void UploadRect(ScummVM::Rect *r);
diff --git a/sword2/driver/sprite.cpp b/sword2/driver/sprite.cpp
index 324f7981bf..023b61f35c 100644
--- a/sword2/driver/sprite.cpp
+++ b/sword2/driver/sprite.cpp
@@ -1298,9 +1298,9 @@ int32 DrawSurface(_spriteInfo *s, uint8 *surface) {
return RDERR_OUTOFMEMORY;
if (scale < 256) {
- SquashImage(sprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, surface, s->w, s->w, s->h);
+ SquashImage(sprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, surface, s->w, s->w, s->h, NULL);
} else {
- StretchImage(sprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, surface, s->w, s->w, s->h);
+ StretchImage(sprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, surface, s->w, s->w, s->h, NULL);
}
freeSprite = true;
@@ -1348,20 +1348,19 @@ uint16 yScale[SCALE_MAXHEIGHT];
int32 DrawSprite(_spriteInfo *s) {
uint8 *src, *dst;
uint8 *sprite, *newSprite;
+ uint8 *backbuf = NULL;
uint8 red, green, blue;
uint16 scale;
int16 i, j;
uint16 srcPitch;
bool freeSprite = false;
+ bool clipped = false;
ScummVM::Rect rd, rs;
// FIXME: There are still a few minor details that I think the
- // original did:
- //
- // * Anti-aliasing sprites when upscaling them.
- // * We don't implement the various graphics quality settings at all.
- //
- // But it should be good enough for now.
+ // original did. Off-hand, I know that at the highest graphics
+ // quality setting sprites should be anti-aliased when they are
+ // upscaled.
// -----------------------------------------------------------------
// Decompression and mirroring
@@ -1445,18 +1444,22 @@ int32 DrawSprite(_spriteInfo *s) {
if (rd.top < 40) {
rs.top = (40 - rd.top) * 256 / scale;
rd.top = 40;
+ clipped = true;
}
if (rd.bottom > 440) {
rs.bottom -= ((rd.bottom - 440) * 256 / scale);
rd.bottom = 440;
+ clipped = true;
}
if (rd.left < 0) {
rs.left = (0 - rd.left) * 256 / scale;
rd.left = 0;
+ clipped = true;
}
if (rd.right > 640) {
rs.right -= ((rd.right - 640) * 256 / scale);
rd.right = 640;
+ clipped = true;
}
// -----------------------------------------------------------------
@@ -1464,6 +1467,10 @@ int32 DrawSprite(_spriteInfo *s) {
// -----------------------------------------------------------------
if (scale != 256) {
+ if ((renderCaps & RDBLTFX_ARITHMETICSTRETCH) && !clipped)
+ backbuf = lpBackBuffer->_pixels + lpBackBuffer->_width * rd.top + rd.left;
+
+
if (s->scaledWidth > SCALE_MAXWIDTH || s->scaledHeight > SCALE_MAXHEIGHT) {
if (freeSprite)
free(sprite);
@@ -1478,14 +1485,14 @@ int32 DrawSprite(_spriteInfo *s) {
}
if (scale < 256) {
- SquashImage(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h);
+ 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);
+ StretchImage(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h, backbuf);
}
if (freeSprite)
@@ -1501,7 +1508,7 @@ int32 DrawSprite(_spriteInfo *s) {
// The light mask is an optional layer that covers the entire room
// and which is used to simulate light and shadows.
- if (lightMask && (scale != 256 || (s->type & RDSPR_SHADOW))) {
+ if ((renderCaps & RDBLTFX_SHADOWBLEND) && lightMask && (scale != 256 || (s->type & RDSPR_SHADOW))) {
uint8 *lightMap;
if (!freeSprite) {
@@ -1536,51 +1543,65 @@ int32 DrawSprite(_spriteInfo *s) {
dst = lpBackBuffer->_pixels + lpBackBuffer->_width * rd.top + rd.left;
if (s->type & RDSPR_BLEND) {
- if (s->blend & 0x01) {
- red = s->blend >> 8;
+ if (renderCaps & RDBLTFX_ALLHARDWARE) {
for (i = 0; i < rs.bottom - rs.top; i++) {
for (j = 0; j < rs.right - rs.left; j++) {
- if (src[j]) {
- uint8 r = (palCopy[src[j]][0] * red + palCopy[dst[j]][0] * (8 - red)) >> 3;
- uint8 g = (palCopy[src[j]][1] * red + palCopy[dst[j]][1] * (8 - red)) >> 3;
- uint8 b = (palCopy[src[j]][2] * red + palCopy[dst[j]][2] * (8 - red)) >> 3;
- dst[j] = QuickMatch(r, g, b);
- }
+ if (src[j] && ((i & 1) == (j & 1)))
+ dst[j] = src[j];
}
src += srcPitch;
dst += lpBackBuffer->_width;
}
- } else if (s->blend & 0x02) {
- // FIXME: This case looks bogus to me. The same value
- // for the red, green and blue parameters, and we
- // multiply with the source color's palette index
- // rather than its color component.
- //
- // But as far as I can see, that's how the original
- // code did it.
- //
- // Does anyone know where this case was used anyway?
-
- 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++) {
- for (j = 0; j < rs.right - rs.left; j++) {
- if (src[j]) {
- uint8 r = (src[j] * red + (16 - src[j]) * palCopy[dst[j]][0]) >> 4;
- uint8 g = (src[j] * green + (16 - src[j]) * palCopy[dst[j]][1]) >> 4;
- uint8 b = (src[j] * blue + (16 - src[j]) * palCopy[dst[j]][2]) >> 4;
- dst[j] = QuickMatch(r, g, b);
+ } else {
+ if (s->blend & 0x01) {
+ red = s->blend >> 8;
+ for (i = 0; i < rs.bottom - rs.top; i++) {
+ for (j = 0; j < rs.right - rs.left; j++) {
+ if (src[j]) {
+ uint8 r = (palCopy[src[j]][0] * red + palCopy[dst[j]][0] * (8 - red)) >> 3;
+ uint8 g = (palCopy[src[j]][1] * red + palCopy[dst[j]][1] * (8 - red)) >> 3;
+ uint8 b = (palCopy[src[j]][2] * red + palCopy[dst[j]][2] * (8 - red)) >> 3;
+ dst[j] = QuickMatch(r, g, b);
+ }
}
+ src += srcPitch;
+ dst += lpBackBuffer->_width;
}
- src += srcPitch;
- dst += lpBackBuffer->_width;
+ } else if (s->blend & 0x02) {
+ // FIXME: This case looks bogus to me. The
+ // same value for the red, green and blue
+ // parameters, and we multiply with the source
+ // color's palette index rather than its color
+ // component.
+ //
+ // But as far as I can see, that's how the
+ // original
+ // code did it.
+ //
+ // Does anyone know where this case was used
+ // anyway?
+
+ 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++) {
+ for (j = 0; j < rs.right - rs.left; j++) {
+ if (src[j]) {
+ uint8 r = (src[j] * red + (16 - src[j]) * palCopy[dst[j]][0]) >> 4;
+ uint8 g = (src[j] * green + (16 - src[j]) * palCopy[dst[j]][1]) >> 4;
+ uint8 b = (src[j] * blue + (16 - src[j]) * palCopy[dst[j]][2]) >> 4;
+ dst[j] = QuickMatch(r, g, b);
+ }
+ }
+ src += srcPitch;
+ dst += lpBackBuffer->_width;
+ }
+ } else {
+ warning("DrawSprite: Invalid blended sprite");
+ if (freeSprite)
+ free(sprite);
+ return RDERR_UNKNOWNTYPE;
}
- } else {
- warning("DrawSprite: Invalid blended sprite");
- if (freeSprite)
- free(sprite);
- return RDERR_UNKNOWNTYPE;
}
} else {
if (s->type & RDSPR_TRANS) {
@@ -3266,85 +3287,30 @@ int32 DrawSprite(_spriteInfo *s) {
-int32 OpenLightMask(_spriteInfo *s)
-
-{
+int32 OpenLightMask(_spriteInfo *s) {
+ // FIXME: The light mask is only needed on higher graphics detail
+ // settings, so to save memory we could simply ignore it on lower
+ // settings. But then we need to figure out how to ensure that it
+ // is properly loaded if the user changes the settings in mid-game.
if (lightMask)
- return(RDERR_NOTCLOSED);
+ return RDERR_NOTCLOSED;
lightMask = (uint8 *) malloc(s->w * s->h);
-
- if (lightMask == NULL)
- return(RDERR_OUTOFMEMORY);
+ if (!lightMask)
+ return RDERR_OUTOFMEMORY;
if (DecompressRLE256(lightMask, s->data, s->w * s->h))
- return(RDERR_DECOMPRESSION);
-
- return(RD_OK);
+ return RDERR_DECOMPRESSION;
+ return RD_OK;
}
-int32 CloseLightMask(void)
-{
-
+int32 CloseLightMask(void) {
if (!lightMask)
- return(RDERR_NOTOPEN);
+ return RDERR_NOTOPEN;
free(lightMask);
-
lightMask = 0;
-
- return(RD_OK);
-
+ return RD_OK;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-