aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/graphics')
-rw-r--r--engines/sci/graphics/animate.cpp2
-rw-r--r--engines/sci/graphics/celobj32.cpp164
-rw-r--r--engines/sci/graphics/celobj32.h11
-rw-r--r--engines/sci/graphics/compare.cpp2
-rw-r--r--engines/sci/graphics/cursor.cpp63
-rw-r--r--engines/sci/graphics/cursor.h12
-rw-r--r--engines/sci/graphics/cursor32.cpp2
-rw-r--r--engines/sci/graphics/font.cpp50
-rw-r--r--engines/sci/graphics/font.h15
-rw-r--r--engines/sci/graphics/maciconbar.cpp4
-rw-r--r--engines/sci/graphics/palette.cpp30
-rw-r--r--engines/sci/graphics/palette.h5
-rw-r--r--engines/sci/graphics/palette32.cpp30
-rw-r--r--engines/sci/graphics/palette32.h8
-rw-r--r--engines/sci/graphics/picture.cpp226
-rw-r--r--engines/sci/graphics/picture.h26
-rw-r--r--engines/sci/graphics/portrait.cpp118
-rw-r--r--engines/sci/graphics/portrait.h19
-rw-r--r--engines/sci/graphics/ports.cpp12
-rw-r--r--engines/sci/graphics/ports.h4
-rw-r--r--engines/sci/graphics/screen.cpp37
-rw-r--r--engines/sci/graphics/screen.h13
-rw-r--r--engines/sci/graphics/screen_item32.cpp10
-rw-r--r--engines/sci/graphics/view.cpp268
-rw-r--r--engines/sci/graphics/view.h24
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;