[Scummvm-cvs-logs] scummvm master -> d5d42d5066df7eb4c11bf703506aea54af18ec93
csnover
csnover at users.noreply.github.com
Mon Aug 1 17:41:43 CEST 2016
This automated email contains information about 8 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
4a637d65c3 SCI32: Enable optional explicit memory management of hunk entries
156c68fe58 SCI32: Implement plane transitions (kSetShowStyle and kSetScroll)
0f535e79f5 SCI32: Add 6-argument signature of kAddPicAt
4e31c9aaf4 SCI32: Don't crash on zero-dimension show rects
2071196f42 SCI32: Add bitmap segment and remove GC option from hunk segment
10f9cb7023 SCI32: Fix crash when destroying GfxTransitions32
6d1f8e8c87 SCI32: Fix invalid memory access after BitmapTable is extended
d5d42d5066 SCI32: Implement bitmap save routine
Commit: 4a637d65c36d7dad3a4d4ec75c243e12bb3b5449
https://github.com/scummvm/scummvm/commit/4a637d65c36d7dad3a4d4ec75c243e12bb3b5449
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-01T10:37:14-05:00
Commit Message:
SCI32: Enable optional explicit memory management of hunk entries
Bitmaps in ScrollWindow and Robot code are managed by the kernel
and not by game scripts, although they must be able to be
referenced through a reg_t. To prevent incorrect GC of bitmaps
that are in use but not referenced by any game script, explicit
memory management of hunk entries can be enabled.
Changed paths:
engines/sci/console.cpp
engines/sci/engine/gc.cpp
engines/sci/engine/kgraphics32.cpp
engines/sci/engine/kscripts.cpp
engines/sci/engine/seg_manager.cpp
engines/sci/engine/seg_manager.h
engines/sci/engine/segment.h
engines/sci/graphics/controls32.cpp
engines/sci/graphics/controls32.h
engines/sci/graphics/paint16.cpp
engines/sci/graphics/paint32.cpp
engines/sci/graphics/palette.cpp
engines/sci/graphics/text32.cpp
engines/sci/graphics/text32.h
engines/sci/graphics/video32.cpp
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 6898745..6acb467 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -1984,7 +1984,7 @@ bool Console::cmdShowSavedBits(int argc, const char **argv) {
byte bakMask = GFX_SCREEN_MASK_VISUAL | GFX_SCREEN_MASK_PRIORITY | GFX_SCREEN_MASK_CONTROL;
int bakSize = _engine->_gfxScreen->bitsGetDataSize(rect, bakMask);
- reg_t bakScreen = segman->allocateHunkEntry("show_saved_bits backup", bakSize);
+ reg_t bakScreen = segman->allocateHunkEntry("show_saved_bits backup", bakSize, true);
byte* bakMemory = segman->getHunkPointer(bakScreen);
assert(bakMemory);
_engine->_gfxScreen->bitsSave(rect, bakMask, bakMemory);
diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp
index b229490..e0467e9 100644
--- a/engines/sci/engine/gc.cpp
+++ b/engines/sci/engine/gc.cpp
@@ -143,23 +143,30 @@ AddrSet *findAllActiveReferences(EngineState *s) {
const Common::Array<SegmentObj *> &heap = s->_segMan->getSegments();
uint heapSize = heap.size();
- // Init: Explicitly loaded scripts
for (uint i = 1; i < heapSize; i++) {
- if (heap[i] && heap[i]->getType() == SEG_TYPE_SCRIPT) {
- Script *script = (Script *)heap[i];
+ if (heap[i]) {
+ // Init: Explicitly loaded scripts
+ if (heap[i]->getType() == SEG_TYPE_SCRIPT) {
+ Script *script = (Script *)heap[i];
- if (script->getLockers()) { // Explicitly loaded?
- wm.pushArray(script->listObjectReferences());
+ if (script->getLockers()) { // Explicitly loaded?
+ wm.pushArray(script->listObjectReferences());
+ }
+ }
+
+ // Init: Explicitly opted-out hunks
+ else if (heap[i]->getType() == SEG_TYPE_HUNK) {
+ HunkTable *ht = static_cast<HunkTable *>(heap[i]);
+
+ for (uint j = 0; j < ht->_table.size(); j++) {
+ if (!ht->_table[j].data.gc) {
+ wm.push(make_reg(i, j));
+ }
+ }
}
}
}
-#ifdef ENABLE_SCI32
- // Init: ScrollWindows
- if (g_sci->_gfxControls32)
- wm.pushArray(g_sci->_gfxControls32->listObjectReferences());
-#endif
-
debugC(kDebugLevelGC, "[GC] -- Finished explicitly loaded scripts, done with root set");
processWorkList(s->_segMan, wm, heap);
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 9cfe532..b8682b3 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -195,14 +195,14 @@ reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
if (subop == 0) {
TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode));
- return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, true);
+ return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, true, true);
} else {
CelInfo32 celInfo;
celInfo.type = kCelTypeView;
celInfo.resourceId = readSelectorValue(segMan, object, SELECTOR(view));
celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel));
- return g_sci->_gfxText32->createFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed);
+ return g_sci->_gfxText32->createFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed, true);
}
}
@@ -534,7 +534,7 @@ reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) {
int16 scaledHeight = argc > 5 ? argv[5].toSint16() : g_sci->_gfxText32->_scaledHeight;
bool useRemap = argc > 6 ? argv[6].toSint16() : false;
- BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap);
+ BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap, true);
memset(bitmap.getPixels(), backColor, width * height);
return bitmap.getObject();
}
@@ -604,7 +604,7 @@ reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
// Then clips. But this seems stupid.
textRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight()));
- reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false);
+ reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false, false);
CelObjMem textCel(textBitmapObject);
textCel.draw(bitmap.getBuffer(), textRect, Common::Point(textRect.left, textRect.top), false);
s->_segMan->freeHunkEntry(textBitmapObject);
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 6fd130b..42e7a20 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -40,7 +40,7 @@ reg_t kLoad(EngineState *s, int argc, reg_t *argv) {
// Request to dynamically allocate hunk memory for later use
if (restype == kResourceTypeMemory)
- return s->_segMan->allocateHunkEntry("kLoad()", resnr);
+ return s->_segMan->allocateHunkEntry("kLoad()", resnr, true);
return make_reg(0, ((restype << 11) | resnr)); // Return the resource identifier as handle
}
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 95e3cd1..e669206 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -393,7 +393,7 @@ void SegManager::freeHunkEntry(reg_t addr) {
ht->freeEntryContents(addr.getOffset());
}
-reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size) {
+reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size, bool gc) {
HunkTable *table;
int offset;
@@ -412,6 +412,7 @@ reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size) {
h->mem = malloc(size);
h->size = size;
h->type = hunk_type;
+ h->gc = gc;
return addr;
}
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index 9da7e58..ba2ba33 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -225,9 +225,11 @@ public:
* @param[in] size Number of bytes to allocate for the hunk entry
* @param[in] hunk_type A descriptive string for the hunk entry, for
* debugging purposes
+ * @param[in] gc Whether to make the hunk eligible for garbage
+ * collection
* @return The offset of the freshly allocated hunk entry
*/
- reg_t allocateHunkEntry(const char *hunk_type, int size);
+ reg_t allocateHunkEntry(const char *hunk_type, int size, bool gc);
/**
* Deallocates a hunk entry
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 50c77d0..6c94c24 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -205,6 +205,7 @@ struct Hunk {
void *mem;
uint32 size;
const char *type;
+ bool gc;
};
template<typename T>
diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp
index f4e9d26..639a35c 100644
--- a/engines/sci/graphics/controls32.cpp
+++ b/engines/sci/graphics/controls32.cpp
@@ -54,18 +54,6 @@ GfxControls32::~GfxControls32() {
}
#pragma mark -
-#pragma mark Garbage collection
-
-Common::Array<reg_t> GfxControls32::listObjectReferences() {
- Common::Array<reg_t> ret;
- ScrollWindowMap::const_iterator it;
- for (it = _scrollWindows.begin(); it != _scrollWindows.end(); ++it)
- ret.push_back(it->_value->getBitmap());
-
- return ret;
-}
-
-#pragma mark -
#pragma mark Text input control
reg_t GfxControls32::kernelEditText(const reg_t controlObject) {
@@ -130,7 +118,7 @@ reg_t GfxControls32::kernelEditText(const reg_t controlObject) {
if (titleObject.isNull()) {
bool dimmed = readSelectorValue(_segMan, controlObject, SELECTOR(dimmed));
- editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true);
+ editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true, false);
} else {
error("Titled bitmaps are not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
}
@@ -383,6 +371,7 @@ void GfxControls32::flashCursor(TextEditor &editor) {
#pragma mark Scrollable window control
ScrollWindow::ScrollWindow(SegManager *segMan, const Common::Rect &gameRect, const Common::Point &position, const reg_t plane, const uint8 defaultForeColor, const uint8 defaultBackColor, const GuiResourceId defaultFontId, const TextAlign defaultAlignment, const int16 defaultBorderColor, const uint16 maxNumEntries) :
+ _segMan(segMan),
_gfxText32(segMan, g_sci->_gfxCache),
_maxNumEntries(maxNumEntries),
_firstVisibleChar(0),
@@ -424,13 +413,13 @@ ScrollWindow::ScrollWindow(SegManager *segMan, const Common::Rect &gameRect, con
}
assert(bitmapRect.width() > 0 && bitmapRect.height() > 0);
- _bitmap = _gfxText32.createFontBitmap(bitmapRect.width(), bitmapRect.height(), _textRect, "", _foreColor, _backColor, skipColor, _fontId, _alignment, _borderColor, false, false);
+ _bitmap = _gfxText32.createFontBitmap(bitmapRect.width(), bitmapRect.height(), _textRect, "", _foreColor, _backColor, skipColor, _fontId, _alignment, _borderColor, false, false, false);
debugC(1, kDebugLevelGraphics, "New ScrollWindow: textRect size: %d x %d, bitmap: %04x:%04x", _textRect.width(), _textRect.height(), PRINT_REG(_bitmap));
}
ScrollWindow::~ScrollWindow() {
- // _gfxText32._bitmap will get GCed once ScrollWindow is gone.
+ _segMan->freeHunkEntry(_bitmap);
// _screenItem will be deleted by GfxFrameout
}
diff --git a/engines/sci/graphics/controls32.h b/engines/sci/graphics/controls32.h
index 460b0b5..680c70d 100644
--- a/engines/sci/graphics/controls32.h
+++ b/engines/sci/graphics/controls32.h
@@ -227,6 +227,8 @@ public:
const reg_t getBitmap() const { return _bitmap; }
private:
+ SegManager *_segMan;
+
typedef Common::Array<ScrollWindowEntry> EntriesList;
/**
@@ -418,11 +420,6 @@ private:
GfxText32 *_gfxText32;
#pragma mark -
-#pragma mark Garbage collection
-public:
- Common::Array<reg_t> listObjectReferences();
-
-#pragma mark -
#pragma mark Text input control
public:
reg_t kernelEditText(const reg_t controlObject);
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index 6004e9c..4517659 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -334,7 +334,7 @@ reg_t GfxPaint16::bitsSave(const Common::Rect &rect, byte screenMask) {
// now actually ask _screen how much space it will need for saving
size = _screen->bitsGetDataSize(workerRect, screenMask);
- memoryId = _segMan->allocateHunkEntry("SaveBits()", size);
+ memoryId = _segMan->allocateHunkEntry("SaveBits()", size, true);
memoryPtr = _segMan->getHunkPointer(memoryId);
if (memoryPtr)
_screen->bitsSave(workerRect, screenMask, memoryPtr);
diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp
index 7773b9f..8a9d9b9 100644
--- a/engines/sci/graphics/paint32.cpp
+++ b/engines/sci/graphics/paint32.cpp
@@ -128,7 +128,7 @@ BitmapResource GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const
outRect.right = (startPoint.x > endPoint.x ? startPoint.x : endPoint.x) + halfThickness + 1;
outRect.bottom = (startPoint.y > endPoint.y ? startPoint.y : endPoint.y) + halfThickness + 1;
- BitmapResource bitmap(_segMan, outRect.width(), outRect.height(), skipColor, 0, 0, g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, 0, false);
+ BitmapResource bitmap(_segMan, outRect.width(), outRect.height(), skipColor, 0, 0, g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, 0, false, true);
byte *pixels = bitmap.getPixels();
memset(pixels, skipColor, bitmap.getWidth() * bitmap.getHeight());
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 1514ad8..a26c92c 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -626,7 +626,7 @@ void GfxPalette::kernelAnimateSet() {
reg_t GfxPalette::kernelSave() {
SegManager *segMan = g_sci->getEngineState()->_segMan;
- reg_t memoryId = segMan->allocateHunkEntry("kPalette(save)", 1024);
+ reg_t memoryId = segMan->allocateHunkEntry("kPalette(save)", 1024, true);
byte *memoryPtr = segMan->getHunkPointer(memoryId);
if (memoryPtr) {
for (int colorNr = 0; colorNr < 256; colorNr++) {
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index 277e6e9..d612ddb 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -59,7 +59,7 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) :
}
}
-reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling) {
+reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling, const bool gc) {
_borderColor = borderColor;
_text = text;
@@ -96,7 +96,7 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
_textRect = Common::Rect();
}
- BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false);
+ BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
_bitmap = bitmap.getObject();
erase(bitmapRect, false);
@@ -109,7 +109,7 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
return _bitmap;
}
-reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed) {
+reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed, const bool gc) {
_borderColor = borderColor;
_text = text;
_textRect = rect;
@@ -135,7 +135,7 @@ reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &
_textRect = Common::Rect();
}
- BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false);
+ BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
_bitmap = bitmap.getObject();
// NOTE: The engine filled the bitmap pixels with 11 here, which is silly
diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h
index f57433f..4092156 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -117,8 +117,8 @@ public:
* Allocates and initialises a new bitmap in the given
* segment manager.
*/
- inline BitmapResource(SegManager *segMan, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool remap) {
- _object = segMan->allocateHunkEntry("Bitmap()", getBitmapSize(width, height));
+ inline BitmapResource(SegManager *segMan, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 paletteSize, const bool remap, const bool gc) {
+ _object = segMan->allocateHunkEntry("Bitmap()", getBitmapSize(width, height) + paletteSize, gc);
_bitmap = segMan->getHunkPointer(_object);
const uint16 bitmapHeaderSize = getBitmapHeaderSize();
@@ -132,7 +132,7 @@ public:
setRemap(remap);
setDataSize(width * height);
WRITE_SCI11ENDIAN_UINT32(_bitmap + 16, 0);
- setHunkPaletteOffset(hunkPaletteOffset);
+ setHunkPaletteOffset(paletteSize > 0 ? (width * height) : 0);
setDataOffset(bitmapHeaderSize);
setUncompressedDataOffset(bitmapHeaderSize);
setControlOffset(0);
@@ -394,12 +394,12 @@ public:
* Creates a plain font bitmap with a flat color
* background.
*/
- reg_t createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, TextAlign alignment, const int16 borderColor, bool dimmed, const bool doScaling);
+ reg_t createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, TextAlign alignment, const int16 borderColor, bool dimmed, const bool doScaling, const bool gc);
/**
* Creates a font bitmap with a view background.
*/
- reg_t createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed);
+ reg_t createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed, const bool gc);
inline int scaleUpWidth(int value) const {
const int scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index dd841f5..4660706 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -117,6 +117,7 @@ VMDPlayer::IOStatus VMDPlayer::close() {
if (!_planeIsOwned && _screenItem != nullptr) {
g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
+ g_sci->getEngineState()->_segMan->freeHunkEntry(_screenItem->_celInfo.bitmap);
_screenItem = nullptr;
} else if (_plane != nullptr) {
g_sci->_gfxFrameout->deletePlane(*_plane);
@@ -231,7 +232,7 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
- BitmapResource vmdBitmap(_segMan, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false);
+ BitmapResource vmdBitmap(_segMan, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false, false);
if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
Commit: 156c68fe58eb9f8d923d1f9dc1c3dac8436c9d82
https://github.com/scummvm/scummvm/commit/156c68fe58eb9f8d923d1f9dc1c3dac8436c9d82
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-01T10:37:14-05:00
Commit Message:
SCI32: Implement plane transitions (kSetShowStyle and kSetScroll)
This commit implements all of the known plane transitions from
SCI2 through SCI2.1mid games. Because kSetShowStyle is always
called indirectly via the Styler game script, it is difficult to
find all the places where transitions are used. As such,
transitions that appeared to never be used have been added as
stubs which will trigger a game crash with a message to report
what was being done, so any missed transition types can be
identified quickly and then implemented.
Changed paths:
A engines/sci/graphics/transitions32.cpp
A engines/sci/graphics/transitions32.h
engines/sci/engine/kernel_tables.h
engines/sci/engine/kgraphics32.cpp
engines/sci/graphics/frameout.cpp
engines/sci/graphics/frameout.h
engines/sci/graphics/plane32.cpp
engines/sci/graphics/plane32.h
engines/sci/module.mk
engines/sci/sci.cpp
engines/sci/sci.h
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 8a1176e..7d622d1 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -772,7 +772,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(EditText), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(MakeSaveCatName), SIG_EVERYWHERE, "rr", NULL, NULL },
{ MAP_CALL(MakeSaveFileName), SIG_EVERYWHERE, "rri", NULL, NULL },
- { MAP_CALL(SetScroll), SIG_EVERYWHERE, "oiiiii(i)", NULL, NULL },
+ { MAP_CALL(SetScroll), SIG_EVERYWHERE, "oiiii(i)(i)", NULL, NULL },
{ MAP_CALL(PalCycle), SIG_EVERYWHERE, "(.*)", kPalCycle_subops, NULL },
// SCI2 Empty functions
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index b8682b3..40c048b 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -56,6 +56,7 @@
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/text32.h"
+#include "sci/graphics/transitions32.h"
#endif
namespace Sci {
@@ -139,7 +140,7 @@ reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) {
}
reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv) {
- g_sci->_gfxFrameout->kernelSetPalStyleRange(argv[0].toUint16(), argv[1].toUint16());
+ g_sci->_gfxTransitions32->kernelSetPalStyleRange(argv[0].toUint16(), argv[1].toUint16());
return s->r_acc;
}
@@ -310,7 +311,7 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
// NOTE: The order of planeObj and showStyle are reversed
// because this is how SCI3 called the corresponding method
// on the KernelMgr
- g_sci->_gfxFrameout->kernelSetShowStyle(argc, planeObj, type, seconds, back, priority, animate, refFrame, pFadeArray, divisions, blackScreen);
+ g_sci->_gfxTransitions32->kernelSetShowStyle(argc, planeObj, type, seconds, back, priority, animate, refFrame, pFadeArray, divisions, blackScreen);
return s->r_acc;
}
@@ -760,28 +761,19 @@ reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
+// Used by LSL6hires intro (room 110)
reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
- // Called in the intro of LSL6 hires (room 110)
- // The end effect of this is the same as the old screen scroll transition
-
- // 7 parameters
- reg_t planeObject = argv[0];
- //int16 x = argv[1].toSint16();
- //int16 y = argv[2].toSint16();
- uint16 pictureId = argv[3].toUint16();
- // param 4: int (0 in LSL6, probably scroll direction? The picture in LSL6 scrolls down)
- // param 5: int (first call is 1, then the subsequent one is 0 in LSL6)
- // param 6: optional int (0 in LSL6)
-
- // Set the new picture directly for now
- //writeSelectorValue(s->_segMan, planeObject, SELECTOR(left), x);
- //writeSelectorValue(s->_segMan, planeObject, SELECTOR(top), y);
- writeSelectorValue(s->_segMan, planeObject, SELECTOR(picture), pictureId);
- // and update our draw list
- g_sci->_gfxFrameout->kernelUpdatePlane(planeObject);
-
- // TODO
- return kStub(s, argc, argv);
+ const reg_t plane = argv[0];
+ const int16 deltaX = argv[1].toSint16();
+ const int16 deltaY = argv[2].toSint16();
+ const GuiResourceId pictureId = argv[3].toUint16();
+ const bool animate = argv[4].toUint16();
+ // NOTE: speed was accepted as an argument, but then never actually used
+ // const int16 speed = argc > 5 ? (bool)argv[5].toSint16() : -1;
+ const bool mirrorX = argc > 6 ? (bool)argv[6].toUint16() : false;
+
+ g_sci->_gfxTransitions32->kernelSetScroll(plane, deltaX, deltaY, pictureId, animate, mirrorX);
+ return s->r_acc;
}
// Used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270)
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index b5b3206..a264516 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -51,31 +51,19 @@
#include "sci/graphics/text32.h"
#include "sci/graphics/frameout.h"
#include "sci/video/robot_decoder.h"
+#include "sci/graphics/transitions32.h"
namespace Sci {
-static int dissolveSequences[2][20] = {
- /* SCI2.1early- */ { 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080 },
- /* SCI2.1mid+ */ { 0, 0, 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080, 73728, 132096, 466944 }
-};
-static int16 divisionsDefaults[2][16] = {
- /* SCI2.1early- */ { 1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 40, 40, 101, 101 },
- /* SCI2.1mid+ */ { 1, 20, 20, 20, 20, 10, 10, 10, 10, 20, 20, 6, 10, 101, 101, 2 }
-};
-static int16 unknownCDefaults[2][16] = {
- /* SCI2.1early- */ { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 0, 0, 0, 0 },
- /* SCI2.1mid+ */ { 0, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 0, 0, 7, 7, 0 }
-};
-
-GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette) :
+GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette, GfxTransitions32 *transitions) :
_isHiRes(false),
_palette(palette),
_resMan(resMan),
_screen(screen),
_segMan(segMan),
+ _transitions(transitions),
_benchmarkingFinished(false),
_throttleFrameOut(true),
- _showStyles(nullptr),
_throttleState(0),
// TODO: Stop using _gfxScreen
_currentBuffer(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr),
@@ -87,14 +75,6 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
_currentBuffer.setPixels(calloc(1, screen->getDisplayWidth() * screen->getDisplayHeight()));
- for (int i = 0; i < 236; i += 2) {
- _styleRanges[i] = 0;
- _styleRanges[i + 1] = -1;
- }
- for (int i = 236; i < ARRAYSIZE(_styleRanges); ++i) {
- _styleRanges[i] = 0;
- }
-
// TODO: Make hires detection work uniformly across all SCI engine
// versions (this flag is normally passed by SCI::MakeGraphicsMgr
// to the GraphicsMgr constructor depending upon video configuration,
@@ -104,16 +84,6 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
_isHiRes = true;
}
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- _dissolveSequenceSeeds = dissolveSequences[0];
- _defaultDivisions = divisionsDefaults[0];
- _defaultUnknownC = unknownCDefaults[0];
- } else {
- _dissolveSequenceSeeds = dissolveSequences[1];
- _defaultDivisions = divisionsDefaults[1];
- _defaultUnknownC = unknownCDefaults[1];
- }
-
switch (g_sci->getGameId()) {
case GID_HOYLE5:
case GID_GK2:
@@ -587,6 +557,115 @@ void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &eraseR
// }
}
+void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, PlaneShowStyle *showStyle) {
+ Palette sourcePalette(_palette->getNextPalette());
+ alterVmap(sourcePalette, sourcePalette, -1, styleRanges);
+
+ int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
+
+ Common::Rect rect(_screen->getDisplayWidth(), _screen->getDisplayHeight());
+ _showList.add(rect);
+ showBits();
+
+ // NOTE: The original engine allocated these as static arrays of 100
+ // pointers to ScreenItemList / RectList
+ ScreenItemListList screenItemLists;
+ EraseListList eraseLists;
+
+ screenItemLists.resize(_planes.size());
+ eraseLists.resize(_planes.size());
+
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
+
+ calcLists(screenItemLists, eraseLists);
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ list->sort();
+ }
+
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
+ (*drawItem)->screenItem->getCelObj().submitPalette();
+ }
+ }
+
+ _remapOccurred = _palette->updateForFrame();
+ _frameNowVisible = false;
+
+ for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
+ drawEraseList(eraseLists[i], *_planes[i]);
+ drawScreenItemList(screenItemLists[i]);
+ }
+
+ Palette nextPalette(_palette->getNextPalette());
+
+ if (prevRoom < 1000) {
+ for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
+ if (styleRanges[i] == -1 || styleRanges[i] == 0) {
+ sourcePalette.colors[i] = nextPalette.colors[i];
+ sourcePalette.colors[i].used = true;
+ }
+ }
+ } else {
+ for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
+ if (styleRanges[i] == -1 || validZeroStyle(styleRanges[i], i)) {
+ sourcePalette.colors[i] = nextPalette.colors[i];
+ sourcePalette.colors[i].used = true;
+ }
+ }
+ }
+
+ _palette->submit(sourcePalette);
+ _palette->updateFFrame();
+ _palette->updateHardware();
+ alterVmap(nextPalette, sourcePalette, 1, _transitions->_styleRanges);
+
+ if (showStyle && showStyle->type != kShowStyleMorph) {
+ _transitions->processEffects(*showStyle);
+ } else {
+ showBits();
+ }
+
+ _frameNowVisible = true;
+
+ for (PlaneList::iterator plane = _planes.begin(); plane != _planes.end(); ++plane) {
+ (*plane)->_redrawAllCount = getScreenCount();
+ }
+
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
+
+ calcLists(screenItemLists, eraseLists);
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ list->sort();
+ }
+
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
+ (*drawItem)->screenItem->getCelObj().submitPalette();
+ }
+ }
+
+ _remapOccurred = _palette->updateForFrame();
+ // NOTE: During this second loop, `_frameNowVisible = false` is
+ // inside the next loop in SCI2.1mid
+ _frameNowVisible = false;
+
+ for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
+ drawEraseList(eraseLists[i], *_planes[i]);
+ drawScreenItemList(screenItemLists[i]);
+ }
+
+ _palette->submit(nextPalette);
+ _palette->updateFFrame();
+ _palette->updateHardware(false);
+ showBits();
+
+ _frameNowVisible = true;
+}
+
/**
* Determines the parts of `r` that aren't overlapped by `other`.
* Returns -1 if `r` and `other` have no intersection.
@@ -1038,118 +1117,6 @@ void GfxFrameout::mergeToShowList(const Common::Rect &drawRect, RectList &showLi
}
}
-void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle) {
- Palette sourcePalette(_palette->getNextPalette());
- alterVmap(sourcePalette, sourcePalette, -1, styleRanges);
-
- int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
-
- Common::Rect rect(_screen->getDisplayWidth(), _screen->getDisplayHeight());
- _showList.add(rect);
- showBits();
-
- // NOTE: The original engine allocated these as static arrays of 100
- // pointers to ScreenItemList / RectList
- ScreenItemListList screenItemLists;
- EraseListList eraseLists;
-
- screenItemLists.resize(_planes.size());
- eraseLists.resize(_planes.size());
-
- if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
- remapMarkRedraw();
- }
-
- calcLists(screenItemLists, eraseLists);
- for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
- list->sort();
- }
-
- for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
- for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
- (*drawItem)->screenItem->getCelObj().submitPalette();
- }
- }
-
- _remapOccurred = _palette->updateForFrame();
- _frameNowVisible = false;
-
- for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
- drawEraseList(eraseLists[i], *_planes[i]);
- drawScreenItemList(screenItemLists[i]);
- }
-
- Palette nextPalette(_palette->getNextPalette());
-
- if (prevRoom < 1000) {
- for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
- if (styleRanges[i] == -1 || styleRanges[i] == 0) {
- sourcePalette.colors[i] = nextPalette.colors[i];
- sourcePalette.colors[i].used = true;
- }
- }
- } else {
- for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
- // TODO: Limiting range 72 to 103 is NOT present in every game
- if (styleRanges[i] == -1 || (styleRanges[i] == 0 && i > 71 && i < 104)) {
- sourcePalette.colors[i] = nextPalette.colors[i];
- sourcePalette.colors[i].used = true;
- }
- }
- }
-
- _palette->submit(sourcePalette);
- _palette->updateFFrame();
- _palette->updateHardware();
- alterVmap(nextPalette, sourcePalette, 1, _styleRanges);
-
- if (showStyle && showStyle->type != kShowStyleUnknown) {
-// TODO: SCI2.1mid transition effects
-// processEffects();
- warning("Transition %d not implemented!", showStyle->type);
- } else {
- showBits();
- }
-
- _frameNowVisible = true;
-
- for (PlaneList::iterator plane = _planes.begin(); plane != _planes.end(); ++plane) {
- (*plane)->_redrawAllCount = getScreenCount();
- }
-
- if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
- remapMarkRedraw();
- }
-
- calcLists(screenItemLists, eraseLists);
- for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
- list->sort();
- }
-
- for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
- for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
- (*drawItem)->screenItem->getCelObj().submitPalette();
- }
- }
-
- _remapOccurred = _palette->updateForFrame();
- // NOTE: During this second loop, `_frameNowVisible = false` is
- // inside the next loop in SCI2.1mid
- _frameNowVisible = false;
-
- for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
- drawEraseList(eraseLists[i], *_planes[i]);
- drawScreenItemList(screenItemLists[i]);
- }
-
- _palette->submit(nextPalette);
- _palette->updateFFrame();
- _palette->updateHardware(false);
- showBits();
-
- _frameNowVisible = true;
-}
-
void GfxFrameout::showBits() {
for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) {
Common::Rect rounded(**rect);
@@ -1233,7 +1200,6 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
}
}
- // NOTE: This is currBuffer->ptr in SCI engine
byte *pixels = (byte *)_currentBuffer.getPixels();
for (int pixelIndex = 0, numPixels = _currentBuffer.screenWidth * _currentBuffer.screenHeight; pixelIndex < numPixels; ++pixelIndex) {
@@ -1256,348 +1222,16 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
}
}
-void GfxFrameout::kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor) {
- if (toColor > fromColor) {
- return;
- }
-
- for (int i = fromColor; i < toColor; ++i) {
- _styleRanges[i] = 0;
- }
-}
-
-inline ShowStyleEntry * GfxFrameout::findShowStyleForPlane(const reg_t planeObj) const {
- ShowStyleEntry *entry = _showStyles;
- while (entry != nullptr) {
- if (entry->plane == planeObj) {
- break;
- }
- entry = entry->next;
- }
-
- return entry;
-}
-
-inline ShowStyleEntry *GfxFrameout::deleteShowStyleInternal(ShowStyleEntry *const showStyle) {
- ShowStyleEntry *lastEntry = nullptr;
-
- for (ShowStyleEntry *testEntry = _showStyles; testEntry != nullptr; testEntry = testEntry->next) {
- if (testEntry == showStyle) {
- break;
- }
- lastEntry = testEntry;
- }
-
- if (lastEntry == nullptr) {
- _showStyles = showStyle->next;
- lastEntry = _showStyles;
- } else {
- lastEntry->next = showStyle->next;
- }
-
- delete[] showStyle->fadeColorRanges;
- delete showStyle;
-
- // TODO: Verify that this is the correct entry to return
- // for the loop in processShowStyles to work correctly
- return lastEntry;
-}
-
-// TODO: 10-argument version is only in SCI3; argc checks are currently wrong for this version
-// and need to be fixed in future
-// TODO: SQ6 does not use 'priority' (exists since SCI2) or 'blackScreen' (exists since SCI3);
-// check to see if other versions use or if they are just always ignored
-void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 back, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen) {
-
- bool hasDivisions = false;
- bool hasFadeArray = false;
-
- // KQ7 2.0b uses a mismatched version of the Styler script (SCI2.1early script
- // for SCI2.1mid engine), so the calls it makes to kSetShowStyle are wrong and
- // put `divisions` where `pFadeArray` is supposed to be
- if (getSciVersion() == SCI_VERSION_2_1_MIDDLE && g_sci->getGameId() == GID_KQ7) {
- hasDivisions = argc > 7;
- hasFadeArray = false;
- divisions = argc > 7 ? pFadeArray.toSint16() : -1;
- pFadeArray = NULL_REG;
- } else if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- hasDivisions = argc > 7;
- hasFadeArray = false;
- } else if (getSciVersion() < SCI_VERSION_3) {
- hasDivisions = argc > 8;
- hasFadeArray = argc > 7;
- } else {
- hasDivisions = argc > 9;
- hasFadeArray = argc > 8;
- }
-
- bool isFadeUp;
- int16 color;
- if (back != -1) {
- isFadeUp = false;
- color = back;
- } else {
- isFadeUp = true;
- color = 0;
- }
-
- if ((getSciVersion() < SCI_VERSION_2_1_MIDDLE && type == 15) || type > 15) {
- error("Illegal show style %d for plane %04x:%04x", type, PRINT_REG(planeObj));
- }
-
- Plane *plane = _planes.findByObject(planeObj);
- if (plane == nullptr) {
- error("Plane %04x:%04x is not present in active planes list", PRINT_REG(planeObj));
- }
-
- bool createNewEntry = true;
- ShowStyleEntry *entry = findShowStyleForPlane(planeObj);
- if (entry != nullptr) {
- // TODO: SCI2.1early has different criteria for show style reuse
- bool useExisting = true;
-
- if (useExisting) {
- useExisting = entry->divisions == (hasDivisions ? divisions : _defaultDivisions[type]) && entry->unknownC == _defaultUnknownC[type];
- }
-
- if (useExisting) {
- createNewEntry = false;
- isFadeUp = true;
- entry->currentStep = 0;
- } else {
- isFadeUp = true;
- color = entry->color;
- deleteShowStyleInternal(entry/*, true*/);
- entry = nullptr;
- }
- }
-
- if (type > 0) {
- if (createNewEntry) {
- entry = new ShowStyleEntry;
- // NOTE: SCI2.1 engine tests if allocation returned a null pointer
- // but then only avoids setting currentStep if this is so. Since
- // this is a nonsensical approach, we do not do that here
- entry->currentStep = 0;
- entry->unknownC = _defaultUnknownC[type];
- entry->processed = false;
- entry->divisions = hasDivisions ? divisions : _defaultDivisions[type];
- entry->plane = planeObj;
-
- entry->fadeColorRanges = nullptr;
- if (hasFadeArray) {
- // NOTE: SCI2.1mid engine does no check to verify that an array is
- // successfully retrieved, and SegMan will cause a fatal error
- // if we try to use a memory segment that is not an array
- SciArray<reg_t> *table = _segMan->lookupArray(pFadeArray);
-
- uint32 rangeCount = table->getSize();
- entry->fadeColorRangesCount = rangeCount;
-
- // NOTE: SCI engine code always allocates memory even if the range
- // table has no entries, but this does not really make sense, so
- // we avoid the allocation call in this case
- if (rangeCount > 0) {
- entry->fadeColorRanges = new uint16[rangeCount];
- for (size_t i = 0; i < rangeCount; ++i) {
- entry->fadeColorRanges[i] = table->getValue(i).toUint16();
- }
- }
- } else {
- entry->fadeColorRangesCount = 0;
- }
- }
-
- // NOTE: The original engine had no nullptr check and would just crash
- // if it got to here
- if (entry == nullptr) {
- error("Cannot edit non-existing ShowStyle entry");
- }
-
- entry->fadeUp = isFadeUp;
- entry->color = color;
- entry->nextTick = g_sci->getTickCount();
- entry->type = type;
- entry->animate = animate;
- entry->delay = (seconds * 60 + entry->divisions - 1) / entry->divisions;
-
- if (entry->delay == 0) {
- if (entry->fadeColorRanges != nullptr) {
- delete[] entry->fadeColorRanges;
- }
- delete entry;
- error("ShowStyle has no duration");
- }
-
- if (frameOutNow) {
- Common::Rect frameOutRect(0, 0);
- frameOut(false, frameOutRect);
- }
-
- if (createNewEntry) {
- // TODO: Implement SCI2.1early and SCI3
- entry->next = _showStyles;
- _showStyles = entry;
- }
- }
-}
-
-// NOTE: Different version of SCI engine support different show styles
-// SCI2 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12, 13, 14
-// SCI2.1 implements 0, 1/2/3/4/5/6/7/8/9/10/11/12/15, 13, 14
-// SCI3 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12/15, 13, 14
-// TODO: Sierra code needs to be replaced with code that uses the
-// computed entry->delay property instead of just counting divisors,
-// as the latter is machine-speed-dependent and leads to wrong
-// transition speeds
-void GfxFrameout::processShowStyles() {
- uint32 now = g_sci->getTickCount();
-
- bool continueProcessing;
-
- // TODO: Change to bool? Engine uses inc to set the value to true,
- // but there does not seem to be any reason to actually count how
- // many times it was set
- int doFrameOut;
- do {
- continueProcessing = false;
- doFrameOut = 0;
- ShowStyleEntry *showStyle = _showStyles;
- while (showStyle != nullptr) {
- bool retval = false;
-
- if (!showStyle->animate) {
- ++doFrameOut;
- }
-
- if (showStyle->nextTick < now || !showStyle->animate) {
- // TODO: Different versions of SCI use different processors!
- // This is the SQ6/KQ7/SCI2.1mid table.
- switch (showStyle->type) {
- case kShowStyleNone: {
- retval = processShowStyleNone(showStyle);
- break;
- }
- case kShowStyleHShutterOut:
- case kShowStyleVShutterOut:
- case kShowStyleWipeLeft:
- case kShowStyleWipeUp:
- case kShowStyleIrisOut:
- case kShowStyleHShutterIn:
- case kShowStyleVShutterIn:
- case kShowStyleWipeRight:
- case kShowStyleWipeDown:
- case kShowStyleIrisIn:
- case kShowStyle11:
- case kShowStyle12:
- case kShowStyleUnknown: {
- retval = processShowStyleMorph(showStyle);
- break;
- }
- case kShowStyleFadeOut: {
- retval = processShowStyleFade(-1, showStyle);
- break;
- }
- case kShowStyleFadeIn: {
- retval = processShowStyleFade(1, showStyle);
- break;
- }
- }
- }
-
- if (!retval) {
- continueProcessing = true;
- }
-
- if (retval && showStyle->processed) {
- showStyle = deleteShowStyleInternal(showStyle);
- } else {
- showStyle = showStyle->next;
- }
- }
-
- if (g_engine->shouldQuit()) {
- return;
- }
-
- if (doFrameOut) {
- frameOut(true);
-
- // TODO: Transitions without the “animate” flag are too
- // fast, but the throttle value is arbitrary. Someone on
- // real hardware probably needs to test what the actual
- // speed of these transitions should be
- throttle();
- }
- } while(continueProcessing && doFrameOut);
-}
-
-bool GfxFrameout::processShowStyleNone(ShowStyleEntry *const showStyle) {
- if (showStyle->fadeUp) {
- _palette->setFade(100, 0, 255);
- } else {
- _palette->setFade(0, 0, 255);
- }
-
- showStyle->processed = true;
- return true;
-}
-
-bool GfxFrameout::processShowStyleMorph(ShowStyleEntry *const showStyle) {
- palMorphFrameOut(_styleRanges, showStyle);
- showStyle->processed = true;
- return true;
-}
-
-// TODO: Normalise use of 'entry' vs 'showStyle'
-bool GfxFrameout::processShowStyleFade(const int direction, ShowStyleEntry *const showStyle) {
- bool unchanged = true;
- if (showStyle->currentStep < showStyle->divisions) {
- int percent;
- if (direction <= 0) {
- percent = showStyle->divisions - showStyle->currentStep - 1;
- } else {
- percent = showStyle->currentStep;
- }
-
- percent *= 100;
- percent /= showStyle->divisions - 1;
-
- if (showStyle->fadeColorRangesCount > 0) {
- for (int i = 0, len = showStyle->fadeColorRangesCount; i < len; i += 2) {
- _palette->setFade(percent, showStyle->fadeColorRanges[i], showStyle->fadeColorRanges[i + 1]);
- }
- } else {
- _palette->setFade(percent, 0, 255);
- }
-
- ++showStyle->currentStep;
- showStyle->nextTick += showStyle->delay;
- unchanged = false;
- }
-
- if (showStyle->currentStep >= showStyle->divisions && unchanged) {
- if (direction > 0) {
- showStyle->processed = true;
- }
-
- return true;
- }
-
- return false;
-}
-
void GfxFrameout::kernelFrameOut(const bool shouldShowBits) {
- if (_showStyles != nullptr) {
- processShowStyles();
+ if (_transitions->hasShowStyles()) {
+ _transitions->processShowStyles();
} else if (_palMorphIsOn) {
- palMorphFrameOut(_styleRanges, nullptr);
+ palMorphFrameOut(_transitions->_styleRanges, nullptr);
_palMorphIsOn = false;
} else {
-// TODO: Window scroll
-// if (g_PlaneScroll) {
-// processScrolls();
-// }
+ if (_transitions->hasScrolls()) {
+ _transitions->processScrolls();
+ }
frameOut(shouldShowBits);
}
@@ -1621,6 +1255,14 @@ void GfxFrameout::throttle() {
}
}
+void GfxFrameout::showRect(const Common::Rect &rect) {
+ if (!rect.isEmpty()) {
+ _showList.clear();
+ _showList.add(rect);
+ showBits();
+ }
+}
+
#pragma mark -
#pragma mark Mouse cursor
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 99658ed..035555a 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -27,130 +27,13 @@
#include "sci/graphics/screen_item32.h"
namespace Sci {
-// TODO: Don't do this this way
-int splitRects(Common::Rect r, const Common::Rect &other, Common::Rect(&outRects)[4]);
-
-// TODO: Verify display styles and adjust names appropriately for
-// types 1 through 12 & 15 (others are correct)
-// Names should be:
-// * VShutterIn, VShutterOut
-// * HShutterIn, HShutterOut
-// * WipeLeft, WipeRight, WipeDown, WipeUp
-// * PixelDissolve
-// * ShutDown and Kill? (and Plain and Fade?)
-enum ShowStyleType /* : uint8 */ {
- kShowStyleNone = 0,
- kShowStyleHShutterOut = 1,
- kShowStyleHShutterIn = 2,
- kShowStyleVShutterOut = 3,
- kShowStyleVShutterIn = 4,
- kShowStyleWipeLeft = 5,
- kShowStyleWipeRight = 6,
- kShowStyleWipeUp = 7,
- kShowStyleWipeDown = 8,
- kShowStyleIrisOut = 9,
- kShowStyleIrisIn = 10,
- kShowStyle11 = 11,
- kShowStyle12 = 12,
- kShowStyleFadeOut = 13,
- kShowStyleFadeIn = 14,
- // TODO: Only in SCI3
- kShowStyleUnknown = 15
-};
-
-/**
- * Show styles represent transitions applied to draw planes.
- * One show style per plane can be active at a time.
- */
-struct ShowStyleEntry {
- /**
- * The ID of the plane this show style belongs to.
- * In SCI2.1mid (at least SQ6), per-plane transitions
- * were removed and a single plane ID is used.
- */
- reg_t plane;
-
- /**
- * The type of the transition.
- */
- ShowStyleType type;
-
- // TODO: This name is probably incorrect
- bool fadeUp;
-
- /**
- * The number of steps for the show style.
- */
- int16 divisions;
-
- // NOTE: This property exists from SCI2 through at least
- // SCI2.1mid but is never used in the actual processing
- // of the styles?
- int unknownC;
-
- /**
- * The color used by transitions that draw CelObjColor
- * screen items. -1 for transitions that do not draw
- * screen items.
- */
- int16 color;
-
- // TODO: Probably uint32
- // TODO: This field probably should be used in order to
- // provide time-accurate processing of show styles. In the
- // actual SCI engine (at least 2–2.1mid) it appears that
- // style transitions are drawn “as fast as possible”, one
- // step per loop, even though this delay field exists
- int delay;
-
- // TODO: Probably bool, but never seems to be true?
- int animate;
-
- /**
- * The wall time at which the next step of the animation
- * should execute.
- */
- uint32 nextTick;
-
- /**
- * During playback of the show style, the current step
- * (out of divisions).
- */
- int currentStep;
-
- /**
- * The next show style.
- */
- ShowStyleEntry *next;
-
- /**
- * Whether or not this style has finished running and
- * is ready for disposal.
- */
- bool processed;
-
- //
- // Engine specific properties for SCI2.1mid through SCI3
- //
-
- /**
- * The number of entries in the fadeColorRanges array.
- */
- uint8 fadeColorRangesCount;
-
- /**
- * A pointer to an dynamically sized array of palette
- * indexes, in the order [ fromColor, toColor, ... ].
- * Only colors within this range are transitioned.
- */
- uint16 *fadeColorRanges;
-};
-
typedef Common::Array<DrawList> ScreenItemListList;
typedef Common::Array<RectList> EraseListList;
class GfxCoordAdjuster32;
class GfxScreen;
+class GfxTransitions32;
+class PlaneShowStyle;
/**
* Frameout class, kFrameout and relevant functions for SCI32 games.
@@ -166,7 +49,7 @@ private:
SegManager *_segMan;
public:
- GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette);
+ GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette, GfxTransitions32 *transitions);
~GfxFrameout();
void clear();
@@ -287,37 +170,10 @@ public:
void kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 pictureX, const int16 pictureY, const bool mirrorX);
#pragma mark -
-
- // TODO: Remap-related?
- void kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor);
-
-#pragma mark -
-#pragma mark Transitions
-private:
- int *_dissolveSequenceSeeds;
- int16 *_defaultDivisions;
- int16 *_defaultUnknownC;
-
- /**
- * TODO: Documentation
- */
- ShowStyleEntry *_showStyles;
-
- inline ShowStyleEntry *findShowStyleForPlane(const reg_t planeObj) const;
- inline ShowStyleEntry *deleteShowStyleInternal(ShowStyleEntry *const showStyle);
- void processShowStyles();
- bool processShowStyleNone(ShowStyleEntry *showStyle);
- bool processShowStyleMorph(ShowStyleEntry *showStyle);
- bool processShowStyleFade(const int direction, ShowStyleEntry *showStyle);
-
-public:
- // NOTE: This signature is taken from SCI3 Phantasmagoria 2
- // and is valid for all implementations of SCI32
- void kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 direction, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen);
-
-#pragma mark -
#pragma mark Rendering
private:
+ GfxTransitions32 *_transitions;
+
/**
* State tracker to provide more accurate 60fps
* video throttling.
@@ -325,11 +181,6 @@ private:
uint8 _throttleState;
/**
- * TODO: Documentation
- */
- int8 _styleRanges[256];
-
- /**
* The internal display pixel buffer. During frameOut,
* this buffer is drawn into according to the draw and
* erase rects calculated by `calcLists`, then drawn out
@@ -428,16 +279,35 @@ private:
void mergeToShowList(const Common::Rect &drawRect, RectList &showList, const int overdrawThreshold);
/**
- * TODO: Documentation
- */
- void palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle);
-
- /**
* Writes the internal frame buffer out to hardware and
* clears the show list.
*/
void showBits();
+ /**
+ * Validates whether the given palette index in the
+ * style range should copy a color from the next
+ * palette to the source palette during a palette
+ * morph operation.
+ */
+ inline bool validZeroStyle(const uint8 style, const int i) const {
+ if (style != 0) {
+ return false;
+ }
+
+ // TODO: Cannot check Shivers or MGDX until those executables can be
+ // unwrapped
+ switch (g_sci->getGameId()) {
+ case GID_KQ7:
+ case GID_PHANTASMAGORIA:
+ case GID_SQ6:
+ return (i > 71 && i < 104);
+ break;
+ default:
+ return true;
+ }
+ }
+
public:
/**
* Whether palMorphFrameOut should be used instead of
@@ -467,6 +337,11 @@ public:
void frameOut(const bool shouldShowBits, const Common::Rect &eraseRect = Common::Rect());
/**
+ * TODO: Documentation
+ */
+ void palMorphFrameOut(const int8 *styleRanges, PlaneShowStyle *showStyle);
+
+ /**
* Modifies the raw pixel data for the next frame with
* new palette indexes based on matched style ranges.
*/
@@ -484,6 +359,12 @@ public:
return 1;
};
+ /**
+ * Draws a portion of the current screen buffer to
+ * hardware. Used to display show styles in SCI2.1mid+.
+ */
+ void showRect(const Common::Rect &rect);
+
#pragma mark -
#pragma mark Mouse cursor
private:
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
index 6b05b2d..cb6ec74 100644
--- a/engines/sci/graphics/plane32.cpp
+++ b/engines/sci/graphics/plane32.cpp
@@ -194,11 +194,11 @@ void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *p
_type = transparent ? kPlaneTypeTransparentPicture : kPlaneTypePicture;
}
-void Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) {
+GuiResourceId Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) {
+ GuiResourceId oldPictureId = _pictureId;
deletePic(pictureId);
addPicInternal(pictureId, &position, mirrorX);
- // NOTE: In SCI engine this method returned the pictureId of the
- // plane, but this return value was never used
+ return oldPictureId;
}
void Plane::changePic() {
diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h
index 3981a2b..f55d97b 100644
--- a/engines/sci/graphics/plane32.h
+++ b/engines/sci/graphics/plane32.h
@@ -336,14 +336,6 @@ private:
/**
* Marks all screen items to be deleted that are within
- * this plane and match the given picture ID, then sets
- * the picture ID of the plane to the new picture ID
- * without adding any screen items.
- */
- void deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId);
-
- /**
- * Marks all screen items to be deleted that are within
* this plane and are picture cels.
*/
void deleteAllPics();
@@ -355,7 +347,7 @@ public:
* new picture resource to the plane at the given
* position.
*/
- void addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX);
+ GuiResourceId addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX);
/**
* If the plane is a picture plane, re-adds all cels
@@ -364,6 +356,14 @@ public:
*/
void changePic();
+ /**
+ * Marks all screen items to be deleted that are within
+ * this plane and match the given picture ID, then sets
+ * the picture ID of the plane to the new picture ID
+ * without adding any screen items.
+ */
+ void deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId);
+
#pragma mark -
#pragma mark Plane - Rendering
private:
diff --git a/engines/sci/graphics/transitions32.cpp b/engines/sci/graphics/transitions32.cpp
new file mode 100644
index 0000000..01956e6
--- /dev/null
+++ b/engines/sci/graphics/transitions32.cpp
@@ -0,0 +1,981 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "sci/engine/segment.h"
+#include "sci/engine/seg_manager.h"
+#include "sci/engine/state.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/text32.h"
+#include "sci/graphics/transitions32.h"
+#include "sci/sci.h"
+
+namespace Sci {
+static int dissolveSequences[2][20] = {
+ /* SCI2.1early- */ { 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080 },
+ /* SCI2.1mid+ */ { 0, 0, 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080, 73728, 132096, 466944 }
+};
+static int16 divisionsDefaults[2][16] = {
+ /* SCI2.1early- */ { 1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 40, 40, 101, 101 },
+ /* SCI2.1mid+ */ { 1, 20, 20, 20, 20, 10, 10, 10, 10, 20, 20, 6, 10, 101, 101, 2 }
+};
+
+GfxTransitions32::GfxTransitions32(SegManager *segMan) :
+ _segMan(segMan),
+ _throttleState(0) {
+ for (int i = 0; i < 236; i += 2) {
+ _styleRanges[i] = 0;
+ _styleRanges[i + 1] = -1;
+ }
+ for (int i = 236; i < ARRAYSIZE(_styleRanges); ++i) {
+ _styleRanges[i] = 0;
+ }
+
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ _dissolveSequenceSeeds = dissolveSequences[0];
+ _defaultDivisions = divisionsDefaults[0];
+ } else {
+ _dissolveSequenceSeeds = dissolveSequences[1];
+ _defaultDivisions = divisionsDefaults[1];
+ }
+}
+
+GfxTransitions32::~GfxTransitions32() {
+ for (ShowStyleList::iterator it = _showStyles.begin(); it != _showStyles.end(); ++it) {
+ deleteShowStyle(it);
+ }
+ _scrolls.clear();
+}
+
+void GfxTransitions32::throttle() {
+ uint8 throttleTime;
+ if (_throttleState == 2) {
+ throttleTime = 34;
+ _throttleState = 0;
+ } else {
+ throttleTime = 33;
+ ++_throttleState;
+ }
+
+ g_sci->getEngineState()->speedThrottler(throttleTime);
+ g_sci->getEngineState()->_throttleTrigger = true;
+}
+
+#pragma mark -
+#pragma mark Show styles
+
+void GfxTransitions32::processShowStyles() {
+ uint32 now = g_sci->getTickCount();
+
+ bool continueProcessing;
+ bool doFrameOut;
+ do {
+ continueProcessing = false;
+ doFrameOut = false;
+ ShowStyleList::iterator showStyle = _showStyles.begin();
+ while (showStyle != _showStyles.end()) {
+ bool finished = false;
+
+ if (!showStyle->animate) {
+ doFrameOut = true;
+ }
+
+ finished = processShowStyle(*showStyle, now);
+
+ if (!finished) {
+ continueProcessing = true;
+ }
+
+ if (finished && showStyle->processed) {
+ showStyle = deleteShowStyle(showStyle);
+ } else {
+ showStyle = ++showStyle;
+ }
+ }
+
+ if (g_engine->shouldQuit()) {
+ return;
+ }
+
+ if (doFrameOut) {
+ g_sci->_gfxFrameout->frameOut(true);
+ throttle();
+ }
+ } while(continueProcessing && doFrameOut);
+}
+
+void GfxTransitions32::processEffects(PlaneShowStyle &showStyle) {
+ switch(showStyle.type) {
+ case kShowStyleHShutterOut:
+ processHShutterOut(showStyle);
+ break;
+ case kShowStyleHShutterIn:
+ processHShutterIn(showStyle);
+ break;
+ case kShowStyleVShutterOut:
+ processVShutterOut(showStyle);
+ break;
+ case kShowStyleVShutterIn:
+ processVShutterIn(showStyle);
+ break;
+ case kShowStyleWipeLeft:
+ processWipeLeft(showStyle);
+ break;
+ case kShowStyleWipeRight:
+ processWipeRight(showStyle);
+ break;
+ case kShowStyleWipeUp:
+ processWipeUp(showStyle);
+ break;
+ case kShowStyleWipeDown:
+ processWipeDown(showStyle);
+ break;
+ case kShowStyleIrisOut:
+ processIrisOut(showStyle);
+ break;
+ case kShowStyleIrisIn:
+ processIrisIn(showStyle);
+ break;
+ case kShowStyleDissolveNoMorph:
+ case kShowStyleDissolve:
+ processPixelDissolve(showStyle);
+ break;
+ case kShowStyleNone:
+ case kShowStyleFadeOut:
+ case kShowStyleFadeIn:
+ case kShowStyleMorph:
+ break;
+ }
+}
+
+// TODO: 10-argument version is only in SCI3; argc checks are currently wrong for this version
+// and need to be fixed in future
+void GfxTransitions32::kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 back, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen) {
+
+ bool hasDivisions = false;
+ bool hasFadeArray = false;
+
+ // KQ7 2.0b uses a mismatched version of the Styler script (SCI2.1early script
+ // for SCI2.1mid engine), so the calls it makes to kSetShowStyle are wrong and
+ // put `divisions` where `pFadeArray` is supposed to be
+ if (getSciVersion() == SCI_VERSION_2_1_MIDDLE && g_sci->getGameId() == GID_KQ7) {
+ hasDivisions = argc > 7;
+ hasFadeArray = false;
+ divisions = argc > 7 ? pFadeArray.toSint16() : -1;
+ pFadeArray = NULL_REG;
+ } else if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ hasDivisions = argc > 7;
+ hasFadeArray = false;
+ } else if (getSciVersion() < SCI_VERSION_3) {
+ hasDivisions = argc > 8;
+ hasFadeArray = argc > 7;
+ } else {
+ hasDivisions = argc > 9;
+ hasFadeArray = argc > 8;
+ }
+
+ bool isFadeUp;
+ int16 color;
+ if (back != -1) {
+ isFadeUp = false;
+ color = back;
+ } else {
+ isFadeUp = true;
+ color = 0;
+ }
+
+ if ((getSciVersion() < SCI_VERSION_2_1_MIDDLE && g_sci->getGameId() != GID_KQ7 && type == 15) || type > 15) {
+ error("Illegal show style %d for plane %04x:%04x", type, PRINT_REG(planeObj));
+ }
+
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObj);
+ if (plane == nullptr) {
+ error("Plane %04x:%04x is not present in active planes list", PRINT_REG(planeObj));
+ }
+
+ bool createNewEntry = true;
+ PlaneShowStyle *entry = findShowStyleForPlane(planeObj);
+ if (entry != nullptr) {
+ bool useExisting = true;
+
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ useExisting = plane->_gameRect.width() == entry->width && plane->_gameRect.height() == entry->height;
+ }
+
+ if (useExisting) {
+ useExisting = entry->divisions == (hasDivisions ? divisions : _defaultDivisions[type]);
+ }
+
+ if (useExisting) {
+ createNewEntry = false;
+ isFadeUp = true;
+ entry->currentStep = 0;
+ } else {
+ isFadeUp = true;
+ color = entry->color;
+ deleteShowStyle(findIteratorForPlane(planeObj));
+ entry = nullptr;
+ }
+ }
+
+ if (type > 0) {
+ if (createNewEntry) {
+ entry = new PlaneShowStyle;
+ // NOTE: SCI2.1 engine tests if allocation returned a null pointer
+ // but then only avoids setting currentStep if this is so. Since
+ // this is a nonsensical approach, we do not do that here
+ entry->currentStep = 0;
+ entry->processed = false;
+ entry->divisions = hasDivisions ? divisions : _defaultDivisions[type];
+ entry->plane = planeObj;
+ entry->fadeColorRangesCount = 0;
+
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ // for pixel dissolve
+ entry->bitmap = NULL_REG;
+ entry->bitmapScreenItem = nullptr;
+
+ // for wipe
+ entry->screenItems.clear();
+ entry->width = plane->_gameRect.width();
+ entry->height = plane->_gameRect.height();
+ } else {
+ entry->fadeColorRanges = nullptr;
+ if (hasFadeArray) {
+ // NOTE: SCI2.1mid engine does no check to verify that an array is
+ // successfully retrieved, and SegMan will cause a fatal error
+ // if we try to use a memory segment that is not an array
+ SciArray<reg_t> *table = _segMan->lookupArray(pFadeArray);
+
+ uint32 rangeCount = table->getSize();
+ entry->fadeColorRangesCount = rangeCount;
+
+ // NOTE: SCI engine code always allocates memory even if the range
+ // table has no entries, but this does not really make sense, so
+ // we avoid the allocation call in this case
+ if (rangeCount > 0) {
+ entry->fadeColorRanges = new uint16[rangeCount];
+ for (size_t i = 0; i < rangeCount; ++i) {
+ entry->fadeColorRanges[i] = table->getValue(i).toUint16();
+ }
+ }
+ }
+ }
+ }
+
+ // NOTE: The original engine had no nullptr check and would just crash
+ // if it got to here
+ if (entry == nullptr) {
+ error("Cannot edit non-existing ShowStyle entry");
+ }
+
+ entry->fadeUp = isFadeUp;
+ entry->color = color;
+ entry->nextTick = g_sci->getTickCount();
+ entry->type = type;
+ entry->animate = animate;
+ entry->delay = (seconds * 60 + entry->divisions - 1) / entry->divisions;
+
+ if (entry->delay == 0) {
+ error("ShowStyle has no duration");
+ }
+
+ if (frameOutNow) {
+ // Creates a reference frame for the pixel dissolves to use
+ g_sci->_gfxFrameout->frameOut(false);
+ }
+
+ if (createNewEntry) {
+ if (getSciVersion() <= SCI_VERSION_2_1_EARLY) {
+ switch (entry->type) {
+ case kShowStyleIrisOut:
+ case kShowStyleIrisIn:
+ configure21EarlyIris(*entry, priority);
+ break;
+ case kShowStyleDissolve:
+ configure21EarlyDissolve(*entry, priority, plane->_gameRect);
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ }
+
+ _showStyles.push_back(*entry);
+ delete entry;
+ }
+ }
+}
+
+void GfxTransitions32::kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor) {
+ if (toColor > fromColor) {
+ return;
+ }
+
+ for (int i = fromColor; i <= toColor; ++i) {
+ _styleRanges[i] = 0;
+ }
+}
+
+PlaneShowStyle *GfxTransitions32::findShowStyleForPlane(const reg_t planeObj) {
+ for (ShowStyleList::iterator it = _showStyles.begin(); it != _showStyles.end(); ++it) {
+ if (it->plane == planeObj) {
+ return &*it;
+ }
+ }
+
+ return nullptr;
+}
+
+ShowStyleList::iterator GfxTransitions32::findIteratorForPlane(const reg_t planeObj) {
+ ShowStyleList::iterator it;
+ for (it = _showStyles.begin(); it != _showStyles.end(); ++it) {
+ if (it->plane == planeObj) {
+ break;
+ }
+ }
+
+ return it;
+}
+
+ShowStyleList::iterator GfxTransitions32::deleteShowStyle(const ShowStyleList::iterator &showStyle) {
+ switch (showStyle->type) {
+ case kShowStyleDissolveNoMorph:
+ case kShowStyleDissolve:
+ if (getSciVersion() <= SCI_VERSION_2_1_EARLY) {
+ _segMan->freeHunkEntry(showStyle->bitmap);
+ g_sci->_gfxFrameout->deleteScreenItem(*showStyle->bitmapScreenItem);
+ }
+ break;
+ case kShowStyleIrisOut:
+ case kShowStyleIrisIn:
+ if (getSciVersion() <= SCI_VERSION_2_1_EARLY) {
+ for (uint i = 0; i < showStyle->screenItems.size(); ++i) {
+ ScreenItem *screenItem = showStyle->screenItems[i];
+ if (screenItem != nullptr) {
+ g_sci->_gfxFrameout->deleteScreenItem(*screenItem);
+ }
+ }
+ }
+ break;
+ case kShowStyleFadeIn:
+ case kShowStyleFadeOut:
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY && showStyle->fadeColorRangesCount > 0) {
+ delete[] showStyle->fadeColorRanges;
+ }
+ break;
+ case kShowStyleNone:
+ case kShowStyleMorph:
+ // do nothing
+ break;
+ default:
+ error("Unknown delete transition type %d", showStyle->type);
+ }
+
+ return _showStyles.erase(showStyle);
+}
+
+void GfxTransitions32::configure21EarlyIris(PlaneShowStyle &showStyle, const int16 priority) {
+ showStyle.numEdges = 4;
+ const int numScreenItems = showStyle.numEdges * showStyle.divisions;
+ showStyle.screenItems.reserve(numScreenItems);
+
+ CelInfo32 celInfo;
+ celInfo.type = kCelTypeColor;
+ celInfo.color = showStyle.color;
+
+ const int width = showStyle.width;
+ const int height = showStyle.height;
+ const int divisions = showStyle.divisions;
+
+ for (int i = 0; i < divisions; ++i) {
+ Common::Rect rect;
+
+ // Top
+ rect.left = (width * i) / (2 * divisions);
+ rect.top = (height * i) / (2 * divisions);
+ rect.right = width - rect.left;
+ rect.bottom = (height + 1) * (i + 1) / (2 * divisions);
+ const int16 topTop = rect.top;
+ const int16 topBottom = rect.bottom;
+
+ showStyle.screenItems.push_back(new ScreenItem(showStyle.plane, celInfo, rect));
+ showStyle.screenItems.back()->_priority = priority;
+ showStyle.screenItems.back()->_fixedPriority = true;
+
+ // Bottom
+ rect.top = height - rect.bottom;
+ rect.bottom = height - topTop;
+ const int16 bottomTop = rect.top;
+
+ showStyle.screenItems.push_back(new ScreenItem(showStyle.plane, celInfo, rect));
+ showStyle.screenItems.back()->_priority = priority;
+ showStyle.screenItems.back()->_fixedPriority = true;
+
+ // Left
+ rect.top = topBottom;
+ rect.right = (width + 1) * (i + 1) / (2 * divisions);
+ rect.bottom = bottomTop;
+ const int16 leftLeft = rect.left;
+
+ showStyle.screenItems.push_back(new ScreenItem(showStyle.plane, celInfo, rect));
+ showStyle.screenItems.back()->_priority = priority;
+ showStyle.screenItems.back()->_fixedPriority = true;
+
+ // Right
+ rect.left = width - rect.right;
+ rect.right = width - leftLeft;
+
+ showStyle.screenItems.push_back(new ScreenItem(showStyle.plane, celInfo, rect));
+ showStyle.screenItems.back()->_priority = priority;
+ showStyle.screenItems.back()->_fixedPriority = true;
+ }
+
+ if (showStyle.fadeUp) {
+ for (int i = 0; i < numScreenItems; ++i) {
+ g_sci->_gfxFrameout->addScreenItem(*showStyle.screenItems[i]);
+ }
+ }
+}
+
+void GfxTransitions32::configure21EarlyDissolve(PlaneShowStyle &showStyle, const int16 priority, const Common::Rect &gameRect) {
+
+ BitmapResource bitmap(_segMan, showStyle.width, showStyle.height, kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
+
+ showStyle.bitmap = bitmap.getObject();
+
+ const Buffer &source = g_sci->_gfxFrameout->getCurrentBuffer();
+ Buffer target(showStyle.width, showStyle.height, bitmap.getPixels());
+
+ target.fillRect(Common::Rect(bitmap.getWidth(), bitmap.getHeight()), kDefaultSkipColor);
+ target.copyRectToSurface(source, 0, 0, gameRect);
+
+ CelInfo32 celInfo;
+ celInfo.type = kCelTypeMem;
+ celInfo.bitmap = bitmap.getObject();
+
+ showStyle.bitmapScreenItem = new ScreenItem(showStyle.plane, celInfo, Common::Point(0, 0), ScaleInfo());
+ showStyle.bitmapScreenItem->_priority = priority;
+ showStyle.bitmapScreenItem->_fixedPriority = true;
+
+ g_sci->_gfxFrameout->addScreenItem(*showStyle.bitmapScreenItem);
+}
+
+bool GfxTransitions32::processShowStyle(PlaneShowStyle &showStyle, uint32 now) {
+ if (showStyle.nextTick >= now && showStyle.animate) {
+ return false;
+ }
+
+ switch (showStyle.type) {
+ default:
+ case kShowStyleNone:
+ return processNone(showStyle);
+ case kShowStyleHShutterOut:
+ case kShowStyleHShutterIn:
+ case kShowStyleVShutterOut:
+ case kShowStyleVShutterIn:
+ case kShowStyleWipeLeft:
+ case kShowStyleWipeRight:
+ case kShowStyleWipeUp:
+ case kShowStyleWipeDown:
+ case kShowStyleDissolveNoMorph:
+ case kShowStyleMorph:
+ return processMorph(showStyle);
+ case kShowStyleDissolve:
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ return processMorph(showStyle);
+ } else {
+ return processPixelDissolve(showStyle);
+ }
+ case kShowStyleIrisOut:
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ return processMorph(showStyle);
+ } else {
+ return processIrisOut(showStyle);
+ }
+ case kShowStyleIrisIn:
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ return processMorph(showStyle);
+ } else {
+ return processIrisIn(showStyle);
+ }
+ case kShowStyleFadeOut:
+ return processFade(-1, showStyle);
+ case kShowStyleFadeIn:
+ return processFade(1, showStyle);
+ }
+}
+
+bool GfxTransitions32::processNone(PlaneShowStyle &showStyle) {
+ if (showStyle.fadeUp) {
+ g_sci->_gfxPalette32->setFade(100, 0, 255);
+ } else {
+ g_sci->_gfxPalette32->setFade(0, 0, 255);
+ }
+
+ showStyle.processed = true;
+ return true;
+}
+
+void GfxTransitions32::processHShutterOut(PlaneShowStyle &showStyle) {
+ error("HShutterOut is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processHShutterIn(PlaneShowStyle &showStyle) {
+ error("HShutterIn is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processVShutterOut(PlaneShowStyle &showStyle) {
+ error("VShutterOut is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processVShutterIn(PlaneShowStyle &showStyle) {
+ error("VShutterIn is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processWipeLeft(PlaneShowStyle &showStyle) {
+ error("WipeLeft is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processWipeRight(PlaneShowStyle &showStyle) {
+ error("WipeRight is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processWipeUp(PlaneShowStyle &showStyle) {
+ error("WipeUp is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processWipeDown(PlaneShowStyle &showStyle) {
+ error("WipeDown is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+bool GfxTransitions32::processIrisOut(PlaneShowStyle &showStyle) {
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ error("IrisOut is not known to be used by any SCI2.1mid+ game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+ }
+
+ return processWipe(-1, showStyle);
+}
+
+bool GfxTransitions32::processIrisIn(PlaneShowStyle &showStyle) {
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ error("IrisIn is not known to be used by any SCI2.1mid+ game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+ }
+
+ return processWipe(1, showStyle);
+}
+
+void GfxTransitions32::processDissolveNoMorph(PlaneShowStyle &showStyle) {
+ error("DissolveNoMorph is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+inline int bitWidth(int number) {
+ int width = 0;
+ while (number != 0) {
+ number >>= 1;
+ width += 1;
+ }
+ return width;
+}
+
+bool GfxTransitions32::processPixelDissolve(PlaneShowStyle &showStyle) {
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ return processPixelDissolve21Mid(showStyle);
+ } else {
+ return processPixelDissolve21Early(showStyle);
+ }
+}
+
+bool GfxTransitions32::processPixelDissolve21Early(PlaneShowStyle &showStyle) {
+ bool unchanged = true;
+
+ BitmapResource bitmap(showStyle.bitmap);
+ Buffer buffer(showStyle.width, showStyle.height, bitmap.getPixels());
+
+ uint32 numPixels = showStyle.width * showStyle.height;
+ uint32 numPixelsPerDivision = (numPixels + showStyle.divisions) / showStyle.divisions;
+
+ uint32 index;
+ if (showStyle.currentStep == 0) {
+ int i = 0;
+ index = numPixels;
+ if (index != 1) {
+ for (;;) {
+ index >>= 1;
+ if (index == 1) {
+ break;
+ }
+ i++;
+ }
+ }
+
+ showStyle.dissolveMask = _dissolveSequenceSeeds[i];
+ index = 53427;
+
+ showStyle.firstPixel = index;
+ showStyle.pixel = index;
+ } else {
+ index = showStyle.pixel;
+ for (;;) {
+ if (index & 1) {
+ index >>= 1;
+ index ^= showStyle.dissolveMask;
+ } else {
+ index >>= 1;
+ }
+
+ if (index < numPixels) {
+ break;
+ }
+ }
+
+ if (index == showStyle.firstPixel) {
+ index = 0;
+ }
+ }
+
+ if (showStyle.currentStep < showStyle.divisions) {
+ for (uint32 i = 0; i < numPixelsPerDivision; ++i) {
+ *(byte *)buffer.getBasePtr(index % showStyle.width, index / showStyle.width) = showStyle.color;
+
+ for (;;) {
+ if (index & 1) {
+ index >>= 1;
+ index ^= showStyle.dissolveMask;
+ } else {
+ index >>= 1;
+ }
+
+ if (index < numPixels) {
+ break;
+ }
+ }
+
+ if (index == showStyle.firstPixel) {
+ buffer.fillRect(Common::Rect(0, 0, showStyle.width, showStyle.height), showStyle.color);
+ break;
+ }
+ }
+
+ showStyle.pixel = index;
+ showStyle.nextTick += showStyle.delay;
+ ++showStyle.currentStep;
+ unchanged = false;
+ if (showStyle.bitmapScreenItem->_created == 0) {
+ showStyle.bitmapScreenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
+ }
+ }
+
+ if ((showStyle.currentStep >= showStyle.divisions) && unchanged) {
+ if (showStyle.fadeUp) {
+ showStyle.processed = true;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool GfxTransitions32::processPixelDissolve21Mid(PlaneShowStyle &showStyle) {
+ // SQ6 room 530
+
+ Plane* plane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(showStyle.plane);
+ const Common::Rect &screenRect = plane->_screenRect;
+ Common::Rect rect;
+
+ const int planeWidth = screenRect.width();
+ const int planeHeight = screenRect.height();
+ const int divisions = showStyle.divisions;
+ const int width = planeWidth / divisions + ((planeWidth % divisions) ? 1 : 0);
+ const int height = planeHeight / divisions + ((planeHeight % divisions) ? 1 : 0);
+
+ const uint32 mask = _dissolveSequenceSeeds[bitWidth(width * height - 1)];
+ int seq = 1;
+
+ uint iteration = 0;
+ const uint numIterationsPerTick = (width * height + divisions) / divisions;
+
+ do {
+ int row = seq / width;
+ int col = seq % width;
+
+ if (row < height) {
+ if (row == height && (planeHeight % divisions)) {
+ if (col == width && (planeWidth % divisions)) {
+ rect.left = col * divisions;
+ rect.top = row * divisions;
+ rect.right = col * divisions + (planeWidth % divisions);
+ rect.bottom = row * divisions + (planeHeight % divisions);
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ } else {
+ rect.left = col * divisions;
+ rect.top = row * divisions;
+ rect.right = col * divisions * 2;
+ rect.bottom = row * divisions + (planeHeight % divisions);
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ }
+ } else {
+ if (col == width && (planeWidth % divisions)) {
+ rect.left = col * divisions;
+ rect.top = row * divisions;
+ rect.right = col * divisions + (planeWidth % divisions) + 1;
+ rect.bottom = row * divisions * 2 + 1;
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ } else {
+ rect.left = col * divisions;
+ rect.top = row * divisions;
+ rect.right = col * divisions * 2 + 1;
+ rect.bottom = row * divisions * 2 + 1;
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ }
+ }
+ }
+
+ if (seq & 1) {
+ seq = (seq >> 1) ^ mask;
+ } else {
+ seq >>= 1;
+ }
+
+ if (++iteration == numIterationsPerTick) {
+ throttle();
+ iteration = 0;
+ }
+ } while(seq != 1 && !g_engine->shouldQuit());
+
+ rect.left = screenRect.left;
+ rect.top = screenRect.top;
+ rect.right = divisions + screenRect.left;
+ rect.bottom = divisions + screenRect.bottom;
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ throttle();
+
+ g_sci->_gfxFrameout->showRect(screenRect);
+ return true;
+}
+
+bool GfxTransitions32::processFade(const int8 direction, PlaneShowStyle &showStyle) {
+ bool unchanged = true;
+ if (showStyle.currentStep < showStyle.divisions) {
+ int percent;
+ if (direction <= 0) {
+ percent = showStyle.divisions - showStyle.currentStep - 1;
+ } else {
+ percent = showStyle.currentStep;
+ }
+
+ percent *= 100;
+ percent /= showStyle.divisions - 1;
+
+ if (showStyle.fadeColorRangesCount > 0) {
+ for (int i = 0, len = showStyle.fadeColorRangesCount; i < len; i += 2) {
+ g_sci->_gfxPalette32->setFade(percent, showStyle.fadeColorRanges[i], showStyle.fadeColorRanges[i + 1]);
+ }
+ } else {
+ g_sci->_gfxPalette32->setFade(percent, 0, 255);
+ }
+
+ ++showStyle.currentStep;
+ showStyle.nextTick += showStyle.delay;
+ unchanged = false;
+ }
+
+ if (showStyle.currentStep >= showStyle.divisions && unchanged) {
+ if (direction > 0) {
+ showStyle.processed = true;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool GfxTransitions32::processMorph(PlaneShowStyle &showStyle) {
+ g_sci->_gfxFrameout->palMorphFrameOut(_styleRanges, &showStyle);
+ showStyle.processed = true;
+ return true;
+}
+
+bool GfxTransitions32::processWipe(const int8 direction, PlaneShowStyle &showStyle) {
+ bool unchanged = true;
+ if (showStyle.currentStep < showStyle.divisions) {
+ int index;
+ if (direction > 0) {
+ index = showStyle.currentStep;
+ } else {
+ index = showStyle.divisions - showStyle.currentStep - 1;
+ }
+
+ index *= showStyle.numEdges;
+ for (int i = 0; i < showStyle.numEdges; ++i) {
+ ScreenItem *screenItem = showStyle.screenItems[index + i];
+ if (showStyle.fadeUp) {
+ g_sci->_gfxFrameout->deleteScreenItem(*screenItem);
+ showStyle.screenItems[index + i] = nullptr;
+ } else {
+ g_sci->_gfxFrameout->addScreenItem(*screenItem);
+ }
+ }
+
+ ++showStyle.currentStep;
+ showStyle.nextTick += showStyle.delay;
+ unchanged = false;
+ }
+
+ if (showStyle.currentStep >= showStyle.divisions && unchanged) {
+ if (showStyle.fadeUp) {
+ showStyle.processed = true;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+#pragma mark -
+#pragma mark Scrolls
+
+void GfxTransitions32::processScrolls() {
+ for (ScrollList::iterator it = _scrolls.begin(); it != _scrolls.end(); ) {
+ bool finished = processScroll(*it);
+ if (finished) {
+ it = _scrolls.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ throttle();
+}
+
+void GfxTransitions32::kernelSetScroll(const reg_t planeId, const int16 deltaX, const int16 deltaY, const GuiResourceId pictureId, const bool animate, const bool mirrorX) {
+
+ for (ScrollList::const_iterator it = _scrolls.begin(); it != _scrolls.end(); ++it) {
+ if (it->plane == planeId) {
+ error("Scroll already exists on plane %04x:%04x", PRINT_REG(planeId));
+ }
+ }
+
+ if (!deltaX && !deltaY) {
+ error("kSetScroll: Scroll has no movement");
+ }
+
+ if (deltaX && deltaY) {
+ error("kSetScroll: Cannot scroll in two dimensions");
+ }
+
+ PlaneScroll *scroll = new PlaneScroll;
+ scroll->plane = planeId;
+ scroll->x = 0;
+ scroll->y = 0;
+ scroll->deltaX = deltaX;
+ scroll->deltaY = deltaY;
+ scroll->newPictureId = pictureId;
+ scroll->animate = animate;
+ scroll->startTick = g_sci->getTickCount();
+
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeId);
+ if (plane == nullptr) {
+ error("kSetScroll: Plane %04x:%04x not found", PRINT_REG(planeId));
+ }
+
+ Plane *visiblePlane = g_sci->_gfxFrameout->getPlanes().findByObject(planeId);
+ if (visiblePlane == nullptr) {
+ error("kSetScroll: Visible plane %04x:%04x not found", PRINT_REG(planeId));
+ }
+
+ const Common::Rect &gameRect = visiblePlane->_gameRect;
+ Common::Point picOrigin;
+
+ if (deltaX) {
+ picOrigin.y = 0;
+
+ if (deltaX > 0) {
+ scroll->x = picOrigin.x = -gameRect.width();
+ } else {
+ scroll->x = picOrigin.x = gameRect.width();
+ }
+ } else {
+ picOrigin.x = 0;
+
+ if (deltaY > 0) {
+ scroll->y = picOrigin.y = -gameRect.height();
+ } else {
+ scroll->y = picOrigin.y = gameRect.height();
+ }
+ }
+
+ scroll->oldPictureId = plane->addPic(pictureId, picOrigin, mirrorX);
+
+ if (animate) {
+ _scrolls.push_front(*scroll);
+ } else {
+ bool finished = false;
+ while (!finished && !g_engine->shouldQuit()) {
+ finished = processScroll(*scroll);
+ g_sci->_gfxFrameout->frameOut(true);
+ throttle();
+ }
+ delete scroll;
+ }
+}
+
+bool GfxTransitions32::processScroll(PlaneScroll &scroll) {
+ bool finished = false;
+ uint32 now = g_sci->getTickCount();
+ if (scroll.startTick >= now) {
+ return false;
+ }
+
+ int deltaX = scroll.deltaX;
+ int deltaY = scroll.deltaY;
+ if (((scroll.x + deltaX) * scroll.y) <= 0) {
+ deltaX = -scroll.x;
+ }
+ if (((scroll.y + deltaY) * scroll.y) <= 0) {
+ deltaY = -scroll.y;
+ }
+
+ scroll.x += deltaX;
+ scroll.y += deltaY;
+
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(scroll.plane);
+
+ if ((scroll.x == 0) && (scroll.y == 0)) {
+ plane->deletePic(scroll.oldPictureId, scroll.newPictureId);
+ finished = true;
+ }
+
+ plane->scrollScreenItems(deltaX, deltaY, true);
+
+ return finished;
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/transitions32.h b/engines/sci/graphics/transitions32.h
new file mode 100644
index 0000000..3968378
--- /dev/null
+++ b/engines/sci/graphics/transitions32.h
@@ -0,0 +1,476 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCI_GRAPHICS_TRANSITIONS32_H
+#define SCI_GRAPHICS_TRANSITIONS32_H
+
+#include "common/list.h"
+#include "common/scummsys.h"
+#include "sci/engine/vm_types.h"
+
+namespace Sci {
+enum ShowStyleType /* : uint8 */ {
+ kShowStyleNone = 0,
+ kShowStyleHShutterOut = 1,
+ kShowStyleHShutterIn = 2,
+ kShowStyleVShutterOut = 3,
+ kShowStyleVShutterIn = 4,
+ kShowStyleWipeLeft = 5,
+ kShowStyleWipeRight = 6,
+ kShowStyleWipeUp = 7,
+ kShowStyleWipeDown = 8,
+ kShowStyleIrisOut = 9,
+ kShowStyleIrisIn = 10,
+ kShowStyleDissolveNoMorph = 11,
+ kShowStyleDissolve = 12,
+ kShowStyleFadeOut = 13,
+ kShowStyleFadeIn = 14,
+ kShowStyleMorph = 15
+};
+
+/**
+ * Show styles represent transitions applied to draw planes.
+ * One show style per plane can be active at a time.
+ */
+struct PlaneShowStyle {
+ /**
+ * The ID of the plane this show style belongs to.
+ * In SCI2.1mid (at least SQ6), per-plane transitions
+ * were removed and a single plane ID is used.
+ */
+ reg_t plane;
+
+ /**
+ * The type of the transition.
+ */
+ ShowStyleType type;
+
+ /**
+ * When true, the show style is an entry transition
+ * to a new room. When false, it is an exit
+ * transition away from an old room.
+ */
+ bool fadeUp;
+
+ /**
+ * The number of steps for the show style.
+ */
+ int16 divisions;
+
+ /**
+ * The color used by transitions that draw CelObjColor
+ * screen items. -1 for transitions that do not draw
+ * screen items.
+ */
+ int16 color;
+
+ // TODO: Probably uint32
+ // TODO: This field probably should be used in order to
+ // provide time-accurate processing of show styles. In the
+ // actual SCI engine (at least 2–2.1mid) it appears that
+ // style transitions are drawn “as fast as possible”, one
+ // step per loop, even though this delay field exists
+ int delay;
+
+ // TODO: Probably bool, but never seems to be true?
+ bool animate;
+
+ /**
+ * The wall time at which the next step of the animation
+ * should execute.
+ */
+ uint32 nextTick;
+
+ /**
+ * During playback of the show style, the current step
+ * (out of divisions).
+ */
+ int currentStep;
+
+ /**
+ * Whether or not this style has finished running and
+ * is ready for disposal.
+ */
+ bool processed;
+
+ //
+ // Engine specific properties for SCI2.1early
+ //
+
+ /**
+ * A list of screen items, each representing one
+ * block of a wipe transition.
+ */
+ Common::Array<ScreenItem *> screenItems;
+
+ /**
+ * For wipe transitions, the number of edges with a
+ * moving wipe (1, 2, or 4).
+ */
+ uint8 numEdges;
+
+ /**
+ * The dimensions of the plane, in game script
+ * coordinates.
+ */
+ int16 width, height;
+
+ /**
+ * For pixel dissolve transitions, the screen item
+ * used to render the transition.
+ */
+ ScreenItem *bitmapScreenItem;
+
+ /**
+ * For pixel dissolve transitions, the bitmap used
+ * to render the transition.
+ */
+ reg_t bitmap;
+
+ /**
+ * The bit mask used by pixel dissolve transitions.
+ */
+ uint32 dissolveMask;
+
+ /**
+ * The first pixel that was dissolved in a pixel
+ * dissolve transition.
+ */
+ uint32 firstPixel;
+
+ /**
+ * The last pixel that was dissolved. Once all
+ * pixels have been dissolved, `pixel` will once
+ * again equal `firstPixel`.
+ */
+ uint32 pixel;
+
+ //
+ // Engine specific properties for SCI2.1mid through SCI3
+ //
+
+ /**
+ * The number of entries in the fadeColorRanges array.
+ */
+ uint8 fadeColorRangesCount;
+
+ /**
+ * A pointer to an dynamically sized array of palette
+ * indexes, in the order [ fromColor, toColor, ... ].
+ * Only colors within this range are transitioned.
+ */
+ uint16 *fadeColorRanges;
+};
+
+/**
+ * PlaneScroll describes a transition between two different
+ * pictures within a single plane.
+ */
+struct PlaneScroll {
+ /**
+ * The ID of the plane to be scrolled.
+ */
+ reg_t plane;
+
+ /**
+ * The current position of the scroll.
+ */
+ int16 x, y;
+
+ /**
+ * The distance that should be scrolled. Only one of
+ * `deltaX` or `deltaY` may be set.
+ */
+ int16 deltaX, deltaY;
+
+ /**
+ * The pic that should be created and scrolled into
+ * view inside the plane.
+ */
+ GuiResourceId newPictureId;
+
+ /**
+ * The picture that should be scrolled out of view
+ * and deleted from the plane.
+ */
+ GuiResourceId oldPictureId;
+
+ /**
+ * If true, the scroll animation is interleaved
+ * with other updates to the graphics. If false,
+ * the scroll will be exclusively animated until
+ * it is finished.
+ */
+ bool animate;
+
+ /**
+ * The tick after which the animation will start.
+ */
+ uint32 startTick;
+};
+
+typedef Common::List<PlaneShowStyle> ShowStyleList;
+typedef Common::List<PlaneScroll> ScrollList;
+
+class GfxTransitions32 {
+public:
+ GfxTransitions32(SegManager *_segMan);
+ ~GfxTransitions32();
+private:
+ SegManager *_segMan;
+
+ /**
+ * Throttles transition playback to prevent
+ * transitions from being instant on fast
+ * computers.
+ */
+ void throttle();
+ int8 _throttleState;
+
+#pragma mark -
+#pragma mark Show styles
+public:
+ inline bool hasShowStyles() const { return !_showStyles.empty(); }
+
+ /**
+ * Processes all active show styles in a loop
+ * until they are finished.
+ */
+ void processShowStyles();
+
+ /**
+ * Processes show styles that are applied
+ * through `GfxFrameout::palMorphFrameOut`.
+ */
+ void processEffects(PlaneShowStyle &showStyle);
+
+ // NOTE: This signature is taken from SCI3 Phantasmagoria 2
+ // and is valid for all implementations of SCI32
+ void kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 direction, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen);
+
+ /**
+ * Sets the range that will be used by
+ * `GfxFrameout::palMorphFrameOut` to alter
+ * palette entries.
+ */
+ void kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor);
+
+ /**
+ * A map of palette entries that can be morphed
+ * by the Morph show style.
+ */
+ int8 _styleRanges[256];
+
+private:
+ /**
+ * Default sequence values for pixel dissolve
+ * transition bit masks.
+ */
+ int *_dissolveSequenceSeeds;
+
+ /**
+ * Default values for `PlaneShowStyle::divisions`
+ * for the current SCI version.
+ */
+ int16 *_defaultDivisions;
+
+ /**
+ * The list of PlaneShowStyles that are
+ * currently active.
+ */
+ ShowStyleList _showStyles;
+
+ /**
+ * Finds a show style that applies to the given
+ * plane.
+ */
+ PlaneShowStyle *findShowStyleForPlane(const reg_t planeObj);
+
+ /**
+ * Finds the iterator for a show style that
+ * applies to the given plane.
+ */
+ ShowStyleList::iterator findIteratorForPlane(const reg_t planeObj);
+
+ /**
+ * Deletes the given PlaneShowStyle and returns
+ * the next PlaneShowStyle from the list of
+ * styles.
+ */
+ ShowStyleList::iterator deleteShowStyle(const ShowStyleList::iterator &showStyle);
+
+ /**
+ * Initializes the given PlaneShowStyle for an
+ * iris effect for SCI2 to 2.1early.
+ */
+ void configure21EarlyIris(PlaneShowStyle &showStyle, const int16 priority);
+
+ /**
+ * Initializes the given PlaneShowStyle for a
+ * pixel dissolve effect for SCI2 to 2.1early.
+ */
+ void configure21EarlyDissolve(PlaneShowStyle &showStyle, const int16 priority, const Common::Rect &gameRect);
+
+ /**
+ * Processes one tick of the given
+ * PlaneShowStyle.
+ */
+ bool processShowStyle(PlaneShowStyle &showStyle, uint32 now);
+
+ /**
+ * Performs an instant transition between two
+ * rooms.
+ */
+ bool processNone(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with a horizontal shutter effect.
+ */
+ void processHShutterOut(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with a horizontal shutter effect.
+ */
+ void processHShutterIn(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with a vertical shutter effect.
+ */
+ void processVShutterOut(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with a vertical shutter effect.
+ */
+ void processVShutterIn(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with a wipe to the left.
+ */
+ void processWipeLeft(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with a wipe to the right.
+ */
+ void processWipeRight(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with a wipe upwards.
+ */
+ void processWipeUp(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with a wipe downwards.
+ */
+ void processWipeDown(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with an iris effect.
+ */
+ bool processIrisOut(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with an iris effect.
+ */
+ bool processIrisIn(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders between
+ * rooms using a block dissolve effect.
+ */
+ void processDissolveNoMorph(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders between
+ * rooms with a pixel dissolve effect.
+ */
+ bool processPixelDissolve(PlaneShowStyle &showStyle);
+
+ /**
+ * SCI2 to 2.1early implementation of pixel
+ * dissolve.
+ */
+ bool processPixelDissolve21Early(PlaneShowStyle &showStyle);
+
+ /**
+ * SCI2.1mid and later implementation of
+ * pixel dissolve.
+ */
+ bool processPixelDissolve21Mid(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that fades to black
+ * between rooms.
+ */
+ bool processFade(const int8 direction, PlaneShowStyle &showStyle);
+
+ /**
+ * Morph transition calls back into the
+ * transition system's `processEffects`
+ * method, which then applies transitions
+ * other than None, Fade, or Morph.
+ */
+ bool processMorph(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a generic transition for any of
+ * the wipe/shutter/iris effects.
+ */
+ bool processWipe(const int8 direction, PlaneShowStyle &showStyle);
+
+#pragma mark -
+#pragma mark Scrolls
+public:
+ inline bool hasScrolls() const { return !_scrolls.empty(); }
+
+ /**
+ * Processes all active plane scrolls
+ * in a loop until they are finished.
+ */
+ void processScrolls();
+
+ void kernelSetScroll(const reg_t plane, const int16 deltaX, const int16 deltaY, const GuiResourceId pictureId, const bool animate, const bool mirrorX);
+
+private:
+ /**
+ * A list of active plane scrolls.
+ */
+ ScrollList _scrolls;
+
+ /**
+ * Performs a scroll of the content of
+ * a plane.
+ */
+ bool processScroll(PlaneScroll &scroll);
+};
+
+} // End of namespace Sci
+#endif
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 1511356..18d97ea 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -91,6 +91,7 @@ MODULE_OBJS += \
graphics/remap32.o \
graphics/screen_item32.o \
graphics/text32.o \
+ graphics/transitions32.o \
graphics/video32.o \
sound/audio32.o \
sound/decoders/sol.o \
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 3ea2756..4c178b6 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -69,6 +69,7 @@
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/text32.h"
+#include "sci/graphics/transitions32.h"
#include "sci/graphics/video32.h"
#include "sci/sound/audio32.h"
// TODO: Move this to video32
@@ -176,6 +177,7 @@ SciEngine::~SciEngine() {
// components
delete _video32;
delete _gfxPalette32;
+ delete _gfxTransitions32;
delete _gfxFrameout;
delete _gfxRemap32;
delete _audio32;
@@ -712,6 +714,7 @@ void SciEngine::initGraphics() {
_gfxPaint32 = 0;
_gfxPalette32 = 0;
_gfxRemap32 = 0;
+ _gfxTransitions32 = 0;
#endif
if (hasMacIconBar())
@@ -741,7 +744,8 @@ void SciEngine::initGraphics() {
_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster);
_gfxPaint32 = new GfxPaint32(_gamestate->_segMan);
_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
- _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette32);
+ _gfxTransitions32 = new GfxTransitions32(_gamestate->_segMan);
+ _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette32, _gfxTransitions32);
_gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache);
_gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32);
_gfxFrameout->run();
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 0020d25..a420952 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -85,6 +85,7 @@ class RobotDecoder;
class GfxFrameout;
class Audio32;
class Video32;
+class GfxTransitions32;
#endif
// our engine debug levels
@@ -377,6 +378,7 @@ public:
Video32 *_video32;
RobotDecoder *_robotDecoder;
GfxFrameout *_gfxFrameout; // kFrameout and the like for 32-bit gfx
+ GfxTransitions32 *_gfxTransitions32;
#endif
AudioPlayer *_audio;
Commit: 0f535e79f59c24545f40d52cf0cf25a3818cfffd
https://github.com/scummvm/scummvm/commit/0f535e79f59c24545f40d52cf0cf25a3818cfffd
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-01T10:37:14-05:00
Commit Message:
SCI32: Add 6-argument signature of kAddPicAt
This is used by Torin in room 50900.
Changed paths:
engines/sci/engine/kernel_tables.h
engines/sci/engine/kgraphics32.cpp
engines/sci/graphics/frameout.cpp
engines/sci/graphics/frameout.h
engines/sci/graphics/plane32.cpp
engines/sci/graphics/plane32.h
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 7d622d1..e0e4dcc 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -823,7 +823,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL },
{ MAP_CALL(Text), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kText_subops, NULL },
- { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii", NULL, NULL },
+ { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii(i)(i)", NULL, NULL },
{ MAP_CALL(GetWindowsOption), SIG_EVERYWHERE, "i", NULL, NULL },
{ MAP_CALL(WinHelp), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(GetConfig), SIG_EVERYWHERE, "ro", NULL, NULL },
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 40c048b..44085da 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -124,8 +124,9 @@ reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) {
int16 x = argv[2].toSint16();
int16 y = argv[3].toSint16();
bool mirrorX = argc > 4 ? argv[4].toSint16() : false;
+ bool deleteDuplicate = argc > 5 ? argv[5].toSint16() : true;
- g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, x, y, mirrorX);
+ g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, x, y, mirrorX, deleteDuplicate);
return s->r_acc;
}
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index a264516..7ea159f 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -485,12 +485,12 @@ void GfxFrameout::updatePlane(Plane &plane) {
#pragma mark -
#pragma mark Pics
-void GfxFrameout::kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 x, const int16 y, const bool mirrorX) {
+void GfxFrameout::kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 x, const int16 y, const bool mirrorX, const bool deleteDuplicate) {
Plane *plane = _planes.findByObject(planeObject);
if (plane == nullptr) {
error("kAddPicAt: Plane %04x:%04x not found", PRINT_REG(planeObject));
}
- plane->addPic(pictureId, Common::Point(x, y), mirrorX);
+ plane->addPic(pictureId, Common::Point(x, y), mirrorX, deleteDuplicate);
}
#pragma mark -
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 035555a..1724ad9 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -167,7 +167,7 @@ public:
#pragma mark -
#pragma mark Pics
public:
- void kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 pictureX, const int16 pictureY, const bool mirrorX);
+ void kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 pictureX, const int16 pictureY, const bool mirrorX, const bool deleteDuplicate);
#pragma mark -
#pragma mark Rendering
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
index cb6ec74..1cd88d6 100644
--- a/engines/sci/graphics/plane32.cpp
+++ b/engines/sci/graphics/plane32.cpp
@@ -194,11 +194,12 @@ void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *p
_type = transparent ? kPlaneTypeTransparentPicture : kPlaneTypePicture;
}
-GuiResourceId Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) {
- GuiResourceId oldPictureId = _pictureId;
- deletePic(pictureId);
+GuiResourceId Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX, const bool deleteDuplicate) {
+ if (deleteDuplicate) {
+ deletePic(pictureId);
+ }
addPicInternal(pictureId, &position, mirrorX);
- return oldPictureId;
+ return _pictureId;
}
void Plane::changePic() {
diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h
index f55d97b..964d20c 100644
--- a/engines/sci/graphics/plane32.h
+++ b/engines/sci/graphics/plane32.h
@@ -347,7 +347,7 @@ public:
* new picture resource to the plane at the given
* position.
*/
- GuiResourceId addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX);
+ GuiResourceId addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX, const bool deleteDuplicate = true);
/**
* If the plane is a picture plane, re-adds all cels
Commit: 4e31c9aaf4aa36b6fea039d1779317e6a943e68b
https://github.com/scummvm/scummvm/commit/4e31c9aaf4aa36b6fea039d1779317e6a943e68b
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-01T10:37:14-05:00
Commit Message:
SCI32: Don't crash on zero-dimension show rects
In the original engine this would have simply resulted in no draw,
but ScummVM is more strict about it. It is not 100% clear whether
these are normal and should be allowed or not, so for the moment
we'll emit a warning whenever a zero-dimension show rect is seen.
For now they only seem to be generated by plane transitions, and
these zero-dimension screen items cannot simply be omitted because
the 2.1early transitions code requires a fixed number of screen
items per step.
Changed paths:
engines/sci/graphics/frameout.cpp
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 7ea159f..1decfa0 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -1143,6 +1143,13 @@ void GfxFrameout::showBits() {
byte *sourceBuffer = (byte *)_currentBuffer.getPixels() + rounded.top * _currentBuffer.screenWidth + rounded.left;
+ // TODO: Sometimes transition screen items generate zero-dimension
+ // show rectangles. Is this a bug?
+ if (rounded.width() == 0 || rounded.height() == 0) {
+ warning("Zero-dimension show rectangle ignored");
+ continue;
+ }
+
g_system->copyRectToScreen(sourceBuffer, _currentBuffer.screenWidth, rounded.left, rounded.top, rounded.width(), rounded.height());
}
Commit: 2071196f4235c75ff020605f53b3d397532e841a
https://github.com/scummvm/scummvm/commit/2071196f4235c75ff020605f53b3d397532e841a
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-01T10:37:14-05:00
Commit Message:
SCI32: Add bitmap segment and remove GC option from hunk segment
Changed paths:
engines/sci/console.cpp
engines/sci/engine/gc.cpp
engines/sci/engine/kernel.cpp
engines/sci/engine/kgraphics32.cpp
engines/sci/engine/kscripts.cpp
engines/sci/engine/savegame.cpp
engines/sci/engine/savegame.h
engines/sci/engine/seg_manager.cpp
engines/sci/engine/seg_manager.h
engines/sci/engine/segment.cpp
engines/sci/engine/segment.h
engines/sci/graphics/celobj32.cpp
engines/sci/graphics/controls32.cpp
engines/sci/graphics/paint16.cpp
engines/sci/graphics/paint32.cpp
engines/sci/graphics/paint32.h
engines/sci/graphics/palette.cpp
engines/sci/graphics/text32.cpp
engines/sci/graphics/text32.h
engines/sci/graphics/transitions32.cpp
engines/sci/graphics/video32.cpp
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 6acb467..3e67a18 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -1984,7 +1984,7 @@ bool Console::cmdShowSavedBits(int argc, const char **argv) {
byte bakMask = GFX_SCREEN_MASK_VISUAL | GFX_SCREEN_MASK_PRIORITY | GFX_SCREEN_MASK_CONTROL;
int bakSize = _engine->_gfxScreen->bitsGetDataSize(rect, bakMask);
- reg_t bakScreen = segman->allocateHunkEntry("show_saved_bits backup", bakSize, true);
+ reg_t bakScreen = segman->allocateHunkEntry("show_saved_bits backup", bakSize);
byte* bakMemory = segman->getHunkPointer(bakScreen);
assert(bakMemory);
_engine->_gfxScreen->bitsSave(rect, bakMask, bakMemory);
@@ -2080,6 +2080,10 @@ bool Console::cmdPrintSegmentTable(int argc, const char **argv) {
case SEG_TYPE_STRING:
debugPrintf("T SCI32 strings (%d)", (*(StringTable *)mobj).entries_used);
break;
+
+ case SEG_TYPE_BITMAP:
+ debugPrintf("T SCI32 bitmaps (%d)", (*(BitmapTable *)mobj).entries_used);
+ break;
#endif
default:
@@ -2214,6 +2218,9 @@ bool Console::segmentInfo(int nr) {
case SEG_TYPE_ARRAY:
debugPrintf("SCI32 arrays\n");
break;
+ case SEG_TYPE_BITMAP:
+ debugPrintf("SCI32 bitmaps\n");
+ break;
#endif
default :
@@ -2815,6 +2822,12 @@ bool Console::cmdViewReference(int argc, const char **argv) {
hexDumpReg(array->getRawData(), array->getSize(), 4, 0, true);
break;
}
+ case SEG_TYPE_BITMAP: {
+ debugPrintf("SCI32 bitmap:\n");
+ const SciBitmap *bitmap = _engine->_gamestate->_segMan->lookupBitmap(reg);
+ Common::hexdump((const byte *) bitmap->getRawData(), bitmap->getRawSize(), 16, 0);
+ break;
+ }
#endif
default: {
const SegmentRef block = _engine->_gamestate->_segMan->dereference(reg);
diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp
index e0467e9..ad4fd19 100644
--- a/engines/sci/engine/gc.cpp
+++ b/engines/sci/engine/gc.cpp
@@ -154,16 +154,18 @@ AddrSet *findAllActiveReferences(EngineState *s) {
}
}
- // Init: Explicitly opted-out hunks
- else if (heap[i]->getType() == SEG_TYPE_HUNK) {
- HunkTable *ht = static_cast<HunkTable *>(heap[i]);
+#ifdef ENABLE_SCI32
+ // Init: Explicitly opted-out bitmaps
+ else if (heap[i]->getType() == SEG_TYPE_BITMAP) {
+ BitmapTable *bt = static_cast<BitmapTable *>(heap[i]);
- for (uint j = 0; j < ht->_table.size(); j++) {
- if (!ht->_table[j].data.gc) {
+ for (uint j = 0; j < bt->_table.size(); j++) {
+ if (!bt->_table[j].data.getShouldGC()) {
wm.push(make_reg(i, j));
}
}
}
+#endif
}
}
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 2afb8b7..d764a88 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -408,6 +408,7 @@ uint16 Kernel::findRegType(reg_t reg) {
#ifdef ENABLE_SCI32
case SEG_TYPE_ARRAY:
case SEG_TYPE_STRING:
+ case SEG_TYPE_BITMAP:
#endif
result |= SIG_TYPE_REFERENCE;
break;
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 44085da..e458109 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -536,13 +536,14 @@ reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) {
int16 scaledHeight = argc > 5 ? argv[5].toSint16() : g_sci->_gfxText32->_scaledHeight;
bool useRemap = argc > 6 ? argv[6].toSint16() : false;
- BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap, true);
+ reg_t bitmapId;
+ SciBitmap &bitmap = *s->_segMan->allocateBitmap(&bitmapId, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap, true);
memset(bitmap.getPixels(), backColor, width * height);
- return bitmap.getObject();
+ return bitmapId;
}
reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) {
- s->_segMan->freeHunkEntry(argv[0]);
+ s->_segMan->freeBitmap(argv[0]);
return s->r_acc;
}
@@ -552,7 +553,7 @@ reg_t kBitmapDrawLine(EngineState *s, int argc, reg_t *argv) {
}
reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv) {
- BitmapResource bitmap(argv[0]);
+ SciBitmap &bitmap = *s->_segMan->lookupBitmap(argv[0]);
CelObjView view(argv[1].toUint16(), argv[2].toSint16(), argv[3].toSint16());
const int16 x = argc > 4 ? argv[4].toSint16() : 0;
@@ -582,7 +583,7 @@ reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv) {
reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
// called e.g. from TextButton::createBitmap() in Torin's Passage, script 64894
- BitmapResource bitmap(argv[0]);
+ SciBitmap &bitmap = *s->_segMan->lookupBitmap(argv[0]);
Common::String text = s->_segMan->getString(argv[1]);
Common::Rect textRect(
argv[2].toSint16(),
@@ -609,7 +610,7 @@ reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false, false);
CelObjMem textCel(textBitmapObject);
textCel.draw(bitmap.getBuffer(), textRect, Common::Point(textRect.left, textRect.top), false);
- s->_segMan->freeHunkEntry(textBitmapObject);
+ s->_segMan->freeBitmap(textBitmapObject);
return s->r_acc;
}
@@ -617,7 +618,7 @@ reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv) {
// called e.g. from TextView::init() and TextView::draw() in Torin's Passage, script 64890
- BitmapResource bitmap(argv[0]);
+ SciBitmap &bitmap = *s->_segMan->lookupBitmap(argv[0]);
Common::Rect fillRect(
argv[1].toSint16(),
argv[2].toSint16(),
@@ -642,7 +643,7 @@ reg_t kBitmapInvert(EngineState *s, int argc, reg_t *argv) {
}
reg_t kBitmapSetDisplace(EngineState *s, int argc, reg_t *argv) {
- BitmapResource bitmap(argv[0]);
+ SciBitmap &bitmap = *s->_segMan->lookupBitmap(argv[0]);
bitmap.setDisplace(Common::Point(argv[1].toSint16(), argv[2].toSint16()));
return s->r_acc;
}
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 42e7a20..6fd130b 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -40,7 +40,7 @@ reg_t kLoad(EngineState *s, int argc, reg_t *argv) {
// Request to dynamically allocate hunk memory for later use
if (restype == kResourceTypeMemory)
- return s->_segMan->allocateHunkEntry("kLoad()", resnr, true);
+ return s->_segMan->allocateHunkEntry("kLoad()", resnr);
return make_reg(0, ((restype << 11) | resnr)); // Return the resource identifier as handle
}
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 31fb848..f49853d 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -158,6 +158,18 @@ void syncWithSerializer(Common::Serializer &s, SciString &obj) {
obj.setValue(i, value);
}
}
+
+void syncWithSerializer(Common::Serializer &s, SciBitmap &obj) {
+ debug("TODO: Sync bitmap");
+
+// if (s.isSaving()) {
+// size = obj.getSize();
+// s.syncAsUint32LE(size);
+// } else {
+// s.syncAsUint32LE(size);
+// obj.setSize(size);
+// }
+}
#endif
#pragma mark -
@@ -273,6 +285,8 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
} else if (type == SEG_TYPE_STRING) {
// Set the correct segment for SCI32 strings
_stringSegId = i;
+ } else if (s.getVersion() >= 36 && type == SEG_TYPE_BITMAP) {
+ _bitmapSegId = i;
#endif
}
@@ -687,6 +701,14 @@ void StringTable::saveLoadWithSerializer(Common::Serializer &ser) {
sync_Table<StringTable>(ser, *this);
}
+
+void BitmapTable::saveLoadWithSerializer(Common::Serializer &ser) {
+ if (ser.getVersion() < 36)
+ return;
+
+ // TODO: Should only include bitmaps with gc = true
+ sync_Table(ser, *this);
+}
#endif
void GfxPalette::palVarySaveLoadPalette(Common::Serializer &s, Palette *palette) {
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index 43909ac..c5c2bce 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -37,6 +37,7 @@ struct EngineState;
*
* Version - new/changed feature
* =============================
+ * 36 - SCI32 bitmap segment
* 35 - SCI32 remap
* 34 - SCI32 palettes, and store play time in ticks
* 33 - new overridePriority flag in MusicEntry
@@ -60,7 +61,7 @@ struct EngineState;
*/
enum {
- CURRENT_SAVEGAME_VERSION = 35,
+ CURRENT_SAVEGAME_VERSION = 36,
MINIMUM_SAVEGAME_VERSION = 14
};
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index e669206..67da4c8 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -43,6 +43,7 @@ SegManager::SegManager(ResourceManager *resMan, ScriptPatcher *scriptPatcher)
#ifdef ENABLE_SCI32
_arraysSegId = 0;
_stringSegId = 0;
+ _bitmapSegId = 0;
#endif
createClassTable();
@@ -72,6 +73,7 @@ void SegManager::resetSegMan() {
#ifdef ENABLE_SCI32
_arraysSegId = 0;
_stringSegId = 0;
+ _bitmapSegId = 0;
#endif
// Reinitialize class table
@@ -393,7 +395,7 @@ void SegManager::freeHunkEntry(reg_t addr) {
ht->freeEntryContents(addr.getOffset());
}
-reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size, bool gc) {
+reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size) {
HunkTable *table;
int offset;
@@ -412,7 +414,6 @@ reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size, bool gc) {
h->mem = malloc(size);
h->size = size;
h->type = hunk_type;
- h->gc = gc;
return addr;
}
@@ -942,6 +943,60 @@ void SegManager::freeString(reg_t addr) {
stringTable.freeEntry(addr.getOffset());
}
+#pragma mark -
+#pragma mark Bitmaps
+
+SciBitmap *SegManager::allocateBitmap(reg_t *addr, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 paletteSize, const bool remap, const bool gc) {
+ BitmapTable *table;
+ int offset;
+
+ if (!_bitmapSegId) {
+ table = (BitmapTable *)allocSegment(new BitmapTable(), &(_bitmapSegId));
+ } else {
+ table = (BitmapTable *)_heap[_bitmapSegId];
+ }
+
+ offset = table->allocEntry();
+
+ *addr = make_reg(_bitmapSegId, offset);
+ SciBitmap *bitmap = &table->at(offset);
+
+ if (bitmap == nullptr) {
+ *addr = NULL_REG;
+ }
+
+ bitmap->create(width, height, skipColor, displaceX, displaceY, scaledWidth, scaledHeight, paletteSize, remap, gc);
+
+ return bitmap;
+}
+
+SciBitmap *SegManager::lookupBitmap(const reg_t addr) {
+ if (_heap[addr.getSegment()]->getType() != SEG_TYPE_BITMAP)
+ error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
+
+ BitmapTable &bitmapTable = *(BitmapTable *)_heap[addr.getSegment()];
+
+ if (!bitmapTable.isValidEntry(addr.getOffset()))
+ error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
+
+ return &(bitmapTable.at(addr.getOffset()));
+}
+
+void SegManager::freeBitmap(const reg_t addr) {
+ if (_heap[addr.getSegment()]->getType() != SEG_TYPE_BITMAP)
+ error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
+
+ BitmapTable &bitmapTable = *(BitmapTable *)_heap[addr.getSegment()];
+
+ if (!bitmapTable.isValidEntry(addr.getOffset()))
+ error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
+
+ bitmapTable.at(addr.getOffset()).destroy();
+ bitmapTable.freeEntry(addr.getOffset());
+}
+
+#pragma mark -
+
#endif
void SegManager::createClassTable() {
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index ba2ba33..acebece 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -29,6 +29,10 @@
#include "sci/engine/vm.h"
#include "sci/engine/vm_types.h"
#include "sci/engine/segment.h"
+#ifdef ENABLE_SCI32
+// TODO: Baaaad?
+#include "sci/graphics/celobj32.h"
+#endif
namespace Sci {
@@ -225,11 +229,9 @@ public:
* @param[in] size Number of bytes to allocate for the hunk entry
* @param[in] hunk_type A descriptive string for the hunk entry, for
* debugging purposes
- * @param[in] gc Whether to make the hunk eligible for garbage
- * collection
* @return The offset of the freshly allocated hunk entry
*/
- reg_t allocateHunkEntry(const char *hunk_type, int size, bool gc);
+ reg_t allocateHunkEntry(const char *hunk_type, int size);
/**
* Deallocates a hunk entry
@@ -435,10 +437,15 @@ public:
SciArray<reg_t> *allocateArray(reg_t *addr);
SciArray<reg_t> *lookupArray(reg_t addr);
void freeArray(reg_t addr);
+
SciString *allocateString(reg_t *addr);
SciString *lookupString(reg_t addr);
void freeString(reg_t addr);
SegmentId getStringSegmentId() { return _stringSegId; }
+
+ SciBitmap *allocateBitmap(reg_t *addr, const int16 width, const int16 height, const uint8 skipColor = kDefaultSkipColor, const int16 displaceX = 0, const int16 displaceY = 0, const int16 scaledWidth = kLowResX, const int16 scaledHeight = kLowResY, const uint32 paletteSize = 0, const bool remap = false, const bool gc = true);
+ SciBitmap *lookupBitmap(reg_t addr);
+ void freeBitmap(reg_t addr);
#endif
const Common::Array<SegmentObj *> &getSegments() const { return _heap; }
@@ -464,6 +471,7 @@ private:
#ifdef ENABLE_SCI32
SegmentId _arraysSegId;
SegmentId _stringSegId;
+ SegmentId _bitmapSegId;
#endif
public:
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index 2cff799..7f690cb 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -70,6 +70,9 @@ SegmentObj *SegmentObj::createSegmentObj(SegmentType type) {
case SEG_TYPE_STRING:
mem = new StringTable();
break;
+ case SEG_TYPE_BITMAP:
+ mem = new BitmapTable();
+ break;
#endif
default:
error("Unknown SegmentObj type %d", type);
@@ -310,6 +313,17 @@ SegmentRef StringTable::dereference(reg_t pointer) {
return ret;
}
+#pragma mark -
+#pragma mark Bitmaps
+
+SegmentRef BitmapTable::dereference(reg_t pointer) {
+ SegmentRef ret;
+ ret.isRaw = true;
+ ret.maxSize = at(pointer.getOffset()).getRawSize();
+ ret.raw = at(pointer.getOffset()).getRawData();
+ return ret;
+}
+
#endif
} // End of namespace Sci
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 6c94c24..c25ede1 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -71,6 +71,7 @@ enum SegmentType {
#ifdef ENABLE_SCI32
SEG_TYPE_ARRAY = 11,
SEG_TYPE_STRING = 12,
+ SEG_TYPE_BITMAP = 13,
#endif
SEG_TYPE_MAX // For sanity checking
@@ -205,7 +206,6 @@ struct Hunk {
void *mem;
uint32 size;
const char *type;
- bool gc;
};
template<typename T>
@@ -520,6 +520,244 @@ struct StringTable : public SegmentObjTable<SciString> {
SegmentRef dereference(reg_t pointer);
};
+#pragma mark -
+#pragma mark Bitmaps
+
+enum {
+ kDefaultSkipColor = 250
+};
+
+#define BITMAP_PROPERTY(size, property, offset)\
+inline uint##size get##property() const {\
+ return READ_SCI11ENDIAN_UINT##size(_data + (offset));\
+}\
+inline void set##property(uint##size value) {\
+ WRITE_SCI11ENDIAN_UINT##size(_data + (offset), (value));\
+}
+
+/**
+ * A convenience class for creating and modifying in-memory
+ * bitmaps.
+ */
+class SciBitmap {
+ byte *_data;
+ int _dataSize;
+ Buffer _buffer;
+ bool _gc;
+
+public:
+ enum BitmapFlags {
+ kBitmapRemap = 2
+ };
+
+ /**
+ * Gets the size of the bitmap header for the current
+ * engine version.
+ */
+ static inline uint16 getBitmapHeaderSize() {
+ // TODO: These values are accurate for each engine, but there may be no reason
+ // to not simply just always use size 40, since SCI2.1mid does not seem to
+ // actually store any data above byte 40, and SCI2 did not allow bitmaps with
+ // scaling resolutions other than the default (320x200). Perhaps SCI3 used
+ // the extra bytes, or there is some reason why they tried to align the header
+ // size with other headers like pic headers?
+// uint32 bitmapHeaderSize;
+// if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
+// bitmapHeaderSize = 46;
+// } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) {
+// bitmapHeaderSize = 40;
+// } else {
+// bitmapHeaderSize = 36;
+// }
+// return bitmapHeaderSize;
+ return 46;
+ }
+
+ /**
+ * Gets the byte size of a bitmap with the given width
+ * and height.
+ */
+ static inline uint32 getBitmapSize(const uint16 width, const uint16 height) {
+ return width * height + getBitmapHeaderSize();
+ }
+
+ inline SciBitmap() : _data(nullptr), _dataSize(0), _gc(true) {}
+
+ /**
+ * Allocates and initialises a new bitmap.
+ */
+ inline void create(const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 paletteSize, const bool remap, const bool gc) {
+
+ _dataSize = getBitmapSize(width, height) + paletteSize;
+ _data = (byte *)realloc(_data, _dataSize);
+ _gc = gc;
+
+ const uint16 bitmapHeaderSize = getBitmapHeaderSize();
+
+ setWidth(width);
+ setHeight(height);
+ setDisplace(Common::Point(displaceX, displaceY));
+ setSkipColor(skipColor);
+ _data[9] = 0;
+ WRITE_SCI11ENDIAN_UINT16(_data + 10, 0);
+ setRemap(remap);
+ setDataSize(width * height);
+ WRITE_SCI11ENDIAN_UINT32(_data + 16, 0);
+ setHunkPaletteOffset(paletteSize > 0 ? (width * height) : 0);
+ setDataOffset(bitmapHeaderSize);
+ setUncompressedDataOffset(bitmapHeaderSize);
+ setControlOffset(0);
+ setScaledWidth(scaledWidth);
+ setScaledHeight(scaledHeight);
+
+ _buffer = Buffer(getWidth(), getHeight(), getPixels());
+ }
+
+ inline void destroy() {
+ free(_data);
+ _data = nullptr;
+ _dataSize = 0;
+ }
+
+ inline int getRawSize() const {
+ return _dataSize;
+ }
+
+ inline byte *getRawData() const {
+ return _data;
+ }
+
+ inline Buffer &getBuffer() {
+ return _buffer;
+ }
+
+ inline bool getShouldGC() const {
+ return _gc;
+ }
+
+ inline void enableGC() {
+ _gc = true;
+ }
+
+ inline void disableGC() {
+ _gc = false;
+ }
+
+ BITMAP_PROPERTY(16, Width, 0);
+ BITMAP_PROPERTY(16, Height, 2);
+
+ inline Common::Point getDisplace() const {
+ return Common::Point(
+ (int16)READ_SCI11ENDIAN_UINT16(_data + 4),
+ (int16)READ_SCI11ENDIAN_UINT16(_data + 6)
+ );
+ }
+
+ inline void setDisplace(const Common::Point &displace) {
+ WRITE_SCI11ENDIAN_UINT16(_data + 4, (uint16)displace.x);
+ WRITE_SCI11ENDIAN_UINT16(_data + 6, (uint16)displace.y);
+ }
+
+ inline uint8 getSkipColor() const {
+ return _data[8];
+ }
+
+ inline void setSkipColor(const uint8 skipColor) {
+ _data[8] = skipColor;
+ }
+
+ inline bool getRemap() const {
+ return READ_SCI11ENDIAN_UINT16(_data + 10) & kBitmapRemap;
+ }
+
+ inline void setRemap(const bool remap) {
+ uint16 flags = READ_SCI11ENDIAN_UINT16(_data + 10);
+ if (remap) {
+ flags |= kBitmapRemap;
+ } else {
+ flags &= ~kBitmapRemap;
+ }
+ WRITE_SCI11ENDIAN_UINT16(_data + 10, flags);
+ }
+
+ BITMAP_PROPERTY(32, DataSize, 12);
+
+ inline uint32 getHunkPaletteOffset() const {
+ return READ_SCI11ENDIAN_UINT32(_data + 20);
+ }
+
+ inline void setHunkPaletteOffset(uint32 hunkPaletteOffset) {
+ if (hunkPaletteOffset) {
+ hunkPaletteOffset += getBitmapHeaderSize();
+ }
+
+ WRITE_SCI11ENDIAN_UINT32(_data + 20, hunkPaletteOffset);
+ }
+
+ BITMAP_PROPERTY(32, DataOffset, 24);
+
+ // NOTE: This property is used as a "magic number" for
+ // validating that a block of memory is a valid bitmap,
+ // and so is always set to the size of the header.
+ BITMAP_PROPERTY(32, UncompressedDataOffset, 28);
+
+ // NOTE: This property always seems to be zero
+ BITMAP_PROPERTY(32, ControlOffset, 32);
+
+ inline uint16 getScaledWidth() const {
+ if (getDataOffset() >= 40) {
+ return READ_SCI11ENDIAN_UINT16(_data + 36);
+ }
+
+ // SCI2 bitmaps did not have scaling ability
+ return 320;
+ }
+
+ inline void setScaledWidth(uint16 scaledWidth) {
+ if (getDataOffset() >= 40) {
+ WRITE_SCI11ENDIAN_UINT16(_data + 36, scaledWidth);
+ }
+ }
+
+ inline uint16 getScaledHeight() const {
+ if (getDataOffset() >= 40) {
+ return READ_SCI11ENDIAN_UINT16(_data + 38);
+ }
+
+ // SCI2 bitmaps did not have scaling ability
+ return 200;
+ }
+
+ inline void setScaledHeight(uint16 scaledHeight) {
+ if (getDataOffset() >= 40) {
+ WRITE_SCI11ENDIAN_UINT16(_data + 38, scaledHeight);
+ }
+ }
+
+ inline byte *getPixels() {
+ return _data + getUncompressedDataOffset();
+ }
+
+ inline byte *getHunkPalette() {
+ if (getHunkPaletteOffset() == 0) {
+ return nullptr;
+ }
+ return _data + getHunkPaletteOffset();
+ }
+};
+
+struct BitmapTable : public SegmentObjTable<SciBitmap> {
+ BitmapTable() : SegmentObjTable<SciBitmap>(SEG_TYPE_BITMAP) {}
+
+ virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {
+ at(sub_addr.getOffset()).destroy();
+ freeEntry(sub_addr.getOffset());
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &ser);
+ SegmentRef dereference(reg_t pointer);
+};
+
#endif
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index a3dcbbb..311684d 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -1088,7 +1088,7 @@ CelObjMem::CelObjMem(const reg_t bitmapObject) {
_celHeaderOffset = 0;
_transparent = true;
- BitmapResource bitmap(bitmapObject);
+ SciBitmap &bitmap = *g_sci->getEngineState()->_segMan->lookupBitmap(bitmapObject);
_width = bitmap.getWidth();
_height = bitmap.getHeight();
_displace = bitmap.getDisplace();
@@ -1104,7 +1104,7 @@ CelObjMem *CelObjMem::duplicate() const {
}
byte *CelObjMem::getResPointer() const {
- return g_sci->getEngineState()->_segMan->getHunkPointer(_info.bitmap);
+ return g_sci->getEngineState()->_segMan->lookupBitmap(_info.bitmap)->getRawData();
}
#pragma mark -
diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp
index 639a35c..7689655 100644
--- a/engines/sci/graphics/controls32.cpp
+++ b/engines/sci/graphics/controls32.cpp
@@ -309,7 +309,7 @@ reg_t GfxControls32::kernelEditText(const reg_t controlObject) {
g_sci->_gfxFrameout->frameOut(true);
}
- _segMan->freeHunkEntry(editor.bitmap);
+ _segMan->freeBitmap(editor.bitmap);
if (textChanged) {
editor.text.trim();
@@ -419,7 +419,7 @@ ScrollWindow::ScrollWindow(SegManager *segMan, const Common::Rect &gameRect, con
}
ScrollWindow::~ScrollWindow() {
- _segMan->freeHunkEntry(_bitmap);
+ _segMan->freeBitmap(_bitmap);
// _screenItem will be deleted by GfxFrameout
}
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index 4517659..6004e9c 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -334,7 +334,7 @@ reg_t GfxPaint16::bitsSave(const Common::Rect &rect, byte screenMask) {
// now actually ask _screen how much space it will need for saving
size = _screen->bitsGetDataSize(workerRect, screenMask);
- memoryId = _segMan->allocateHunkEntry("SaveBits()", size, true);
+ memoryId = _segMan->allocateHunkEntry("SaveBits()", size);
memoryPtr = _segMan->getHunkPointer(memoryId);
if (memoryPtr)
_screen->bitsSave(workerRect, screenMask, memoryPtr);
diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp
index 8a9d9b9..338b709 100644
--- a/engines/sci/graphics/paint32.cpp
+++ b/engines/sci/graphics/paint32.cpp
@@ -37,11 +37,12 @@ reg_t GfxPaint32::kernelAddLine(const reg_t planeObject, const Common::Point &st
}
Common::Rect gameRect;
- BitmapResource bitmap = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
+ reg_t bitmapId = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
+ SciBitmap &bitmap = *_segMan->lookupBitmap(bitmapId);
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
- celInfo.bitmap = bitmap.getObject();
+ celInfo.bitmap = bitmapId;
// SSCI stores the line color on `celInfo`, even though
// this is not a `kCelTypeColor`, as a hack so that
// `kUpdateLine` can get the originally used color
@@ -59,10 +60,10 @@ reg_t GfxPaint32::kernelAddLine(const reg_t planeObject, const Common::Point &st
void GfxPaint32::kernelUpdateLine(ScreenItem *screenItem, Plane *plane, const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness) {
Common::Rect gameRect;
- BitmapResource bitmap = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
+ reg_t bitmapId = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
- _segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
- screenItem->_celInfo.bitmap = bitmap.getObject();
+ _segMan->freeBitmap(screenItem->_celInfo.bitmap);
+ screenItem->_celInfo.bitmap = bitmapId;
screenItem->_celInfo.color = color;
screenItem->_position = startPoint;
screenItem->_priority = priority;
@@ -80,7 +81,7 @@ void GfxPaint32::kernelDeleteLine(const reg_t screenItemObject, const reg_t plan
return;
}
- _segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
+ _segMan->freeBitmap(screenItem->_celInfo.bitmap);
g_sci->_gfxFrameout->deleteScreenItem(*screenItem, *plane);
}
@@ -116,7 +117,7 @@ void GfxPaint32::plotter(int x, int y, int color, void *data) {
}
}
-BitmapResource GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, uint16 pattern, uint8 thickness, Common::Rect &outRect) {
+reg_t GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, uint16 pattern, uint8 thickness, Common::Rect &outRect) {
const uint8 skipColor = color != kDefaultSkipColor ? kDefaultSkipColor : 0;
// Thickness is expected to be 2n+1
@@ -128,7 +129,8 @@ BitmapResource GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const
outRect.right = (startPoint.x > endPoint.x ? startPoint.x : endPoint.x) + halfThickness + 1;
outRect.bottom = (startPoint.y > endPoint.y ? startPoint.y : endPoint.y) + halfThickness + 1;
- BitmapResource bitmap(_segMan, outRect.width(), outRect.height(), skipColor, 0, 0, g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, 0, false, true);
+ reg_t bitmapId;
+ SciBitmap &bitmap = *_segMan->allocateBitmap(&bitmapId, outRect.width(), outRect.height(), skipColor, 0, 0, g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, 0, false, true);
byte *pixels = bitmap.getPixels();
memset(pixels, skipColor, bitmap.getWidth() * bitmap.getHeight());
@@ -174,7 +176,7 @@ BitmapResource GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const
Graphics::drawThickLine2(drawRect.left, drawRect.top, drawRect.right, drawRect.bottom, thickness, color, plotter, &properties);
}
- return bitmap;
+ return bitmapId;
}
diff --git a/engines/sci/graphics/paint32.h b/engines/sci/graphics/paint32.h
index 6d5a957..3c3b7b4 100644
--- a/engines/sci/graphics/paint32.h
+++ b/engines/sci/graphics/paint32.h
@@ -24,8 +24,8 @@
#define SCI_GRAPHICS_PAINT32_H
namespace Sci {
-class BitmapResource;
class Plane;
+class SciBitmap;
class ScreenItem;
class SegManager;
@@ -54,7 +54,7 @@ public:
private:
typedef struct {
- BitmapResource *bitmap;
+ SciBitmap *bitmap;
bool pattern[16];
uint8 patternIndex;
bool solid;
@@ -64,7 +64,7 @@ private:
static void plotter(int x, int y, int color, void *data);
- BitmapResource makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness, Common::Rect &outRect);
+ reg_t makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness, Common::Rect &outRect);
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index a26c92c..1514ad8 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -626,7 +626,7 @@ void GfxPalette::kernelAnimateSet() {
reg_t GfxPalette::kernelSave() {
SegManager *segMan = g_sci->getEngineState()->_segMan;
- reg_t memoryId = segMan->allocateHunkEntry("kPalette(save)", 1024, true);
+ reg_t memoryId = segMan->allocateHunkEntry("kPalette(save)", 1024);
byte *memoryPtr = segMan->getHunkPointer(memoryId);
if (memoryPtr) {
for (int colorNr = 0; colorNr < 256; colorNr++) {
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index d612ddb..f81d509 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -96,8 +96,7 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
_textRect = Common::Rect();
}
- BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
- _bitmap = bitmap.getObject();
+ _segMan->allocateBitmap(&_bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
erase(bitmapRect, false);
@@ -135,8 +134,7 @@ reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &
_textRect = Common::Rect();
}
- BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
- _bitmap = bitmap.getObject();
+ SciBitmap &bitmap = *_segMan->allocateBitmap(&_bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
// NOTE: The engine filled the bitmap pixels with 11 here, which is silly
// because then it just erased the bitmap using the skip color. So we don't
@@ -180,8 +178,8 @@ void GfxText32::setFont(const GuiResourceId fontId) {
void GfxText32::drawFrame(const Common::Rect &rect, const int16 size, const uint8 color, const bool doScaling) {
Common::Rect targetRect = doScaling ? scaleRect(rect) : rect;
- byte *bitmap = _segMan->getHunkPointer(_bitmap);
- byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28) + rect.top * _width + rect.left;
+ SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap);
+ byte *pixels = bitmap.getPixels() + rect.top * _width + rect.left;
// NOTE: Not fully disassembled, but this should be right
int16 rectWidth = targetRect.width();
@@ -210,8 +208,8 @@ void GfxText32::drawFrame(const Common::Rect &rect, const int16 size, const uint
}
void GfxText32::drawChar(const char charIndex) {
- byte *bitmap = _segMan->getHunkPointer(_bitmap);
- byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28);
+ SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap);
+ byte *pixels = bitmap.getPixels();
_font->drawToBuffer(charIndex, _drawPosition.y, _drawPosition.x, _foreColor, _dimmed, pixels, _width, _height);
_drawPosition.x += _font->getCharWidth(charIndex);
@@ -328,14 +326,14 @@ void GfxText32::drawText(const uint index, uint length) {
}
}
-void GfxText32::invertRect(const reg_t bitmap, int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling) {
+void GfxText32::invertRect(const reg_t bitmapId, int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling) {
Common::Rect targetRect = rect;
if (doScaling) {
bitmapStride = bitmapStride * _scaledWidth / g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
targetRect = scaleRect(rect);
}
- byte *bitmapData = _segMan->getHunkPointer(bitmap);
+ SciBitmap &bitmap = *_segMan->lookupBitmap(bitmapId);
// NOTE: SCI code is super weird here; it seems to be trying to look at the
// entire size of the bitmap including the header, instead of just the pixel
@@ -345,14 +343,14 @@ void GfxText32::invertRect(const reg_t bitmap, int16 bitmapStride, const Common:
// function was never updated to match? Or maybe they exploit the
// configurable stride length somewhere else to do stair stepping inverts...
uint32 invertSize = targetRect.height() * bitmapStride + targetRect.width();
- uint32 bitmapSize = READ_SCI11ENDIAN_UINT32(bitmapData + 12);
+ uint32 bitmapSize = bitmap.getDataSize();
if (invertSize >= bitmapSize) {
error("InvertRect too big: %u >= %u", invertSize, bitmapSize);
}
// NOTE: Actual engine just added the bitmap header size hardcoded here
- byte *pixel = bitmapData + READ_SCI11ENDIAN_UINT32(bitmapData + 28) + bitmapStride * targetRect.top + targetRect.left;
+ byte *pixel = bitmap.getPixels() + bitmapStride * targetRect.top + targetRect.left;
int16 stride = bitmapStride - targetRect.width();
int16 targetHeight = targetRect.height();
@@ -615,7 +613,7 @@ Common::Rect GfxText32::getTextSize(const Common::String &text, int16 maxWidth,
void GfxText32::erase(const Common::Rect &rect, const bool doScaling) {
Common::Rect targetRect = doScaling ? scaleRect(rect) : rect;
- BitmapResource bitmap(_bitmap);
+ SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap);
bitmap.getBuffer().fillRect(targetRect, _backColor);
}
@@ -652,7 +650,7 @@ int16 GfxText32::getTextCount(const Common::String &text, const uint index, cons
}
void GfxText32::scrollLine(const Common::String &lineText, int numLines, uint8 color, TextAlign align, GuiResourceId fontId, ScrollDirection dir) {
- BitmapResource bmr(_bitmap);
+ SciBitmap &bmr = *_segMan->lookupBitmap(_bitmap);
byte *pixels = bmr.getPixels();
int h = _font->getHeight();
diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h
index 4092156..44bd48a 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -42,210 +42,6 @@ enum ScrollDirection {
kScrollDown
};
-enum BitmapFlags {
- kBitmapRemap = 2
-};
-
-enum {
- kDefaultSkipColor = 250
-};
-
-#define BITMAP_PROPERTY(size, property, offset)\
-inline uint##size get##property() const {\
- return READ_SCI11ENDIAN_UINT##size(_bitmap + (offset));\
-}\
-inline void set##property(uint##size value) {\
- WRITE_SCI11ENDIAN_UINT##size(_bitmap + (offset), (value));\
-}
-
-/**
- * A convenience class for creating and modifying in-memory
- * bitmaps.
- */
-class BitmapResource {
- byte *_bitmap;
- reg_t _object;
- Buffer _buffer;
-
- /**
- * Gets the size of the bitmap header for the current
- * engine version.
- */
- static inline uint16 getBitmapHeaderSize() {
- // TODO: These values are accurate for each engine, but there may be no reason
- // to not simply just always use size 40, since SCI2.1mid does not seem to
- // actually store any data above byte 40, and SCI2 did not allow bitmaps with
- // scaling resolutions other than the default (320x200). Perhaps SCI3 used
- // the extra bytes, or there is some reason why they tried to align the header
- // size with other headers like pic headers?
-// uint32 bitmapHeaderSize;
-// if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
-// bitmapHeaderSize = 46;
-// } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) {
-// bitmapHeaderSize = 40;
-// } else {
-// bitmapHeaderSize = 36;
-// }
-// return bitmapHeaderSize;
- return 46;
- }
-
- /**
- * Gets the byte size of a bitmap with the given width
- * and height.
- */
- static inline uint32 getBitmapSize(const uint16 width, const uint16 height) {
- return width * height + getBitmapHeaderSize();
- }
-
-public:
- /**
- * Create a bitmap resource for an existing bitmap.
- * Ownership of the bitmap is retained by the caller.
- */
- inline BitmapResource(reg_t bitmap) :
- _bitmap(g_sci->getEngineState()->_segMan->getHunkPointer(bitmap)),
- _object(bitmap) {
- if (_bitmap == nullptr || getUncompressedDataOffset() != getBitmapHeaderSize()) {
- error("Invalid Text bitmap %04x:%04x", PRINT_REG(bitmap));
- }
-
- _buffer = Buffer(getWidth(), getHeight(), getPixels());
- }
-
- /**
- * Allocates and initialises a new bitmap in the given
- * segment manager.
- */
- inline BitmapResource(SegManager *segMan, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 paletteSize, const bool remap, const bool gc) {
- _object = segMan->allocateHunkEntry("Bitmap()", getBitmapSize(width, height) + paletteSize, gc);
- _bitmap = segMan->getHunkPointer(_object);
-
- const uint16 bitmapHeaderSize = getBitmapHeaderSize();
-
- setWidth(width);
- setHeight(height);
- setDisplace(Common::Point(displaceX, displaceY));
- setSkipColor(skipColor);
- _bitmap[9] = 0;
- WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, 0);
- setRemap(remap);
- setDataSize(width * height);
- WRITE_SCI11ENDIAN_UINT32(_bitmap + 16, 0);
- setHunkPaletteOffset(paletteSize > 0 ? (width * height) : 0);
- setDataOffset(bitmapHeaderSize);
- setUncompressedDataOffset(bitmapHeaderSize);
- setControlOffset(0);
- setScaledWidth(scaledWidth);
- setScaledHeight(scaledHeight);
-
- _buffer = Buffer(getWidth(), getHeight(), getPixels());
- }
-
- inline reg_t getObject() const {
- return _object;
- }
-
- inline Buffer &getBuffer() {
- return _buffer;
- }
-
- BITMAP_PROPERTY(16, Width, 0);
- BITMAP_PROPERTY(16, Height, 2);
-
- inline Common::Point getDisplace() const {
- return Common::Point(
- (int16)READ_SCI11ENDIAN_UINT16(_bitmap + 4),
- (int16)READ_SCI11ENDIAN_UINT16(_bitmap + 6)
- );
- }
-
- inline void setDisplace(const Common::Point &displace) {
- WRITE_SCI11ENDIAN_UINT16(_bitmap + 4, (uint16)displace.x);
- WRITE_SCI11ENDIAN_UINT16(_bitmap + 6, (uint16)displace.y);
- }
-
- inline uint8 getSkipColor() const {
- return _bitmap[8];
- }
-
- inline void setSkipColor(const uint8 skipColor) {
- _bitmap[8] = skipColor;
- }
-
- inline bool getRemap() const {
- return READ_SCI11ENDIAN_UINT16(_bitmap + 10) & kBitmapRemap;
- }
-
- inline void setRemap(const bool remap) {
- uint16 flags = READ_SCI11ENDIAN_UINT16(_bitmap + 10);
- if (remap) {
- flags |= kBitmapRemap;
- } else {
- flags &= ~kBitmapRemap;
- }
- WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, flags);
- }
-
- BITMAP_PROPERTY(32, DataSize, 12);
-
- inline uint32 getHunkPaletteOffset() const {
- return READ_SCI11ENDIAN_UINT32(_bitmap + 20);
- }
-
- inline void setHunkPaletteOffset(uint32 hunkPaletteOffset) {
- if (hunkPaletteOffset) {
- hunkPaletteOffset += getBitmapHeaderSize();
- }
-
- WRITE_SCI11ENDIAN_UINT32(_bitmap + 20, hunkPaletteOffset);
- }
-
- BITMAP_PROPERTY(32, DataOffset, 24);
-
- // NOTE: This property is used as a "magic number" for
- // validating that a block of memory is a valid bitmap,
- // and so is always set to the size of the header.
- BITMAP_PROPERTY(32, UncompressedDataOffset, 28);
-
- // NOTE: This property always seems to be zero
- BITMAP_PROPERTY(32, ControlOffset, 32);
-
- inline uint16 getScaledWidth() const {
- if (getDataOffset() >= 40) {
- return READ_SCI11ENDIAN_UINT16(_bitmap + 36);
- }
-
- // SCI2 bitmaps did not have scaling ability
- return 320;
- }
-
- inline void setScaledWidth(uint16 scaledWidth) {
- if (getDataOffset() >= 40) {
- WRITE_SCI11ENDIAN_UINT16(_bitmap + 36, scaledWidth);
- }
- }
-
- inline uint16 getScaledHeight() const {
- if (getDataOffset() >= 40) {
- return READ_SCI11ENDIAN_UINT16(_bitmap + 38);
- }
-
- // SCI2 bitmaps did not have scaling ability
- return 200;
- }
-
- inline void setScaledHeight(uint16 scaledHeight) {
- if (getDataOffset() >= 40) {
- WRITE_SCI11ENDIAN_UINT16(_bitmap + 38, scaledHeight);
- }
- }
-
- inline byte *getPixels() {
- return _bitmap + getUncompressedDataOffset();
- }
-};
-
class GfxFont;
/**
diff --git a/engines/sci/graphics/transitions32.cpp b/engines/sci/graphics/transitions32.cpp
index 01956e6..251e439 100644
--- a/engines/sci/graphics/transitions32.cpp
+++ b/engines/sci/graphics/transitions32.cpp
@@ -362,7 +362,7 @@ ShowStyleList::iterator GfxTransitions32::deleteShowStyle(const ShowStyleList::i
case kShowStyleDissolveNoMorph:
case kShowStyleDissolve:
if (getSciVersion() <= SCI_VERSION_2_1_EARLY) {
- _segMan->freeHunkEntry(showStyle->bitmap);
+ _segMan->freeBitmap(showStyle->bitmap);
g_sci->_gfxFrameout->deleteScreenItem(*showStyle->bitmapScreenItem);
}
break;
@@ -459,9 +459,10 @@ void GfxTransitions32::configure21EarlyIris(PlaneShowStyle &showStyle, const int
void GfxTransitions32::configure21EarlyDissolve(PlaneShowStyle &showStyle, const int16 priority, const Common::Rect &gameRect) {
- BitmapResource bitmap(_segMan, showStyle.width, showStyle.height, kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
+ reg_t bitmapId;
+ SciBitmap &bitmap = *_segMan->allocateBitmap(&bitmapId, showStyle.width, showStyle.height, kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
- showStyle.bitmap = bitmap.getObject();
+ showStyle.bitmap = bitmapId;
const Buffer &source = g_sci->_gfxFrameout->getCurrentBuffer();
Buffer target(showStyle.width, showStyle.height, bitmap.getPixels());
@@ -471,7 +472,7 @@ void GfxTransitions32::configure21EarlyDissolve(PlaneShowStyle &showStyle, const
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
- celInfo.bitmap = bitmap.getObject();
+ celInfo.bitmap = bitmapId;
showStyle.bitmapScreenItem = new ScreenItem(showStyle.plane, celInfo, Common::Point(0, 0), ScaleInfo());
showStyle.bitmapScreenItem->_priority = priority;
@@ -608,7 +609,7 @@ bool GfxTransitions32::processPixelDissolve(PlaneShowStyle &showStyle) {
bool GfxTransitions32::processPixelDissolve21Early(PlaneShowStyle &showStyle) {
bool unchanged = true;
- BitmapResource bitmap(showStyle.bitmap);
+ SciBitmap &bitmap = *_segMan->lookupBitmap(showStyle.bitmap);
Buffer buffer(showStyle.width, showStyle.height, bitmap.getPixels());
uint32 numPixels = showStyle.width * showStyle.height;
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 4660706..dc2641c 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -117,7 +117,7 @@ VMDPlayer::IOStatus VMDPlayer::close() {
if (!_planeIsOwned && _screenItem != nullptr) {
g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
- g_sci->getEngineState()->_segMan->freeHunkEntry(_screenItem->_celInfo.bitmap);
+ g_sci->getEngineState()->_segMan->freeBitmap(_screenItem->_celInfo.bitmap);
_screenItem = nullptr;
} else if (_plane != nullptr) {
g_sci->_gfxFrameout->deletePlane(*_plane);
@@ -232,14 +232,15 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
- BitmapResource vmdBitmap(_segMan, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false, false);
+ reg_t bitmapId;
+ SciBitmap &vmdBitmap = *_segMan->allocateBitmap(&bitmapId, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false, false);
if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
}
CelInfo32 vmdCelInfo;
- vmdCelInfo.bitmap = vmdBitmap.getObject();
+ vmdCelInfo.bitmap = bitmapId;
_decoder->setSurfaceMemory(vmdBitmap.getPixels(), vmdBitmap.getWidth(), vmdBitmap.getHeight(), 1);
if (_planeIsOwned) {
Commit: 10f9cb7023e2f68d5489b6f73b46a6e541f86b72
https://github.com/scummvm/scummvm/commit/10f9cb7023e2f68d5489b6f73b46a6e541f86b72
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-01T10:37:14-05:00
Commit Message:
SCI32: Fix crash when destroying GfxTransitions32
Changed paths:
engines/sci/graphics/transitions32.cpp
diff --git a/engines/sci/graphics/transitions32.cpp b/engines/sci/graphics/transitions32.cpp
index 251e439..bceb0fa 100644
--- a/engines/sci/graphics/transitions32.cpp
+++ b/engines/sci/graphics/transitions32.cpp
@@ -60,9 +60,9 @@ GfxTransitions32::GfxTransitions32(SegManager *segMan) :
}
GfxTransitions32::~GfxTransitions32() {
- for (ShowStyleList::iterator it = _showStyles.begin(); it != _showStyles.end(); ++it) {
- deleteShowStyle(it);
- }
+ for (ShowStyleList::iterator it = _showStyles.begin();
+ it != _showStyles.end();
+ it = deleteShowStyle(it));
_scrolls.clear();
}
Commit: 6d1f8e8c876983f22e94ba8966b02d8cc088d2a5
https://github.com/scummvm/scummvm/commit/6d1f8e8c876983f22e94ba8966b02d8cc088d2a5
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-01T10:37:14-05:00
Commit Message:
SCI32: Fix invalid memory access after BitmapTable is extended
When new bitmaps are added and the underlying Common::Array needs
to move to expand, this invalidates all pointers to bitmaps, which
makes it basically impossible to use the bitmap segment since you
never know if a reference is going to be invalidated due to an
array move.
To solve this, BitmapTable is changed to hold pointers to
SciBitmaps that are allocated separately on the heap instead, so
when those bitmaps are looked up, the resulting pointers are valid
for the lifetime of the bitmap, instead of the lifetime of the
Common::Array used internally by BitmapTable.
Changed paths:
engines/sci/engine/gc.cpp
engines/sci/engine/savegame.cpp
engines/sci/engine/seg_manager.cpp
engines/sci/engine/segment.cpp
engines/sci/engine/segment.h
diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp
index ad4fd19..6c1713b 100644
--- a/engines/sci/engine/gc.cpp
+++ b/engines/sci/engine/gc.cpp
@@ -160,7 +160,7 @@ AddrSet *findAllActiveReferences(EngineState *s) {
BitmapTable *bt = static_cast<BitmapTable *>(heap[i]);
for (uint j = 0; j < bt->_table.size(); j++) {
- if (!bt->_table[j].data.getShouldGC()) {
+ if (bt->_table[j].data && bt->_table[j].data->getShouldGC() == false) {
wm.push(make_reg(i, j));
}
}
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index f49853d..62f9c5a 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -159,7 +159,7 @@ void syncWithSerializer(Common::Serializer &s, SciString &obj) {
}
}
-void syncWithSerializer(Common::Serializer &s, SciBitmap &obj) {
+void syncWithSerializer(Common::Serializer &s, SciBitmap *obj) {
debug("TODO: Sync bitmap");
// if (s.isSaving()) {
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 67da4c8..6084529 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -959,7 +959,7 @@ SciBitmap *SegManager::allocateBitmap(reg_t *addr, const int16 width, const int1
offset = table->allocEntry();
*addr = make_reg(_bitmapSegId, offset);
- SciBitmap *bitmap = &table->at(offset);
+ SciBitmap *bitmap = table->at(offset);
if (bitmap == nullptr) {
*addr = NULL_REG;
@@ -977,21 +977,20 @@ SciBitmap *SegManager::lookupBitmap(const reg_t addr) {
BitmapTable &bitmapTable = *(BitmapTable *)_heap[addr.getSegment()];
if (!bitmapTable.isValidEntry(addr.getOffset()))
- error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
+ error("Attempt to use invalid entry %04x:%04x as bitmap", PRINT_REG(addr));
- return &(bitmapTable.at(addr.getOffset()));
+ return (bitmapTable.at(addr.getOffset()));
}
void SegManager::freeBitmap(const reg_t addr) {
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_BITMAP)
- error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
+ error("Attempt to free non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
BitmapTable &bitmapTable = *(BitmapTable *)_heap[addr.getSegment()];
if (!bitmapTable.isValidEntry(addr.getOffset()))
- error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
+ error("Attempt to free invalid entry %04x:%04x as bitmap", PRINT_REG(addr));
- bitmapTable.at(addr.getOffset()).destroy();
bitmapTable.freeEntry(addr.getOffset());
}
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index 7f690cb..7943946 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -313,17 +313,6 @@ SegmentRef StringTable::dereference(reg_t pointer) {
return ret;
}
-#pragma mark -
-#pragma mark Bitmaps
-
-SegmentRef BitmapTable::dereference(reg_t pointer) {
- SegmentRef ret;
- ret.isRaw = true;
- ret.maxSize = at(pointer.getOffset()).getRawSize();
- ret.raw = at(pointer.getOffset()).getRawData();
- return ret;
-}
-
#endif
} // End of namespace Sci
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index c25ede1..8e7cf9e 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -535,6 +535,8 @@ inline void set##property(uint##size value) {\
WRITE_SCI11ENDIAN_UINT##size(_data + (offset), (value));\
}
+class BitmapTable;
+
/**
* A convenience class for creating and modifying in-memory
* bitmaps.
@@ -583,6 +585,39 @@ public:
inline SciBitmap() : _data(nullptr), _dataSize(0), _gc(true) {}
+ inline SciBitmap(const SciBitmap &other) {
+ _dataSize = other._dataSize;
+ _data = (byte *)malloc(other._dataSize);
+ memcpy(_data, other._data, other._dataSize);
+ if (_dataSize) {
+ _buffer = Buffer(getWidth(), getHeight(), getPixels());
+ }
+ _gc = other._gc;
+ }
+
+ inline ~SciBitmap() {
+ free(_data);
+ _data = nullptr;
+ _dataSize = 0;
+ }
+
+ inline SciBitmap &operator=(const SciBitmap &other) {
+ if (this == &other) {
+ return *this;
+ }
+
+ free(_data);
+ _dataSize = other._dataSize;
+ _data = (byte *)malloc(other._dataSize);
+ memcpy(_data, other._data, _dataSize);
+ if (_dataSize) {
+ _buffer = Buffer(getWidth(), getHeight(), getPixels());
+ }
+ _gc = other._gc;
+
+ return *this;
+ }
+
/**
* Allocates and initialises a new bitmap.
*/
@@ -613,12 +648,6 @@ public:
_buffer = Buffer(getWidth(), getHeight(), getPixels());
}
- inline void destroy() {
- free(_data);
- _data = nullptr;
- _dataSize = 0;
- }
-
inline int getRawSize() const {
return _dataSize;
}
@@ -746,16 +775,46 @@ public:
}
};
-struct BitmapTable : public SegmentObjTable<SciBitmap> {
- BitmapTable() : SegmentObjTable<SciBitmap>(SEG_TYPE_BITMAP) {}
+struct BitmapTable : public SegmentObjTable<SciBitmap *> {
+ BitmapTable() : SegmentObjTable<SciBitmap *>(SEG_TYPE_BITMAP) {}
- virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {
- at(sub_addr.getOffset()).destroy();
+ virtual ~BitmapTable() {
+ for (uint i = 0; i < _table.size(); i++) {
+ if (isValidEntry(i)) {
+ freeEntryContents(i);
+ }
+ }
+ }
+
+ int allocEntry() {
+ int offset = SegmentObjTable<SciBitmap *>::allocEntry();
+ at(offset) = new SciBitmap;
+ return offset;
+ }
+
+ void freeEntryContents(const int offset) {
+ delete at(offset);
+ at(offset) = nullptr;
+ }
+
+ virtual void freeEntry(const int offset) override {
+ SegmentObjTable<SciBitmap *>::freeEntry(offset);
+ freeEntryContents(offset);
+ }
+
+ virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) override {
freeEntry(sub_addr.getOffset());
}
+ SegmentRef dereference(reg_t pointer) {
+ SegmentRef ret;
+ ret.isRaw = true;
+ ret.maxSize = at(pointer.getOffset())->getRawSize();
+ ret.raw = at(pointer.getOffset())->getRawData();
+ return ret;
+ }
+
void saveLoadWithSerializer(Common::Serializer &ser);
- SegmentRef dereference(reg_t pointer);
};
#endif
Commit: d5d42d5066df7eb4c11bf703506aea54af18ec93
https://github.com/scummvm/scummvm/commit/d5d42d5066df7eb4c11bf703506aea54af18ec93
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-01T10:37:14-05:00
Commit Message:
SCI32: Implement bitmap save routine
Changed paths:
engines/sci/engine/savegame.cpp
engines/sci/engine/segment.h
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 62f9c5a..d86af50 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -159,16 +159,22 @@ void syncWithSerializer(Common::Serializer &s, SciString &obj) {
}
}
-void syncWithSerializer(Common::Serializer &s, SciBitmap *obj) {
- debug("TODO: Sync bitmap");
-
-// if (s.isSaving()) {
-// size = obj.getSize();
-// s.syncAsUint32LE(size);
-// } else {
-// s.syncAsUint32LE(size);
-// obj.setSize(size);
-// }
+void syncWithSerializer(Common::Serializer &s, SciBitmap *&obj) {
+ bool hasEntry;
+ if (s.isSaving()) {
+ hasEntry = obj != nullptr;
+ }
+ s.syncAsByte(hasEntry);
+
+ if (hasEntry) {
+ if (s.isLoading()) {
+ obj = new SciBitmap;
+ }
+
+ obj->saveLoadWithSerializer(s);
+ } else {
+ obj = nullptr;
+ }
}
#endif
@@ -703,12 +709,29 @@ void StringTable::saveLoadWithSerializer(Common::Serializer &ser) {
}
void BitmapTable::saveLoadWithSerializer(Common::Serializer &ser) {
- if (ser.getVersion() < 36)
+ if (ser.getVersion() < 36) {
return;
+ }
- // TODO: Should only include bitmaps with gc = true
sync_Table(ser, *this);
}
+
+void SciBitmap::saveLoadWithSerializer(Common::Serializer &s) {
+ if (s.getVersion() < 36) {
+ return;
+ }
+
+ s.syncAsByte(_gc);
+ s.syncAsUint32LE(_dataSize);
+ if (s.isLoading()) {
+ _data = (byte *)malloc(_dataSize);
+ }
+ s.syncBytes(_data, _dataSize);
+
+ if (s.isLoading()) {
+ _buffer = Buffer(getWidth(), getHeight(), getPixels());
+ }
+}
#endif
void GfxPalette::palVarySaveLoadPalette(Common::Serializer &s, Palette *palette) {
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 8e7cf9e..a99f613 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -541,7 +541,7 @@ class BitmapTable;
* A convenience class for creating and modifying in-memory
* bitmaps.
*/
-class SciBitmap {
+class SciBitmap : public Common::Serializable {
byte *_data;
int _dataSize;
Buffer _buffer;
@@ -773,6 +773,8 @@ public:
}
return _data + getHunkPaletteOffset();
}
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
struct BitmapTable : public SegmentObjTable<SciBitmap *> {
More information about the Scummvm-git-logs
mailing list