2009-10-13 15:28:27 +00:00
|
|
|
/* 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.
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/util.h"
|
|
|
|
#include "common/stack.h"
|
|
|
|
#include "graphics/primitives.h"
|
|
|
|
|
|
|
|
#include "sci/sci.h"
|
2010-06-23 15:23:37 +00:00
|
|
|
#include "sci/engine/kernel.h"
|
2009-10-13 15:28:27 +00:00
|
|
|
#include "sci/engine/state.h"
|
2010-01-29 11:03:54 +00:00
|
|
|
#include "sci/engine/selector.h"
|
2009-10-19 13:26:13 +00:00
|
|
|
#include "sci/engine/vm.h"
|
2010-01-31 12:35:15 +00:00
|
|
|
#include "sci/graphics/cache.h"
|
2010-01-31 15:07:36 +00:00
|
|
|
#include "sci/graphics/cursor.h"
|
2010-01-31 12:35:15 +00:00
|
|
|
#include "sci/graphics/ports.h"
|
|
|
|
#include "sci/graphics/paint16.h"
|
2010-06-20 15:01:31 +00:00
|
|
|
#include "sci/graphics/palette.h"
|
2010-01-05 01:37:57 +00:00
|
|
|
#include "sci/graphics/view.h"
|
|
|
|
#include "sci/graphics/screen.h"
|
|
|
|
#include "sci/graphics/transitions.h"
|
|
|
|
#include "sci/graphics/animate.h"
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
namespace Sci {
|
|
|
|
|
2010-04-24 21:45:17 +00:00
|
|
|
GfxAnimate::GfxAnimate(EngineState *state, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions)
|
|
|
|
: _s(state), _cache(cache), _ports(ports), _paint16(paint16), _screen(screen), _palette(palette), _cursor(cursor), _transitions(transitions) {
|
2009-10-13 15:28:27 +00:00
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
GfxAnimate::~GfxAnimate() {
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::init() {
|
2010-06-29 14:54:15 +00:00
|
|
|
_lastCastData.clear();
|
2009-10-21 20:57:42 +00:00
|
|
|
|
|
|
|
_ignoreFastCast = false;
|
2009-10-21 21:07:21 +00:00
|
|
|
// fastCast object is not found in any SCI games prior SCI1
|
2009-10-21 20:57:42 +00:00
|
|
|
if (getSciVersion() <= SCI_VERSION_01)
|
|
|
|
_ignoreFastCast = true;
|
2009-10-21 21:07:21 +00:00
|
|
|
// Also if fastCast object exists at gamestartup, we can assume that the interpreter doesnt do kAnimate aborts
|
2010-06-13 22:01:10 +00:00
|
|
|
// (found in Larry 1)
|
|
|
|
if (getSciVersion() > SCI_VERSION_0_EARLY) {
|
|
|
|
if (!_s->_segMan->findObjectByName("fastCast").isNull())
|
|
|
|
_ignoreFastCast = true;
|
|
|
|
}
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::disposeLastCast() {
|
2010-06-29 14:54:15 +00:00
|
|
|
_lastCastData.clear();
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
|
2009-10-13 15:28:27 +00:00
|
|
|
reg_t curAddress = list->first;
|
|
|
|
Node *curNode = _s->_segMan->lookupNode(curAddress);
|
|
|
|
reg_t curObject;
|
|
|
|
uint16 signal;
|
|
|
|
|
|
|
|
while (curNode) {
|
|
|
|
curObject = curNode->value;
|
2009-10-19 14:33:48 +00:00
|
|
|
|
2009-10-21 20:57:42 +00:00
|
|
|
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.
|
2010-06-09 09:17:48 +00:00
|
|
|
if (!_s->variables[VAR_GLOBAL][84].isNull()) {
|
|
|
|
if (!strcmp(_s->_segMan->getObjectName(_s->variables[VAR_GLOBAL][84]), "fastCast"))
|
2009-10-21 20:57:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2009-10-19 14:33:48 +00:00
|
|
|
|
2010-05-29 23:37:15 +00:00
|
|
|
signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
|
2009-10-21 19:19:03 +00:00
|
|
|
if (!(signal & kSignalFrozen)) {
|
2010-07-22 17:53:32 +00:00
|
|
|
reg_t nextNode = curNode->succ;
|
|
|
|
|
2009-10-13 15:28:27 +00:00
|
|
|
// Call .doit method of that object
|
2010-06-10 09:18:57 +00:00
|
|
|
invokeSelector(_s, curObject, SELECTOR(doit), argc, argv, 0);
|
2010-06-25 17:25:00 +00:00
|
|
|
|
|
|
|
// If a game is being loaded, stop processing
|
|
|
|
if (_s->abortScriptProcessing != kAbortNone || g_engine->shouldQuit())
|
|
|
|
return true; // Stop processing
|
|
|
|
|
2010-07-22 17:25:21 +00:00
|
|
|
// 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.
|
|
|
|
curNode = _s->_segMan->lookupNode(curAddress, false);
|
2010-07-22 17:53:32 +00:00
|
|
|
|
|
|
|
// Sanity check: If the node has been deleted, it shouldn't have a successor node
|
|
|
|
if (!curNode && !nextNode.isNull())
|
|
|
|
error("kAnimate: list node has been deleted, but it has a successor node");
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-04-16 12:58:14 +00:00
|
|
|
|
|
|
|
if (curNode) {
|
|
|
|
curAddress = curNode->succ;
|
|
|
|
curNode = _s->_segMan->lookupNode(curAddress);
|
|
|
|
}
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2009-10-19 13:26:13 +00:00
|
|
|
return true;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2010-06-29 14:54:15 +00:00
|
|
|
bool sortHelper(const AnimateEntry &entry1, const AnimateEntry &entry2) {
|
|
|
|
if (entry1.y == entry2.y) {
|
2010-05-24 15:39:30 +00:00
|
|
|
// 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
|
2010-06-29 14:54:15 +00:00
|
|
|
if (entry1.z == entry2.z)
|
|
|
|
return entry1.givenOrderNo < entry2.givenOrderNo;
|
2010-05-24 15:39:30 +00:00
|
|
|
else
|
2010-06-29 14:54:15 +00:00
|
|
|
return entry1.z < entry2.z;
|
2010-05-24 15:39:30 +00:00
|
|
|
}
|
2010-06-29 14:54:15 +00:00
|
|
|
return entry1.y < entry2.y;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::makeSortedList(List *list) {
|
2009-10-13 15:28:27 +00:00
|
|
|
reg_t curAddress = list->first;
|
|
|
|
Node *curNode = _s->_segMan->lookupNode(curAddress);
|
2010-06-29 14:54:15 +00:00
|
|
|
int16 listNr;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2010-06-29 14:54:15 +00:00
|
|
|
// Clear lists
|
2009-10-13 15:28:27 +00:00
|
|
|
_list.clear();
|
2010-06-29 14:54:15 +00:00
|
|
|
_lastCastData.clear();
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
// Fill the list
|
2010-06-29 14:54:15 +00:00
|
|
|
for (listNr = 0; curNode != 0; listNr++) {
|
|
|
|
AnimateEntry listEntry;
|
|
|
|
const reg_t curObject = curNode->value;
|
|
|
|
listEntry.object = curObject;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
// Get data from current object
|
2010-06-29 14:54:15 +00:00
|
|
|
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));
|
2010-01-15 21:13:33 +00:00
|
|
|
if (getSciVersion() >= SCI_VERSION_1_1) {
|
|
|
|
// Cel scaling
|
2010-06-29 14:54:15 +00:00
|
|
|
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));
|
2010-01-15 21:32:18 +00:00
|
|
|
} else {
|
2010-06-29 14:54:15 +00:00
|
|
|
listEntry.scaleX = 128;
|
|
|
|
listEntry.scaleY = 128;
|
2010-01-15 21:32:18 +00:00
|
|
|
}
|
2010-01-15 21:13:33 +00:00
|
|
|
} else {
|
2010-06-29 14:54:15 +00:00
|
|
|
listEntry.scaleSignal = 0;
|
|
|
|
listEntry.scaleX = 128;
|
|
|
|
listEntry.scaleY = 128;
|
2010-01-15 21:13:33 +00:00
|
|
|
}
|
2010-06-29 14:54:15 +00:00
|
|
|
// listEntry.celRect is filled in AnimateFill()
|
|
|
|
listEntry.showBitsFlag = false;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
_list.push_back(listEntry);
|
|
|
|
|
|
|
|
curAddress = curNode->succ;
|
|
|
|
curNode = _s->_segMan->lookupNode(curAddress);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now sort the list according y and z (descending)
|
|
|
|
Common::sort(_list.begin(), _list.end(), sortHelper);
|
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::fill(byte &old_picNotValid) {
|
2009-10-13 15:28:27 +00:00
|
|
|
reg_t curObject;
|
|
|
|
uint16 signal;
|
2010-02-04 22:17:58 +00:00
|
|
|
GfxView *view = NULL;
|
2010-06-29 14:54:47 +00:00
|
|
|
AnimateList::iterator it;
|
2010-06-29 14:54:31 +00:00
|
|
|
const AnimateList::iterator end = _list.end();
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.begin(); it != end; ++it) {
|
|
|
|
curObject = it->object;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
// Get the corresponding view
|
2010-06-29 14:54:47 +00:00
|
|
|
view = _cache->getView(it->viewId);
|
2010-01-25 01:39:44 +00:00
|
|
|
|
2009-10-13 15:28:27 +00:00
|
|
|
// adjust loop and cel, if any of those is invalid
|
2010-06-29 14:54:47 +00:00
|
|
|
if (it->loopNo >= view->getLoopCount()) {
|
|
|
|
it->loopNo = 0;
|
|
|
|
writeSelectorValue(_s->_segMan, curObject, SELECTOR(loop), it->loopNo);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-06-29 14:54:47 +00:00
|
|
|
if (it->celNo >= view->getCelCount(it->loopNo)) {
|
|
|
|
it->celNo = 0;
|
|
|
|
writeSelectorValue(_s->_segMan, curObject, SELECTOR(cel), it->celNo);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2010-06-23 12:58:14 +00:00
|
|
|
// Process global scaling, if needed
|
2010-06-29 14:54:47 +00:00
|
|
|
if (it->scaleSignal & kScaleSignalDoScaling) {
|
|
|
|
if (it->scaleSignal & kScaleSignalGlobalScaling) {
|
2010-06-23 12:58:14 +00:00
|
|
|
// Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY
|
|
|
|
int16 maxScale = readSelectorValue(_s->_segMan, curObject, SELECTOR(maxScale));
|
2010-06-29 14:54:47 +00:00
|
|
|
int16 celHeight = view->getHeight(it->loopNo, it->celNo);
|
2010-06-23 14:06:31 +00:00
|
|
|
int16 maxCelHeight = (maxScale * celHeight) >> 7;
|
|
|
|
reg_t globalVar2 = _s->variables[VAR_GLOBAL][2]; // current room object
|
2010-06-23 13:42:09 +00:00
|
|
|
int16 vanishingY = readSelectorValue(_s->_segMan, globalVar2, SELECTOR(vanishingY));
|
2010-06-23 14:06:31 +00:00
|
|
|
|
|
|
|
int16 fixedPortY = _ports->getPort()->rect.bottom - vanishingY;
|
2010-06-29 14:54:47 +00:00
|
|
|
int16 fixedEntryY = it->y - vanishingY;
|
2010-06-23 14:06:31 +00:00
|
|
|
if (!fixedEntryY)
|
|
|
|
fixedEntryY = 1;
|
|
|
|
|
|
|
|
if ((celHeight == 0) || (fixedPortY == 0))
|
|
|
|
error("global scaling panic");
|
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
it->scaleY = ( maxCelHeight * fixedEntryY ) / fixedPortY;
|
|
|
|
it->scaleY = (it->scaleY * 128) / celHeight;
|
2010-06-23 14:06:31 +00:00
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
it->scaleX = it->scaleY;
|
2010-06-23 12:58:14 +00:00
|
|
|
|
|
|
|
// and set objects scale selectors
|
2010-06-29 14:54:47 +00:00
|
|
|
writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX), it->scaleX);
|
|
|
|
writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY), it->scaleY);
|
2010-06-23 12:58:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-13 15:28:27 +00:00
|
|
|
// Create rect according to coordinates and given cel
|
2010-06-29 14:54:47 +00:00
|
|
|
if (it->scaleSignal & kScaleSignalDoScaling) {
|
|
|
|
view->getCelScaledRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->scaleX, it->scaleY, it->celRect);
|
2010-01-16 16:17:45 +00:00
|
|
|
} else {
|
2010-06-29 14:54:47 +00:00
|
|
|
view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
|
2010-01-16 16:17:45 +00:00
|
|
|
}
|
2010-06-29 14:54:47 +00:00
|
|
|
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);
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
signal = it->signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
// Calculate current priority according to y-coordinate
|
2009-10-21 19:19:03 +00:00
|
|
|
if (!(signal & kSignalFixedPriority)) {
|
2010-06-29 14:54:47 +00:00
|
|
|
it->priority = _ports->kernelCoordinateToPriority(it->y);
|
|
|
|
writeSelectorValue(_s->_segMan, curObject, SELECTOR(priority), it->priority);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-01-25 01:39:44 +00:00
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalNoUpdate) {
|
|
|
|
if (signal & (kSignalForceUpdate | kSignalViewUpdated)
|
|
|
|
|| (signal & kSignalHidden && !(signal & kSignalRemoveView))
|
|
|
|
|| (!(signal & kSignalHidden) && signal & kSignalRemoveView)
|
|
|
|
|| (signal & kSignalAlwaysUpdate))
|
2009-10-13 15:28:27 +00:00
|
|
|
old_picNotValid++;
|
2010-06-26 21:36:25 +00:00
|
|
|
signal &= ~kSignalStopUpdate;
|
2009-10-13 15:28:27 +00:00
|
|
|
} else {
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalStopUpdate || signal & kSignalAlwaysUpdate)
|
2009-10-13 15:28:27 +00:00
|
|
|
old_picNotValid++;
|
2010-06-26 21:36:25 +00:00
|
|
|
signal &= ~kSignalForceUpdate;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-06-29 14:54:47 +00:00
|
|
|
it->signal = signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::update() {
|
2009-10-13 15:28:27 +00:00
|
|
|
reg_t curObject;
|
|
|
|
uint16 signal;
|
|
|
|
reg_t bitsHandle;
|
|
|
|
Common::Rect rect;
|
2010-06-29 14:54:47 +00:00
|
|
|
AnimateList::iterator it;
|
2010-06-29 14:54:31 +00:00
|
|
|
const AnimateList::iterator end = _list.end();
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
// Remove all no-update cels, if requested
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.reverse_begin(); it != end; --it) {
|
|
|
|
curObject = it->object;
|
|
|
|
signal = it->signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalNoUpdate) {
|
|
|
|
if (!(signal & kSignalRemoveView)) {
|
2010-05-29 23:37:15 +00:00
|
|
|
bitsHandle = readSelector(_s->_segMan, curObject, SELECTOR(underBits));
|
2009-10-13 15:28:27 +00:00
|
|
|
if (_screen->_picNotValid != 1) {
|
2010-01-31 12:35:15 +00:00
|
|
|
_paint16->bitsRestore(bitsHandle);
|
2010-06-29 14:54:47 +00:00
|
|
|
it->showBitsFlag = true;
|
2009-10-13 15:28:27 +00:00
|
|
|
} else {
|
2010-01-31 12:35:15 +00:00
|
|
|
_paint16->bitsFree(bitsHandle);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-05-29 23:37:15 +00:00
|
|
|
writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-06-26 21:36:25 +00:00
|
|
|
signal &= ~kSignalForceUpdate;
|
2010-06-26 20:28:42 +00:00
|
|
|
if (signal & kSignalViewUpdated)
|
|
|
|
signal &= ~(kSignalViewUpdated | kSignalNoUpdate);
|
2009-10-21 19:19:03 +00:00
|
|
|
} else if (signal & kSignalStopUpdate) {
|
2010-06-26 21:36:25 +00:00
|
|
|
signal &= ~kSignalStopUpdate;
|
|
|
|
signal |= kSignalNoUpdate;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-06-29 14:54:47 +00:00
|
|
|
it->signal = signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Draw always-update cels
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.begin(); it != end; ++it) {
|
|
|
|
curObject = it->object;
|
|
|
|
signal = it->signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalAlwaysUpdate) {
|
2009-10-13 15:28:27 +00:00
|
|
|
// draw corresponding cel
|
2010-06-29 14:54:47 +00:00
|
|
|
_paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
|
|
|
|
it->showBitsFlag = true;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2010-06-26 21:36:25 +00:00
|
|
|
signal &= ~(kSignalStopUpdate | kSignalViewUpdated | kSignalNoUpdate | kSignalForceUpdate);
|
2009-10-21 19:19:03 +00:00
|
|
|
if ((signal & kSignalIgnoreActor) == 0) {
|
2010-06-29 14:54:47 +00:00
|
|
|
rect = it->celRect;
|
|
|
|
rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, rect.top, rect.bottom - 1);
|
2010-05-15 08:57:13 +00:00
|
|
|
_paint16->fillRect(rect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-06-29 14:54:47 +00:00
|
|
|
it->signal = signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Saving background for all NoUpdate-cels
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.begin(); it != end; ++it) {
|
|
|
|
curObject = it->object;
|
|
|
|
signal = it->signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalNoUpdate) {
|
|
|
|
if (signal & kSignalHidden) {
|
|
|
|
signal |= kSignalRemoveView;
|
2009-10-13 15:28:27 +00:00
|
|
|
} else {
|
2010-06-26 21:36:25 +00:00
|
|
|
signal &= ~kSignalRemoveView;
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalIgnoreActor)
|
2010-06-29 14:54:47 +00:00
|
|
|
bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
|
2009-10-13 15:28:27 +00:00
|
|
|
else
|
2010-06-29 14:54:47 +00:00
|
|
|
bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_ALL);
|
2010-05-29 23:37:15 +00:00
|
|
|
writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-06-29 14:54:47 +00:00
|
|
|
it->signal = signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw NoUpdate cels
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.begin(); it != end; ++it) {
|
|
|
|
curObject = it->object;
|
|
|
|
signal = it->signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalNoUpdate && !(signal & kSignalHidden)) {
|
2009-10-13 15:28:27 +00:00
|
|
|
// draw corresponding cel
|
2010-06-29 14:54:47 +00:00
|
|
|
_paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
|
|
|
|
it->showBitsFlag = true;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2010-06-26 21:36:25 +00:00
|
|
|
if (!(signal & kSignalIgnoreActor)) {
|
2010-06-29 14:54:47 +00:00
|
|
|
rect = it->celRect;
|
|
|
|
rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, rect.top, rect.bottom - 1);
|
2010-05-15 08:57:13 +00:00
|
|
|
_paint16->fillRect(rect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::drawCels() {
|
2009-10-13 15:28:27 +00:00
|
|
|
reg_t curObject;
|
|
|
|
uint16 signal;
|
|
|
|
reg_t bitsHandle;
|
2010-06-29 14:54:47 +00:00
|
|
|
AnimateList::iterator it;
|
2010-06-29 14:54:31 +00:00
|
|
|
const AnimateList::iterator end = _list.end();
|
2010-06-29 14:54:15 +00:00
|
|
|
_lastCastData.clear();
|
2009-10-30 09:26:14 +00:00
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.begin(); it != end; ++it) {
|
|
|
|
curObject = it->object;
|
|
|
|
signal = it->signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if (!(signal & (kSignalNoUpdate | kSignalHidden | kSignalAlwaysUpdate))) {
|
2009-10-13 15:28:27 +00:00
|
|
|
// Save background
|
2010-06-29 14:54:47 +00:00
|
|
|
bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_ALL);
|
2010-05-29 23:37:15 +00:00
|
|
|
writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
// draw corresponding cel
|
2010-06-29 14:54:47 +00:00
|
|
|
_paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
|
|
|
|
it->showBitsFlag = true;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalRemoveView) {
|
2010-06-26 21:36:25 +00:00
|
|
|
signal &= ~kSignalRemoveView;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
2010-06-29 14:54:47 +00:00
|
|
|
it->signal = signal;
|
2009-10-30 09:26:14 +00:00
|
|
|
|
|
|
|
// Remember that entry in lastCast
|
2010-06-29 14:54:47 +00:00
|
|
|
_lastCastData.push_back(*it);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::updateScreen(byte oldPicNotValid) {
|
2009-10-17 20:42:19 +00:00
|
|
|
reg_t curObject;
|
2009-10-13 15:28:27 +00:00
|
|
|
uint16 signal;
|
2010-06-29 14:54:47 +00:00
|
|
|
AnimateList::iterator it;
|
2010-06-29 14:54:31 +00:00
|
|
|
const AnimateList::iterator end = _list.end();
|
2009-10-17 20:42:19 +00:00
|
|
|
Common::Rect lsRect;
|
|
|
|
Common::Rect workerRect;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.begin(); it != end; ++it) {
|
|
|
|
curObject = it->object;
|
|
|
|
signal = it->signal;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
if (it->showBitsFlag || !(signal & (kSignalRemoveView | kSignalNoUpdate) ||
|
2009-10-21 19:19:03 +00:00
|
|
|
(!(signal & kSignalRemoveView) && (signal & kSignalNoUpdate) && oldPicNotValid))) {
|
2010-05-29 23:37:15 +00:00
|
|
|
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));
|
2009-10-17 20:42:19 +00:00
|
|
|
|
|
|
|
workerRect = lsRect;
|
2010-06-29 14:54:47 +00:00
|
|
|
workerRect.clip(it->celRect);
|
2009-10-17 20:42:19 +00:00
|
|
|
|
|
|
|
if (!workerRect.isEmpty()) {
|
|
|
|
workerRect = lsRect;
|
2010-06-29 14:54:47 +00:00
|
|
|
workerRect.extend(it->celRect);
|
2009-10-17 20:42:19 +00:00
|
|
|
} else {
|
2010-01-31 12:35:15 +00:00
|
|
|
_paint16->bitsShow(lsRect);
|
2010-06-29 14:54:47 +00:00
|
|
|
workerRect = it->celRect;
|
2009-10-17 20:42:19 +00:00
|
|
|
}
|
2010-06-29 14:54:47 +00:00
|
|
|
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);
|
2010-06-23 20:13:33 +00:00
|
|
|
// may get used for debugging
|
|
|
|
//_paint16->frameRect(workerRect);
|
2010-01-31 12:35:15 +00:00
|
|
|
_paint16->bitsShow(workerRect);
|
2009-10-17 20:42:19 +00:00
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalHidden) {
|
2010-06-29 14:54:47 +00:00
|
|
|
it->signal |= kSignalRemoveView;
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-10-17 20:42:19 +00:00
|
|
|
// use this for debug purposes
|
|
|
|
// _screen->copyToScreen();
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::restoreAndDelete(int argc, reg_t *argv) {
|
2009-10-13 15:28:27 +00:00
|
|
|
reg_t curObject;
|
|
|
|
uint16 signal;
|
2010-06-29 14:54:47 +00:00
|
|
|
AnimateList::iterator it;
|
2010-06-29 14:54:31 +00:00
|
|
|
const AnimateList::iterator end = _list.end();
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2009-10-21 15:12:10 +00:00
|
|
|
|
2010-06-29 14:54:31 +00:00
|
|
|
// 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.
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.begin(); it != end; ++it) {
|
|
|
|
curObject = it->object;
|
|
|
|
signal = it->signal;
|
2009-10-21 15:12:10 +00:00
|
|
|
|
|
|
|
// Finally update signal
|
2010-05-29 23:37:15 +00:00
|
|
|
writeSelectorValue(_s->_segMan, curObject, SELECTOR(signal), signal);
|
2009-10-21 15:12:10 +00:00
|
|
|
}
|
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.reverse_begin(); it != end; --it) {
|
|
|
|
curObject = it->object;
|
2010-06-29 14:54:31 +00:00
|
|
|
// We read out signal here again, this is not by accident but to ensure
|
|
|
|
// that we got an up-to-date signal
|
2010-05-29 23:37:15 +00:00
|
|
|
signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if ((signal & (kSignalNoUpdate | kSignalRemoveView)) == 0) {
|
2010-05-29 23:37:15 +00:00
|
|
|
_paint16->bitsRestore(readSelector(_s->_segMan, curObject, SELECTOR(underBits)));
|
|
|
|
writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2009-10-21 19:19:03 +00:00
|
|
|
if (signal & kSignalDisposeMe) {
|
2009-10-13 15:28:27 +00:00
|
|
|
// Call .delete_ method of that object
|
2010-06-10 09:18:57 +00:00
|
|
|
invokeSelector(_s, curObject, SELECTOR(delete_), argc, argv, 0);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::reAnimate(Common::Rect rect) {
|
2010-06-29 14:54:15 +00:00
|
|
|
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);
|
2009-10-30 09:26:14 +00:00
|
|
|
}
|
2010-01-31 12:35:15 +00:00
|
|
|
_paint16->bitsShow(rect);
|
2009-10-30 09:26:14 +00:00
|
|
|
// restoring
|
2010-06-29 14:54:15 +00:00
|
|
|
while (it != _lastCastData.begin()) { // FIXME: HACK, this iterator use is not very safe
|
|
|
|
it--;
|
|
|
|
_paint16->bitsRestore(it->castHandle);
|
2009-10-30 09:26:14 +00:00
|
|
|
}
|
|
|
|
} else {
|
2010-01-31 12:35:15 +00:00
|
|
|
_paint16->bitsShow(rect);
|
2009-10-30 09:26:14 +00:00
|
|
|
}
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::addToPicDrawCels() {
|
2009-10-13 15:28:27 +00:00
|
|
|
reg_t curObject;
|
2010-02-04 22:17:58 +00:00
|
|
|
GfxView *view = NULL;
|
2010-06-29 14:54:47 +00:00
|
|
|
AnimateList::iterator it;
|
2010-06-29 14:54:31 +00:00
|
|
|
const AnimateList::iterator end = _list.end();
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
for (it = _list.begin(); it != end; ++it) {
|
|
|
|
curObject = it->object;
|
2009-10-13 15:28:27 +00:00
|
|
|
|
2010-06-29 14:54:47 +00:00
|
|
|
if (it->priority == -1)
|
|
|
|
it->priority = _ports->kernelCoordinateToPriority(it->y);
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
// Get the corresponding view
|
2010-06-29 14:54:47 +00:00
|
|
|
view = _cache->getView(it->viewId);
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
// Create rect according to coordinates and given cel
|
2010-06-29 14:54:47 +00:00
|
|
|
view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
|
2009-10-13 15:28:27 +00:00
|
|
|
|
|
|
|
// draw corresponding cel
|
2010-06-29 14:54:47 +00:00
|
|
|
_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);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
void GfxAnimate::addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) {
|
2010-02-04 22:17:58 +00:00
|
|
|
GfxView *view = _cache->getView(viewId);
|
2009-10-13 15:28:27 +00:00
|
|
|
Common::Rect celRect;
|
|
|
|
|
|
|
|
// Create rect according to coordinates and given cel
|
2010-06-28 11:20:14 +00:00
|
|
|
view->getCelRect(loopNo, celNo, leftPos, topPos, priority, celRect);
|
2010-01-31 12:35:15 +00:00
|
|
|
_paint16->drawCel(view, loopNo, celNo, celRect, priority, 0);
|
2009-10-13 15:28:27 +00:00
|
|
|
}
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
|
|
|
|
void GfxAnimate::animateShowPic() {
|
|
|
|
Port *picPort = _ports->_picWind;
|
|
|
|
Common::Rect picRect = picPort->rect;
|
|
|
|
bool previousCursorState = _cursor->isVisible();
|
|
|
|
|
|
|
|
if (previousCursorState)
|
2010-02-05 14:48:51 +00:00
|
|
|
_cursor->kernelHide();
|
2010-01-31 15:07:36 +00:00
|
|
|
// Adjust picRect to become relative to screen
|
|
|
|
picRect.translate(picPort->left, picPort->top);
|
|
|
|
_transitions->doit(picRect);
|
|
|
|
if (previousCursorState)
|
2010-02-05 14:48:51 +00:00
|
|
|
_cursor->kernelShow();
|
2010-01-31 15:07:36 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
2010-06-20 15:01:31 +00:00
|
|
|
if (getSciVersion() >= SCI_VERSION_1_1)
|
|
|
|
_palette->palVaryUpdate();
|
|
|
|
|
2010-01-31 15:07:36 +00:00
|
|
|
if (listReference.isNull()) {
|
|
|
|
disposeLastCast();
|
|
|
|
if (_screen->_picNotValid)
|
|
|
|
animateShowPic();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
List *list = _s->_segMan->lookupList(listReference);
|
|
|
|
if (!list)
|
|
|
|
error("kAnimate called with non-list as parameter");
|
|
|
|
|
|
|
|
if (cycle) {
|
|
|
|
if (!invoke(list, argc, argv))
|
|
|
|
return;
|
2010-06-18 15:40:18 +00:00
|
|
|
|
|
|
|
// Look up the list again, as it may have been modified
|
|
|
|
list = _s->_segMan->lookupList(listReference);
|
2010-01-31 15:07:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Port *oldPort = _ports->setPort((Port *)_ports->_picWind);
|
|
|
|
disposeLastCast();
|
|
|
|
|
|
|
|
makeSortedList(list);
|
|
|
|
fill(old_picNotValid);
|
|
|
|
|
|
|
|
if (old_picNotValid) {
|
2010-06-29 14:54:47 +00:00
|
|
|
// 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.
|
2010-04-24 21:45:17 +00:00
|
|
|
if (getSciVersion() >= SCI_VERSION_1_EGA)
|
2010-04-24 20:08:03 +00:00
|
|
|
_ports->beginUpdate(_ports->_picWind);
|
2010-01-31 15:07:36 +00:00
|
|
|
update();
|
2010-04-24 21:45:17 +00:00
|
|
|
if (getSciVersion() >= SCI_VERSION_1_EGA)
|
2010-04-24 20:08:03 +00:00
|
|
|
_ports->endUpdate(_ports->_picWind);
|
2010-01-31 15:07:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
drawCels();
|
|
|
|
|
|
|
|
if (_screen->_picNotValid)
|
|
|
|
animateShowPic();
|
|
|
|
|
|
|
|
updateScreen(old_picNotValid);
|
|
|
|
restoreAndDelete(argc, argv);
|
|
|
|
|
2010-06-29 14:54:15 +00:00
|
|
|
if (_lastCastData.size() > 1)
|
2010-01-31 15:07:36 +00:00
|
|
|
_s->_throttleTrigger = true;
|
|
|
|
|
|
|
|
_ports->setPort(oldPort);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GfxAnimate::addToPicSetPicNotValid() {
|
|
|
|
if (getSciVersion() <= SCI_VERSION_1_EARLY)
|
|
|
|
_screen->_picNotValid = 1;
|
|
|
|
else
|
|
|
|
_screen->_picNotValid = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv) {
|
|
|
|
List *list;
|
|
|
|
|
|
|
|
_ports->setPort((Port *)_ports->_picWind);
|
|
|
|
|
|
|
|
list = _s->_segMan->lookupList(listReference);
|
|
|
|
if (!list)
|
|
|
|
error("kAddToPic called with non-list as parameter");
|
|
|
|
|
|
|
|
makeSortedList(list);
|
|
|
|
addToPicDrawCels();
|
|
|
|
|
|
|
|
addToPicSetPicNotValid();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GfxAnimate::kernelAddToPicView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) {
|
|
|
|
_ports->setPort((Port *)_ports->_picWind);
|
|
|
|
addToPicDrawView(viewId, loopNo, celNo, leftPos, topPos, priority, control);
|
|
|
|
addToPicSetPicNotValid();
|
|
|
|
}
|
|
|
|
|
2009-10-13 15:28:27 +00:00
|
|
|
} // End of namespace Sci
|