diff options
Diffstat (limited to 'sword2/driver')
-rw-r--r-- | sword2/driver/d_draw.cpp | 33 | ||||
-rw-r--r-- | sword2/driver/driver96.h | 10 | ||||
-rw-r--r-- | sword2/driver/menu.cpp | 2 | ||||
-rw-r--r-- | sword2/driver/render.cpp | 64 | ||||
-rw-r--r-- | sword2/driver/render.h | 4 | ||||
-rw-r--r-- | sword2/driver/sprite.cpp | 196 |
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; } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |