diff options
Diffstat (limited to 'engines/sci/graphics/celobj32.cpp')
-rw-r--r-- | engines/sci/graphics/celobj32.cpp | 164 |
1 files changed, 96 insertions, 68 deletions
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 |