diff options
author | Tony Puccinelli | 2010-08-10 23:21:08 +0000 |
---|---|---|
committer | Tony Puccinelli | 2010-08-10 23:21:08 +0000 |
commit | 682807f0e916b189c69b60765418ee1ccc327cbf (patch) | |
tree | e8b220b934f6b14d4dac290181fce0c1b209579a /engines/sci/graphics/view.cpp | |
parent | 83f1531cb8fa5ba43c246143ecdde2cb1d140a8e (diff) | |
parent | fffec23a02cc88ed8daba0a3b50007b7e220c075 (diff) | |
download | scummvm-rg350-682807f0e916b189c69b60765418ee1ccc327cbf.tar.gz scummvm-rg350-682807f0e916b189c69b60765418ee1ccc327cbf.tar.bz2 scummvm-rg350-682807f0e916b189c69b60765418ee1ccc327cbf.zip |
merged trunk into branch, reverted Cruise Singleton changes
svn-id: r51961
Diffstat (limited to 'engines/sci/graphics/view.cpp')
-rw-r--r-- | engines/sci/graphics/view.cpp | 483 |
1 files changed, 286 insertions, 197 deletions
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index 2ba14fbd8f..1c865f6bcf 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -28,6 +28,7 @@ #include "sci/engine/state.h" #include "sci/graphics/screen.h" #include "sci/graphics/palette.h" +#include "sci/graphics/coordadjuster.h" #include "sci/graphics/view.h" namespace Sci { @@ -35,6 +36,7 @@ namespace Sci { GfxView::GfxView(ResourceManager *resMan, GfxScreen *screen, GfxPalette *palette, GuiResourceId resourceId) : _resMan(resMan), _screen(screen), _palette(palette), _resourceId(resourceId) { assert(resourceId != -1); + _coordAdjuster = g_sci->_gfxCoordAdjuster; initData(resourceId); } @@ -62,6 +64,7 @@ void GfxView::initData(GuiResourceId resourceId) { error("view resource %d not found", resourceId); } _resourceData = _resource->data; + _resourceSize = _resource->size; byte *celData, *loopData; uint16 celOffset; @@ -75,12 +78,32 @@ void GfxView::initData(GuiResourceId resourceId) { byte seekEntry; bool isEGA = false; bool isCompressed = true; + ViewType curViewType = _resMan->getViewType(); _loopCount = 0; _embeddedPal = false; _EGAmapping = NULL; + _isSci2Hires = false; + _isScaleable = true; + + // we adjust inside getCelRect for SCI0EARLY (that version didn't have the +1 when calculating bottom) + _adjustForSci0Early = getSciVersion() == SCI_VERSION_0_EARLY ? -1 : 0; + + // If we find an SCI1/SCI1.1 view (not amiga), we switch to that type for + // EGA. This could get used to make view patches for EGA games, where the + // new views include more colors. Users could manually adjust old views to + // make them look better (like removing dithered colors that aren't caught + // by our undithering or even improve the graphics overall). + if (curViewType == kViewEga) { + if (_resourceData[1] == 0x80) { + curViewType = kViewVga; + } else { + if (READ_LE_UINT16(_resourceData + 4) == 1) + curViewType = kViewVga11; + } + } - switch (_resMan->getViewType()) { + switch (curViewType) { case kViewEga: // View-format SCI0 (and Amiga 16 colors) isEGA = true; case kViewAmiga: // View-format Amiga (32 colors) @@ -95,19 +118,21 @@ void GfxView::initData(GuiResourceId resourceId) { palOffset = READ_LE_UINT16(_resourceData + 6); if (palOffset && palOffset != 0x100) { - // Some SCI0/SCI01 games also have an offset set. It seems that it points to a 16-byte mapping table - // but on those games using that mapping will actually screw things up. - // On the other side: vga sci1 games have this pointing to a VGA palette - // and ega sci1 games have this pointing to a 8x16 byte mapping table that needs to get applied then + // Some SCI0/SCI01 games also have an offset set. It seems that it + // points to a 16-byte mapping table but on those games using that + // mapping will actually screw things up. On the other side: VGA + // SCI1 games have this pointing to a VGA palette and EGA SCI1 games + // have this pointing to a 8x16 byte mapping table that needs to get + // applied then. if (!isEGA) { - _palette->createFromData(&_resourceData[palOffset], &_viewPalette); + _palette->createFromData(&_resourceData[palOffset], _resourceSize - palOffset, &_viewPalette); _embeddedPal = true; } else { // Only use the EGA-mapping, when being SCI1 if (getSciVersion() >= SCI_VERSION_1_EGA) { _EGAmapping = &_resourceData[palOffset]; for (EGAmapNr = 0; EGAmapNr < SCI_VIEW_EGAMAPPING_COUNT; EGAmapNr++) { - if (memcmp(_EGAmapping, EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE)!=0) + if (memcmp(_EGAmapping, EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE) != 0) break; _EGAmapping += SCI_VIEW_EGAMAPPING_SIZE; } @@ -141,8 +166,8 @@ void GfxView::initData(GuiResourceId resourceId) { // For EGA // Width:WORD Height:WORD DisplaceX:BYTE DisplaceY:BYTE ClearKey:BYTE EGAData starts now directly cel = &_loop[loopNo].cel[celNo]; - cel->width = READ_LE_UINT16(celData); - cel->height = READ_LE_UINT16(celData + 2); + cel->scriptWidth = cel->width = READ_LE_UINT16(celData); + cel->scriptHeight = cel->height = READ_LE_UINT16(celData + 2); cel->displaceX = (signed char)celData[4]; cel->displaceY = celData[5]; cel->clearKey = celData[6]; @@ -168,13 +193,30 @@ void GfxView::initData(GuiResourceId resourceId) { break; case kViewVga11: // View-format SCI1.1+ - // HeaderSize:WORD LoopCount:BYTE Unknown:BYTE Version:WORD Unknown:WORD PaletteOffset:WORD - headerSize = READ_SCI11ENDIAN_UINT16(_resourceData + 0) + 2; // headerSize is not part of the header, so its added + // HeaderSize:WORD LoopCount:BYTE Flags:BYTE Version:WORD Unknown:WORD PaletteOffset:WORD + headerSize = READ_SCI11ENDIAN_UINT16(_resourceData + 0) + 2; // headerSize is not part of the header, so it's added assert(headerSize >= 16); _loopCount = _resourceData[2]; assert(_loopCount); + _isSci2Hires = _resourceData[5] == 1 ? true : false; palOffset = READ_SCI11ENDIAN_UINT32(_resourceData + 8); - // FIXME: After LoopCount there is another byte and its set for view 50 within Laura Bow 2 CD, check what it means + // flags is actually a bit-mask + // it seems it was only used for some early sci1.1 games (or even just laura bow 2) + // later interpreters dont support it at all anymore + // we assume that if flags is 0h the view does not support flags and default to scaleable + // if it's 1h then we assume that the view is not to be scaled + // if it's 40h then we assume that the view is scaleable + switch (_resourceData[3]) { + case 1: + _isScaleable = false; + break; + case 0x40: + case 0: + break; // don't do anything, we already have _isScaleable set + default: + error("unsupported flags byte inside sci1.1 view"); + break; + } loopData = _resourceData + headerSize; loopSize = _resourceData[12]; @@ -183,7 +225,7 @@ void GfxView::initData(GuiResourceId resourceId) { assert(celSize >= 32); if (palOffset) { - _palette->createFromData(&_resourceData[palOffset], &_viewPalette); + _palette->createFromData(&_resourceData[palOffset], _resourceSize - palOffset, &_viewPalette); _embeddedPal = true; } @@ -210,8 +252,8 @@ void GfxView::initData(GuiResourceId resourceId) { _loop[loopNo].cel = new CelInfo[celCount]; for (celNo = 0; celNo < celCount; celNo++) { cel = &_loop[loopNo].cel[celNo]; - cel->width = READ_SCI11ENDIAN_UINT16(celData); - cel->height = READ_SCI11ENDIAN_UINT16(celData + 2); + cel->scriptWidth = cel->width = READ_SCI11ENDIAN_UINT16(celData); + cel->scriptHeight = cel->height = READ_SCI11ENDIAN_UINT16(celData + 2); cel->displaceX = READ_SCI11ENDIAN_UINT16(celData + 4); cel->displaceY = READ_SCI11ENDIAN_UINT16(celData + 6); @@ -221,6 +263,9 @@ void GfxView::initData(GuiResourceId resourceId) { cel->offsetEGA = 0; cel->offsetRLE = READ_SCI11ENDIAN_UINT32(celData + 24); cel->offsetLiteral = READ_SCI11ENDIAN_UINT32(celData + 28); + // GK1-hires content is actually uncompressed, we need to swap both so that we process it as such + if ((cel->offsetRLE) && (!cel->offsetLiteral)) + SWAP(cel->offsetRLE, cel->offsetLiteral); cel->rawBitmap = 0; if (_loop[loopNo].mirrorFlag) @@ -229,6 +274,29 @@ void GfxView::initData(GuiResourceId resourceId) { celData += celSize; } } +#ifdef ENABLE_SCI32 + // adjust width/height returned to scripts + switch (getSciVersion()) { + case SCI_VERSION_2: + if (_isSci2Hires) { + for (loopNo = 0; loopNo < _loopCount; loopNo++) { + for (celNo = 0; celNo < _loop[loopNo].celCount; celNo++) { + _screen->adjustBackUpscaledCoordinates(_loop[loopNo].cel[celNo].scriptWidth, _loop[loopNo].cel[celNo].scriptHeight); + } + } + } + break; + + case SCI_VERSION_2_1: + for (loopNo = 0; loopNo < _loopCount; loopNo++) { + for (celNo = 0; celNo < _loop[loopNo].celCount; celNo++) { + _coordAdjuster->fromDisplayToScript(_loop[loopNo].cel[celNo].scriptHeight, _loop[loopNo].cel[celNo].scriptWidth); + } + } + default: + break; + } +#endif break; default: @@ -236,65 +304,72 @@ void GfxView::initData(GuiResourceId resourceId) { } } -GuiResourceId GfxView::getResourceId() { +GuiResourceId GfxView::getResourceId() const { return _resourceId; } -int16 GfxView::getWidth(int16 loopNo, int16 celNo) { - loopNo = CLIP<int16>(loopNo, 0, _loopCount - 1); - celNo = CLIP<int16>(celNo, 0, _loop[loopNo].celCount - 1); - return _loopCount ? _loop[loopNo].cel[celNo].width : 0; +int16 GfxView::getWidth(int16 loopNo, int16 celNo) const { + return _loopCount ? getCelInfo(loopNo, celNo)->width : 0; } -int16 GfxView::getHeight(int16 loopNo, int16 celNo) { - loopNo = CLIP<int16>(loopNo, 0, _loopCount -1); - celNo = CLIP<int16>(celNo, 0, _loop[loopNo].celCount - 1); - return _loopCount ? _loop[loopNo].cel[celNo].height : 0; +int16 GfxView::getHeight(int16 loopNo, int16 celNo) const { + return _loopCount ? getCelInfo(loopNo, celNo)->height : 0; } -CelInfo *GfxView::getCelInfo(int16 loopNo, int16 celNo) { +const CelInfo *GfxView::getCelInfo(int16 loopNo, int16 celNo) const { + assert(_loopCount); loopNo = CLIP<int16>(loopNo, 0, _loopCount - 1); celNo = CLIP<int16>(celNo, 0, _loop[loopNo].celCount - 1); - return _loopCount ? &_loop[loopNo].cel[celNo] : NULL; + return &_loop[loopNo].cel[celNo]; } -LoopInfo *GfxView::getLoopInfo(int16 loopNo) { +uint16 GfxView::getCelCount(int16 loopNo) const { + assert(_loopCount); loopNo = CLIP<int16>(loopNo, 0, _loopCount - 1); - return _loopCount ? &_loop[loopNo] : NULL; + return _loop[loopNo].celCount; } -void GfxView::getCelRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect *outRect) { - CelInfo *celInfo = getCelInfo(loopNo, celNo); - if (celInfo) { - outRect->left = x + celInfo->displaceX - (celInfo->width >> 1); - outRect->right = outRect->left + celInfo->width; - outRect->bottom = y + celInfo->displaceY - z + 1; - outRect->top = outRect->bottom - celInfo->height; - } +Palette *GfxView::getPalette() { + return _embeddedPal ? &_viewPalette : NULL; } -void GfxView::getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, int16 scaleX, int16 scaleY, Common::Rect *outRect) { +bool GfxView::isSci2Hires() { + return _isSci2Hires; +} + +bool GfxView::isScaleable() { + return _isScaleable; +} + +void GfxView::getCelRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const { + const CelInfo *celInfo = getCelInfo(loopNo, celNo); + outRect.left = x + celInfo->displaceX - (celInfo->width >> 1); + outRect.right = outRect.left + celInfo->width; + outRect.bottom = y + celInfo->displaceY - z + 1 + _adjustForSci0Early; + outRect.top = outRect.bottom - celInfo->height; +} + +void GfxView::getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, int16 scaleX, int16 scaleY, Common::Rect &outRect) const { int16 scaledDisplaceX, scaledDisplaceY; int16 scaledWidth, scaledHeight; - CelInfo *celInfo = getCelInfo(loopNo, celNo); - if (celInfo) { - // Scaling displaceX/Y, Width/Height - scaledDisplaceX = (celInfo->displaceX * scaleX) >> 7; - scaledDisplaceY = (celInfo->displaceY * scaleY) >> 7; - scaledWidth = (celInfo->width * scaleX) >> 7; - scaledHeight = (celInfo->height * scaleY) >> 7; - scaledWidth = CLIP<int16>(scaledWidth, 0, _screen->getWidth()); - scaledHeight = CLIP<int16>(scaledHeight, 0, _screen->getHeight()); - - outRect->left = x + scaledDisplaceX - (scaledWidth >> 1); - outRect->right = outRect->left + scaledWidth; - outRect->bottom = y + scaledDisplaceY - z + 1; - outRect->top = outRect->bottom - scaledHeight; - } + const CelInfo *celInfo = getCelInfo(loopNo, celNo); + + // Scaling displaceX/Y, Width/Height + scaledDisplaceX = (celInfo->displaceX * scaleX) >> 7; + scaledDisplaceY = (celInfo->displaceY * scaleY) >> 7; + scaledWidth = (celInfo->width * scaleX) >> 7; + scaledHeight = (celInfo->height * scaleY) >> 7; + scaledWidth = CLIP<int16>(scaledWidth, 0, _screen->getWidth()); + scaledHeight = CLIP<int16>(scaledHeight, 0, _screen->getHeight()); + + outRect.left = x + scaledDisplaceX - (scaledWidth >> 1); + outRect.right = outRect.left + scaledWidth; + outRect.bottom = y + scaledDisplaceY - z + 1; + outRect.top = outRect.bottom - scaledHeight; } void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount) { - CelInfo *celInfo = getCelInfo(loopNo, celNo); + const CelInfo *celInfo = getCelInfo(loopNo, celNo); byte *rlePtr; byte *literalPtr; uint32 pixelNo = 0, runLength; @@ -309,78 +384,42 @@ void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCou memset(outPtr + pixelNo, pixel & 0x0F, MIN<uint32>(runLength, pixelCount - pixelNo)); pixelNo += runLength; } - return; - } - - rlePtr = _resourceData + celInfo->offsetRLE; - if (!celInfo->offsetLiteral) { // no additional literal data - if (_resMan->isAmiga32color()) { - // decompression for amiga views - while (pixelNo < pixelCount) { - pixel = *rlePtr++; - if (pixel & 0x07) { // fill with color - runLength = pixel & 0x07; - pixel = pixel >> 3; - while (runLength-- && pixelNo < pixelCount) { - outPtr[pixelNo++] = pixel; - } - } else { // fill with transparent - runLength = pixel >> 3; - pixelNo += runLength; - } - } - return; - } else { - // decompression for data that has just one combined stream - while (pixelNo < pixelCount) { - pixel = *rlePtr++; - runLength = pixel & 0x3F; - switch (pixel & 0xC0) { - case 0: // copy bytes as-is - while (runLength-- && pixelNo < pixelCount) - outPtr[pixelNo++] = *rlePtr++; - break; - case 0x80: // fill with color - memset(outPtr + pixelNo, *rlePtr++, MIN<uint32>(runLength, pixelCount - pixelNo)); - pixelNo += runLength; - break; - case 0xC0: // fill with transparent - pixelNo += runLength; - break; - } - } - return; - } } else { - literalPtr = _resourceData + celInfo->offsetLiteral; - if (celInfo->offsetRLE) { - if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) { - // Crazy-Ass compression for SCI1.1+ Mac + // We fill the buffer with transparent pixels, so that we can later skip + // over pixels to automatically have them transparent + // Also some RLE compressed cels are possibly ending with the last + // non-transparent pixel (is this even possible with the current code?) + memset(outPtr, _loop[loopNo].cel[celNo].clearKey, pixelCount); + + rlePtr = _resourceData + celInfo->offsetRLE; + if (!celInfo->offsetLiteral) { // no additional literal data + if (_resMan->isAmiga32color()) { + // decompression for amiga views while (pixelNo < pixelCount) { - uint32 pixelLine = pixelNo; - runLength = *rlePtr++; - pixelNo += runLength; - runLength = *rlePtr++; - while (runLength-- && pixelNo < pixelCount) { - outPtr[pixelNo] = *literalPtr++; - if (outPtr[pixelNo] == 255) - outPtr[pixelNo] = 0; - pixelNo++; + pixel = *rlePtr++; + if (pixel & 0x07) { // fill with color + runLength = pixel & 0x07; + pixel = pixel >> 3; + while (runLength-- && pixelNo < pixelCount) { + outPtr[pixelNo++] = pixel; + } + } else { // fill with transparent + runLength = pixel >> 3; + pixelNo += runLength; } - pixelNo = pixelLine + celInfo->width; } } else { - // decompression for data that has separate rle and literal streams + // decompression for data that has just one combined stream while (pixelNo < pixelCount) { pixel = *rlePtr++; runLength = pixel & 0x3F; switch (pixel & 0xC0) { case 0: // copy bytes as-is while (runLength-- && pixelNo < pixelCount) - outPtr[pixelNo++] = *literalPtr++; + outPtr[pixelNo++] = *rlePtr++; break; case 0x80: // fill with color - memset(outPtr + pixelNo, *literalPtr++, MIN<uint32>(runLength, pixelCount - pixelNo)); + memset(outPtr + pixelNo, *rlePtr++, MIN<uint32>(runLength, pixelCount - pixelNo)); pixelNo += runLength; break; case 0xC0: // fill with transparent @@ -390,15 +429,53 @@ void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCou } } } else { - // literal stream only, so no compression - memcpy(outPtr, literalPtr, pixelCount); + literalPtr = _resourceData + celInfo->offsetLiteral; + if (celInfo->offsetRLE) { + if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) { + // compression for SCI1.1+ Mac + while (pixelNo < pixelCount) { + uint32 pixelLine = pixelNo; + runLength = *rlePtr++; + pixelNo += runLength; + runLength = *rlePtr++; + while (runLength-- && pixelNo < pixelCount) { + outPtr[pixelNo] = *literalPtr++; + if (outPtr[pixelNo] == 255) + outPtr[pixelNo] = 0; + pixelNo++; + } + pixelNo = pixelLine + celInfo->width; + } + } else { + // decompression for data that has separate rle and literal streams + while (pixelNo < pixelCount) { + pixel = *rlePtr++; + runLength = pixel & 0x3F; + switch (pixel & 0xC0) { + case 0: // copy bytes as-is + while (runLength-- && pixelNo < pixelCount) + outPtr[pixelNo++] = *literalPtr++; + break; + case 0x80: // fill with color + memset(outPtr + pixelNo, *literalPtr++, MIN<uint32>(runLength, pixelCount - pixelNo)); + pixelNo += runLength; + break; + case 0xC0: // fill with transparent + pixelNo += runLength; + break; + } + } + } + } else { + // literal stream only, so no compression + memcpy(outPtr, literalPtr, pixelCount); + pixelNo = pixelCount; + } } - return; } - error("Unable to decompress view"); } -byte *GfxView::getBitmap(int16 loopNo, int16 celNo) { +const byte *GfxView::getBitmap(int16 loopNo, int16 celNo) { loopNo = CLIP<int16>(loopNo, 0, _loopCount -1); celNo = CLIP<int16>(celNo, 0, _loop[loopNo].celCount - 1); if (_loop[loopNo].cel[celNo].rawBitmap) @@ -411,9 +488,7 @@ byte *GfxView::getBitmap(int16 loopNo, int16 celNo) { _loop[loopNo].cel[celNo].rawBitmap = new byte[pixelCount]; byte *pBitmap = _loop[loopNo].cel[celNo].rawBitmap; - // Some RLE compressed cels end with the last non-transparent pixel, thats why we fill it up here - // FIXME: change this to fill the remaining bytes within unpackCel() - memset(pBitmap, _loop[loopNo].cel[celNo].clearKey, pixelCount); + // unpack the actual cel bitmap data unpackCel(loopNo, celNo, pBitmap, pixelCount); if (!_resMan->isVGA()) { @@ -429,17 +504,21 @@ byte *GfxView::getBitmap(int16 loopNo, int16 celNo) { return _loop[loopNo].cel[celNo].rawBitmap; } -// Called after unpacking an EGA cel, this will try to undither (parts) of the cel if the dithering in here -// matches dithering used by the current picture +/** + * Called after unpacking an EGA cel, this will try to undither (parts) of the + * cel if the dithering in here matches dithering used by the current picture. + */ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte clearKey) { int16 *unditherMemorial = _screen->unditherGetMemorial(); - // It makes no sense to go further, if no memorial data from current picture is available + // It makes no sense to go further, if no memorial data from current picture + // is available if (!unditherMemorial) return; // Makes no sense to process bitmaps that are 3 pixels wide or less - if (width <= 3) return; + if (width <= 3) + return; // If EGA mapping is used for this view, dont do undithering as well if (_EGAmapping) @@ -453,7 +532,8 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl memset(&bitmapMemorial, 0, sizeof(bitmapMemorial)); - // Count all seemingly dithered pixel-combinations as soon as at least 4 pixels are adjacent + // Count all seemingly dithered pixel-combinations as soon as at least 4 + // pixels are adjacent curPtr = bitmapPtr; for (y = 0; y < height; y++) { color1 = curPtr[0]; color2 = (curPtr[1] << 4) | curPtr[2]; @@ -466,17 +546,20 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl } } - // Now compare both memorial tables to find out matching dithering-combinations + // Now compare both memorial tables to find out matching + // dithering-combinations bool unditherTable[SCI_SCREEN_UNDITHERMEMORIAL_SIZE]; byte color, unditherCount = 0; memset(&unditherTable, false, sizeof(unditherTable)); for (color = 0; color < 255; color++) { if ((bitmapMemorial[color] > 5) && (unditherMemorial[color] > 200)) { - // match found, check if colorKey is contained -> if so, we ignore of course + // match found, check if colorKey is contained -> if so, we ignore + // of course color1 = color & 0x0F; color2 = color >> 4; if ((color1 != clearKey) && (color2 != clearKey) && (color1 != color2)) { // so set this and the reversed color-combination for undithering - unditherTable[color] = true; unditherTable[(color1 << 4) | color2] = true; + unditherTable[color] = true; + unditherTable[(color1 << 4) | color2] = true; unditherCount++; } } @@ -493,8 +576,9 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl for (x = 1; x < width; x++) { color = (color << 4) | curPtr[1]; if (unditherTable[color]) { - // some color with black? turn colors around otherwise it wont be the right color at all - if ((color & 0xF0)==0) + // Some color with black? Turn colors around, otherwise it won't + // be the right color at all. + if ((color & 0xF0) == 0) color = (color << 4) | (color >> 4); curPtr[0] = color; curPtr[1] = color; } @@ -504,15 +588,15 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl } } -void GfxView::draw(Common::Rect rect, Common::Rect clipRect, Common::Rect clipRectTranslated, int16 loopNo, int16 celNo, byte priority, uint16 EGAmappingNr, bool upscaledHires) { - Palette *palette = _embeddedPal ? &_viewPalette : &_palette->_sysPalette; - CelInfo *celInfo = getCelInfo(loopNo, celNo); - byte *bitmap = getBitmap(loopNo, celNo); - int16 celHeight = celInfo->height, celWidth = celInfo->width; - int16 width, height; - byte clearKey = celInfo->clearKey; - byte color; - byte drawMask = priority == 255 ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY; +void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const Common::Rect &clipRectTranslated, + int16 loopNo, int16 celNo, byte priority, uint16 EGAmappingNr, bool upscaledHires) { + const Palette *palette = _embeddedPal ? &_viewPalette : &_palette->_sysPalette; + const CelInfo *celInfo = getCelInfo(loopNo, celNo); + const byte *bitmap = getBitmap(loopNo, celNo); + const int16 celHeight = celInfo->height; + const int16 celWidth = celInfo->width; + const byte clearKey = celInfo->clearKey; + const byte drawMask = (priority == 255) ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY; int x, y; if (_embeddedPal) { @@ -520,24 +604,27 @@ void GfxView::draw(Common::Rect rect, Common::Rect clipRect, Common::Rect clipRe _palette->set(&_viewPalette, false); } - width = MIN(clipRect.width(), celWidth); - height = MIN(clipRect.height(), celHeight); + const int16 width = MIN(clipRect.width(), celWidth); + const int16 height = MIN(clipRect.height(), celHeight); bitmap += (clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left); if (!_EGAmapping) { for (y = 0; y < height; y++, bitmap += celWidth) { for (x = 0; x < width; x++) { - color = bitmap[x]; + const byte color = bitmap[x]; if (color != clearKey) { + const int x2 = clipRectTranslated.left + x; + const int y2 = clipRectTranslated.top + y; if (!upscaledHires) { - if (priority >= _screen->getPriority(clipRectTranslated.left + x, clipRectTranslated.top + y)) - _screen->putPixel(clipRectTranslated.left + x, clipRectTranslated.top + y, drawMask, palette->mapping[color], priority, 0); + if (priority >= _screen->getPriority(x2, y2)) + _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); } else { - // UpscaledHires means view is hires and is supposed to get drawn onto lowres screen - // FIXME(?): we can't read priority directly with the hires coordinates. may not be needed at all - // in kq6 - _screen->putPixelOnDisplay(clipRectTranslated.left + x, clipRectTranslated.top + y, palette->mapping[color]); + // UpscaledHires means view is hires and is supposed to + // get drawn onto lowres screen. + // FIXME(?): we can't read priority directly with the + // hires coordinates. may not be needed at all in kq6 + _screen->putPixelOnDisplay(x2, y2, palette->mapping[color]); } } } @@ -546,30 +633,34 @@ void GfxView::draw(Common::Rect rect, Common::Rect clipRect, Common::Rect clipRe byte *EGAmapping = _EGAmapping + (EGAmappingNr * SCI_VIEW_EGAMAPPING_SIZE); for (y = 0; y < height; y++, bitmap += celWidth) { for (x = 0; x < width; x++) { - color = EGAmapping[bitmap[x]]; - if (color != clearKey && priority >= _screen->getPriority(clipRectTranslated.left + x, clipRectTranslated.top + y)) - _screen->putPixel(clipRectTranslated.left + x, clipRectTranslated.top + y, drawMask, color, priority, 0); + const byte color = EGAmapping[bitmap[x]]; + const int x2 = clipRectTranslated.left + x; + const int y2 = clipRectTranslated.top + y; + if (color != clearKey && priority >= _screen->getPriority(x2, y2)) + _screen->putPixel(x2, y2, drawMask, color, priority, 0); } } } } -// We don't fully follow sierra sci here, I did the scaling algo myself and it's definitely not pixel-perfect -// with the one sierra is using. It shouldn't matter because the scaled cel rect is definitely the same as in sierra sci -void GfxView::drawScaled(Common::Rect rect, Common::Rect clipRect, Common::Rect clipRectTranslated, int16 loopNo, int16 celNo, byte priority, int16 scaleX, int16 scaleY) { - Palette *palette = _embeddedPal ? &_viewPalette : &_palette->_sysPalette; - CelInfo *celInfo = getCelInfo(loopNo, celNo); - byte *bitmap = getBitmap(loopNo, celNo); - int16 celHeight = celInfo->height, celWidth = celInfo->width; - byte clearKey = celInfo->clearKey; - byte color; - byte drawMask = priority == 255 ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY; - int x, y; - uint16 scalingX[320]; - uint16 scalingY[200]; +/** + * We don't fully follow sierra sci here, I did the scaling algo myself and it + * is definitely not pixel-perfect with the one sierra is using. It shouldn't + * matter because the scaled cel rect is definitely the same as in sierra sci. + */ +void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect, const Common::Rect &clipRectTranslated, + int16 loopNo, int16 celNo, byte priority, int16 scaleX, int16 scaleY) { + const Palette *palette = _embeddedPal ? &_viewPalette : &_palette->_sysPalette; + const CelInfo *celInfo = getCelInfo(loopNo, celNo); + const byte *bitmap = getBitmap(loopNo, celNo); + const int16 celHeight = celInfo->height; + const int16 celWidth = celInfo->width; + const byte clearKey = celInfo->clearKey; + const byte drawMask = (priority == 255) ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY; + uint16 scalingX[640]; + uint16 scalingY[480]; int16 scaledWidth, scaledHeight; - int16 pixelNo, scaledPixel, scaledPixelNo, prevScaledPixelNo; - uint16 offsetX, offsetY; + int pixelNo, scaledPixel, scaledPixelNo, prevScaledPixelNo; if (_embeddedPal) { // Merge view palette in... @@ -582,65 +673,63 @@ void GfxView::drawScaled(Common::Rect rect, Common::Rect clipRect, Common::Rect scaledHeight = CLIP<int16>(scaledHeight, 0, _screen->getHeight()); // Do we really need to do this?! - memset(scalingX, 0, sizeof(scalingX)); - memset(scalingY, 0, sizeof(scalingY)); + //memset(scalingX, 0, sizeof(scalingX)); + //memset(scalingY, 0, sizeof(scalingY)); // Create height scaling table pixelNo = 0; scaledPixel = scaledPixelNo = prevScaledPixelNo = 0; while (pixelNo < celHeight) { scaledPixelNo = scaledPixel >> 7; - if (prevScaledPixelNo < scaledPixelNo) - memset(&scalingY[prevScaledPixelNo], pixelNo, scaledPixelNo - prevScaledPixelNo); - scalingY[scaledPixelNo] = pixelNo; - prevScaledPixelNo = scaledPixelNo + 1; + assert(scaledPixelNo < ARRAYSIZE(scalingY)); + for (; prevScaledPixelNo <= scaledPixelNo; prevScaledPixelNo++) + scalingY[prevScaledPixelNo] = pixelNo; pixelNo++; scaledPixel += scaleY; } + pixelNo--; scaledPixelNo++; - if (scaledPixelNo < scaledHeight) - memset(&scalingY[scaledPixelNo], pixelNo - 1, scaledHeight - scaledPixelNo); + for (; scaledPixelNo < scaledHeight; scaledPixelNo++) + scalingY[scaledPixelNo] = pixelNo; // Create width scaling table pixelNo = 0; scaledPixel = scaledPixelNo = prevScaledPixelNo = 0; while (pixelNo < celWidth) { scaledPixelNo = scaledPixel >> 7; - if (prevScaledPixelNo < scaledPixelNo) - memset(&scalingX[prevScaledPixelNo], pixelNo, scaledPixelNo - prevScaledPixelNo); - scalingX[scaledPixelNo] = pixelNo; - prevScaledPixelNo = scaledPixelNo + 1; + assert(scaledPixelNo < ARRAYSIZE(scalingX)); + for (; prevScaledPixelNo <= scaledPixelNo; prevScaledPixelNo++) + scalingX[prevScaledPixelNo] = pixelNo; pixelNo++; scaledPixel += scaleX; } + pixelNo--; scaledPixelNo++; - if (scaledPixelNo < scaledWidth) - memset(&scalingX[scaledPixelNo], pixelNo - 1, scaledWidth - scaledPixelNo); + for (; scaledPixelNo < scaledWidth; scaledPixelNo++) + scalingX[scaledPixelNo] = pixelNo; scaledWidth = MIN(clipRect.width(), scaledWidth); scaledHeight = MIN(clipRect.height(), scaledHeight); - offsetY = clipRect.top - rect.top; - offsetX = clipRect.left - rect.left; + const int16 offsetY = clipRect.top - rect.top; + const int16 offsetX = clipRect.left - rect.left; - for (y = 0; y < scaledHeight; y++) { - for (x = 0; x < scaledWidth; x++) { - color = bitmap[scalingY[y + offsetY] * celWidth + scalingX[x + offsetX]]; - if (color != clearKey && priority >= _screen->getPriority(clipRectTranslated.left + x, clipRectTranslated.top + y)) { - _screen->putPixel(clipRectTranslated.left + x, clipRectTranslated.top + y, drawMask, palette->mapping[color], priority, 0); + // Happens in SQ6, first room + if (offsetX < 0 || offsetY < 0) + return; + + assert(scaledHeight + offsetY <= ARRAYSIZE(scalingY)); + assert(scaledWidth + offsetX <= ARRAYSIZE(scalingX)); + for (int y = 0; y < scaledHeight; y++) { + for (int x = 0; x < scaledWidth; x++) { + const byte color = bitmap[scalingY[y + offsetY] * celWidth + scalingX[x + offsetX]]; + const int x2 = clipRectTranslated.left + x; + const int y2 = clipRectTranslated.top + y; + if (color != clearKey && priority >= _screen->getPriority(x2, y2)) { + _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); } } } } -uint16 GfxView::getCelCount(int16 loopNo) { - if ((loopNo < 0) || (loopNo >= _loopCount)) - return 0; - return _loop[loopNo].celCount; -} - -Palette *GfxView::getPalette() { - return _embeddedPal ? &_viewPalette : &_palette->_sysPalette; -} - } // End of namespace Sci |