aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics/celobj32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/graphics/celobj32.cpp')
-rw-r--r--engines/sci/graphics/celobj32.cpp164
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