aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics/animate.cpp
diff options
context:
space:
mode:
authorTony Puccinelli2010-08-10 23:21:08 +0000
committerTony Puccinelli2010-08-10 23:21:08 +0000
commit682807f0e916b189c69b60765418ee1ccc327cbf (patch)
treee8b220b934f6b14d4dac290181fce0c1b209579a /engines/sci/graphics/animate.cpp
parent83f1531cb8fa5ba43c246143ecdde2cb1d140a8e (diff)
parentfffec23a02cc88ed8daba0a3b50007b7e220c075 (diff)
downloadscummvm-rg350-682807f0e916b189c69b60765418ee1ccc327cbf.tar.gz
scummvm-rg350-682807f0e916b189c69b60765418ee1ccc327cbf.tar.bz2
scummvm-rg350-682807f0e916b189c69b60765418ee1ccc327cbf.zip
merged trunk into branch, reverted Cruise Singleton changes
svn-id: r51961
Diffstat (limited to 'engines/sci/graphics/animate.cpp')
-rw-r--r--engines/sci/graphics/animate.cpp582
1 files changed, 311 insertions, 271 deletions
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index 71c7b7dd7f..ab4362cda9 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -28,6 +28,8 @@
#include "graphics/primitives.h"
#include "sci/sci.h"
+#include "sci/event.h"
+#include "sci/engine/kernel.h"
#include "sci/engine/state.h"
#include "sci/engine/selector.h"
#include "sci/engine/vm.h"
@@ -35,6 +37,7 @@
#include "sci/graphics/cursor.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/paint16.h"
+#include "sci/graphics/palette.h"
#include "sci/graphics/view.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/transitions.h"
@@ -48,28 +51,25 @@ GfxAnimate::GfxAnimate(EngineState *state, GfxCache *cache, GfxPorts *ports, Gfx
}
GfxAnimate::~GfxAnimate() {
- free(_listData);
- free(_lastCastData);
}
void GfxAnimate::init() {
- _listData = NULL;
- _listCount = 0;
- _lastCastData = NULL;
- _lastCastCount = 0;
+ _lastCastData.clear();
_ignoreFastCast = false;
// fastCast object is not found in any SCI games prior SCI1
if (getSciVersion() <= SCI_VERSION_01)
_ignoreFastCast = true;
// Also if fastCast object exists at gamestartup, we can assume that the interpreter doesnt do kAnimate aborts
- // (found in larry 1)
- if (!_s->_segMan->findObjectByName("fastCast").isNull())
- _ignoreFastCast = true;
+ // (found in Larry 1)
+ if (getSciVersion() > SCI_VERSION_0_EARLY) {
+ if (!_s->_segMan->findObjectByName("fastCast").isNull())
+ _ignoreFastCast = true;
+ }
}
void GfxAnimate::disposeLastCast() {
- _lastCastCount = 0;
+ _lastCastData.clear();
}
bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
@@ -84,20 +84,27 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
if (!_ignoreFastCast) {
// Check if the game has a fastCast object set
// if we don't abort kAnimate processing, at least in kq5 there will be animation cels drawn into speech boxes.
- reg_t global84 = _s->script_000->_localsBlock->_locals[84];
-
- if (!global84.isNull()) {
- if (!strcmp(_s->_segMan->getObjectName(global84), "fastCast"))
+ if (!_s->variables[VAR_GLOBAL][84].isNull()) {
+ if (!strcmp(_s->_segMan->getObjectName(_s->variables[VAR_GLOBAL][84]), "fastCast"))
return false;
}
}
- signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
+ signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
if (!(signal & kSignalFrozen)) {
// Call .doit method of that object
- invoke_selector(_s, curObject, g_sci->getKernel()->_selectorCache.doit, kContinueOnInvalidSelector, argc, argv, 0);
- // Lookup node again, since the nodetable it was in may have been reallocated
- curNode = _s->_segMan->lookupNode(curAddress);
+ invokeSelector(_s, curObject, SELECTOR(doit), argc, argv, 0);
+
+ // If a game is being loaded, stop processing
+ if (_s->abortScriptProcessing != kAbortNone || g_engine->shouldQuit())
+ return true; // Stop processing
+
+ // Lookup node again, since the nodetable it was in may have been reallocated.
+ // The node might have been deallocated at this point (e.g. LSL2, room 42),
+ // in which case the node reference will be null and the loop will stop below.
+ // If the node is deleted from kDeleteKey, it won't have a successor node, thus
+ // list processing will stop here (which is what SSCI does).
+ curNode = _s->_segMan->lookupNode(curAddress, false);
}
if (curNode) {
@@ -108,141 +115,163 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
return true;
}
-bool sortHelper(const AnimateEntry* entry1, const AnimateEntry* entry2) {
- return (entry1->y == entry2->y) ? (entry1->z < entry2->z) : (entry1->y < entry2->y);
+bool sortHelper(const AnimateEntry &entry1, const AnimateEntry &entry2) {
+ if (entry1.y == entry2.y) {
+ // if both y and z are the same, use the order we were given originally
+ // this is needed for special cases like iceman room 35
+ if (entry1.z == entry2.z)
+ return entry1.givenOrderNo < entry2.givenOrderNo;
+ else
+ return entry1.z < entry2.z;
+ }
+ return entry1.y < entry2.y;
}
void GfxAnimate::makeSortedList(List *list) {
reg_t curAddress = list->first;
Node *curNode = _s->_segMan->lookupNode(curAddress);
- reg_t curObject;
- AnimateEntry *listEntry;
- int16 listNr, listCount = 0;
-
- // Count the list entries
- while (curNode) {
- listCount++;
- curAddress = curNode->succ;
- curNode = _s->_segMan->lookupNode(curAddress);
- }
+ int16 listNr;
+ // Clear lists
_list.clear();
-
- // No entries -> exit immediately
- if (listCount == 0)
- return;
-
- // Adjust list size, if needed
- if ((_listData == NULL) || (_listCount < listCount)) {
- free(_listData);
- _listData = (AnimateEntry *)malloc(listCount * sizeof(AnimateEntry));
- if (!_listData)
- error("Could not allocate memory for _listData");
- _listCount = listCount;
-
- free(_lastCastData);
- _lastCastData = (AnimateEntry *)malloc(listCount * sizeof(AnimateEntry));
- if (!_lastCastData)
- error("Could not allocate memory for _lastCastData");
- _lastCastCount = 0;
- }
+ _lastCastData.clear();
// Fill the list
- curAddress = list->first;
- curNode = _s->_segMan->lookupNode(curAddress);
- listEntry = _listData;
- for (listNr = 0; listNr < listCount; listNr++) {
- curObject = curNode->value;
- listEntry->object = curObject;
+ for (listNr = 0; curNode != 0; listNr++) {
+ AnimateEntry listEntry;
+ const reg_t curObject = curNode->value;
+ listEntry.object = curObject;
// Get data from current object
- listEntry->viewId = GET_SEL32V(_s->_segMan, curObject, SELECTOR(view));
- listEntry->loopNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(loop));
- listEntry->celNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(cel));
- listEntry->paletteNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(palette));
- listEntry->x = GET_SEL32V(_s->_segMan, curObject, SELECTOR(x));
- listEntry->y = GET_SEL32V(_s->_segMan, curObject, SELECTOR(y));
- listEntry->z = GET_SEL32V(_s->_segMan, curObject, SELECTOR(z));
- listEntry->priority = GET_SEL32V(_s->_segMan, curObject, SELECTOR(priority));
- listEntry->signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
+ listEntry.givenOrderNo = listNr;
+ listEntry.viewId = readSelectorValue(_s->_segMan, curObject, SELECTOR(view));
+ listEntry.loopNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(loop));
+ listEntry.celNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(cel));
+ listEntry.paletteNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(palette));
+ listEntry.x = readSelectorValue(_s->_segMan, curObject, SELECTOR(x));
+ listEntry.y = readSelectorValue(_s->_segMan, curObject, SELECTOR(y));
+ listEntry.z = readSelectorValue(_s->_segMan, curObject, SELECTOR(z));
+ listEntry.priority = readSelectorValue(_s->_segMan, curObject, SELECTOR(priority));
+ listEntry.signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
if (getSciVersion() >= SCI_VERSION_1_1) {
// Cel scaling
- listEntry->scaleSignal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleSignal));
- if (listEntry->scaleSignal & kScaleSignalDoScaling) {
- listEntry->scaleX = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleX));
- listEntry->scaleY = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleY));
+ listEntry.scaleSignal = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleSignal));
+ if (listEntry.scaleSignal & kScaleSignalDoScaling) {
+ listEntry.scaleX = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX));
+ listEntry.scaleY = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY));
} else {
- listEntry->scaleX = 128;
- listEntry->scaleY = 128;
+ listEntry.scaleX = 128;
+ listEntry.scaleY = 128;
}
- // TODO
- // On scaleSignal bit 1 sierra sci does some stuff with global var 2, current Port
- // and some other stuff and sets scaleX/Y accordingly. It seems this functionality is needed in at
- // least sq5 right when starting the game before wilco exists the room. Currently we dont get scaling
- // but sierra sci does scaling there. I dont fully understand the code yet, that's why i didnt implement
- // anything.
} else {
- listEntry->scaleSignal = 0;
- listEntry->scaleX = 128;
- listEntry->scaleY = 128;
+ listEntry.scaleSignal = 0;
+ listEntry.scaleX = 128;
+ listEntry.scaleY = 128;
}
- // listEntry->celRect is filled in AnimateFill()
- listEntry->showBitsFlag = false;
+ // listEntry.celRect is filled in AnimateFill()
+ listEntry.showBitsFlag = false;
_list.push_back(listEntry);
- listEntry++;
curAddress = curNode->succ;
curNode = _s->_segMan->lookupNode(curAddress);
}
+ // Possible TODO: As noted in the comment in sortHelper we actually
+ // require a stable sorting algorithm here. Since Common::sort is not stable
+ // at the time of writing this comment, we work around that in our ordering
+ // comparator. If that changes in the future or we want to use some
+ // stable sorting algorithm here, we should change that.
+ // In that case we should test such changes intensively. A good place to test stable sort
+ // is iceman, cupboard within the submarine. If sort isn't stable, the cupboard will be
+ // half-open, half-closed. Of course that's just one of many special cases.
+
// Now sort the list according y and z (descending)
Common::sort(_list.begin(), _list.end(), sortHelper);
}
void GfxAnimate::fill(byte &old_picNotValid) {
reg_t curObject;
- AnimateEntry *listEntry;
uint16 signal;
GfxView *view = NULL;
- AnimateList::iterator listIterator;
- AnimateList::iterator listEnd = _list.end();
+ AnimateList::iterator it;
+ const AnimateList::iterator end = _list.end();
- listIterator = _list.begin();
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
+ for (it = _list.begin(); it != end; ++it) {
+ curObject = it->object;
+ signal = it->signal;
// Get the corresponding view
- view = _cache->getView(listEntry->viewId);
+ view = _cache->getView(it->viewId);
// adjust loop and cel, if any of those is invalid
- if (listEntry->loopNo >= view->getLoopCount()) {
- listEntry->loopNo = 0;
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(loop), listEntry->loopNo);
+ if (it->loopNo >= view->getLoopCount()) {
+ it->loopNo = 0;
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(loop), it->loopNo);
+ }
+ if (it->celNo >= view->getCelCount(it->loopNo)) {
+ it->celNo = 0;
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(cel), it->celNo);
+ }
+
+ // Process global scaling, if needed
+ if (it->scaleSignal & kScaleSignalDoScaling) {
+ if (it->scaleSignal & kScaleSignalGlobalScaling) {
+ // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY
+ int16 maxScale = readSelectorValue(_s->_segMan, curObject, SELECTOR(maxScale));
+ int16 celHeight = view->getHeight(it->loopNo, it->celNo);
+ int16 maxCelHeight = (maxScale * celHeight) >> 7;
+ reg_t globalVar2 = _s->variables[VAR_GLOBAL][2]; // current room object
+ int16 vanishingY = readSelectorValue(_s->_segMan, globalVar2, SELECTOR(vanishingY));
+
+ int16 fixedPortY = _ports->getPort()->rect.bottom - vanishingY;
+ int16 fixedEntryY = it->y - vanishingY;
+ if (!fixedEntryY)
+ fixedEntryY = 1;
+
+ if ((celHeight == 0) || (fixedPortY == 0))
+ error("global scaling panic");
+
+ it->scaleY = ( maxCelHeight * fixedEntryY ) / fixedPortY;
+ it->scaleY = (it->scaleY * 128) / celHeight;
+
+ it->scaleX = it->scaleY;
+
+ // and set objects scale selectors
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX), it->scaleX);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY), it->scaleY);
+ }
}
- if (listEntry->celNo >= view->getCelCount(listEntry->loopNo)) {
- listEntry->celNo = 0;
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(cel), listEntry->celNo);
+
+ if (!view->isScaleable()) {
+ // Laura Bow 2 (especially floppy) depends on this, some views are not supposed to be scaleable
+ // this "feature" was removed in later versions of SCI1.1
+ it->scaleSignal = 0;
+ it->scaleY = it->scaleX = 128;
}
+ bool setNsRect = true;
+
// Create rect according to coordinates and given cel
- if (listEntry->scaleSignal & kScaleSignalDoScaling) {
- view->getCelScaledRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, listEntry->scaleX, listEntry->scaleY, &listEntry->celRect);
+ if (it->scaleSignal & kScaleSignalDoScaling) {
+ view->getCelScaledRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->scaleX, it->scaleY, it->celRect);
+ // when being scaled, only set nsRect, if object will get drawn
+ if ((signal & kSignalHidden) && !(signal & kSignalAlwaysUpdate))
+ setNsRect = false;
} else {
- view->getCelRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, &listEntry->celRect);
+ view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
+ }
+ if (setNsRect) {
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), it->celRect.left);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), it->celRect.top);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight), it->celRect.right);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom), it->celRect.bottom);
}
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsLeft), listEntry->celRect.left);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsTop), listEntry->celRect.top);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsRight), listEntry->celRect.right);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsBottom), listEntry->celRect.bottom);
-
- signal = listEntry->signal;
// Calculate current priority according to y-coordinate
if (!(signal & kSignalFixedPriority)) {
- listEntry->priority = _ports->kernelCoordinateToPriority(listEntry->y);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(priority), listEntry->priority);
+ it->priority = _ports->kernelCoordinateToPriority(it->y);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(priority), it->priority);
}
if (signal & kSignalNoUpdate) {
@@ -251,205 +280,182 @@ void GfxAnimate::fill(byte &old_picNotValid) {
|| (!(signal & kSignalHidden) && signal & kSignalRemoveView)
|| (signal & kSignalAlwaysUpdate))
old_picNotValid++;
- signal &= 0xFFFF ^ kSignalStopUpdate;
+ signal &= ~kSignalStopUpdate;
} else {
if (signal & kSignalStopUpdate || signal & kSignalAlwaysUpdate)
old_picNotValid++;
- signal &= 0xFFFF ^ kSignalForceUpdate;
+ signal &= ~kSignalForceUpdate;
}
- listEntry->signal = signal;
-
- listIterator++;
+ it->signal = signal;
}
}
void GfxAnimate::update() {
reg_t curObject;
- AnimateEntry *listEntry;
uint16 signal;
reg_t bitsHandle;
Common::Rect rect;
- AnimateList::iterator listIterator;
- AnimateList::iterator listBegin = _list.begin();
- AnimateList::iterator listEnd = _list.end();
+ AnimateList::iterator it;
+ const AnimateList::iterator end = _list.end();
// Remove all no-update cels, if requested
- listIterator = _list.reverse_begin();
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
- signal = listEntry->signal;
+ for (it = _list.reverse_begin(); it != end; --it) {
+ curObject = it->object;
+ signal = it->signal;
if (signal & kSignalNoUpdate) {
if (!(signal & kSignalRemoveView)) {
- bitsHandle = GET_SEL32(_s->_segMan, curObject, SELECTOR(underBits));
+ bitsHandle = readSelector(_s->_segMan, curObject, SELECTOR(underBits));
if (_screen->_picNotValid != 1) {
_paint16->bitsRestore(bitsHandle);
- listEntry->showBitsFlag = true;
+ it->showBitsFlag = true;
} else {
_paint16->bitsFree(bitsHandle);
}
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(underBits), 0);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
}
- signal &= 0xFFFF ^ kSignalForceUpdate;
- signal &= signal & kSignalViewUpdated ? 0xFFFF ^ (kSignalViewUpdated | kSignalNoUpdate) : 0xFFFF;
+ signal &= ~kSignalForceUpdate;
+ if (signal & kSignalViewUpdated)
+ signal &= ~(kSignalViewUpdated | kSignalNoUpdate);
} else if (signal & kSignalStopUpdate) {
- signal = (signal & (0xFFFF ^ kSignalStopUpdate)) | kSignalNoUpdate;
+ signal &= ~kSignalStopUpdate;
+ signal |= kSignalNoUpdate;
}
- listEntry->signal = signal;
- listIterator--;
+ it->signal = signal;
}
// Draw always-update cels
- listIterator = listBegin;
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
- signal = listEntry->signal;
+ for (it = _list.begin(); it != end; ++it) {
+ curObject = it->object;
+ signal = it->signal;
if (signal & kSignalAlwaysUpdate) {
// draw corresponding cel
- _paint16->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo, listEntry->scaleX, listEntry->scaleY);
- listEntry->showBitsFlag = true;
+ _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
+ it->showBitsFlag = true;
- signal &= 0xFFFF ^ (kSignalStopUpdate | kSignalViewUpdated | kSignalNoUpdate | kSignalForceUpdate);
+ signal &= ~(kSignalStopUpdate | kSignalViewUpdated | kSignalNoUpdate | kSignalForceUpdate);
if ((signal & kSignalIgnoreActor) == 0) {
- rect = listEntry->celRect;
- rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(listEntry->priority) - 1, rect.top, rect.bottom - 1);
+ rect = it->celRect;
+ rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, rect.top, rect.bottom - 1);
_paint16->fillRect(rect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
}
- listEntry->signal = signal;
+ it->signal = signal;
}
- listIterator++;
}
// Saving background for all NoUpdate-cels
- listIterator = listBegin;
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
- signal = listEntry->signal;
+ for (it = _list.begin(); it != end; ++it) {
+ curObject = it->object;
+ signal = it->signal;
if (signal & kSignalNoUpdate) {
if (signal & kSignalHidden) {
signal |= kSignalRemoveView;
} else {
- signal &= 0xFFFF ^ kSignalRemoveView;
+ signal &= ~kSignalRemoveView;
if (signal & kSignalIgnoreActor)
- bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
+ bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
else
- bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_ALL);
- PUT_SEL32(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
+ bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_ALL);
+ writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
}
- listEntry->signal = signal;
+ it->signal = signal;
}
- listIterator++;
}
// Draw NoUpdate cels
- listIterator = listBegin;
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
- signal = listEntry->signal;
+ for (it = _list.begin(); it != end; ++it) {
+ curObject = it->object;
+ signal = it->signal;
if (signal & kSignalNoUpdate && !(signal & kSignalHidden)) {
// draw corresponding cel
- _paint16->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo, listEntry->scaleX, listEntry->scaleY);
- listEntry->showBitsFlag = true;
+ _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
+ it->showBitsFlag = true;
- if ((signal & kSignalIgnoreActor) == 0) {
- rect = listEntry->celRect;
- rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(listEntry->priority) - 1, rect.top, rect.bottom - 1);
+ if (!(signal & kSignalIgnoreActor)) {
+ rect = it->celRect;
+ rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, rect.top, rect.bottom - 1);
_paint16->fillRect(rect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
}
}
- listIterator++;
}
}
void GfxAnimate::drawCels() {
reg_t curObject;
- AnimateEntry *listEntry;
- AnimateEntry *lastCastEntry = _lastCastData;
uint16 signal;
reg_t bitsHandle;
- AnimateList::iterator listIterator;
- AnimateList::iterator listEnd = _list.end();
- _lastCastCount = 0;
+ AnimateList::iterator it;
+ const AnimateList::iterator end = _list.end();
+ _lastCastData.clear();
- listIterator = _list.begin();
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
- signal = listEntry->signal;
+ for (it = _list.begin(); it != end; ++it) {
+ curObject = it->object;
+ signal = it->signal;
if (!(signal & (kSignalNoUpdate | kSignalHidden | kSignalAlwaysUpdate))) {
// Save background
- bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_ALL);
- PUT_SEL32(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
+ bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_ALL);
+ writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
// draw corresponding cel
- _paint16->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo, listEntry->scaleX, listEntry->scaleY);
- listEntry->showBitsFlag = true;
+ _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
+ it->showBitsFlag = true;
if (signal & kSignalRemoveView) {
- signal &= 0xFFFF ^ kSignalRemoveView;
+ signal &= ~kSignalRemoveView;
}
- listEntry->signal = signal;
+ it->signal = signal;
// Remember that entry in lastCast
- memcpy(lastCastEntry, listEntry, sizeof(AnimateEntry));
- lastCastEntry++; _lastCastCount++;
+ _lastCastData.push_back(*it);
}
- listIterator++;
}
}
void GfxAnimate::updateScreen(byte oldPicNotValid) {
reg_t curObject;
- AnimateEntry *listEntry;
uint16 signal;
- AnimateList::iterator listIterator;
- AnimateList::iterator listEnd = _list.end();
+ AnimateList::iterator it;
+ const AnimateList::iterator end = _list.end();
Common::Rect lsRect;
Common::Rect workerRect;
- listIterator = _list.begin();
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
- signal = listEntry->signal;
+ for (it = _list.begin(); it != end; ++it) {
+ curObject = it->object;
+ signal = it->signal;
- if (listEntry->showBitsFlag || !(signal & (kSignalRemoveView | kSignalNoUpdate) ||
+ if (it->showBitsFlag || !(signal & (kSignalRemoveView | kSignalNoUpdate) ||
(!(signal & kSignalRemoveView) && (signal & kSignalNoUpdate) && oldPicNotValid))) {
- lsRect.left = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsLeft));
- lsRect.top = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsTop));
- lsRect.right = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsRight));
- lsRect.bottom = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsBottom));
+ lsRect.left = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsLeft));
+ lsRect.top = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsTop));
+ lsRect.right = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsRight));
+ lsRect.bottom = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsBottom));
workerRect = lsRect;
- workerRect.clip(listEntry->celRect);
+ workerRect.clip(it->celRect);
if (!workerRect.isEmpty()) {
workerRect = lsRect;
- workerRect.extend(listEntry->celRect);
+ workerRect.extend(it->celRect);
} else {
_paint16->bitsShow(lsRect);
- workerRect = listEntry->celRect;
+ workerRect = it->celRect;
}
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsLeft), workerRect.left);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsTop), workerRect.top);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsRight), workerRect.right);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsBottom), workerRect.bottom);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsLeft), it->celRect.left);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsTop), it->celRect.top);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsRight), it->celRect.right);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsBottom), it->celRect.bottom);
+ // may get used for debugging
+ //_paint16->frameRect(workerRect);
_paint16->bitsShow(workerRect);
if (signal & kSignalHidden) {
- listEntry->signal |= kSignalRemoveView;
+ it->signal |= kSignalRemoveView;
}
}
-
- listIterator++;
}
// use this for debug purposes
// _screen->copyToScreen();
@@ -457,64 +463,53 @@ void GfxAnimate::updateScreen(byte oldPicNotValid) {
void GfxAnimate::restoreAndDelete(int argc, reg_t *argv) {
reg_t curObject;
- AnimateEntry *listEntry;
uint16 signal;
- AnimateList::iterator listIterator;
- AnimateList::iterator listEnd = _list.end();
+ AnimateList::iterator it;
+ const AnimateList::iterator end = _list.end();
- // This has to be done in a separate loop. At least in sq1 some .dispose modifies FIXEDLOOP flag in signal for
- // another object. In that case we would overwrite the new signal with our version of the old signal
- listIterator = _list.begin();
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
- signal = listEntry->signal;
+ // This has to be done in a separate loop. At least in sq1 some .dispose
+ // modifies FIXEDLOOP flag in signal for another object. In that case we
+ // would overwrite the new signal with our version of the old signal.
+ for (it = _list.begin(); it != end; ++it) {
+ curObject = it->object;
+ signal = it->signal;
// Finally update signal
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(signal), signal);
- listIterator++;
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(signal), signal);
}
- listIterator = _list.reverse_begin();
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
- // We read out signal here again, this is not by accident but to ensure that we got an up-to-date signal
- signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
+ for (it = _list.reverse_begin(); it != end; --it) {
+ curObject = it->object;
+ // We read out signal here again, this is not by accident but to ensure
+ // that we got an up-to-date signal
+ signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
if ((signal & (kSignalNoUpdate | kSignalRemoveView)) == 0) {
- _paint16->bitsRestore(GET_SEL32(_s->_segMan, curObject, SELECTOR(underBits)));
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(underBits), 0);
+ _paint16->bitsRestore(readSelector(_s->_segMan, curObject, SELECTOR(underBits)));
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
}
if (signal & kSignalDisposeMe) {
// Call .delete_ method of that object
- invoke_selector(_s, curObject, g_sci->getKernel()->_selectorCache.delete_, kContinueOnInvalidSelector, argc, argv, 0);
+ invokeSelector(_s, curObject, SELECTOR(delete_), argc, argv, 0);
}
- listIterator--;
}
}
void GfxAnimate::reAnimate(Common::Rect rect) {
- AnimateEntry *lastCastEntry;
- uint16 lastCastCount;
-
- if (_lastCastCount > 0) {
- lastCastEntry = _lastCastData;
- lastCastCount = _lastCastCount;
- while (lastCastCount > 0) {
- lastCastEntry->castHandle = _paint16->bitsSave(lastCastEntry->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
- _paint16->drawCel(lastCastEntry->viewId, lastCastEntry->loopNo, lastCastEntry->celNo, lastCastEntry->celRect, lastCastEntry->priority, lastCastEntry->paletteNo, lastCastEntry->scaleX, lastCastEntry->scaleY);
- lastCastEntry++; lastCastCount--;
+ if (!_lastCastData.empty()) {
+ AnimateArray::iterator it;
+ AnimateArray::iterator end = _lastCastData.end();
+ for (it = _lastCastData.begin(); it != end; ++it) {
+ it->castHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
+ _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
}
_paint16->bitsShow(rect);
// restoring
- lastCastCount = _lastCastCount;
- while (lastCastCount > 0) {
- lastCastEntry--;
- _paint16->bitsRestore(lastCastEntry->castHandle);
- lastCastCount--;
+ while (it != _lastCastData.begin()) { // FIXME: HACK, this iterator use is not very safe
+ it--;
+ _paint16->bitsRestore(it->castHandle);
}
} else {
_paint16->bitsShow(rect);
@@ -523,43 +518,46 @@ void GfxAnimate::reAnimate(Common::Rect rect) {
void GfxAnimate::addToPicDrawCels() {
reg_t curObject;
- AnimateEntry *listEntry;
GfxView *view = NULL;
- AnimateList::iterator listIterator;
- AnimateList::iterator listEnd = _list.end();
+ AnimateList::iterator it;
+ const AnimateList::iterator end = _list.end();
- listIterator = _list.begin();
- while (listIterator != listEnd) {
- listEntry = *listIterator;
- curObject = listEntry->object;
+ for (it = _list.begin(); it != end; ++it) {
+ curObject = it->object;
- if (listEntry->priority == -1)
- listEntry->priority = _ports->kernelCoordinateToPriority(listEntry->y);
+ if (it->priority == -1)
+ it->priority = _ports->kernelCoordinateToPriority(it->y);
// Get the corresponding view
- view = _cache->getView(listEntry->viewId);
+ view = _cache->getView(it->viewId);
// Create rect according to coordinates and given cel
- view->getCelRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, &listEntry->celRect);
+ view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
// draw corresponding cel
- _paint16->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo);
- if ((listEntry->signal & kSignalIgnoreActor) == 0) {
- listEntry->celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(listEntry->priority) - 1, listEntry->celRect.top, listEntry->celRect.bottom - 1);
- _paint16->fillRect(listEntry->celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
+ _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo);
+ if ((it->signal & kSignalIgnoreActor) == 0) {
+ it->celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, it->celRect.top, it->celRect.bottom - 1);
+ _paint16->fillRect(it->celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
}
-
- listIterator++;
}
}
-void GfxAnimate::addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) {
+void GfxAnimate::addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 x, int16 y, int16 priority, int16 control) {
GfxView *view = _cache->getView(viewId);
Common::Rect celRect;
+ if (priority == -1)
+ priority = _ports->kernelCoordinateToPriority(y);
+
// Create rect according to coordinates and given cel
- view->getCelRect(loopNo, celNo, leftPos, topPos, priority, &celRect);
+ view->getCelRect(loopNo, celNo, x, y, 0, celRect);
_paint16->drawCel(view, loopNo, celNo, celRect, priority, 0);
+
+ if (control != -1) {
+ celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(priority) - 1, celRect.top, celRect.bottom - 1);
+ _paint16->fillRect(celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, control);
+ }
}
@@ -575,14 +573,14 @@ void GfxAnimate::animateShowPic() {
_transitions->doit(picRect);
if (previousCursorState)
_cursor->kernelShow();
-
- // We set SCI1.1 priority band information here
- _ports->priorityBandsRecall();
}
void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t *argv) {
byte old_picNotValid = _screen->_picNotValid;
+ if (getSciVersion() >= SCI_VERSION_1_1)
+ _palette->palVaryUpdate();
+
if (listReference.isNull()) {
disposeLastCast();
if (_screen->_picNotValid)
@@ -597,6 +595,9 @@ void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t
if (cycle) {
if (!invoke(list, argc, argv))
return;
+
+ // Look up the list again, as it may have been modified
+ list = _s->_segMan->lookupList(listReference);
}
Port *oldPort = _ports->setPort((Port *)_ports->_picWind);
@@ -606,9 +607,9 @@ void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t
fill(old_picNotValid);
if (old_picNotValid) {
- // beginUpdate()/endUpdate() were introduced SCI1
- // calling those for SCI0 will work most of the time but breaks minor stuff like percentage bar of qfg1ega
- // at the character skill screen
+ // beginUpdate()/endUpdate() were introduced SCI1.
+ // Calling those for SCI0 will work most of the time but breaks minor
+ // stuff like percentage bar of qfg1ega at the character skill screen.
if (getSciVersion() >= SCI_VERSION_1_EGA)
_ports->beginUpdate(_ports->_picWind);
update();
@@ -624,10 +625,49 @@ void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t
updateScreen(old_picNotValid);
restoreAndDelete(argc, argv);
- if (getLastCastCount() > 1)
- _s->_throttleTrigger = true;
+ // We update the screen here as well, some scenes like EQ1 credits run w/o calling kGetEvent thus we wouldn't update
+ // screen at all
+ g_sci->getEventManager()->updateScreen();
_ports->setPort(oldPort);
+
+
+ // Now trigger speed throttler
+ switch (_lastCastData.size()) {
+ case 0:
+ // No entries drawn -> no speed throttler triggering
+ break;
+ case 1: {
+
+ // One entry drawn -> check if that entry was a speed benchmark view, if not enable speed throttler
+ AnimateEntry *onlyCast = &_lastCastData[0];
+ if ((onlyCast->viewId == 0) && (onlyCast->loopNo == 13) && (onlyCast->celNo == 0)) {
+ // this one is used by jones talkie
+ if ((onlyCast->celRect.height() == 8) && (onlyCast->celRect.width() == 8))
+ return;
+ }
+ // first loop and first cel used?
+ if ((onlyCast->loopNo == 0) && (onlyCast->celNo == 0)) {
+ // and that cel has a known speed benchmark resolution
+ int16 onlyHeight = onlyCast->celRect.height();
+ int16 onlyWidth = onlyCast->celRect.width();
+ if (((onlyWidth == 12) && (onlyHeight == 35)) || // regular benchmark view ("fred", "Speedy", "ego")
+ ((onlyWidth == 29) && (onlyHeight == 45)) || // King's Quest 5 french "fred"
+ ((onlyWidth == 1) && (onlyHeight == 1))) { // Laura Bow 2 Talkie
+ // check further that there is only one cel in that view
+ GfxView *onlyView = _cache->getView(onlyCast->viewId);
+ if ((onlyView->getLoopCount() == 1) && (onlyView->getCelCount(0)))
+ return;
+ }
+ }
+ _s->_throttleTrigger = true;
+ break;
+ }
+ default:
+ // More than 1 entry drawn -> time for speed throttling
+ _s->_throttleTrigger = true;
+ break;
+ }
}
void GfxAnimate::addToPicSetPicNotValid() {
@@ -652,9 +692,9 @@ void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv)
addToPicSetPicNotValid();
}
-void GfxAnimate::kernelAddToPicView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) {
+void GfxAnimate::kernelAddToPicView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 x, int16 y, int16 priority, int16 control) {
_ports->setPort((Port *)_ports->_picWind);
- addToPicDrawView(viewId, loopNo, celNo, leftPos, topPos, priority, control);
+ addToPicDrawView(viewId, loopNo, celNo, x, y, priority, control);
addToPicSetPicNotValid();
}