diff options
Diffstat (limited to 'engines/sci/graphics')
25 files changed, 522 insertions, 633 deletions
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp index 8d92cb905f..317e98feab 100644 --- a/engines/sci/graphics/animate.cpp +++ b/engines/sci/graphics/animate.cpp @@ -122,7 +122,7 @@ bool GfxAnimate::detectFastCast() { // within that game. Which means even though we detect it as having the capability, it's never actually used. // The original multilingual KQ5 interpreter did have this feature disabled. // Sierra probably used latest system scripts and that's why we detect it. - if (_scriptPatcher->findSignature(magicDWord, magicDWordOffset, fastCastSignature, "fast cast detection", scriptData, scriptSize) >= 0) { + if (_scriptPatcher->findSignature(magicDWord, magicDWordOffset, fastCastSignature, "fast cast detection", SciSpan<const byte>(scriptData, scriptSize)) >= 0) { // Signature found, game seems to use fast cast for kAnimate return true; } diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp index 8540b636fc..75f6280460 100644 --- a/engines/sci/graphics/celobj32.cpp +++ b/engines/sci/graphics/celobj32.cpp @@ -30,6 +30,7 @@ #include "sci/graphics/remap32.h" #include "sci/graphics/text32.h" #include "sci/engine/workarounds.h" +#include "sci/util.h" namespace Sci { #pragma mark CelScaler @@ -273,8 +274,15 @@ public: _sourceHeight(celObj._height), #endif _sourceWidth(celObj._width) { - const byte *resource = celObj.getResPointer(); - _pixels = resource + READ_SCI11ENDIAN_UINT32(resource + celObj._celHeaderOffset + 24); + const SciSpan<const byte> resource = celObj.getResPointer(); + const uint32 pixelsOffset = resource.getUint32SEAt(celObj._celHeaderOffset + 24); + const int32 numPixels = MIN<int32>(resource.size() - pixelsOffset, celObj._width * celObj._height); + + if (numPixels < celObj._width * celObj._height) { + warning("%s is truncated", celObj._info.toString().c_str()); + } + + _pixels = resource.getUnsafeDataAt(pixelsOffset, numPixels); } inline const byte *getRow(const int16 y) const { @@ -285,7 +293,7 @@ public: struct READER_Compressed { private: - const byte *const _resource; + const SciSpan<const byte> _resource; byte _buffer[kCelScalerTableSize]; uint32 _controlOffset; uint32 _dataOffset; @@ -304,20 +312,38 @@ public: _maxWidth(maxWidth) { assert(maxWidth <= celObj._width); - const byte *const celHeader = _resource + celObj._celHeaderOffset; - _dataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 24); - _uncompressedDataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 28); - _controlOffset = READ_SCI11ENDIAN_UINT32(celHeader + 32); + const SciSpan<const byte> celHeader = _resource.subspan(celObj._celHeaderOffset); + _dataOffset = celHeader.getUint32SEAt(24); + _uncompressedDataOffset = celHeader.getUint32SEAt(28); + _controlOffset = celHeader.getUint32SEAt(32); } inline const byte *getRow(const int16 y) { assert(y >= 0 && y < _sourceHeight); if (y != _y) { // compressed data segment for row - const byte *row = _resource + _dataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + y * 4); + const uint32 rowOffset = _resource.getUint32SEAt(_controlOffset + y * sizeof(uint32)); + + uint32 rowCompressedSize; + if (y + 1 < _sourceHeight) { + rowCompressedSize = _resource.getUint32SEAt(_controlOffset + (y + 1) * sizeof(uint32)) - rowOffset; + } else { + rowCompressedSize = _resource.size() - rowOffset - _dataOffset; + } + + const byte *row = _resource.getUnsafeDataAt(_dataOffset + rowOffset, rowCompressedSize); // uncompressed data segment for row - const byte *literal = _resource + _uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + _sourceHeight * 4 + y * 4); + const uint32 literalOffset = _resource.getUint32SEAt(_controlOffset + _sourceHeight * sizeof(uint32) + y * sizeof(uint32)); + + uint32 literalRowSize; + if (y + 1 < _sourceHeight) { + literalRowSize = _resource.getUint32SEAt(_controlOffset + _sourceHeight * sizeof(uint32) + (y + 1) * sizeof(uint32)) - literalOffset; + } else { + literalRowSize = _resource.size() - literalOffset - _uncompressedDataOffset; + } + + const byte *literal = _resource.getUnsafeDataAt(_uncompressedDataOffset + literalOffset, literalRowSize); uint8 length; for (int16 i = 0; i < _maxWidth; i += length) { @@ -573,7 +599,8 @@ uint8 CelObj::readPixel(uint16 x, const uint16 y, bool mirrorX) const { void CelObj::submitPalette() const { if (_hunkPaletteOffset) { - const HunkPalette palette(getResPointer() + _hunkPaletteOffset); + const SciSpan<const byte> data = getResPointer(); + const HunkPalette palette(data.subspan(_hunkPaletteOffset)); g_sci->_gfxPalette32->submit(palette); } } @@ -817,8 +844,7 @@ int16 CelObjView::getNumLoops(const GuiResourceId viewId) { return 0; } - assert(resource->size >= 3); - return resource->data[2]; + return resource->getUint8At(2); } int16 CelObjView::getNumCels(const GuiResourceId viewId, int16 loopNo) { @@ -828,7 +854,7 @@ int16 CelObjView::getNumCels(const GuiResourceId viewId, int16 loopNo) { return 0; } - const byte *const data = resource->data; + const SciSpan<const byte> &data = *resource; const uint16 loopCount = data[2]; @@ -849,19 +875,14 @@ int16 CelObjView::getNumCels(const GuiResourceId viewId, int16 loopNo) { return 0; } - const uint16 viewHeaderSize = READ_SCI11ENDIAN_UINT16(data); + const uint16 viewHeaderSize = data.getUint16SEAt(0); const uint8 loopHeaderSize = data[12]; const uint8 viewHeaderFieldSize = 2; -#ifndef NDEBUG - const byte *const dataMax = data + resource->size; -#endif - const byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopNo); - assert(loopHeader + 3 <= dataMax); + SciSpan<const byte> loopHeader = data.subspan(viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopNo)); - if ((int8)loopHeader[0] != -1) { - loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * (int8)loopHeader[0]); - assert(loopHeader >= data && loopHeader + 3 <= dataMax); + if (loopHeader.getInt8At(0) != -1) { + loopHeader = data.subspan(viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopHeader.getInt8At(0))); } return loopHeader[2]; @@ -889,10 +910,6 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int return; } - // TODO: The next code should be moved to a common file that - // generates view resource metadata for both SCI16 and SCI32 - // implementations - const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false); // NOTE: SCI2.1/SQ6 just silently returns here. @@ -900,10 +917,10 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int error("View resource %d not found", viewId); } - const byte *const data = resource->data; + const Resource &data = *resource; - _xResolution = READ_SCI11ENDIAN_UINT16(data + 14); - _yResolution = READ_SCI11ENDIAN_UINT16(data + 16); + _xResolution = data.getUint16SEAt(14); + _yResolution = data.getUint16SEAt(16); if (_xResolution == 0 && _yResolution == 0) { byte sizeFlag = data[5]; @@ -930,18 +947,18 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int error("Loop is less than 0"); } - const uint16 viewHeaderSize = READ_SCI11ENDIAN_UINT16(data); + const uint16 viewHeaderSize = data.getUint16SEAt(0); const uint8 loopHeaderSize = data[12]; const uint8 viewHeaderFieldSize = 2; - const byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * _info.loopNo); + SciSpan<const byte> loopHeader = data.subspan(viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * _info.loopNo)); - if ((int8)loopHeader[0] != -1) { + if (loopHeader.getInt8At(0) != -1) { if (loopHeader[1] == 1) { _mirrorX = true; } - loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * (int8)loopHeader[0]); + loopHeader = data.subspan(viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopHeader.getInt8At(0))); } uint8 celCount = loopHeader[2]; @@ -962,18 +979,19 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int error("Cel is less than 0 on loop 0"); } - _hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 8); - _celHeaderOffset = READ_SCI11ENDIAN_UINT32(loopHeader + 12) + (data[13] * _info.celNo); + _hunkPaletteOffset = data.getUint32SEAt(8); + _celHeaderOffset = loopHeader.getUint32SEAt(12) + (data[13] * _info.celNo); - const byte *const celHeader = data + _celHeaderOffset; + const SciSpan<const byte> celHeader = data.subspan(_celHeaderOffset); - _width = READ_SCI11ENDIAN_UINT16(celHeader); - _height = READ_SCI11ENDIAN_UINT16(celHeader + 2); - _origin.x = _width / 2 - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4); + _width = celHeader.getUint16SEAt(0); + _height = celHeader.getUint16SEAt(2); + assert(_width <= kCelScalerTableSize && _height <= kCelScalerTableSize); + _origin.x = _width / 2 - celHeader.getInt16SEAt(4); if (g_sci->_features->usesAlternateSelectors() && _mirrorX) { _origin.x = _width - _origin.x - 1; } - _origin.y = _height - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6) - 1; + _origin.y = _height - celHeader.getInt16SEAt(6) - 1; _skipColor = celHeader[8]; _compressionType = (CelCompressionType)celHeader[9]; @@ -984,7 +1002,7 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int if (celHeader[10] & 128) { // NOTE: This is correct according to SCI2.1/SQ6/DOS; // the engine re-reads the byte value as a word value - uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10); + const uint16 flags = celHeader.getUint16SEAt(10); _transparent = flags & 1 ? true : false; _remap = flags & 2 ? true : false; } else if (_compressionType == kCelCompressionNone) { @@ -997,7 +1015,9 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int } bool CelObjView::analyzeUncompressedForRemap() const { - const byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24); + const SciSpan<const byte> data = getResPointer(); + const uint32 pixelsOffset = data.getUint32SEAt(_celHeaderOffset + 24); + const byte *pixels = data.getUnsafeDataAt(pixelsOffset, _width * _height); for (int i = 0; i < _width * _height; ++i) { const byte pixel = pixels[i]; if ( @@ -1038,12 +1058,12 @@ CelObjView *CelObjView::duplicate() const { return new CelObjView(*this); } -byte *CelObjView::getResPointer() const { +const SciSpan<const byte> CelObjView::getResPointer() const { Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false); if (resource == nullptr) { error("Failed to load view %d from resource manager", _info.resourceId); } - return resource->data; + return *resource; } #pragma mark - @@ -1079,31 +1099,31 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) { error("Pic resource %d not found", picId); } - const byte *const data = resource->data; + const Resource &data = *resource; - _celCount = data[2]; + _celCount = data.getUint8At(2); if (_info.celNo >= _celCount) { error("Cel number %d greater than cel count %d", _info.celNo, _celCount); } - _celHeaderOffset = READ_SCI11ENDIAN_UINT16(data) + (READ_SCI11ENDIAN_UINT16(data + 4) * _info.celNo); - _hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 6); + _celHeaderOffset = data.getUint16SEAt(0) + (data.getUint16SEAt(4) * _info.celNo); + _hunkPaletteOffset = data.getUint32SEAt(6); - const byte *const celHeader = data + _celHeaderOffset; + const SciSpan<const byte> celHeader = data.subspan(_celHeaderOffset); - _width = READ_SCI11ENDIAN_UINT16(celHeader); - _height = READ_SCI11ENDIAN_UINT16(celHeader + 2); - _origin.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4); - _origin.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6); + _width = celHeader.getUint16SEAt(0); + _height = celHeader.getUint16SEAt(2); + _origin.x = celHeader.getInt16SEAt(4); + _origin.y = celHeader.getInt16SEAt(6); _skipColor = celHeader[8]; _compressionType = (CelCompressionType)celHeader[9]; - _priority = READ_SCI11ENDIAN_UINT16(celHeader + 36); - _relativePosition.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 38); - _relativePosition.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 40); + _priority = celHeader.getInt16SEAt(36); + _relativePosition.x = celHeader.getInt16SEAt(38); + _relativePosition.y = celHeader.getInt16SEAt(40); - const uint16 sizeFlag1 = READ_SCI11ENDIAN_UINT16(data + 10); - const uint16 sizeFlag2 = READ_SCI11ENDIAN_UINT16(data + 12); + const uint16 sizeFlag1 = data.getUint16SEAt(10); + const uint16 sizeFlag2 = data.getUint16SEAt(12); if (sizeFlag2) { _xResolution = sizeFlag1; @@ -1119,10 +1139,10 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) { _yResolution = 400; } - if (celHeader[10] & 128) { + if (celHeader.getUint8At(10) & 128) { // NOTE: This is correct according to SCI2.1/SQ6/DOS; // the engine re-reads the byte value as a word value - const uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10); + const uint16 flags = celHeader.getUint16SEAt(10); _transparent = flags & 1 ? true : false; _remap = flags & 2 ? true : false; } else { @@ -1137,9 +1157,16 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) { } bool CelObjPic::analyzeUncompressedForSkip() const { - const byte *const resource = getResPointer(); - const byte *const pixels = resource + READ_SCI11ENDIAN_UINT32(resource + _celHeaderOffset + 24); - for (int i = 0; i < _width * _height; ++i) { + const SciSpan<const byte> resource = getResPointer(); + const uint32 pixelsOffset = resource.getUint32SEAt(_celHeaderOffset + 24); + const int32 numPixels = MIN<int32>(resource.size() - pixelsOffset, _width * _height); + + if (numPixels < _width * _height) { + warning("%s is truncated", _info.toString().c_str()); + } + + const byte *const pixels = resource.getUnsafeDataAt(pixelsOffset, numPixels); + for (int32 i = 0; i < numPixels; ++i) { uint8 pixel = pixels[i]; if (pixel == _skipColor) { return true; @@ -1159,12 +1186,12 @@ CelObjPic *CelObjPic::duplicate() const { return new CelObjPic(*this); } -byte *CelObjPic::getResPointer() const { +const SciSpan<const byte> CelObjPic::getResPointer() const { const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false); if (resource == nullptr) { error("Failed to load pic %d from resource manager", _info.resourceId); } - return resource->data; + return *resource; } #pragma mark - @@ -1199,8 +1226,9 @@ CelObjMem *CelObjMem::duplicate() const { return new CelObjMem(*this); } -byte *CelObjMem::getResPointer() const { - return g_sci->getEngineState()->_segMan->lookupBitmap(_info.bitmap)->getRawData(); +const SciSpan<const byte> CelObjMem::getResPointer() const { + SciBitmap &bitmap = *g_sci->getEngineState()->_segMan->lookupBitmap(_info.bitmap); + return SciSpan<const byte>(bitmap.getRawData(), bitmap.getRawSize(), Common::String::format("bitmap %04x:%04x", PRINT_REG(_info.bitmap))); } #pragma mark - @@ -1237,7 +1265,7 @@ CelObjColor *CelObjColor::duplicate() const { return new CelObjColor(*this); } -byte *CelObjColor::getResPointer() const { +const SciSpan<const byte> CelObjColor::getResPointer() const { error("Unsupported method"); } } // End of namespace Sci diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h index 3e3f81ac62..351a8856b2 100644 --- a/engines/sci/graphics/celobj32.h +++ b/engines/sci/graphics/celobj32.h @@ -27,6 +27,7 @@ #include "common/rect.h" #include "sci/resource.h" #include "sci/engine/vm_types.h" +#include "sci/util.h" namespace Sci { typedef Common::Rational Ratio; @@ -413,7 +414,7 @@ public: * Retrieves a pointer to the raw resource data for this * cel. This method cannot be used with a CelObjColor. */ - virtual byte *getResPointer() const = 0; + virtual const SciSpan<const byte> getResPointer() const = 0; /** * Reads the pixel at the given coordinates. This method @@ -535,7 +536,7 @@ public: void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX, const Ratio &scaleX, const Ratio &scaleY); virtual CelObjView *duplicate() const override; - virtual byte *getResPointer() const override; + virtual const SciSpan<const byte> getResPointer() const override; }; #pragma mark - @@ -580,7 +581,7 @@ public: virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override; virtual CelObjPic *duplicate() const override; - virtual byte *getResPointer() const override; + virtual const SciSpan<const byte> getResPointer() const override; }; #pragma mark - @@ -598,7 +599,7 @@ public: virtual ~CelObjMem() override {}; virtual CelObjMem *duplicate() const override; - virtual byte *getResPointer() const override; + virtual const SciSpan<const byte> getResPointer() const override; }; #pragma mark - @@ -622,7 +623,7 @@ public: virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override; virtual CelObjColor *duplicate() const override; - virtual byte *getResPointer() const override; + virtual const SciSpan<const byte> getResPointer() const override; }; } // End of namespace Sci diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp index 36026a8134..582dd328dc 100644 --- a/engines/sci/graphics/compare.cpp +++ b/engines/sci/graphics/compare.cpp @@ -197,7 +197,7 @@ bool GfxCompare::kernelIsItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo, const CelInfo *celInfo = tmpView->getCelInfo(loopNo, celNo); position.x = CLIP<int>(position.x, 0, celInfo->width - 1); position.y = CLIP<int>(position.y, 0, celInfo->height - 1); - const byte *celData = tmpView->getBitmap(loopNo, celNo); + const SciSpan<const byte> &celData = tmpView->getBitmap(loopNo, celNo); bool result = (celData[position.y * celInfo->width + position.x] == celInfo->clearKey); return result; } diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp index 7cf9a574ef..c29e547b83 100644 --- a/engines/sci/graphics/cursor.cpp +++ b/engines/sci/graphics/cursor.cpp @@ -58,7 +58,6 @@ GfxCursor::GfxCursor(ResourceManager *resMan, GfxPalette *palette, GfxScreen *sc _zoomPicView = 0; _zoomColor = 0; _zoomMultiplier = 0; - _cursorSurface = 0; if (g_sci && g_sci->getGameId() == GID_KQ6 && g_sci->getPlatform() == Common::kPlatformWindows) _useOriginalKQ6WinCursors = ConfMan.getBool("windows_cursors"); @@ -110,20 +109,17 @@ void GfxCursor::purgeCache() { void GfxCursor::kernelSetShape(GuiResourceId resourceId) { Resource *resource; - byte *resourceData; Common::Point hotspot = Common::Point(0, 0); byte colorMapping[4]; int16 x, y; byte color; int16 maskA, maskB; byte *pOut; - byte *rawBitmap = new byte[SCI_CURSOR_SCI0_HEIGHTWIDTH * SCI_CURSOR_SCI0_HEIGHTWIDTH]; int16 heightWidth; if (resourceId == -1) { // no resourceId given, so we actually hide the cursor kernelHide(); - delete[] rawBitmap; return; } @@ -131,20 +127,18 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) { resource = _resMan->findResource(ResourceId(kResourceTypeCursor, resourceId), false); if (!resource) error("cursor resource %d not found", resourceId); - if (resource->size != SCI_CURSOR_SCI0_RESOURCESIZE) + if (resource->size() != SCI_CURSOR_SCI0_RESOURCESIZE) error("cursor resource %d has invalid size", resourceId); - resourceData = resource->data; - if (getSciVersion() <= SCI_VERSION_01) { // SCI0 cursors contain hotspot flags, not actual hotspot coordinates. // If bit 0 of resourceData[3] is set, the hotspot should be centered, // otherwise it's in the top left of the mouse cursor. - hotspot.x = hotspot.y = resourceData[3] ? SCI_CURSOR_SCI0_HEIGHTWIDTH / 2 : 0; + hotspot.x = hotspot.y = resource->getUint8At(3) ? SCI_CURSOR_SCI0_HEIGHTWIDTH / 2 : 0; } else { // Cursors in newer SCI versions contain actual hotspot coordinates. - hotspot.x = READ_LE_UINT16(resourceData); - hotspot.y = READ_LE_UINT16(resourceData + 2); + hotspot.x = resource->getUint16LEAt(0); + hotspot.y = resource->getUint16LEAt(2); } // Now find out what colors we are supposed to use @@ -160,13 +154,13 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) { if (g_sci->getGameId() == GID_LONGBOW) colorMapping[3] = _palette->matchColor(223, 223, 223) & SCI_PALETTE_MATCH_COLORMASK; // Light Grey - // Seek to actual data - resourceData += 4; + Common::SpanOwner<SciSpan<byte> > rawBitmap; + rawBitmap->allocate(SCI_CURSOR_SCI0_HEIGHTWIDTH * SCI_CURSOR_SCI0_HEIGHTWIDTH, resource->name() + " copy"); - pOut = rawBitmap; + pOut = rawBitmap->getUnsafeDataAt(0, SCI_CURSOR_SCI0_HEIGHTWIDTH * SCI_CURSOR_SCI0_HEIGHTWIDTH); for (y = 0; y < SCI_CURSOR_SCI0_HEIGHTWIDTH; y++) { - maskA = READ_LE_UINT16(resourceData + (y << 1)); - maskB = READ_LE_UINT16(resourceData + 32 + (y << 1)); + maskA = resource->getUint16LEAt(4 + (y << 1)); + maskB = resource->getUint16LEAt(4 + 32 + (y << 1)); for (x = 0; x < SCI_CURSOR_SCI0_HEIGHTWIDTH; x++) { color = (((maskA << x) & 0x8000) | (((maskB << x) >> 1) & 0x4000)) >> 14; @@ -181,9 +175,10 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) { heightWidth *= 2; hotspot.x *= 2; hotspot.y *= 2; - byte *upscaledBitmap = new byte[heightWidth * heightWidth]; - _screen->scale2x(rawBitmap, upscaledBitmap, SCI_CURSOR_SCI0_HEIGHTWIDTH, SCI_CURSOR_SCI0_HEIGHTWIDTH); - delete[] rawBitmap; + + Common::SpanOwner<SciSpan<byte> > upscaledBitmap; + upscaledBitmap->allocate(heightWidth * heightWidth, "upscaled cursor bitmap"); + _screen->scale2x(*rawBitmap, *upscaledBitmap, SCI_CURSOR_SCI0_HEIGHTWIDTH, SCI_CURSOR_SCI0_HEIGHTWIDTH); rawBitmap = upscaledBitmap; } @@ -192,10 +187,8 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) { resourceId, hotspot.x, hotspot.y, heightWidth, heightWidth); } - CursorMan.replaceCursor(rawBitmap, heightWidth, heightWidth, hotspot.x, hotspot.y, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR); + CursorMan.replaceCursor(rawBitmap->getUnsafeDataAt(0, heightWidth * heightWidth), heightWidth, heightWidth, hotspot.x, hotspot.y, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR); kernelShow(); - - delete[] rawBitmap; } void GfxCursor::kernelSetView(GuiResourceId viewNum, int loopNum, int celNum, Common::Point *hotspot) { @@ -261,19 +254,19 @@ void GfxCursor::kernelSetView(GuiResourceId viewNum, int loopNum, int celNum, Co return; } - const byte *rawBitmap = cursorView->getBitmap(loopNum, celNum); + const SciSpan<const byte> &rawBitmap = cursorView->getBitmap(loopNum, celNum); if (_upscaledHires && !_useOriginalKQ6WinCursors) { // Scale cursor by 2x - note: sierra didn't do this, but it looks much better width *= 2; height *= 2; cursorHotspot->x *= 2; cursorHotspot->y *= 2; - byte *cursorBitmap = new byte[width * height]; - _screen->scale2x(rawBitmap, cursorBitmap, celInfo->width, celInfo->height); - CursorMan.replaceCursor(cursorBitmap, width, height, cursorHotspot->x, cursorHotspot->y, clearKey); - delete[] cursorBitmap; + Common::SpanOwner<SciSpan<byte> > cursorBitmap; + cursorBitmap->allocate(width * height, "upscaled cursor bitmap"); + _screen->scale2x(rawBitmap, *cursorBitmap, celInfo->width, celInfo->height); + CursorMan.replaceCursor(cursorBitmap->getUnsafeDataAt(0, width * height), width, height, cursorHotspot->x, cursorHotspot->y, clearKey); } else { - CursorMan.replaceCursor(rawBitmap, width, height, cursorHotspot->x, cursorHotspot->y, clearKey); + CursorMan.replaceCursor(rawBitmap.getUnsafeDataAt(0, width * height), width, height, cursorHotspot->x, cursorHotspot->y, clearKey); } kernelShow(); @@ -386,10 +379,10 @@ void GfxCursor::refreshPosition() { if (_zoomZoneActive) { // Cursor const CelInfo *cursorCelInfo = _zoomCursorView->getCelInfo(_zoomCursorLoop, _zoomCursorCel); - const byte *cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel); + const SciSpan<const byte> &cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel); // Pic const CelInfo *picCelInfo = _zoomPicView->getCelInfo(0, 0); - const byte *rawPicBitmap = _zoomPicView->getBitmap(0, 0); + const SciSpan<const byte> &rawPicBitmap = _zoomPicView->getBitmap(0, 0); // Compute hotspot of cursor Common::Point cursorHotspot = Common::Point((cursorCelInfo->width >> 1) - cursorCelInfo->displaceX, cursorCelInfo->height - cursorCelInfo->displaceY - 1); @@ -426,7 +419,7 @@ void GfxCursor::refreshPosition() { } } - CursorMan.replaceCursor(_cursorSurface, cursorCelInfo->width, cursorCelInfo->height, cursorHotspot.x, cursorHotspot.y, cursorCelInfo->clearKey); + CursorMan.replaceCursor(_cursorSurface->getUnsafeDataAt(0, cursorCelInfo->width * cursorCelInfo->height), cursorCelInfo->width, cursorCelInfo->height, cursorHotspot.x, cursorHotspot.y, cursorCelInfo->clearKey); } } @@ -449,8 +442,7 @@ void GfxCursor::kernelClearZoomZone() { _zoomCursorView = 0; delete _zoomPicView; _zoomPicView = 0; - delete[] _cursorSurface; - _cursorSurface = 0; + _cursorSurface.clear(); } void GfxCursor::kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor) { @@ -474,10 +466,7 @@ void GfxCursor::kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourc _zoomCursorLoop = (byte)loopNum; _zoomCursorCel = (byte)celNum; _zoomPicView = new GfxView(_resMan, _screen, _palette, picNum); - const CelInfo *cursorCelInfo = _zoomCursorView->getCelInfo(_zoomCursorLoop, _zoomCursorCel); - const byte *cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel); - _cursorSurface = new byte[cursorCelInfo->width * cursorCelInfo->height]; - memcpy(_cursorSurface, cursorBitmap, cursorCelInfo->width * cursorCelInfo->height); + _cursorSurface->allocateFromSpan(_zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel)); _zoomZone = zone; kernelSetMoveZone(_zoomZone); @@ -537,7 +526,7 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu assert(resource); - Common::MemoryReadStream resStream(resource->data, resource->size); + Common::MemoryReadStream resStream(resource->toStream()); Graphics::MacCursor *macCursor = new Graphics::MacCursor(); if (!macCursor->readFromStream(resStream)) { diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h index 36518ea5db..8d9ce7c0ab 100644 --- a/engines/sci/graphics/cursor.h +++ b/engines/sci/graphics/cursor.h @@ -27,13 +27,15 @@ #include "common/hashmap.h" #include "sci/sci.h" #include "sci/graphics/helpers.h" +#include "sci/util.h" namespace Sci { -#define SCI_CURSOR_SCI0_HEIGHTWIDTH 16 -#define SCI_CURSOR_SCI0_RESOURCESIZE 68 - -#define SCI_CURSOR_SCI0_TRANSPARENCYCOLOR 1 +enum { + SCI_CURSOR_SCI0_HEIGHTWIDTH = 16, + SCI_CURSOR_SCI0_RESOURCESIZE = 68, + SCI_CURSOR_SCI0_TRANSPARENCYCOLOR = 1 +}; class GfxView; class GfxPalette; @@ -117,7 +119,7 @@ private: GfxView *_zoomPicView; byte _zoomColor; byte _zoomMultiplier; - byte *_cursorSurface; + Common::SpanOwner<SciSpan<byte> > _cursorSurface; CursorCache _cachedCursors; diff --git a/engines/sci/graphics/cursor32.cpp b/engines/sci/graphics/cursor32.cpp index 34a6d547e1..e8450b773e 100644 --- a/engines/sci/graphics/cursor32.cpp +++ b/engines/sci/graphics/cursor32.cpp @@ -244,7 +244,7 @@ void GfxCursor32::setView(const GuiResourceId viewId, const int16 loopNo, const debug(0, "Mac cursor %d not found", viewNum); return; } - Common::MemoryReadStream resStream(resource->data, resource->size); + Common::MemoryReadStream resStream(resource->toStream()); Graphics::MacCursor *macCursor = new Graphics::MacCursor(); if (!macCursor->readFromStream(resStream)) { diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp index 2268ec0459..ff2f361d93 100644 --- a/engines/sci/graphics/font.cpp +++ b/engines/sci/graphics/font.cpp @@ -40,16 +40,15 @@ GfxFontFromResource::GfxFontFromResource(ResourceManager *resMan, GfxScreen *scr if (!_resource) { error("font resource %d not found", resourceId); } - _resourceData = _resource->data; - _numChars = READ_SCI32ENDIAN_UINT16(_resourceData + 2); - _fontHeight = READ_SCI32ENDIAN_UINT16(_resourceData + 4); + _numChars = _resource->getUint16SE32At(2); + _fontHeight = _resource->getUint16SE32At(4); _chars = new Charinfo[_numChars]; // filling info for every char for (int16 i = 0; i < _numChars; i++) { - _chars[i].offset = READ_SCI32ENDIAN_UINT16(_resourceData + 6 + i * 2); - _chars[i].width = _resourceData[_chars[i].offset]; - _chars[i].height = _resourceData[_chars[i].offset + 1]; + _chars[i].offset = _resource->getUint16SE32At(6 + i * 2); + _chars[i].width = _resource->getUint8At(_chars[i].offset); + _chars[i].height = _resource->getUint8At(_chars[i].offset + 1); } } @@ -62,20 +61,33 @@ GuiResourceId GfxFontFromResource::getResourceId() { return _resourceId; } -byte GfxFontFromResource::getHeight() { +uint8 GfxFontFromResource::getHeight() { return _fontHeight; } -byte GfxFontFromResource::getCharWidth(uint16 chr) { +uint8 GfxFontFromResource::getCharWidth(uint16 chr) { return chr < _numChars ? _chars[chr].width : 0; } -byte GfxFontFromResource::getCharHeight(uint16 chr) { +uint8 GfxFontFromResource::getCharHeight(uint16 chr) { return chr < _numChars ? _chars[chr].height : 0; } -byte *GfxFontFromResource::getCharData(uint16 chr) { - return chr < _numChars ? _resourceData + _chars[chr].offset + 2 : 0; +SciSpan<const byte> GfxFontFromResource::getCharData(uint16 chr) { + if (chr >= _numChars) { + return SciSpan<const byte>(); + } + + const uint32 size = (chr + 1 >= _numChars ? _resource->size() : _chars[chr + 1].offset) - _chars[chr].offset - 2; + return _resource->subspan(_chars[chr].offset + 2, size); } void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput) { + if (chr >= _numChars) { + // SSCI silently ignores attempts to draw characters that do not exist + // in the font; for now, emit warnings if this happens, to learn if + // it leads to any bugs + warning("%s is missing glyph %d", _resource->name().c_str(), chr); + return; + } + // Make sure we're comparing against the correct dimensions // If the font we're drawing is already upscaled, make sure we use the full screen width/height uint16 screenWidth = _screen->fontIsUpscaled() ? _screen->getDisplayWidth() : _screen->getWidth(); @@ -87,13 +99,13 @@ void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bo int y = 0; int16 greyedTop = top; - byte *pIn = getCharData(chr); + SciSpan<const byte> charData = getCharData(chr); for (int i = 0; i < charHeight; i++, y++) { if (greyedOutput) mask = ((greyedTop++) % 2) ? 0xAA : 0x55; for (int done = 0; done < charWidth; done++) { if ((done & 7) == 0) // fetching next data byte - b = *(pIn++) & mask; + b = *(charData++) & mask; if (b & 0x80) // if MSB is set - paint it _screen->putFontPixel(top, left + done, y, color); b = b << 1; @@ -104,19 +116,27 @@ void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bo #ifdef ENABLE_SCI32 void GfxFontFromResource::drawToBuffer(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput, byte *buffer, int16 bufWidth, int16 bufHeight) { + if (chr >= _numChars) { + // SSCI silently ignores attempts to draw characters that do not exist + // in the font; for now, emit warnings if this happens, to learn if + // it leads to any bugs + warning("%s is missing glyph %d", _resource->name().c_str(), chr); + return; + } + int charWidth = MIN<int>(getCharWidth(chr), bufWidth - left); int charHeight = MIN<int>(getCharHeight(chr), bufHeight - top); byte b = 0, mask = 0xFF; int y = 0; int16 greyedTop = top; - byte *pIn = getCharData(chr); + SciSpan<const byte> charData = getCharData(chr); for (int i = 0; i < charHeight; i++, y++) { if (greyedOutput) mask = ((greyedTop++) % 2) ? 0xAA : 0x55; for (int done = 0; done < charWidth; done++) { if ((done & 7) == 0) // fetching next data byte - b = *(pIn++) & mask; + b = *(charData++) & mask; if (b & 0x80) { // if MSB is set - paint it int offset = (top + y) * bufWidth + (left + done); buffer[offset] = color; diff --git a/engines/sci/graphics/font.h b/engines/sci/graphics/font.h index b79fb2f0ba..4e26510804 100644 --- a/engines/sci/graphics/font.h +++ b/engines/sci/graphics/font.h @@ -24,6 +24,7 @@ #define SCI_GRAPHICS_FONT_H #include "sci/graphics/helpers.h" +#include "sci/util.h" namespace Sci { @@ -51,8 +52,8 @@ public: ~GfxFontFromResource(); GuiResourceId getResourceId(); - byte getHeight(); - byte getCharWidth(uint16 chr); + uint8 getHeight(); + uint8 getCharWidth(uint16 chr); void draw(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput); #ifdef ENABLE_SCI32 // SCI2/2.1 equivalent @@ -60,23 +61,21 @@ public: #endif private: - byte getCharHeight(uint16 chr); - byte *getCharData(uint16 chr); + uint8 getCharHeight(uint16 chr); + SciSpan<const byte> getCharData(uint16 chr); ResourceManager *_resMan; GfxScreen *_screen; Resource *_resource; GuiResourceId _resourceId; - byte *_resourceData; struct Charinfo { - byte width; - byte height; + uint8 width, height; int16 offset; }; - byte _fontHeight; + uint8 _fontHeight; uint16 _numChars; Charinfo *_chars; }; diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp index e10b9fddbf..3a62760398 100644 --- a/engines/sci/graphics/maciconbar.cpp +++ b/engines/sci/graphics/maciconbar.cpp @@ -203,11 +203,11 @@ void GfxMacIconBar::setInventoryIcon(int16 icon) { Graphics::Surface *GfxMacIconBar::loadPict(ResourceId id) { Resource *res = g_sci->getResMan()->findResource(id, false); - if (!res || res->size == 0) + if (!res || res->size() == 0) return 0; Image::PICTDecoder pictDecoder; - Common::MemoryReadStream stream(res->data, res->size); + Common::MemoryReadStream stream(res->toStream()); if (!pictDecoder.loadStream(stream)) return 0; diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 6fe1fb1b49..307c8aedde 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -134,12 +134,12 @@ void GfxPalette::setDefault() { #define SCI_PAL_FORMAT_CONSTANT 1 #define SCI_PAL_FORMAT_VARIABLE 0 -void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut) const { +void GfxPalette::createFromData(const SciSpan<const byte> &data, Palette *paletteOut) const { int palFormat = 0; - int palOffset = 0; - int palColorStart = 0; - int palColorCount = 0; - int colorNo = 0; + uint palOffset = 0; + uint palColorStart = 0; + uint palColorCount = 0; + uint colorNo = 0; memset(paletteOut, 0, sizeof(Palette)); @@ -148,16 +148,16 @@ void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut) paletteOut->mapping[colorNo] = colorNo; } - if (bytesLeft < 37) { + if (data.size() < 37) { // This happens when loading palette of picture 0 in sq5 - the resource is broken and doesn't contain a full // palette - debugC(kDebugLevelResMan, "GfxPalette::createFromData() - not enough bytes in resource (%d), expected palette header", bytesLeft); + debugC(kDebugLevelResMan, "GfxPalette::createFromData() - not enough bytes in resource (%lu), expected palette header", data.size()); return; } // palette formats in here are not really version exclusive, we can not use sci-version to differentiate between them // they were just called that way, because they started appearing in sci1.1 for example - if ((data[0] == 0 && data[1] == 1) || (data[0] == 0 && data[1] == 0 && READ_SCI11ENDIAN_UINT16(data + 29) == 0)) { + if ((data[0] == 0 && data[1] == 1) || (data[0] == 0 && data[1] == 0 && data.getUint16SEAt(29) == 0)) { // SCI0/SCI1 palette palFormat = SCI_PAL_FORMAT_VARIABLE; // CONSTANT; palOffset = 260; @@ -168,13 +168,13 @@ void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut) palFormat = data[32]; palOffset = 37; palColorStart = data[25]; - palColorCount = READ_SCI11ENDIAN_UINT16(data + 29); + palColorCount = data.getUint16SEAt(29); } switch (palFormat) { case SCI_PAL_FORMAT_CONSTANT: // Check, if enough bytes left - if (bytesLeft < palOffset + (3 * palColorCount)) { + if (data.size() < palOffset + (3 * palColorCount)) { warning("GfxPalette::createFromData() - not enough bytes in resource, expected palette colors"); return; } @@ -187,7 +187,7 @@ void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut) } break; case SCI_PAL_FORMAT_VARIABLE: - if (bytesLeft < palOffset + (4 * palColorCount)) { + if (data.size() < palOffset + (4 * palColorCount)) { warning("GfxPalette::createFromData() - not enough bytes in resource, expected palette colors"); return; } @@ -237,7 +237,7 @@ bool GfxPalette::setAmiga() { } // Called from picture class, some amiga sci1 games set half of the palette -void GfxPalette::modifyAmigaPalette(byte *data) { +void GfxPalette::modifyAmigaPalette(const SciSpan<const byte> &data) { int16 curPos = 0; for (int curColor = 0; curColor < 16; curColor++) { @@ -525,7 +525,7 @@ bool GfxPalette::kernelSetFromResource(GuiResourceId resourceId, bool force) { Palette palette; if (palResource) { - createFromData(palResource->data, palResource->size, &palette); + createFromData(*palResource, &palette); set(&palette, force); return true; } @@ -723,7 +723,7 @@ bool GfxPalette::palVaryLoadTargetPalette(GuiResourceId resourceId) { Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false); if (palResource) { // Load and initialize destination palette - createFromData(palResource->data, palResource->size, &_palVaryTargetPalette); + createFromData(*palResource, &_palVaryTargetPalette); return true; } return false; @@ -810,7 +810,7 @@ int16 GfxPalette::kernelPalVaryChangeTarget(GuiResourceId resourceId) { Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false); if (palResource) { Palette insertPalette; - createFromData(palResource->data, palResource->size, &insertPalette); + createFromData(*palResource, &insertPalette); // insert new palette into target insert(&insertPalette, &_palVaryTargetPalette); // update palette and set on screen diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h index 2178de8a91..af74169976 100644 --- a/engines/sci/graphics/palette.h +++ b/engines/sci/graphics/palette.h @@ -25,6 +25,7 @@ #include "common/array.h" #include "sci/graphics/helpers.h" +#include "sci/util.h" namespace Sci { @@ -47,9 +48,9 @@ public: bool isUsing16bitColorMatch(); void setDefault(); - void createFromData(byte *data, int bytesLeft, Palette *paletteOut) const; + void createFromData(const SciSpan<const byte> &data, Palette *paletteOut) const; bool setAmiga(); - void modifyAmigaPalette(byte *data); + void modifyAmigaPalette(const SciSpan<const byte> &data); void setEGA(); void set(Palette *sciPal, bool force, bool forceRealMerge = false); bool insert(Palette *newPalette, Palette *destPalette); diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp index 56e1940224..febb6820d0 100644 --- a/engines/sci/graphics/palette32.cpp +++ b/engines/sci/graphics/palette32.cpp @@ -37,15 +37,15 @@ namespace Sci { #pragma mark HunkPalette -HunkPalette::HunkPalette(byte *rawPalette) : +HunkPalette::HunkPalette(const SciSpan<const byte> &rawPalette) : _version(0), // NOTE: The header size in palettes is garbage. In at least KQ7 2.00b and // Phant1, the 999.pal sets this value to 0. In most other palettes it is // set to 14, but the *actual* size of the header structure used in SSCI is // 13, which is reflected by `kHunkPaletteHeaderSize`. // _headerSize(rawPalette[0]), - _numPalettes(rawPalette[10]), - _data(nullptr) { + _numPalettes(rawPalette.getUint8At(10)), + _data() { assert(_numPalettes == 0 || _numPalettes == 1); if (_numPalettes) { _data = rawPalette; @@ -54,7 +54,7 @@ HunkPalette::HunkPalette(byte *rawPalette) : } void HunkPalette::setVersion(const uint32 version) const { - if (_numPalettes != _data[10]) { + if (_numPalettes != _data.getUint8At(10)) { error("Invalid HunkPalette"); } @@ -64,20 +64,21 @@ void HunkPalette::setVersion(const uint32 version) const { error("Invalid HunkPalette"); } - WRITE_SCI11ENDIAN_UINT32(getPalPointer() + kEntryVersionOffset, version); + byte *palette = const_cast<byte *>(getPalPointer().getUnsafeDataAt(kEntryVersionOffset, sizeof(uint32))); + WRITE_SCI11ENDIAN_UINT32(palette, version); _version = version; } } const HunkPalette::EntryHeader HunkPalette::getEntryHeader() const { - const byte *const data = getPalPointer(); + const SciSpan<const byte> data(getPalPointer()); EntryHeader header; - header.startColor = data[10]; - header.numColors = READ_SCI11ENDIAN_UINT16(data + 14); - header.used = data[16]; - header.sharedUsed = data[17]; - header.version = READ_SCI11ENDIAN_UINT32(data + kEntryVersionOffset); + header.startColor = data.getUint8At(10); + header.numColors = data.getUint16SEAt(14); + header.used = data.getUint8At(16); + header.sharedUsed = data.getUint8At(17); + header.version = data.getUint32SEAt(kEntryVersionOffset); return header; } @@ -94,7 +95,8 @@ const Palette HunkPalette::toPalette() const { if (_numPalettes) { const EntryHeader header = getEntryHeader(); - const byte *data = getPalPointer() + kEntryHeaderSize; + const uint32 dataSize = header.numColors * (/* RGB */ 3 + (header.sharedUsed ? 0 : 1)); + const byte *data = getPalPointer().getUnsafeDataAt(kEntryHeaderSize, dataSize); const int16 end = header.startColor + header.numColors; assert(end <= 256); @@ -169,7 +171,7 @@ bool GfxPalette32::loadPalette(const GuiResourceId resourceId) { return false; } - const HunkPalette palette(palResource->data); + const HunkPalette palette(*palResource); submit(palette); return true; } @@ -296,7 +298,7 @@ Palette GfxPalette32::getPaletteFromResource(const GuiResourceId resourceId) con error("Could not load vary palette %d", resourceId); } - const HunkPalette rawPalette(palResource->data); + const HunkPalette rawPalette(*palResource); return rawPalette.toPalette(); } diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h index c4cfb35096..d6d7d0dbd1 100644 --- a/engines/sci/graphics/palette32.h +++ b/engines/sci/graphics/palette32.h @@ -35,7 +35,7 @@ namespace Sci { */ class HunkPalette { public: - HunkPalette(byte *rawPalette); + HunkPalette(const SciSpan<const byte> &rawPalette); /** * Gets the version of the palette. Used to avoid resubmitting a HunkPalette @@ -118,7 +118,7 @@ private: /** * The raw palette data for this hunk palette. */ - byte *_data; + SciSpan<const byte> _data; /** * Returns a struct that describes the palette held by this HunkPalette. The @@ -129,8 +129,8 @@ private: /** * Returns a pointer to the palette data within the hunk palette. */ - byte *getPalPointer() const { - return _data + kHunkPaletteHeaderSize + (2 * _numPalettes); + SciSpan<const byte> getPalPointer() const { + return _data.subspan(kHunkPaletteHeaderSize + (2 * _numPalettes)); } }; diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index 864327feaa..9e9dede1ae 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -20,6 +20,7 @@ * */ +#include "common/span.h" #include "common/stack.h" #include "common/system.h" @@ -68,22 +69,16 @@ void GfxPicture::draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int1 _EGApaletteNo = EGApaletteNo; _priority = 0; - headerSize = READ_LE_UINT16(_resource->data); + headerSize = _resource->getUint16LEAt(0); switch (headerSize) { case 0x26: // SCI 1.1 VGA picture _resourceType = SCI_PICTURE_TYPE_SCI11; drawSci11Vga(); break; -#ifdef ENABLE_SCI32 - case 0x0e: // SCI32 VGA picture - _resourceType = SCI_PICTURE_TYPE_SCI32; - drawSci32Vga(0, 0, 0, 0, 0, false); - break; -#endif default: // VGA, EGA or Amiga vector data _resourceType = SCI_PICTURE_TYPE_REGULAR; - drawVectorData(_resource->data, _resource->size); + drawVectorData(*_resource); } } @@ -100,16 +95,15 @@ void GfxPicture::reset() { } void GfxPicture::drawSci11Vga() { - byte *inbuffer = _resource->data; - int size = _resource->size; + SciSpan<const byte> inbuffer(*_resource); int priorityBandsCount = inbuffer[3]; int has_cel = inbuffer[4]; - int vector_dataPos = READ_LE_UINT32(inbuffer + 16); - int vector_size = size - vector_dataPos; - int palette_data_ptr = READ_LE_UINT32(inbuffer + 28); - int cel_headerPos = READ_LE_UINT32(inbuffer + 32); - int cel_RlePos = READ_LE_UINT32(inbuffer + cel_headerPos + 24); - int cel_LiteralPos = READ_LE_UINT32(inbuffer + cel_headerPos + 28); + int vector_dataPos = inbuffer.getUint32LEAt(16); + int vector_size = _resource->size() - vector_dataPos; + int palette_data_ptr = inbuffer.getUint32LEAt(28); + int cel_headerPos = inbuffer.getUint32LEAt(32); + int cel_RlePos = inbuffer.getUint32LEAt(cel_headerPos + 24); + int cel_LiteralPos = inbuffer.getUint32LEAt(cel_headerPos + 28); Palette palette; // Header @@ -132,113 +126,24 @@ void GfxPicture::drawSci11Vga() { // display Cel-data if (has_cel) { // Create palette and set it - _palette->createFromData(inbuffer + palette_data_ptr, size - palette_data_ptr, &palette); + _palette->createFromData(inbuffer.subspan(palette_data_ptr), &palette); _palette->set(&palette, true); - drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, 0, 0, false); + drawCelData(inbuffer, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, 0, 0, false); } // process vector data - drawVectorData(inbuffer + vector_dataPos, vector_size); + drawVectorData(inbuffer.subspan(vector_dataPos, vector_size)); // Set priority band information - _ports->priorityBandsInitSci11(inbuffer + 40); -} - -#ifdef ENABLE_SCI32 -int16 GfxPicture::getSci32celCount() { - byte *inbuffer = _resource->data; - return inbuffer[2]; -} - -int16 GfxPicture::getSci32celX(int16 celNo) { - byte *inbuffer = _resource->data; - int header_size = READ_SCI11ENDIAN_UINT16(inbuffer); - int cel_headerPos = header_size + 42 * celNo; - return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 38); -} - -int16 GfxPicture::getSci32celY(int16 celNo) { - byte *inbuffer = _resource->data; - int header_size = READ_SCI11ENDIAN_UINT16(inbuffer); - int cel_headerPos = header_size + 42 * celNo; - return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 40); -} - -int16 GfxPicture::getSci32celWidth(int16 celNo) { - byte *inbuffer = _resource->data; - int header_size = READ_SCI11ENDIAN_UINT16(inbuffer); - int cel_headerPos = header_size + 42 * celNo; - return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 0); -} - -int16 GfxPicture::getSci32celHeight(int16 celNo) { - byte *inbuffer = _resource->data; - int header_size = READ_SCI11ENDIAN_UINT16(inbuffer); - int cel_headerPos = header_size + 42 * celNo; - return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 2); -} - - -int16 GfxPicture::getSci32celPriority(int16 celNo) { - byte *inbuffer = _resource->data; - int header_size = READ_SCI11ENDIAN_UINT16(inbuffer); - int cel_headerPos = header_size + 42 * celNo; - return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 36); -} - -void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool mirrored) { - byte *inbuffer = _resource->data; - int size = _resource->size; - int header_size = READ_SCI11ENDIAN_UINT16(inbuffer); - int palette_data_ptr = READ_SCI11ENDIAN_UINT32(inbuffer + 6); -// int celCount = inbuffer[2]; - int cel_headerPos = header_size; - int cel_RlePos, cel_LiteralPos; - Palette palette; - - // HACK - _mirroredFlag = mirrored; - _addToFlag = false; - _resourceType = SCI_PICTURE_TYPE_SCI32; - - if (celNo == 0) { - // Create palette and set it - _palette->createFromData(inbuffer + palette_data_ptr, size - palette_data_ptr, &palette); - _palette->set(&palette, true); - } - - // Header - // 0[headerSize:WORD] 2[celCount:BYTE] 3[Unknown:BYTE] 4[celHeaderSize:WORD] 6[paletteOffset:DWORD] 10[Unknown:WORD] 12[Unknown:WORD] - // cel-header follow afterwards, each is 42 bytes - // Cel-Header - // 0[width:WORD] 2[height:WORD] 4[displaceX:WORD] 6[displaceY:WORD] 8[clearColor:BYTE] 9[compressed:BYTE] - // offset 10-23 is unknown - // 24[rleOffset:DWORD] 28[literalOffset:DWORD] 32[Unknown:WORD] 34[Unknown:WORD] 36[priority:WORD] 38[relativeXpos:WORD] 40[relativeYpos:WORD] - - cel_headerPos += 42 * celNo; - - if (mirrored) { - // switch around relativeXpos - Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea(); - drawX = displayArea.width() - drawX - READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 0); - } - - cel_RlePos = READ_SCI11ENDIAN_UINT32(inbuffer + cel_headerPos + 24); - cel_LiteralPos = READ_SCI11ENDIAN_UINT32(inbuffer + cel_headerPos + 28); - - drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, drawX, drawY, pictureX, pictureY, false); - cel_headerPos += 42; + _ports->priorityBandsInitSci11(inbuffer.subspan(40)); } -#endif -extern void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCount, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData); +extern void unpackCelData(const SciSpan<const byte> &inBuffer, SciSpan<byte> &celBitmap, byte clearColor, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData); -void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool isEGA) { - byte *celBitmap = NULL; - byte *ptr = NULL; - byte *headerPtr = inbuffer + headerPos; - byte *rlePtr = inbuffer + rlePos; +void GfxPicture::drawCelData(const SciSpan<const byte> &inbuffer, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool isEGA) { + const SciSpan<const byte> headerPtr = inbuffer.subspan(headerPos); + const SciSpan<const byte> rlePtr = inbuffer.subspan(rlePos); // displaceX, displaceY fields are ignored, and may contain garbage // (e.g. pic 261 in Dr. Brain 1 Spanish - bug #3614914) //int16 displaceX, displaceY; @@ -254,30 +159,16 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos if (!isEGA && !_addToFlag) priority = 0; -#ifdef ENABLE_SCI32 - if (_resourceType != SCI_PICTURE_TYPE_SCI32) { -#endif - // Width/height here are always LE, even in Mac versions - width = READ_LE_UINT16(headerPtr + 0); - height = READ_LE_UINT16(headerPtr + 2); - //displaceX = (signed char)headerPtr[4]; - //displaceY = (unsigned char)headerPtr[5]; - if (_resourceType == SCI_PICTURE_TYPE_SCI11) - // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise - clearColor = _screen->getColorWhite(); - else - clearColor = headerPtr[6]; -#ifdef ENABLE_SCI32 - } else { - width = READ_SCI11ENDIAN_UINT16(headerPtr + 0); - height = READ_SCI11ENDIAN_UINT16(headerPtr + 2); - //displaceX = READ_SCI11ENDIAN_UINT16(headerPtr + 4); // probably signed?!? - //displaceY = READ_SCI11ENDIAN_UINT16(headerPtr + 6); // probably signed?!? - clearColor = headerPtr[8]; - if (headerPtr[9] == 0) - compression = false; - } -#endif + // Width/height here are always LE, even in Mac versions + width = headerPtr.getUint16LEAt(0); + height = headerPtr.getUint16LEAt(2); + //displaceX = (signed char)headerPtr[4]; + //displaceY = (unsigned char)headerPtr[5]; + if (_resourceType == SCI_PICTURE_TYPE_SCI11) + // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise + clearColor = _screen->getColorWhite(); + else + clearColor = headerPtr[6]; //if (displaceX || displaceY) // error("unsupported embedded cel-data in picture"); @@ -285,7 +176,8 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos // We will unpack cel-data into a temporary buffer and then plot it to screen // That needs to be done cause a mirrored picture may be requested pixelCount = width * height; - celBitmap = new byte[pixelCount]; + Common::SpanOwner<SciSpan<byte> > celBitmap; + celBitmap->allocate(pixelCount, _resource->name()); if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2) { // See GfxView::unpackCel() for why this black/white swap is done @@ -296,22 +188,11 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos clearColor = 0; } - if (compression) - unpackCelData(inbuffer, celBitmap, clearColor, pixelCount, rlePos, literalPos, _resMan->getViewType(), width, false); - else + if (compression) { + unpackCelData(inbuffer, *celBitmap, clearColor, rlePos, literalPos, _resMan->getViewType(), width, false); + } else // No compression (some SCI32 pictures) - memcpy(celBitmap, rlePtr, pixelCount); - - if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2) { - // See GfxView::unpackCel() for why this black/white swap is done - // This picture swap is only needed in SCI32, not SCI1.1 - for (int i = 0; i < pixelCount; i++) { - if (celBitmap[i] == 0) - celBitmap[i] = 0xff; - else if (celBitmap[i] == 0xff) - celBitmap[i] = 0; - } - } + memcpy(celBitmap->getUnsafeDataAt(0, pixelCount), rlePtr.getUnsafeDataAt(0, pixelCount), pixelCount); Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea(); @@ -356,13 +237,12 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos // but white and that won't matter because the screen is supposed to be already white. It seems that most (if not all) // SCI1.1 games use color 0 as transparency and SCI1 games use color 255 as transparency. Sierra SCI seems to paint // the whole data to screen and wont skip over transparent pixels. So this will actually make it work like Sierra. - // SCI32 doesn't use _addToFlag at all. - if (!_addToFlag && _resourceType != SCI_PICTURE_TYPE_SCI32) + if (!_addToFlag) clearColor = _screen->getColorWhite(); byte drawMask = priority > 15 ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL | GFX_SCREEN_MASK_PRIORITY; - ptr = celBitmap; + SciSpan<const byte> ptr = *celBitmap; ptr += skipCelBitmapPixels; ptr += skipCelBitmapLines * width; @@ -440,8 +320,6 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos } } } - - delete[] celBitmap; } enum { @@ -549,7 +427,7 @@ static const byte vector_defaultEGApriority[PIC_EGAPRIORITY_SIZE] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; -void GfxPicture::drawVectorData(byte *data, int dataSize) { +void GfxPicture::drawVectorData(const SciSpan<const byte> &data) { byte pic_op; byte pic_color = _screen->getColorDefaultVectorData(); byte pic_priority = 255, pic_control = 255; @@ -558,7 +436,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { byte *EGApalette = &EGApalettes[_EGApaletteNo * PIC_EGAPALETTE_SIZE]; byte EGApriority[PIC_EGAPRIORITY_SIZE] = {0}; bool isEGA = false; - int curPos = 0; + uint curPos = 0; uint16 size; byte pixel; int i; @@ -591,7 +469,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { } // Drawing - while (curPos < dataSize) { + while (curPos < data.size()) { #ifdef DEBUG_PICTURE_DRAW debug("Picture op: %X (%s) at %d", data[curPos], picOpcodeNames[data[curPos] - 0xF0], curPos); _screen->copyToScreen(); @@ -774,7 +652,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { break; case PIC_OPX_EGA_EMBEDDED_VIEW: vectorGetAbsCoordsNoMirror(data, curPos, x, y); - size = READ_LE_UINT16(data + curPos); curPos += 2; + size = data.getUint16LEAt(curPos); curPos += 2; // hardcoded in SSCI, 16 for SCI1early excluding Space Quest 4, 0 for anything else // fixes sq4 pictures 546+547 (Vohaul's head and Roger Jr trapped). Bug #5250 // fixes sq4 picture 631 (SQ1 view from cockpit). Bug 5249 @@ -783,11 +661,11 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { } else { _priority = 0; } - drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, 0, 0, true); + drawCelData(data, curPos, curPos + 8, 0, x, y, 0, 0, true); curPos += size; break; case PIC_OPX_EGA_SET_PRIORITY_TABLE: - _ports->priorityBandsInit(data + curPos); + _ports->priorityBandsInit(data.subspan(curPos, 14)); curPos += 14; break; default: @@ -810,7 +688,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { curPos += 256 + 4 + 1024; } else { // Setting half of the Amiga palette - _palette->modifyAmigaPalette(&data[curPos]); + _palette->modifyAmigaPalette(data.subspan(curPos)); curPos += 32; } } else { @@ -824,7 +702,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { break; case PIC_OPX_VGA_EMBEDDED_VIEW: // draw cel vectorGetAbsCoordsNoMirror(data, curPos, x, y); - size = READ_LE_UINT16(data + curPos); curPos += 2; + size = data.getUint16LEAt(curPos); curPos += 2; if (getSciVersion() <= SCI_VERSION_1_EARLY) { // During SCI1Early sierra always used 0 as priority for cels inside picture resources // fixes Space Quest 4 orange ship lifting off (bug #6446) @@ -832,15 +710,15 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { } else { _priority = pic_priority; // set global priority so the cel gets drawn using current priority as well } - drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, 0, 0, false); + drawCelData(data, curPos, curPos + 8, 0, x, y, 0, 0, false); curPos += size; break; case PIC_OPX_VGA_PRIORITY_TABLE_EQDIST: - _ports->priorityBandsInit(-1, READ_LE_UINT16(data + curPos), READ_LE_UINT16(data + curPos + 2)); + _ports->priorityBandsInit(-1, data.getUint16LEAt(curPos), data.getUint16LEAt(curPos + 2)); curPos += 4; break; case PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT: - _ports->priorityBandsInit(data + curPos); + _ports->priorityBandsInit(data.subspan(curPos, 14)); curPos += 14; break; default: @@ -886,20 +764,20 @@ bool GfxPicture::vectorIsNonOpcode(byte pixel) { return true; } -void GfxPicture::vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y) { +void GfxPicture::vectorGetAbsCoords(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y) { byte pixel = data[curPos++]; x = data[curPos++] + ((pixel & 0xF0) << 4); y = data[curPos++] + ((pixel & 0x0F) << 8); if (_mirroredFlag) x = 319 - x; } -void GfxPicture::vectorGetAbsCoordsNoMirror(byte *data, int &curPos, int16 &x, int16 &y) { +void GfxPicture::vectorGetAbsCoordsNoMirror(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y) { byte pixel = data[curPos++]; x = data[curPos++] + ((pixel & 0xF0) << 4); y = data[curPos++] + ((pixel & 0x0F) << 8); } -void GfxPicture::vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y) { +void GfxPicture::vectorGetRelCoords(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y) { byte pixel = data[curPos++]; if (pixel & 0x80) { x -= ((pixel >> 4) & 7) * (_mirroredFlag ? -1 : 1); @@ -913,7 +791,7 @@ void GfxPicture::vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y) } } -void GfxPicture::vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16 &y) { +void GfxPicture::vectorGetRelCoordsMed(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y) { byte pixel = data[curPos++]; if (pixel & 0x80) { y -= (pixel & 0x7F); @@ -928,7 +806,7 @@ void GfxPicture::vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16 } } -void GfxPicture::vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture) { +void GfxPicture::vectorGetPatternTexture(const SciSpan<const byte> &data, uint &curPos, int16 pattern_Code, int16 &pattern_Texture) { if (pattern_Code & SCI_PATTERN_CODE_USE_TEXTURE) { pattern_Texture = (data[curPos++] >> 1) & 0x7f; } diff --git a/engines/sci/graphics/picture.h b/engines/sci/graphics/picture.h index 1be1ae3004..48f80323b1 100644 --- a/engines/sci/graphics/picture.h +++ b/engines/sci/graphics/picture.h @@ -23,6 +23,8 @@ #ifndef SCI_GRAPHICS_PICTURE_H #define SCI_GRAPHICS_PICTURE_H +#include "sci/util.h" + namespace Sci { #define SCI_PATTERN_CODE_RECTANGLE 0x10 @@ -54,28 +56,18 @@ public: GuiResourceId getResourceId(); void draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo); -#ifdef ENABLE_SCI32 - int16 getSci32celCount(); - int16 getSci32celY(int16 celNo); - int16 getSci32celX(int16 celNo); - int16 getSci32celWidth(int16 celNo); - int16 getSci32celHeight(int16 celNo); - int16 getSci32celPriority(int16 celNo); - void drawSci32Vga(int16 celNo, int16 callerX, int16 callerY, int16 pictureX, int16 pictureY, bool mirrored); -#endif - private: void initData(GuiResourceId resourceId); void reset(); void drawSci11Vga(); - void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool isEGA); - void drawVectorData(byte *data, int size); + void drawCelData(const SciSpan<const byte> &inbuffer, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool isEGA); + void drawVectorData(const SciSpan<const byte> &data); bool vectorIsNonOpcode(byte pixel); - void vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y); - void vectorGetAbsCoordsNoMirror(byte *data, int &curPos, int16 &x, int16 &y); - void vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y); - void vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16 &y); - void vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture); + void vectorGetAbsCoords(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y); + void vectorGetAbsCoordsNoMirror(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y); + void vectorGetRelCoords(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y); + void vectorGetRelCoordsMed(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y); + void vectorGetPatternTexture(const SciSpan<const byte> &data, uint &curPos, int16 pattern_Code, int16 &pattern_Texture); void vectorFloodFill(int16 x, int16 y, byte color, byte prio, byte control); void vectorPattern(int16 x, int16 y, byte pic_color, byte pic_priority, byte pic_control, byte code, byte texture); void vectorPatternBox(Common::Rect box, byte color, byte prio, byte control); diff --git a/engines/sci/graphics/portrait.cpp b/engines/sci/graphics/portrait.cpp index 045a923569..675883e6d3 100644 --- a/engines/sci/graphics/portrait.cpp +++ b/engines/sci/graphics/portrait.cpp @@ -39,12 +39,6 @@ Portrait::Portrait(ResourceManager *resMan, EventManager *event, GfxScreen *scre init(); } -Portrait::~Portrait() { - delete[] _lipSyncDataOffsetTable; - delete[] _bitmaps; - delete[] _fileData; -} - void Portrait::init() { // .BIN files are loaded from actors directory and from .\ directory // header: @@ -90,31 +84,28 @@ void Portrait::init() { // 4 bytes appended, seem to be random // 9E11120E for alex // 9E9E9E9E for vizier - int32 fileSize = 0; - Common::SeekableReadStream *file = - SearchMan.createReadStreamForMember("actors/" + _resourceName + ".bin"); + Common::String fileName = "actors/" + _resourceName + ".bin"; + Common::SeekableReadStream *file = SearchMan.createReadStreamForMember(fileName); + ; if (!file) { - file = SearchMan.createReadStreamForMember(_resourceName + ".bin"); + fileName = _resourceName + ".bin"; + file = SearchMan.createReadStreamForMember(fileName); if (!file) error("portrait %s.bin not found", _resourceName.c_str()); } - fileSize = file->size(); - _fileData = new byte[fileSize]; - file->read(_fileData, fileSize); + _fileData->allocateFromStream(*file, Common::kSpanMaxSize, fileName); delete file; - if (strncmp((char *)_fileData, "WIN", 3)) { + if (strncmp((const char *)_fileData->getUnsafeDataAt(0, 3), "WIN", 3)) { error("portrait %s doesn't have valid header", _resourceName.c_str()); } - _width = READ_LE_UINT16(_fileData + 3); - _height = READ_LE_UINT16(_fileData + 5); - _bitmapCount = READ_LE_UINT16(_fileData + 7); - _lipSyncIDCount = READ_LE_UINT16(_fileData + 11); - - _bitmaps = new PortraitBitmap[_bitmapCount]; + _width = _fileData->getUint16LEAt(3); + _height = _fileData->getUint16LEAt(5); + _bitmaps.resize(_fileData->getUint16LEAt(7)); + _lipSyncIDCount = _fileData->getUint16LEAt(11); - uint16 portraitPaletteSize = READ_LE_UINT16(_fileData + 13); - byte *data = _fileData + 17; + uint16 portraitPaletteSize = _fileData->getUint16LEAt(13); + SciSpan<const byte> data = _fileData->subspan(17); // Read palette memset(&_portraitPalette, 0, sizeof(Palette)); uint16 palSize = 0, palNr = 0; @@ -128,42 +119,40 @@ void Portrait::init() { } // Read all bitmaps - PortraitBitmap *curBitmap = _bitmaps; uint16 bitmapNr; uint16 bytesPerLine; - for (bitmapNr = 0; bitmapNr < _bitmapCount; bitmapNr++) { - curBitmap->width = READ_LE_UINT16(data + 2); - curBitmap->height = READ_LE_UINT16(data + 4); - bytesPerLine = READ_LE_UINT16(data + 6); - if (bytesPerLine < curBitmap->width) + for (bitmapNr = 0; bitmapNr < _bitmaps.size(); bitmapNr++) { + PortraitBitmap &curBitmap = _bitmaps[bitmapNr]; + curBitmap.width = data.getUint16LEAt(2); + curBitmap.height = data.getUint16LEAt(4); + bytesPerLine = data.getUint16LEAt(6); + if (bytesPerLine < curBitmap.width) error("kPortrait: bytesPerLine larger than actual width"); - curBitmap->extraBytesPerLine = bytesPerLine - curBitmap->width; - curBitmap->rawBitmap = data + 14; - data += 14 + (curBitmap->height * bytesPerLine); - curBitmap++; + curBitmap.extraBytesPerLine = bytesPerLine - curBitmap.width; + curBitmap.rawBitmap = data.subspan(14, curBitmap.width * curBitmap.height); + data += 14 + (curBitmap.height * bytesPerLine); } // Offset table follows - curBitmap = _bitmaps; - int32 offsetTableSize = READ_LE_UINT32(data); - assert((bitmapNr + 1) * 14 <= offsetTableSize); + uint32 offsetTableSize = data.getUint32LEAt(0); + assert((bitmapNr + 1U) * 14U <= offsetTableSize); data += 4; - byte *dataOffsetTable = data + 14; // we skip first bitmap offsets - for (bitmapNr = 0; bitmapNr < _bitmapCount; bitmapNr++) { - curBitmap->displaceX = READ_LE_UINT16(dataOffsetTable); - curBitmap->displaceY = READ_LE_UINT16(dataOffsetTable + 2); + SciSpan<const byte> dataOffsetTable = data.subspan(14); // we skip first bitmap offsets + for (bitmapNr = 0; bitmapNr < _bitmaps.size(); bitmapNr++) { + PortraitBitmap &curBitmap = _bitmaps[bitmapNr]; + curBitmap.displaceX = dataOffsetTable.getUint16LEAt(0); + curBitmap.displaceY = dataOffsetTable.getUint16LEAt(2); dataOffsetTable += 14; - curBitmap++; } data += offsetTableSize; // raw lip-sync ID table follows uint32 lipSyncIDTableSize; - lipSyncIDTableSize = READ_LE_UINT32(data); + lipSyncIDTableSize = data.getUint32LEAt(0); data += 4; - assert( lipSyncIDTableSize == (_lipSyncIDCount * 4) ); + assert(lipSyncIDTableSize == _lipSyncIDCount * 4); _lipSyncIDTable = data; data += lipSyncIDTableSize; @@ -174,23 +163,23 @@ void Portrait::init() { uint16 lipSyncDataNr; uint16 lipSyncCurOffset; - lipSyncDataTableSize = READ_LE_UINT32(data); + lipSyncDataTableSize = data.getUint32LEAt(0); data += 4; - assert( lipSyncDataTableSize == 0x220 ); // always this size, just a safety-check + assert(lipSyncDataTableSize == 0x220); // always this size, just a safety-check _lipSyncData = data; lipSyncDataTableLastOffset = lipSyncDataTableSize - 1; - _lipSyncDataOffsetTable = new uint16[ _lipSyncIDCount ]; + _lipSyncDataOffsetTable.resize(_lipSyncIDCount); lipSyncDataNr = 0; lipSyncCurOffset = 0; - while ( (lipSyncCurOffset < lipSyncDataTableSize) && (lipSyncDataNr < _lipSyncIDCount) ) { + while (lipSyncCurOffset < lipSyncDataTableSize && lipSyncDataNr < _lipSyncIDCount) { // We are currently at the start of ID-frame data _lipSyncDataOffsetTable[lipSyncDataNr] = lipSyncCurOffset; // Look for end of ID-frame data lipSyncData = *data++; lipSyncCurOffset++; - while ( (lipSyncData != 0xFF) && (lipSyncCurOffset < lipSyncDataTableLastOffset) ) { + while (lipSyncData != 0xFF && lipSyncCurOffset < lipSyncDataTableLastOffset) { // Either terminator (0xFF) or frame-data (1 byte tick count and 1 byte bitmap ID) data++; lipSyncData = *data++; @@ -198,7 +187,6 @@ void Portrait::init() { } lipSyncDataNr++; } - _lipSyncDataOffsetTableEnd = data; // last 4 bytes seem to be garbage } @@ -277,7 +265,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint // Do animation depending on rave resource till audio is done playing int16 raveTicks; uint16 raveID; - byte *raveLipSyncData; + SciSpan<const byte> raveLipSyncData; byte raveLipSyncTicks; byte raveLipSyncBitmapNr; int timerPosition = 0; @@ -286,7 +274,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint SciEvent curEvent; bool userAbort = false; - while ((raveOffset < raveResource->size) && (!userAbort)) { + while (raveOffset < raveResource->size() && !userAbort) { // rave string starts with tick count, followed by lipSyncID, tick count and so on raveTicks = raveGetTicks(raveResource, &raveOffset); if (raveTicks < 0) @@ -297,7 +285,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint if (raveID) { raveLipSyncData = raveGetLipSyncData(raveID); } else { - raveLipSyncData = NULL; + raveLipSyncData = SciSpan<const byte>(); } #ifdef DEBUG_PORTRAIT @@ -330,7 +318,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint // Tick = 0xFF is the terminator for the data timerPositionWithin = timerPosition; raveLipSyncTicks = *raveLipSyncData++; - while ( (raveLipSyncData < _lipSyncDataOffsetTableEnd) && (raveLipSyncTicks != 0xFF) ) { + while (raveLipSyncData.size() && raveLipSyncTicks != 0xFF) { if (raveLipSyncTicks) raveLipSyncTicks--; // 1 -> wait 0 ticks, 2 -> wait 1 tick, etc. timerPositionWithin += raveLipSyncTicks; @@ -357,7 +345,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint // bitmap nr within sync data is base 1, we need base 0 raveLipSyncBitmapNr--; - if (raveLipSyncBitmapNr < _bitmapCount) { + if (raveLipSyncBitmapNr < _bitmaps.size()) { drawBitmap(0); drawBitmap(raveLipSyncBitmapNr); bitsShow(); @@ -435,14 +423,14 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint // returns ASCII ticks from lip sync string as uint16 int16 Portrait::raveGetTicks(Resource *resource, uint *offset) { uint curOffset = *offset; - byte *curData = resource->data + curOffset; + SciSpan<const byte> curData = resource->subspan(curOffset); byte curByte; uint16 curValue = 0; - if (curOffset >= resource->size) + if (curOffset >= resource->size()) return -1; - while (curOffset < resource->size) { + while (curOffset < resource->size()) { curByte = *curData++; curOffset++; if ( curByte == ' ' ) break; @@ -460,11 +448,11 @@ int16 Portrait::raveGetTicks(Resource *resource, uint *offset) { // returns ASCII ID from lip sync string as uint16 uint16 Portrait::raveGetID(Resource *resource, uint *offset) { uint curOffset = *offset; - byte *curData = resource->data + curOffset; + SciSpan<const byte> curData = resource->subspan(curOffset); byte curByte = 0; uint16 curValue = 0; - while (curOffset < resource->size) { + while (curOffset < resource->size()) { curByte = *curData++; curOffset++; if ( curByte == ' ' ) break; @@ -480,9 +468,9 @@ uint16 Portrait::raveGetID(Resource *resource, uint *offset) { } // Searches for a specific lip sync ID and returns pointer to lip sync data or NULL in case ID was not found -byte *Portrait::raveGetLipSyncData(uint16 raveID) { +SciSpan<const byte> Portrait::raveGetLipSyncData(const uint16 raveID) { uint lipSyncIDNr = 0; - byte *lipSyncIDPtr = _lipSyncIDTable; + SciSpan<const byte> lipSyncIDPtr = _lipSyncIDTable; byte lipSyncIDByte1, lipSyncIDByte2; uint16 lipSyncID; @@ -490,20 +478,19 @@ byte *Portrait::raveGetLipSyncData(uint16 raveID) { while (lipSyncIDNr < _lipSyncIDCount) { lipSyncIDByte1 = *lipSyncIDPtr++; lipSyncIDByte2 = *lipSyncIDPtr++; - lipSyncID = ( lipSyncIDByte1 << 8 ) | lipSyncIDByte2; + lipSyncID = (lipSyncIDByte1 << 8) | lipSyncIDByte2; - if ( lipSyncID == raveID ) { - return _lipSyncData + _lipSyncDataOffsetTable[lipSyncIDNr]; + if (lipSyncID == raveID) { + return _lipSyncData.subspan(_lipSyncDataOffsetTable[lipSyncIDNr]); } lipSyncIDNr++; lipSyncIDPtr += 2; // ID is every 4 bytes } - return NULL; + return SciSpan<const byte>(); } void Portrait::drawBitmap(uint16 bitmapNr) { - byte *data = _bitmaps[bitmapNr].rawBitmap; uint16 bitmapHeight = _bitmaps[bitmapNr].height; uint16 bitmapWidth = _bitmaps[bitmapNr].width; Common::Point bitmapPosition = _position; @@ -511,6 +498,7 @@ void Portrait::drawBitmap(uint16 bitmapNr) { bitmapPosition.x += _bitmaps[bitmapNr].displaceX; bitmapPosition.y += _bitmaps[bitmapNr].displaceY; + const byte *data = _bitmaps[bitmapNr].rawBitmap.getUnsafeDataAt(0, bitmapWidth * bitmapHeight); for (int y = 0; y < bitmapHeight; y++) { for (int x = 0; x < bitmapWidth; x++) { _screen->putPixelOnDisplay(bitmapPosition.x + x, bitmapPosition.y + y, _portraitPalette.mapping[*data++]); diff --git a/engines/sci/graphics/portrait.h b/engines/sci/graphics/portrait.h index e0888daa86..b6f5a17af7 100644 --- a/engines/sci/graphics/portrait.h +++ b/engines/sci/graphics/portrait.h @@ -23,13 +23,15 @@ #ifndef SCI_GRAPHICS_PORTRAITS_H #define SCI_GRAPHICS_PORTRAITS_H +#include "sci/util.h" + namespace Sci { struct PortraitBitmap { int16 width, height; int16 extraBytesPerLine; uint16 displaceX, displaceY; - byte *rawBitmap; + SciSpan<const byte> rawBitmap; }; /** @@ -40,7 +42,6 @@ struct PortraitBitmap { class Portrait { public: Portrait(ResourceManager *resMan, EventManager *event, GfxScreen *screen, GfxPalette *palette, AudioPlayer *audio, Common::String resourceName); - ~Portrait(); void setupAudio(uint16 resourceId, uint16 noun, uint16 verb, uint16 cond, uint16 seq); void doit(Common::Point position, uint16 resourceId, uint16 noun, uint16 verb, uint16 cond, uint16 seq); @@ -54,7 +55,7 @@ private: int16 raveGetTicks(Resource *resource, uint *offset); uint16 raveGetID(Resource *resource, uint *offset); - byte *raveGetLipSyncData(uint16 raveID); + SciSpan<const byte> raveGetLipSyncData(const uint16 raveID); ResourceManager *_resMan; EventManager *_event; @@ -66,19 +67,17 @@ private: uint16 _width; Palette _portraitPalette; - uint16 _bitmapCount; - PortraitBitmap *_bitmaps; + Common::Array<PortraitBitmap> _bitmaps; Common::String _resourceName; - byte *_fileData; + Common::SpanOwner<SciSpan<const byte> > _fileData; uint32 _lipSyncIDCount; - byte *_lipSyncIDTable; + SciSpan<const byte> _lipSyncIDTable; - byte *_lipSyncData; - uint16 *_lipSyncDataOffsetTable; - byte *_lipSyncDataOffsetTableEnd; + SciSpan<const byte> _lipSyncData; + Common::Array<uint16> _lipSyncDataOffsetTable; Common::Point _position; }; diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp index 0d00ce01e6..eb66896b53 100644 --- a/engines/sci/graphics/ports.cpp +++ b/engines/sci/graphics/ports.cpp @@ -674,13 +674,13 @@ void GfxPorts::priorityBandsInit(int16 bandCount, int16 top, int16 bottom) { _priorityBottom--; } -void GfxPorts::priorityBandsInit(byte *data) { +void GfxPorts::priorityBandsInit(const SciSpan<const byte> &data) { int i = 0, inx; byte priority = 0; for (inx = 0; inx < 14; inx++) { - priority = *data++; - while (i < priority) + priority = data[inx]; + while (i < priority && i < 200) _priorityBands[i++] = inx; } while (i < 200) @@ -688,13 +688,13 @@ void GfxPorts::priorityBandsInit(byte *data) { } // Gets used to read priority bands data from sci1.1 pictures -void GfxPorts::priorityBandsInitSci11(byte *data) { +void GfxPorts::priorityBandsInitSci11(SciSpan<const byte> data) { byte priorityBands[14]; for (int bandNo = 0; bandNo < 14; bandNo++) { - priorityBands[bandNo] = READ_LE_UINT16(data); + priorityBands[bandNo] = data.getUint16LEAt(0); data += 2; } - priorityBandsInit(priorityBands); + priorityBandsInit(SciSpan<const byte>(priorityBands, 14)); } void GfxPorts::kernelInitPriorityBands() { diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h index 51aca09f54..cd25645df9 100644 --- a/engines/sci/graphics/ports.h +++ b/engines/sci/graphics/ports.h @@ -93,8 +93,8 @@ public: void clipLine(Common::Point &start, Common::Point &end); void priorityBandsInit(int16 bandCount, int16 top, int16 bottom); - void priorityBandsInit(byte *data); - void priorityBandsInitSci11(byte *data); + void priorityBandsInit(const SciSpan<const byte> &data); + void priorityBandsInitSci11(SciSpan<const byte> data); void kernelInitPriorityBands(); void kernelGraphAdjustPriority(int top, int bottom); diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index de6df39bb9..e69c432712 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -719,40 +719,41 @@ void GfxScreen::debugShowMap(int mapNo) { copyToScreen(); } -void GfxScreen::scale2x(const byte *src, byte *dst, int16 srcWidth, int16 srcHeight, byte bytesPerPixel) { +void GfxScreen::scale2x(const SciSpan<const byte> &src, SciSpan<byte> &dst, int16 srcWidth, int16 srcHeight, byte bytesPerPixel) { assert(bytesPerPixel == 1 || bytesPerPixel == 2); const int newWidth = srcWidth * 2; const int pitch = newWidth * bytesPerPixel; - const byte *srcPtr = src; + const byte *srcPtr = src.getUnsafeDataAt(0, srcWidth * srcHeight * bytesPerPixel); + byte *dstPtr = dst.getUnsafeDataAt(0, srcWidth * srcHeight * bytesPerPixel); if (bytesPerPixel == 1) { for (int y = 0; y < srcHeight; y++) { for (int x = 0; x < srcWidth; x++) { const byte color = *srcPtr++; - dst[0] = color; - dst[1] = color; - dst[newWidth] = color; - dst[newWidth + 1] = color; - dst += 2; + dstPtr[0] = color; + dstPtr[1] = color; + dstPtr[newWidth] = color; + dstPtr[newWidth + 1] = color; + dstPtr += 2; } - dst += newWidth; + dstPtr += newWidth; } } else if (bytesPerPixel == 2) { for (int y = 0; y < srcHeight; y++) { for (int x = 0; x < srcWidth; x++) { const byte color = *srcPtr++; const byte color2 = *srcPtr++; - dst[0] = color; - dst[1] = color2; - dst[2] = color; - dst[3] = color2; - dst[pitch] = color; - dst[pitch + 1] = color2; - dst[pitch + 2] = color; - dst[pitch + 3] = color2; - dst += 4; + dstPtr[0] = color; + dstPtr[1] = color2; + dstPtr[2] = color; + dstPtr[3] = color2; + dstPtr[pitch] = color; + dstPtr[pitch + 1] = color2; + dstPtr[pitch + 2] = color; + dstPtr[pitch + 3] = color2; + dstPtr += 4; } - dst += pitch; + dstPtr += pitch; } } } diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h index 63ee4ed09e..46214b71d4 100644 --- a/engines/sci/graphics/screen.h +++ b/engines/sci/graphics/screen.h @@ -31,8 +31,10 @@ namespace Sci { -#define SCI_SCREEN_UPSCALEDMAXHEIGHT 200 -#define SCI_SCREEN_UPSCALEDMAXWIDTH 320 +enum { + SCI_SCREEN_UPSCALEDMAXHEIGHT = 200, + SCI_SCREEN_UPSCALEDMAXWIDTH = 320 +}; enum GfxScreenUpscaledMode { GFX_SCREEN_UPSCALED_DISABLED = 0, @@ -76,11 +78,6 @@ public: byte getColorWhite() { return _colorWhite; } byte getColorDefaultVectorData() { return _colorDefaultVectorData; } -#ifdef ENABLE_SCI32 - byte *getDisplayScreen() { return _displayScreen; } - byte *getPriorityScreen() { return _priorityScreen; } -#endif - void clearForRestoreGame(); void copyToScreen(); void copyFromScreen(byte *buffer); @@ -120,7 +117,7 @@ public: void bitsGetRect(byte *memoryPtr, Common::Rect *destRect); void bitsRestore(byte *memoryPtr); - void scale2x(const byte *src, byte *dst, int16 srcWidth, int16 srcHeight, byte bytesPerPixel = 1); + void scale2x(const SciSpan<const byte> &src, SciSpan<byte> &dst, int16 srcWidth, int16 srcHeight, byte bytesPerPixel = 1); void adjustToUpscaledCoordinates(int16 &y, int16 &x, Sci32ViewNativeResolution viewScalingType = SCI_VIEW_NATIVERES_NONE); void adjustBackUpscaledCoordinates(int16 &y, int16 &x, Sci32ViewNativeResolution viewScalingType = SCI_VIEW_NATIVERES_NONE); diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp index c07e07538e..77ff9a3d75 100644 --- a/engines/sci/graphics/screen_item32.cpp +++ b/engines/sci/graphics/screen_item32.cpp @@ -183,9 +183,9 @@ void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const boo // NOTE: +2 because the header size field itself is excluded from // the header size in the data - const uint16 headerSize = READ_SCI11ENDIAN_UINT16(view->data) + 2; - const uint8 loopCount = view->data[2]; - const uint8 loopSize = view->data[12]; + const uint16 headerSize = view->getUint16SEAt(0) + 2; + const uint8 loopCount = view->getUint8At(2); + const uint8 loopSize = view->getUint8At(12); // loopNo is set to be an unsigned integer in SSCI, so if it's a // negative value, it'll be fixed accordingly @@ -195,10 +195,10 @@ void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const boo writeSelectorValue(segMan, object, SELECTOR(loop), maxLoopNo); } - byte *loopData = view->data + headerSize + (_celInfo.loopNo * loopSize); + SciSpan<const byte> loopData = view->subspan(headerSize + (_celInfo.loopNo * loopSize)); const int8 seekEntry = loopData[0]; if (seekEntry != -1) { - loopData = view->data + headerSize + (seekEntry * loopSize); + loopData = view->subspan(headerSize + (seekEntry * loopSize)); } // celNo is set to be an unsigned integer in SSCI, so if it's a diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index 0c09fcbb30..2dc7775345 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -21,7 +21,6 @@ */ #include "sci/sci.h" -#include "sci/util.h" #include "sci/engine/state.h" #include "sci/graphics/screen.h" #include "sci/graphics/palette.h" @@ -39,16 +38,7 @@ GfxView::GfxView(ResourceManager *resMan, GfxScreen *screen, GfxPalette *palette } GfxView::~GfxView() { - // Iterate through the loops - for (uint16 loopNum = 0; loopNum < _loopCount; loopNum++) { - // and through the cells of each loop - for (uint16 celNum = 0; celNum < _loop[loopNum].celCount; celNum++) { - delete[] _loop[loopNum].cel[celNum].rawBitmap; - } - delete[] _loop[loopNum].cel; - } - delete[] _loop; - + _loop.clear(); _resMan->unlockResource(_resource); } @@ -111,10 +101,8 @@ void GfxView::initData(GuiResourceId resourceId) { if (!_resource) { error("view resource %d not found", resourceId); } - _resourceData = _resource->data; - _resourceSize = _resource->size; - byte *celData, *loopData; + SciSpan<const byte> celData, loopData; uint16 celOffset; CelInfo *cel; uint16 celCount = 0; @@ -130,7 +118,7 @@ void GfxView::initData(GuiResourceId resourceId) { _loopCount = 0; _embeddedPal = false; - _EGAmapping = NULL; + _EGAmapping.clear(); _sci2ScaleRes = SCI_VIEW_NATIVERES_NONE; _isScaleable = true; @@ -143,11 +131,10 @@ void GfxView::initData(GuiResourceId resourceId) { // 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) { + if (_resource->getUint8At(1) == 0x80) { curViewType = kViewVga; - } else { - if (READ_LE_UINT16(_resourceData + 4) == 1) - curViewType = kViewVga11; + } else if (_resource->getUint16LEAt(4) == 1) { + curViewType = kViewVga11; } } @@ -159,12 +146,12 @@ void GfxView::initData(GuiResourceId resourceId) { case kViewVga: // View-format SCI1 // LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD... - _loopCount = _resourceData[0]; + _loopCount = _resource->getUint8At(0); // bit 0x8000 of _resourceData[1] means palette is set - if (_resourceData[1] & 0x40) + if (_resource->getUint8At(1) & 0x40) isCompressed = false; - mirrorBits = READ_LE_UINT16(_resourceData + 2); - palOffset = READ_LE_UINT16(_resourceData + 6); + mirrorBits = _resource->getUint16LEAt(2); + palOffset = _resource->getUint16LEAt(6); if (palOffset && palOffset != 0x100) { // Some SCI0/SCI01 games also have an offset set. It seems that it @@ -174,7 +161,7 @@ void GfxView::initData(GuiResourceId resourceId) { // have this pointing to a 8x16 byte mapping table that needs to get // applied then. if (!isEGA) { - _palette->createFromData(&_resourceData[palOffset], _resourceSize - palOffset, &_viewPalette); + _palette->createFromData(_resource->subspan(palOffset), &_viewPalette); _embeddedPal = true; } else { // Only use the EGA-mapping, when being SCI1 EGA @@ -182,44 +169,43 @@ void GfxView::initData(GuiResourceId resourceId) { // with broken mapping tables. I guess those games won't use the mapping, so I rather disable it // for them if (getSciVersion() == SCI_VERSION_1_EGA_ONLY) { - _EGAmapping = &_resourceData[palOffset]; for (EGAmapNr = 0; EGAmapNr < SCI_VIEW_EGAMAPPING_COUNT; EGAmapNr++) { - if (memcmp(_EGAmapping, EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE) != 0) + const SciSpan<const byte> mapping = _resource->subspan(palOffset + EGAmapNr * SCI_VIEW_EGAMAPPING_SIZE, SCI_VIEW_EGAMAPPING_SIZE); + if (memcmp(mapping.getUnsafeDataAt(0, SCI_VIEW_EGAMAPPING_SIZE), EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE) != 0) break; - _EGAmapping += SCI_VIEW_EGAMAPPING_SIZE; } // If all mappings are "straight", then we actually ignore the mapping if (EGAmapNr == SCI_VIEW_EGAMAPPING_COUNT) - _EGAmapping = NULL; + _EGAmapping.clear(); else - _EGAmapping = &_resourceData[palOffset]; + _EGAmapping = _resource->subspan(palOffset, SCI_VIEW_EGAMAPPING_COUNT * SCI_VIEW_EGAMAPPING_SIZE); } } } - _loop = new LoopInfo[_loopCount]; + _loop.resize(_loopCount); for (loopNo = 0; loopNo < _loopCount; loopNo++) { - loopData = _resourceData + READ_LE_UINT16(_resourceData + 8 + loopNo * 2); + loopData = _resource->subspan(_resource->getUint16LEAt(8 + loopNo * 2)); // CelCount:WORD Unknown:WORD CelOffset0:WORD CelOffset1:WORD... - celCount = READ_LE_UINT16(loopData); + celCount = loopData.getUint16LEAt(0); _loop[loopNo].celCount = celCount; _loop[loopNo].mirrorFlag = mirrorBits & 1 ? true : false; mirrorBits >>= 1; // read cel info - _loop[loopNo].cel = new CelInfo[celCount]; + _loop[loopNo].cel.resize(celCount); for (celNo = 0; celNo < celCount; celNo++) { - celOffset = READ_LE_UINT16(loopData + 4 + celNo * 2); - celData = _resourceData + celOffset; + celOffset = loopData.getUint16LEAt(4 + celNo * 2); + celData = _resource->subspan(celOffset); // For VGA // Width:WORD Height:WORD DisplaceX:BYTE DisplaceY:BYTE ClearKey:BYTE Unknown:BYTE RLEData starts now directly // For EGA // Width:WORD Height:WORD DisplaceX:BYTE DisplaceY:BYTE ClearKey:BYTE EGAData starts now directly cel = &_loop[loopNo].cel[celNo]; - cel->scriptWidth = cel->width = READ_LE_UINT16(celData); - cel->scriptHeight = cel->height = READ_LE_UINT16(celData + 2); + cel->scriptWidth = cel->width = celData.getUint16LEAt(0); + cel->scriptHeight = cel->height = celData.getUint16LEAt(2); cel->displaceX = (signed char)celData[4]; cel->displaceY = celData[5]; cel->clearKey = celData[6]; @@ -251,7 +237,7 @@ void GfxView::initData(GuiResourceId resourceId) { cel->offsetLiteral = celOffset + 8; } } - cel->rawBitmap = 0; + cel->rawBitmap.clear(); if (_loop[loopNo].mirrorFlag) cel->displaceX = -cel->displaceX; } @@ -260,15 +246,15 @@ void GfxView::initData(GuiResourceId resourceId) { case kViewVga11: // View-format SCI1.1+ // 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 + headerSize = _resource->getUint16SEAt(0) + 2; // headerSize is not part of the header, so it's added assert(headerSize >= 16); - _loopCount = _resourceData[2]; + _loopCount = _resource->getUint8At(2); assert(_loopCount); - palOffset = READ_SCI11ENDIAN_UINT32(_resourceData + 8); + palOffset = _resource->getUint32SEAt(8); // For SCI32, this is a scale flag if (getSciVersion() >= SCI_VERSION_2) { - _sci2ScaleRes = (Sci32ViewNativeResolution)_resourceData[5]; + _sci2ScaleRes = (Sci32ViewNativeResolution)_resource->getUint8At(5); if (_screen->getUpscaledHires() == GFX_SCREEN_UPSCALED_DISABLED) _sci2ScaleRes = SCI_VIEW_NATIVERES_NONE; } @@ -279,7 +265,7 @@ void GfxView::initData(GuiResourceId resourceId) { // 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]) { + switch (_resource->getUint8At(3)) { case 1: _isScaleable = false; break; @@ -288,31 +274,31 @@ void GfxView::initData(GuiResourceId resourceId) { case 0: break; // don't do anything, we already have _isScaleable set default: - error("unsupported flags byte (%d) inside sci1.1 view", _resourceData[3]); + error("unsupported flags byte (%d) inside sci1.1 view", _resource->getUint8At(3)); break; } - loopData = _resourceData + headerSize; - loopSize = _resourceData[12]; + loopData = _resource->subspan(headerSize); + loopSize = _resource->getUint8At(12); assert(loopSize >= 16); - celSize = _resourceData[13]; + celSize = _resource->getUint8At(13); assert(celSize >= 32); if (palOffset) { - _palette->createFromData(&_resourceData[palOffset], _resourceSize - palOffset, &_viewPalette); + _palette->createFromData(_resource->subspan(palOffset), &_viewPalette); _embeddedPal = true; } - _loop = new LoopInfo[_loopCount]; + _loop.resize(_loopCount); for (loopNo = 0; loopNo < _loopCount; loopNo++) { - loopData = _resourceData + headerSize + (loopNo * loopSize); + loopData = _resource->subspan(headerSize + (loopNo * loopSize)); seekEntry = loopData[0]; if (seekEntry != 255) { if (seekEntry >= _loopCount) error("Bad loop-pointer in sci 1.1 view"); _loop[loopNo].mirrorFlag = true; - loopData = _resourceData + headerSize + (seekEntry * loopSize); + loopData = _resource->subspan(headerSize + (seekEntry * loopSize)); } else { _loop[loopNo].mirrorFlag = false; } @@ -320,16 +306,18 @@ void GfxView::initData(GuiResourceId resourceId) { celCount = loopData[2]; _loop[loopNo].celCount = celCount; - celData = _resourceData + READ_SCI11ENDIAN_UINT32(loopData + 12); + const uint32 celDataOffset = loopData.getUint32SEAt(12); // read cel info - _loop[loopNo].cel = new CelInfo[celCount]; + _loop[loopNo].cel.resize(celCount); for (celNo = 0; celNo < celCount; celNo++) { + celData = _resource->subspan(celDataOffset + celNo * celSize, celSize); + cel = &_loop[loopNo].cel[celNo]; - 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); + cel->scriptWidth = cel->width = celData.getInt16SEAt(0); + cel->scriptHeight = cel->height = celData.getInt16SEAt(2); + cel->displaceX = celData.getInt16SEAt(4); + cel->displaceY = celData.getInt16SEAt(6); if (cel->displaceY < 0) cel->displaceY += 255; // sierra did this adjust in their sci1.1 getCelRect() - not sure about sci32 @@ -337,18 +325,16 @@ void GfxView::initData(GuiResourceId resourceId) { cel->clearKey = celData[8]; cel->offsetEGA = 0; - cel->offsetRLE = READ_SCI11ENDIAN_UINT32(celData + 24); - cel->offsetLiteral = READ_SCI11ENDIAN_UINT32(celData + 28); + cel->offsetRLE = celData.getUint32SEAt(24); + cel->offsetLiteral = celData.getUint32SEAt(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; + cel->rawBitmap.clear(); if (_loop[loopNo].mirrorFlag) cel->displaceX = -cel->displaceX; - - celData += celSize; } } break; @@ -367,20 +353,16 @@ void GfxView::initData(GuiResourceId resourceId) { // View 995, Loop 13, Cel 2 = "DUAL" (<- our injected view) if ((g_sci->isCD()) && (resourceId == 995)) { // security checks - if (_loopCount >= 14) { - if ((_loop[13].celCount == 2) && (_loop[13].cel[0].width == 46) && (_loop[13].cel[0].height == 11)) { - // copy current cels over - CelInfo *newCels = new CelInfo[3]; - memcpy(newCels, _loop[13].cel, sizeof(CelInfo) * 2); - delete[] _loop[13].cel; - _loop[13].celCount++; - _loop[13].cel = newCels; - // Duplicate cel 0 to cel 2 - memcpy(&_loop[13].cel[2], &_loop[13].cel[0], sizeof(CelInfo)); - // copy over our data (which is uncompressed bitmap data) - _loop[13].cel[2].rawBitmap = new byte[sizeof(ViewInject_LauraBow2_Dual)]; - memcpy(_loop[13].cel[2].rawBitmap, ViewInject_LauraBow2_Dual, sizeof(ViewInject_LauraBow2_Dual)); - } + if (_loop.size() >= 14 && + _loop[13].cel.size() == 2 && + _loop[13].cel[0].width == 46 && + _loop[13].cel[0].height == 11) { + + _loop[13].cel.resize(3); + // Duplicate cel 0 to cel 2 + _loop[13].cel[2] = _loop[13].cel[0]; + // use our data (which is uncompressed bitmap data) + _loop[13].cel[2].rawBitmap->allocateFromSpan(SciSpan<const byte>(ViewInject_LauraBow2_Dual, sizeof(ViewInject_LauraBow2_Dual))); } } break; @@ -393,25 +375,18 @@ void GfxView::initData(GuiResourceId resourceId) { // View 947, Loop 12, Cel 1 = "DUAL" (pressed) (<- our injected view) if ((g_sci->isCD()) && (resourceId == 947)) { // security checks - if (_loopCount == 12) { - if ((_loop[8].celCount == 2) && (_loop[8].cel[0].width == 50) && (_loop[8].cel[0].height == 15)) { - // add another loop - LoopInfo *newLoops = new LoopInfo[_loopCount + 1]; - memcpy(newLoops, _loop, sizeof(LoopInfo) * _loopCount); - delete[] _loop; - _loop = newLoops; - _loopCount++; - // copy loop 8 to loop 12 - memcpy(&_loop[12], &_loop[8], sizeof(LoopInfo)); - _loop[12].cel = new CelInfo[2]; - // duplicate all cels of loop 8 and into loop 12 - memcpy(_loop[12].cel, _loop[8].cel, sizeof(CelInfo) * _loop[8].celCount); - // copy over our data (which is uncompressed bitmap data) - _loop[12].cel[0].rawBitmap = new byte[sizeof(ViewInject_KingsQuest6_Dual1)]; - memcpy(_loop[12].cel[0].rawBitmap, ViewInject_KingsQuest6_Dual1, sizeof(ViewInject_KingsQuest6_Dual1)); - _loop[12].cel[1].rawBitmap = new byte[sizeof(ViewInject_KingsQuest6_Dual2)]; - memcpy(_loop[12].cel[1].rawBitmap, ViewInject_KingsQuest6_Dual2, sizeof(ViewInject_KingsQuest6_Dual2)); - } + if (_loop.size() == 12 && + _loop[8].cel.size() == 2 && + _loop[8].cel[0].width == 50 && + _loop[8].cel[0].height == 15) { + + // add another loop + _loop.resize(_loop.size() + 1); + // copy loop 8 to loop 12 + _loop[12] = _loop[8]; + // use our data (which is uncompressed bitmap data) + _loop[12].cel[0].rawBitmap->allocateFromSpan(SciSpan<const byte>(ViewInject_KingsQuest6_Dual1, sizeof(ViewInject_KingsQuest6_Dual1))); + _loop[12].cel[1].rawBitmap->allocateFromSpan(SciSpan<const byte>(ViewInject_KingsQuest6_Dual2, sizeof(ViewInject_KingsQuest6_Dual2))); } } break; @@ -491,16 +466,19 @@ void GfxView::getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int1 outRect.top = outRect.bottom - scaledHeight; } -void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCount, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData) { - byte *outPtr = celBitmap; +void unpackCelData(const SciSpan<const byte> &inBuffer, SciSpan<byte> &celBitmap, byte clearColor, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData) { + const int pixelCount = celBitmap.size(); + byte *outPtr = celBitmap.getUnsafeDataAt(0); byte curByte, runLength; - byte *rlePtr = inBuffer + rlePos; + // TODO: Calculate correct maximum dimensions + const byte *rlePtr = inBuffer.getUnsafeDataAt(rlePos); // The existence of a literal position pointer signifies data with two // separate streams, most likely a SCI1.1 view - byte *literalPtr = inBuffer + literalPos; + const byte *literalPtr = inBuffer.getUnsafeDataAt(literalPos, inBuffer.size() - literalPos); + const byte *const endOfResource = inBuffer.getUnsafeDataAt(inBuffer.size(), 0); int pixelNr = 0; - memset(celBitmap, clearColor, pixelCount); + memset(celBitmap.getUnsafeDataAt(0), clearColor, celBitmap.size()); // View unpacking: // @@ -545,14 +523,17 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo uint32 pixelLine = pixelNr; if (hasByteLengths) { + assert (rlePtr + 2 <= endOfResource); pixelNr += *rlePtr++; runLength = *rlePtr++; } else { + assert (rlePtr + 4 <= endOfResource); pixelNr += READ_BE_UINT16(rlePtr); runLength = READ_BE_UINT16(rlePtr + 2); rlePtr += 4; } + assert(literalPtr + MIN<int>(runLength, pixelCount - pixelNr) <= endOfResource); while (runLength-- && pixelNr < pixelCount) outPtr[pixelNr++] = *literalPtr++; @@ -566,7 +547,7 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo while (pixelNr < pixelCount) { curByte = *rlePtr++; runLength = curByte >> 4; - memset(outPtr + pixelNr, curByte & 0x0F, MIN<uint16>(runLength, pixelCount - pixelNr)); + memset(outPtr + pixelNr, curByte & 0x0F, MIN<uint16>(runLength, pixelCount - pixelNr)); pixelNr += runLength; } break; @@ -576,7 +557,7 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo if (curByte & 0x07) { // fill with color runLength = curByte & 0x07; curByte = curByte >> 3; - memset(outPtr + pixelNr, curByte, MIN<uint16>(runLength, pixelCount - pixelNr)); + memset(outPtr + pixelNr, curByte, MIN<uint16>(runLength, pixelCount - pixelNr)); } else { // skip the next pixels (transparency) runLength = curByte >> 3; } @@ -589,7 +570,7 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo if (curByte & 0xC0) { // fill with color runLength = curByte >> 6; curByte = curByte & 0x3F; - memset(outPtr + pixelNr, curByte, MIN<uint16>(runLength, pixelCount - pixelNr)); + memset(outPtr + pixelNr, curByte, MIN<uint16>(runLength, pixelCount - pixelNr)); } else { // skip the next pixels (transparency) runLength = curByte & 0x3F; } @@ -638,12 +619,12 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo } } -void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount) { +void GfxView::unpackCel(int16 loopNo, int16 celNo, SciSpan<byte> &outPtr) { const CelInfo *celInfo = getCelInfo(loopNo, celNo); if (celInfo->offsetEGA) { // decompression for EGA views - unpackCelData(_resourceData, outPtr, 0, pixelCount, celInfo->offsetEGA, 0, _resMan->getViewType(), celInfo->width, false); + unpackCelData(*_resource, outPtr, 0, celInfo->offsetEGA, 0, _resMan->getViewType(), celInfo->width, false); } else { // We fill the buffer with transparent pixels, so that we can later skip // over pixels to automatically have them transparent @@ -667,11 +648,11 @@ void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCou } bool isMacSci11ViewData = g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() == SCI_VERSION_1_1; - unpackCelData(_resourceData, outPtr, clearColor, pixelCount, celInfo->offsetRLE, celInfo->offsetLiteral, _resMan->getViewType(), celInfo->width, isMacSci11ViewData); + unpackCelData(*_resource, outPtr, clearColor, celInfo->offsetRLE, celInfo->offsetLiteral, _resMan->getViewType(), celInfo->width, isMacSci11ViewData); // Swap 0 and 0xff pixels for Mac SCI1.1+ games (see above) if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) { - for (uint32 i = 0; i < pixelCount; i++) { + for (uint32 i = 0; i < outPtr.size(); i++) { if (outPtr[i] == 0) outPtr[i] = 0xff; else if (outPtr[i] == 0xff) @@ -681,39 +662,44 @@ void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCou } } -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) - return _loop[loopNo].cel[celNo].rawBitmap; +const SciSpan<const byte> &GfxView::getBitmap(int16 loopNo, int16 celNo) { + loopNo = CLIP<int16>(loopNo, 0, _loop.size() - 1); + celNo = CLIP<int16>(celNo, 0, _loop[loopNo].cel.size() - 1); - uint16 width = _loop[loopNo].cel[celNo].width; - uint16 height = _loop[loopNo].cel[celNo].height; - // allocating memory to store cel's bitmap - int pixelCount = width * height; - _loop[loopNo].cel[celNo].rawBitmap = new byte[pixelCount]; - byte *pBitmap = _loop[loopNo].cel[celNo].rawBitmap; + CelInfo &cel = _loop[loopNo].cel[celNo]; + + if (cel.rawBitmap) + return *cel.rawBitmap; + + const uint16 width = cel.width; + const uint16 height = cel.height; + const uint pixelCount = width * height; + const Common::String sourceName = Common::String::format("%s loop %d cel %d", _resource->name().c_str(), loopNo, celNo); + + SciSpan<byte> outBitmap = cel.rawBitmap->allocate(pixelCount, sourceName); // unpack the actual cel bitmap data - unpackCel(loopNo, celNo, pBitmap, pixelCount); + unpackCel(loopNo, celNo, outBitmap); if (_resMan->getViewType() == kViewEga) - unditherBitmap(pBitmap, width, height, _loop[loopNo].cel[celNo].clearKey); + unditherBitmap(outBitmap, width, height, _loop[loopNo].cel[celNo].clearKey); // mirroring the cel if needed if (_loop[loopNo].mirrorFlag) { + byte *pBitmap = outBitmap.getUnsafeDataAt(0, width * height); for (int i = 0; i < height; i++, pBitmap += width) for (int j = 0; j < width / 2; j++) SWAP(pBitmap[j], pBitmap[width - j - 1]); } - return _loop[loopNo].cel[celNo].rawBitmap; + + return *cel.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. */ -void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte clearKey) { +void GfxView::unditherBitmap(SciSpan<byte> &bitmapPtr, int16 width, int16 height, byte clearKey) { int16 *ditheredPicColors = _screen->unditherGetDitheredBgColors(); // It makes no sense to go further, if there isn't any dithered color data @@ -731,7 +717,6 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl // Walk through the bitmap and remember all combinations of colors int16 ditheredBitmapColors[DITHERED_BG_COLORS_SIZE]; - byte *curPtr; byte color1, color2; byte nextColor1, nextColor2; int16 y, x; @@ -742,8 +727,8 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl // pixels are adjacent and check pixels in the following line as well to // be the reverse pixel combination int16 checkHeight = height - 1; - curPtr = bitmapPtr; - byte *nextPtr = curPtr + width; + byte *curPtr = bitmapPtr.getUnsafeDataAt(0, checkHeight * width); + const byte *nextPtr = bitmapPtr.getUnsafeDataAt(width, checkHeight * width); for (y = 0; y < checkHeight; y++) { color1 = curPtr[0]; color2 = (curPtr[1] << 4) | curPtr[2]; nextColor1 = nextPtr[0] << 4; nextColor2 = (nextPtr[2] << 4) | nextPtr[1]; @@ -783,9 +768,9 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl return; // We now need to replace color-combinations - curPtr = bitmapPtr; + curPtr = bitmapPtr.getUnsafeDataAt(0, height * width); for (y = 0; y < height; y++) { - color = *curPtr; + color = curPtr[0]; for (x = 1; x < width; x++) { color = (color << 4) | curPtr[1]; if (unditherTable[color]) { @@ -806,12 +791,11 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const 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 SciSpan<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 > 15 ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY; - int x, y; if (_embeddedPal) // Merge view palette in... @@ -820,12 +804,16 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const 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 (!width || !height) { + return; + } + + const byte *bitmapData = bitmap.getUnsafeDataAt((clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left), celWidth * (height - 1) + width); if (!_EGAmapping) { - for (y = 0; y < height; y++, bitmap += celWidth) { - for (x = 0; x < width; x++) { - const byte color = bitmap[x]; + for (int y = 0; y < height; y++, bitmapData += celWidth) { + for (int x = 0; x < width; x++) { + const byte color = bitmapData[x]; if (color != clearKey) { const int x2 = clipRectTranslated.left + x; const int y2 = clipRectTranslated.top + y; @@ -850,10 +838,10 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const } } } else { - byte *EGAmapping = _EGAmapping + (EGAmappingNr * SCI_VIEW_EGAMAPPING_SIZE); - for (y = 0; y < height; y++, bitmap += celWidth) { - for (x = 0; x < width; x++) { - const byte color = EGAmapping[bitmap[x]]; + const SciSpan<const byte> EGAmapping = _EGAmapping.subspan(EGAmappingNr * SCI_VIEW_EGAMAPPING_SIZE, SCI_VIEW_EGAMAPPING_SIZE); + for (int y = 0; y < height; y++, bitmapData += celWidth) { + for (int x = 0; x < width; x++) { + const byte color = EGAmapping[bitmapData[x]]; const int x2 = clipRectTranslated.left + x; const int y2 = clipRectTranslated.top + y; if (color != clearKey && priority >= _screen->getPriority(x2, y2)) @@ -872,7 +860,7 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect, 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 SciSpan<const byte> &bitmap = getBitmap(loopNo, celNo); const int16 celHeight = celInfo->height; const int16 celWidth = celInfo->width; const byte clearKey = celInfo->clearKey; @@ -933,15 +921,17 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect, const int16 offsetY = clipRect.top - rect.top; const int16 offsetX = clipRect.left - rect.left; + // TODO: Remove? This class is not for SCI32 // Happens in SQ6, first room if (offsetX < 0 || offsetY < 0) return; assert(scaledHeight + offsetY <= ARRAYSIZE(scalingY)); assert(scaledWidth + offsetX <= ARRAYSIZE(scalingX)); + const byte *bitmapData = bitmap.getUnsafeDataAt(0, celWidth * celHeight); 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 byte color = bitmapData[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)) { diff --git a/engines/sci/graphics/view.h b/engines/sci/graphics/view.h index 5e422468b5..808e203682 100644 --- a/engines/sci/graphics/view.h +++ b/engines/sci/graphics/view.h @@ -23,6 +23,8 @@ #ifndef SCI_GRAPHICS_VIEW_H #define SCI_GRAPHICS_VIEW_H +#include "sci/util.h" + namespace Sci { enum Sci32ViewNativeResolution { @@ -41,17 +43,19 @@ struct CelInfo { uint16 offsetEGA; uint32 offsetRLE; uint32 offsetLiteral; - byte *rawBitmap; + Common::SpanOwner<SciSpan<const byte> > rawBitmap; }; struct LoopInfo { bool mirrorFlag; uint16 celCount; - CelInfo *cel; + Common::Array<CelInfo> cel; }; -#define SCI_VIEW_EGAMAPPING_SIZE 16 -#define SCI_VIEW_EGAMAPPING_COUNT 8 +enum { + SCI_VIEW_EGAMAPPING_SIZE = 16, + SCI_VIEW_EGAMAPPING_COUNT = 8 +}; class GfxScreen; class GfxPalette; @@ -73,7 +77,7 @@ public: void getCelRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const; void getCelSpecialHoyle4Rect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const; void getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, int16 scaleX, int16 scaleY, Common::Rect &outRect) const; - const byte *getBitmap(int16 loopNo, int16 celNo); + const SciSpan<const byte> &getBitmap(int16 loopNo, int16 celNo); void draw(const Common::Rect &rect, const Common::Rect &clipRect, const Common::Rect &clipRectTranslated, int16 loopNo, int16 celNo, byte priority, uint16 EGAmappingNr, bool upscaledHires); void drawScaled(const Common::Rect &rect, const Common::Rect &clipRect, const Common::Rect &clipRectTranslated, int16 loopNo, int16 celNo, byte priority, int16 scaleX, int16 scaleY); uint16 getLoopCount() const { return _loopCount; } @@ -88,8 +92,8 @@ public: private: void initData(GuiResourceId resourceId); - void unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount); - void unditherBitmap(byte *bitmap, int16 width, int16 height, byte clearKey); + void unpackCel(int16 loopNo, int16 celNo, SciSpan<byte> &outPtr); + void unditherBitmap(SciSpan<byte> &bitmap, int16 width, int16 height, byte clearKey); ResourceManager *_resMan; GfxCoordAdjuster16 *_coordAdjuster; @@ -98,18 +102,16 @@ private: GuiResourceId _resourceId; Resource *_resource; - byte *_resourceData; - int _resourceSize; uint16 _loopCount; - LoopInfo *_loop; + Common::Array<LoopInfo> _loop; bool _embeddedPal; Palette _viewPalette; // specifies scaling resolution for SCI2 views (see gk1/windows, Wolfgang in room 720) Sci32ViewNativeResolution _sci2ScaleRes; - byte *_EGAmapping; + SciSpan<const byte> _EGAmapping; // this is set for sci0early to adjust for the getCelRect() change int16 _adjustForSci0Early; |