aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/mohawk/module.mk1
-rw-r--r--engines/mohawk/view.cpp810
-rw-r--r--engines/mohawk/view.h271
3 files changed, 1082 insertions, 0 deletions
diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk
index efecb1bf98..892b99df50 100644
--- a/engines/mohawk/module.mk
+++ b/engines/mohawk/module.mk
@@ -24,6 +24,7 @@ MODULE_OBJS = \
riven_vars.o \
sound.o \
video.o \
+ view.o \
myst_stacks/channelwood.o \
myst_stacks/credits.o \
myst_stacks/demo.o \
diff --git a/engines/mohawk/view.cpp b/engines/mohawk/view.cpp
new file mode 100644
index 0000000000..54ed552535
--- /dev/null
+++ b/engines/mohawk/view.cpp
@@ -0,0 +1,810 @@
+/* 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 "mohawk/view.h"
+#include "mohawk/resource.h"
+#include "mohawk/graphics.h"
+#include "common/stream.h"
+#include "common/system.h"
+
+namespace Mohawk {
+
+Module::Module() {
+}
+
+Module::~Module() {
+}
+
+Feature::Feature(View *view) : _view(view) {
+}
+
+Feature::~Feature() {
+}
+
+void Feature::setNodeDefaults(Feature *prev, Feature *next) {
+ _prev = prev;
+ _next = next;
+
+ _moveProc = NULL;
+ _drawProc = NULL;
+ _doneProc = NULL;
+ _frameProc = NULL;
+
+ _data.bounds = Common::Rect();
+ _data.clipRect = Common::Rect();
+ _data.useClipRect = 0;
+
+ _region = 0;
+ _id = 0; // This is dealt with elsewhere.
+ _scrbId = 0;
+ _storedScrbId = 0;
+
+ _data.scrbIndex = 0;
+ _data.compoundSHAPIndex = 0;
+ _data.bitmapIds[0] = 0;
+
+ _data.unknown192 = 0;
+ _data.currFrame = 0;
+
+ _data.syncChannel = 0;
+ _data.enabled = 1;
+
+ _data.paused = 0; // new
+ _data.hidden = 0; // new
+
+ _flags = 0;
+
+ _dirty = 1;
+ _needsReset = 1;
+ _justReset = 0; // old
+ _notifyDone = 0;
+ _done = 0; // new
+
+ _nextTime = 0;
+ _delayTime = 0;
+}
+
+void Feature::resetFeatureScript(uint16 enabled, uint16 scrbId) {
+ if (!scrbId)
+ scrbId = _scrbId;
+ if (scrbId != _scrbId || _needsReset) {
+ if (_needsReset)
+ _data.bounds = Common::Rect();
+ _scrbId = scrbId;
+ _view->getnthScriptSetGroup(_data.scrbIndex, _data.compoundSHAPIndex, scrbId);
+ }
+ if (_data.scrbIndex == 0xFFFF) {
+ _data.enabled = 0;
+ _data.bitmapIds[0] = 0;
+ _data.scrbIndex = 0;
+ _data.compoundSHAPIndex = 0;
+ resetFrame();
+ return;
+ }
+
+ resetScript();
+ resetFrame();
+ _nextTime = 0; // New feature code uses _view->_lastIdleTime, but should be equivalent.
+ _data.enabled = enabled;
+ _dirty = 1;
+
+ finishResetFeatureScript();
+
+ _needsReset = 0;
+
+ if (_region) {
+ // TODO: mark _region as dirty
+ } else {
+ // TODO: mark _data.bounds as dirty
+ }
+}
+
+void Feature::resetFeature(bool notifyDone, Module::FeatureProc doneProc, uint16 scrbId) {
+ resetFeatureScript(1, scrbId);
+ _doneProc = doneProc;
+ _notifyDone = notifyDone;
+}
+
+void Feature::hide(bool clip) {
+ // FIXME: stuff
+
+ if (!_data.hidden && clip) {
+ if (_region) {
+ // TODO: mark _region as dirty
+ } else {
+ // TODO: mark _data.bounds as dirty
+ }
+ }
+
+ _data.hidden++;
+ _data.paused++;
+}
+
+void Feature::show() {
+ if (_data.hidden == 1) {
+ if (_region) {
+ // TODO: mark _region as dirty
+ } else {
+ // TODO: mark _data.bounds as dirty
+ }
+ }
+
+ _data.hidden--;
+ _data.paused--;
+}
+
+void Feature::moveAndUpdate(Common::Point newPos) {
+ if (newPos == _data.currentPos)
+ return;
+
+ _nextTime = 0;
+ _dirty = 1;
+ // TODO: mark _data.bounds as dirty
+
+ if (_data.bitmapIds[0])
+ _data.bounds.moveTo(newPos);
+
+ int xDiff = _data.currentPos.x - newPos.x;
+ int yDiff = _data.currentPos.y - newPos.y;
+
+ for (uint i = 0; i < FEATURE_BITMAP_ITEMS; i++) {
+ uint16 bitmapId = _data.bitmapIds[i];
+ if (!bitmapId) // || bitmapId > compoundSHAP.size()
+ break;
+ _data.bitmapPos[i].x -= xDiff;
+ _data.bitmapPos[i].y -= yDiff;
+ }
+
+ _data.currentPos = newPos;
+}
+
+void Feature::defaultDraw() {
+ if (_data.useClipRect) {
+ // TODO: set clip rect
+ }
+ uint16 compoundSHAPId = _view->getCompoundSHAPId(_data.compoundSHAPIndex);
+ for (uint i = 0; i < FEATURE_BITMAP_ITEMS; i++) {
+ uint16 bitmapId = _data.bitmapIds[i];
+ if (!bitmapId) // || bitmapId > compoundSHAP.size()
+ break;
+ _view->getGfx()->copyAnimSubImageToScreen(compoundSHAPId, bitmapId - 1, _data.bitmapPos[i].x, _data.bitmapPos[i].y);
+ }
+ if (_data.useClipRect) {
+ // TODO: restore clip rgn
+ }
+}
+
+OldFeature::OldFeature(View *view) : Feature(view) {
+}
+
+OldFeature::~OldFeature() {
+}
+
+void OldFeature::resetFrame() {
+ _data.currFrame = 0;
+ _data.currOffset = 1;
+}
+
+void OldFeature::resetFeatureScript(uint16 enabled, uint16 scrbId) {
+ if ((_flags & kFeatureOldAlternateScripts) && (_justReset || !_needsReset)) {
+ if (_storedScrbId)
+ return;
+ if (_flags & kFeatureOldRandom) {
+ _storedScrbId = -(int16)_scrbId;
+ _flags &= ~kFeatureOldRandom;
+ } else {
+ _storedScrbId = _scrbId;
+ }
+ }
+
+ Feature::resetFeatureScript(enabled, scrbId);
+}
+
+void OldFeature::resetScript() {
+ Common::SeekableReadStream *ourSCRB = _view->getSCRB(_data.scrbIndex, _scrbId);
+ _data.endFrame = ourSCRB->readUint16BE() - 1;
+ delete ourSCRB;
+}
+
+void OldFeature::finishResetFeatureScript() {
+ _justReset = 1;
+
+ if (_flags & kFeatureOldAdjustByPos) {
+ Common::SeekableReadStream *ourSCRB = _view->getSCRB(_data.scrbIndex, _scrbId);
+ ourSCRB->seek(4);
+ _data.nextPos.x = ourSCRB->readUint16BE();
+ _data.nextPos.y = ourSCRB->readUint16BE();
+ delete ourSCRB;
+ }
+}
+
+NewFeature::NewFeature(View *view) : Feature(view) {
+}
+
+NewFeature::~NewFeature() {
+}
+
+void NewFeature::resetFrame() {
+ _data.currOffset = 26;
+}
+
+void NewFeature::resetFeatureScript(uint16 enabled, uint16 scrbId) {
+ // TODO: _frameProc(this, -3);
+ // TODO: set unknown184 to 0x01010101
+
+ Feature::resetFeatureScript(enabled, scrbId);
+}
+
+void NewFeature::resetScript() {
+ // FIXME: registrations, etc
+ Common::SeekableReadStream *ourSCRB = _view->getSCRB(_data.scrbIndex, _scrbId);
+ ourSCRB->seek(16);
+ Common::Point scriptBase, scriptSize;
+ scriptBase.x = ourSCRB->readUint16BE();
+ scriptBase.y = ourSCRB->readUint16BE();
+ scriptSize.x = ourSCRB->readUint16BE();
+ scriptSize.y = ourSCRB->readUint16BE();
+ ourSCRB->seek(26);
+ Common::Point one, two;
+ while (true) {
+ if (ourSCRB->pos() == ourSCRB->size())
+ error("resetScript (getNewXYAndReg) ran out of script");
+ byte opcode = ourSCRB->readByte();
+ byte size = ourSCRB->readByte();
+ if (opcode != 0x10) {
+ ourSCRB->skip(size - 2);
+ } else if (size) {
+ assert(size >= 1);
+ ourSCRB->skip(2);
+ int16 x = ourSCRB->readUint16BE();
+ int16 y = ourSCRB->readUint16BE();
+ one.x = -x;
+ one.y = -y;
+ two.x = scriptBase.x + x;
+ two.y = scriptBase.y + y;
+ break;
+ }
+ }
+ delete ourSCRB;
+
+ if ((_needsReset || false /* TODO: param */) && (_unknown168 == 0x7FFFFFFF || false /* TODO: param */)) {
+ _data.currentPos = two;
+ _data.nextPos = one;
+ _unknown168 = 0;
+ if (_needsReset || false /* TODO: param */) {
+ _data.bounds = Common::Rect(scriptBase.x, scriptBase.y, scriptSize.x, scriptSize.y);
+ }
+ } else {
+ if (false /* FIXME: 0 shapes? */) {
+ _data.nextPos.x = one.x + two.x - _data.currentPos.x;
+ _data.nextPos.y = one.y + two.y - _data.currentPos.y;
+ } else if (_unknown168 != 0x7FFFFFFF) {
+ _data.nextPos = one;
+ }
+ }
+ // _needsReset = 0; (handled by caller)
+}
+
+void NewFeature::finishResetFeatureScript() {
+ _done = 0;
+}
+
+View::View(MohawkEngine *vm) : _vm(vm) {
+ _currentModule = NULL;
+
+ _backgroundId = 0xffff;
+
+ for (uint i = 0; i < 14; i++) { // used to be 8
+ _compoundSHAPGroups[i] = 0;
+ }
+ _numSCRBGroups = 0;
+}
+
+View::~View() {
+}
+
+void View::idleView() {
+ assert(_currentModule);
+
+ _lastIdleTime = getTime();
+
+ for (Feature *node = _rootNode; node; node = node->_next) {
+ if (node->_moveProc)
+ (_currentModule->*(node->_moveProc))(node);
+ }
+
+ // TODO: find a way this works for all clients
+ //if (/* TODO: _sortView */ true && !_inDialog) {
+ // sortView();
+ //}
+ sortView();
+
+ for (Feature *node = _rootNode; node; node = node->_next) {
+ if (node->_dirty) {
+ // TODO: clipping
+ _needsUpdate = true;
+ }
+ if (node->_drawProc)
+ (_currentModule->*(node->_drawProc))(node);
+ node->_dirty = 0;
+ }
+
+ if (_needsUpdate) {
+ finishDraw();
+ _vm->_system->updateScreen();
+ _needsUpdate = false;
+ if (_backgroundId != 0xffff)
+ _gfx->copyAnimImageToScreen(_backgroundId);
+ }
+}
+
+void View::setModule(Module *module) {
+ if (_currentModule) {
+ module->shutdown();
+ delete module;
+ }
+
+ _currentModule = NULL;
+
+ if (module) {
+ _currentModule = module;
+ module->init();
+ }
+}
+
+Common::Array<uint16> View::getSHPL(uint16 id) {
+ Common::SeekableReadStream *stream;
+
+ if (_vm->hasResource(ID_TCNT, id)) {
+ stream = _vm->getResource(ID_TCNT, id);
+ } else {
+ stream = _vm->getResource(ID_SHPL, id);
+ stream->seek(4);
+ setColors(stream);
+ stream->seek(0);
+ }
+
+ uint16 base = stream->readUint16BE();
+ uint16 count = stream->readUint16BE();
+ delete stream;
+
+ Common::Array<uint16> items;
+ for (uint i = 0; i < count; i++)
+ items.push_back(base + i);
+
+ return items;
+}
+
+void View::installBG(uint16 id) {
+ // getShapes
+ Common::Array<uint16> shapes = getSHPL(id);
+ if (_vm->hasResource(ID_TPAL, id)) {
+ Common::SeekableReadStream *stream = _vm->getResource(ID_TPAL, id);
+ setColors(stream);
+ delete stream;
+ }
+
+ if (shapes.size() != 1) {
+ // TODO
+ warning("background with id 0x%04x has the wrong number of shapes (%d)", id, shapes.size());
+ _backgroundId = id;
+ _gfx->copyAnimImageToScreen(_backgroundId);
+ } else {
+ // DrawViewBackground
+ _backgroundId = shapes[0];
+ _gfx->copyAnimImageToScreen(_backgroundId);
+ }
+}
+
+void View::setColors(Common::SeekableReadStream *tpalStream) {
+ uint16 colorStart = tpalStream->readUint16BE();
+ uint16 colorCount = tpalStream->readUint16BE();
+ byte *palette = new byte[colorCount * 4];
+
+ for (uint16 i = 0; i < colorCount; i++) {
+ palette[i * 4] = tpalStream->readByte();
+ palette[i * 4 + 1] = tpalStream->readByte();
+ palette[i * 4 + 2] = tpalStream->readByte();
+ palette[i * 4 + 3] = tpalStream->readByte();
+ }
+
+ // TODO: copy into temporary buffer
+ _vm->_system->setPalette(palette, colorStart, colorCount);
+ delete[] palette;
+
+ // original does pdLightenUp here..
+}
+
+void View::copyFadeColors(uint start, uint count) {
+ // TODO
+}
+
+uint16 View::getCompoundSHAPId(uint16 shapIndex) {
+ return _compoundSHAPGroups[shapIndex];
+}
+
+void View::installGroupOfSCRBs(bool main, uint base, uint size, uint count) {
+ if (main) {
+ // TODO: _dropSpots.clear();
+ _numSCRBGroups = 0;
+ _SCRBEntries.clear();
+ }
+
+ if (_numSCRBGroups >= 14) // used to be 8
+ error("installGroupOfSCRBs called when we already had 14 groups");
+
+ for (uint i = 0; i < size; i++)
+ _SCRBEntries.push_back(base + i);
+
+ // TODO: think about this
+ if (count == 0)
+ count = size;
+ else if (count > size) {
+ for (uint i = 0; i < count - size; i++)
+ _SCRBEntries.push_back(0);
+ } else
+ error("installGroupOfSCRBs got count %d, size %d", count, size);
+
+ _SCRBGroupBases[_numSCRBGroups] = base;
+ _SCRBGroupSizes[_numSCRBGroups] = count;
+ _numSCRBGroups++;
+}
+
+void View::freeScripts() {
+ freeFeatureShapes();
+
+ for (uint i = 0; i < 14; i++) { // used to be 8
+ _SCRBGroupBases[i] = 0;
+ _SCRBGroupSizes[i] = 0;
+ }
+ _SCRBEntries.clear();
+ _numSCRBGroups = 0;
+}
+
+void View::installFeatureShapes(bool regs, uint groupId, uint16 resourceBase) {
+ if (groupId >= 14) // used to be 8
+ error("installFeatureShapes called for invalid group %d", groupId);
+
+ if (_compoundSHAPGroups[groupId])
+ error("installFeatureShapes called for existing group %d", groupId);
+
+ _compoundSHAPGroups[groupId] = resourceBase;
+
+ if (regs) {
+ // TODO
+ }
+}
+
+void View::freeFeatureShapes() {
+ for (uint i = 0; i < 14; i++) { // used to be 8
+ _compoundSHAPGroups[i] = 0;
+ // TODO: wipe regs data
+ }
+}
+
+uint16 View::getGroupFromBaseId(uint16 baseId) {
+ for (uint i = 0; i < 14; i++) {
+ if (_compoundSHAPGroups[i] == baseId)
+ return i;
+ }
+
+ // TODO: error?
+ return 0xffff;
+}
+
+void View::getnthScriptSetGroup(uint16 &scrbIndex, uint16 &shapIndex, uint16 scrbId) {
+ scrbIndex = 0;
+ for (uint i = 0; i < _numSCRBGroups; i++) {
+ if (_SCRBGroupBases[i] <= scrbId && _SCRBGroupBases[i] + _SCRBGroupSizes[i] > scrbId) {
+ shapIndex = i;
+ scrbIndex += scrbId - _SCRBGroupBases[i];
+ return;
+ }
+ scrbIndex += _SCRBGroupSizes[i];
+ }
+ scrbIndex = 0xffff;
+}
+
+Common::SeekableReadStream *View::getSCRB(uint16 index, uint16 id) {
+ // If we don't have an entry, load the load provided id.
+ // (The 0xffff check is a default parameter hack.)
+ if (!_SCRBEntries[index] && id != 0xffff)
+ _SCRBEntries[index] = id;
+
+ // FIXME
+ if (_vm->hasResource(ID_SCRB, _SCRBEntries[index]))
+ return _vm->getResource(ID_SCRB, _SCRBEntries[index]);
+ return _vm->getResource(ID_TSCR, _SCRBEntries[index]);
+}
+
+Feature *View::getFeaturePtr(uint16 id) {
+ for (Feature *node = _cursorNode; node; node = node->_prev) {
+ if (node->_id == id)
+ return node;
+ }
+
+ return NULL;
+}
+
+uint16 View::getNewFeatureId() {
+ uint16 nextId = 0;
+ Feature *node;
+ for (node = _rootNode; node; node = node->_next) {
+ // The original doesn't check for 0xffff but I don't want to fudge with signed integers.
+ if (node->_id != 0xffff && node->_id > nextId)
+ nextId = node->_id;
+ }
+ return nextId + 1;
+}
+
+void View::removeFeature(Feature *feature, bool free) {
+ // TODO: or bounds into dirty feature bounds
+
+ feature->_prev->_next = feature->_next;
+ feature->_next->_prev = feature->_prev;
+ feature->_next = NULL;
+ feature->_prev = NULL;
+
+ if (free)
+ delete feature;
+}
+
+void View::insertUnderCursor(Feature *feature) {
+ feature->_next = _cursorNode;
+ feature->_prev = _cursorNode->_prev;
+ feature->_prev->_next = feature;
+ feature->_next->_prev = feature;
+}
+
+Feature *View::pointOnFeature(bool topdown, uint32 flags, Common::Point pos) {
+ flags &= 0x7fffff;
+ Feature *curr = _rootNode->_next;
+ if (topdown)
+ curr = _cursorNode->_prev;
+ while (curr) {
+ if ((curr->_flags & 0x7fffff) == flags)
+ if (curr->_data.bounds.contains(pos))
+ return curr;
+ if (topdown)
+ curr = curr->_prev;
+ else
+ curr = curr->_next;
+ }
+ return NULL;
+}
+
+void View::sortView() {
+ Feature *base = _rootNode;
+ Feature *next = base->_next;
+ Feature *otherRoot = NULL;
+ Feature *otherBase = NULL;
+ Feature *objectRoot = NULL;
+ Feature *objectBase = NULL;
+ Feature *staticRoot = NULL;
+ Feature *staticBase = NULL;
+
+ // Remove all features.
+ base->_next = NULL;
+
+ // Iterate through all the previous features, placing them in the appropriate list.
+ while (next) {
+ Feature *curr = next;
+ next = next->_next;
+
+ if (curr->_flags & kFeatureSortBackground) {
+ // These are behind everything else (e.g. stars, drop spot highlights),
+ // so we insert this node directly after the current base.
+ base->_next = curr;
+ curr->_prev = base;
+ curr->_next = NULL;
+ base = base->_next;
+ } else if (curr->_flags & kFeatureSortStatic) {
+ // Insert this node into the list of static objects.
+ if (staticBase) {
+ staticBase->_next = curr;
+ curr->_prev = staticBase;
+ curr->_next = NULL;
+ staticBase = curr;
+ } else {
+ staticBase = curr;
+ staticRoot = curr;
+ curr->_prev = NULL;
+ curr->_next = NULL;
+ }
+ } else if (curr->_flags & kFeatureObjectMask) { // This is == 1 or == 2 in old code.
+ // Insert this node into the list of objects.
+ if (objectRoot) {
+ objectBase->_next = curr;
+ curr->_prev = objectBase;
+ curr->_next = NULL;
+ objectBase = curr;
+ } else {
+ objectBase = curr;
+ objectRoot = curr;
+ curr->_prev = NULL;
+ curr->_next = NULL;
+ }
+ } else {
+ if (!(curr->_flags & kFeatureOldSortForeground))
+ curr->_flags |= kFeatureSortStatic;
+
+ // Insert this node into the list of other features.
+ if (otherRoot) {
+ otherBase->_next = curr;
+ curr->_prev = otherBase;
+ curr->_next = NULL;
+ otherBase = curr;
+ } else {
+ otherBase = curr;
+ otherRoot = curr;
+ curr->_prev = NULL;
+ curr->_next = NULL;
+ }
+ }
+ }
+
+ // Add the static features after the background ones.
+ Feature *curr = staticRoot;
+ while (curr) {
+ Feature *prev = curr;
+ curr = curr->_next;
+ base->_next = prev;
+ prev->_prev = base;
+ base = base->_next;
+ base->_next = NULL;
+ }
+
+ // Add the other features on top..
+ _rootNode = mergeLists(_rootNode, sortOneList(otherRoot));
+ // Then finally, add the objects.
+ _rootNode = mergeLists(_rootNode, sortOneList(objectRoot));
+}
+
+Feature *View::sortOneList(Feature *root) {
+ if (!root)
+ return NULL;
+
+ // Save the next feature and then clear the list.
+ Feature *curr = root->_next;
+ root->_next = NULL;
+ root->_prev = NULL;
+
+ // Iterate over all the features.
+ while (curr) {
+ Feature *prev = curr;
+ curr = curr->_next;
+ Common::Rect &prevRect = prev->_data.bounds;
+
+ // Check against all features currently in the list.
+ Feature *check = root;
+ while (check) {
+ Common::Rect &checkRect = check->_data.bounds;
+
+ if ((prev->_flags & kFeatureOldSortForeground) || (prevRect.bottom >= checkRect.bottom && (prevRect.bottom != checkRect.bottom || prevRect.left >= checkRect.left))) {
+ // If we're meant to be in front of everything else, or we're in front of the check object..
+ if (!check->_next) {
+ // This is the end of the list: add ourselves there.
+ check->_next = prev;
+ prev->_prev = check;
+ prev->_next = NULL;
+ break;
+ }
+ } else {
+ // We're meant to be behind this object. Insert ourselves here.
+ prev->_prev = check->_prev;
+ prev->_next = check;
+ check->_prev = prev;
+ if (prev->_prev)
+ prev->_prev->_next = prev;
+ else
+ root = prev;
+ break;
+ }
+
+ check = check->_next;
+ }
+ }
+
+ return root;
+}
+
+Feature *View::mergeLists(Feature *root, Feature *mergeRoot) {
+ Feature *base = root;
+ // Skip anything marked as being behind everything else.
+ while (base->_next && (base->_next->_flags & kFeatureSortBackground))
+ base = base->_next;
+
+ // Iterate over all the objects in the root to be merged.
+ Feature *curr = mergeRoot;
+ while (curr) {
+ Feature *prev = curr;
+ curr = curr->_next;
+ Common::Rect &prevRect = prev->_data.bounds;
+
+ // Check against all objects currently in the list.
+ Feature *check = base;
+ if (prev->_flags & kFeatureOldSortForeground) {
+ // This object is meant to be in front of everything else,
+ // put it at the end of the list.
+ while (check && check->_next)
+ check = check->_next;
+ check->_next = prev;
+ prev->_prev = check;
+ prev->_next = NULL;
+ continue;
+ }
+
+ while (check) {
+ if (check->_flags & kFeatureOldSortForeground) {
+ // The other object is meant to be in front of everything else,
+ // put ourselves before it.
+ prev->_prev = check->_prev;
+ prev->_next = check;
+ check->_prev = prev;
+ // The original doesn't bother with this 'if'.
+ if (prev->_prev)
+ prev->_prev->_next = prev;
+ else
+ root = prev;
+ break;
+ }
+
+ if (!check->_next) {
+ // We're at the end of the list, so we have to go here.
+ check->_next = prev;
+ prev->_prev = check;
+ prev->_next = NULL;
+ base = prev;
+ break;
+ }
+
+ Common::Rect &checkRect = check->_data.bounds;
+
+ if (prevRect.bottom < checkRect.bottom || (prevRect.bottom == checkRect.bottom && prevRect.left < checkRect.left)) {
+ if (prevRect.bottom < checkRect.top || (
+ (!(check->_flags & kFeatureSortCheckLeft) || prevRect.left >= checkRect.left) &&
+ (!(check->_flags & kFeatureSortCheckTop) || prevRect.top >= checkRect.top) &&
+ (!(check->_flags & kFeatureSortCheckRight) || prevRect.right <= checkRect.right))) {
+ // Insert ourselves before this one.
+ prev->_prev = check->_prev;
+ prev->_next = check;
+ check->_prev = prev;
+ if (prev->_prev)
+ prev->_prev->_next = prev;
+ else
+ root = prev;
+ base = prev->_next;
+ break;
+ }
+ }
+
+ check = check->_next;
+ }
+ }
+
+ return root;
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/view.h b/engines/mohawk/view.h
new file mode 100644
index 0000000000..14a47eebe4
--- /dev/null
+++ b/engines/mohawk/view.h
@@ -0,0 +1,271 @@
+/* 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$
+ *
+ */
+
+#ifndef MOHAWK_VIEW_H
+#define MOHAWK_VIEW_H
+
+#include "mohawk/mohawk.h"
+#include "common/rect.h"
+
+namespace Mohawk {
+
+class GraphicsManager;
+
+class Feature;
+class View;
+
+enum {
+ kFeatureObjectMask = 0xff, // both (sort of)
+ kFeatureOldSortForeground = 0x1000, // old
+ kFeatureOldDropSpot = 0x2000, // old
+ kFeatureOldNoClip = 0x4000, // old
+ kFeatureNewSortForeground = 0x4000, // new
+ kFeatureSortBackground = 0x8000, // both
+ kFeatureOldReset = 0x10000, // old
+ kFeatureOldDisable = 0x20000, // old
+ kFeatureOldAlternateScripts = 0x40000, // old
+ kFeatureOldDisableOnReset = 0x80000, // old
+ kFeatureDisableOnEnd = 0x100000, // both
+ kFeatureNewDisable = 0x200000, // new
+ kFeatureNewDisableOnReset = 0x400000, // new
+ kFeatureOldAdjustByPos = 0x800000, // old
+ kFeatureNewNoLoop = 0x800000, // new
+ kFeatureOldDisabled = 0x1000000, // old
+ kFeatureOldRandom = 0x2000000, // old
+ kFeatureNewClip = 0x2000000, // new
+ kFeatureSortStatic = 0x4000000, // both
+ kFeatureInternalRegion = 0x8000000, // both
+ kFeatureSortCheckRight = 0x10000000, // both
+ kFeatureSortCheckTop = 0x20000000, // both
+ kFeatureSortCheckLeft = 0x40000000, // both
+ kFeatureNewInternalTiming = 0x80000000 // new
+};
+
+class Module {
+public:
+ Module();
+ virtual ~Module();
+
+ virtual void init() = 0;
+ virtual void shutdown() = 0;
+ virtual void update() = 0;
+
+ typedef void (Module::*HotspotProc)(uint);
+ typedef void (Module::*FeatureProc)(Feature *);
+ typedef bool (Module::*BooleanProc)(Feature *);
+ typedef void (Module::*PickupProc)(Feature *, Common::Point, uint32, Common::Rect *);
+};
+
+// This is memcpy()ed around, beware.
+#define FEATURE_BITMAP_ITEMS 48 // this is 24 in old
+struct FeatureData {
+ uint16 bitmapIds[FEATURE_BITMAP_ITEMS];
+ Common::Point bitmapPos[FEATURE_BITMAP_ITEMS];
+
+ uint16 unknown192; // old?
+
+ uint16 scrbIndex;
+ uint16 compoundSHAPIndex;
+ uint16 endFrame; // old?
+ uint16 currFrame; // old?
+ uint32 currOffset;
+
+ Common::Rect bounds;
+
+ Common::Point currentPos;
+ Common::Point nextPos;
+
+ uint16 unknown220; // old?
+
+ uint16 syncChannel;
+ uint16 enabled;
+ byte paused; // new
+ byte hidden; // new
+
+ uint16 useClipRect;
+ Common::Rect clipRect;
+};
+
+class Feature {
+public:
+ Feature(View *view);
+ virtual ~Feature();
+
+ virtual void resetFrame() = 0;
+
+ virtual void setNodeDefaults(Feature *prev, Feature *next);
+ virtual void resetFeatureScript(uint16 enabled, uint16 scrbId);
+ virtual void resetFeature(bool notifyDone, Module::FeatureProc doneProc, uint16 scrbId);
+
+ void hide(bool clip);
+ void show();
+
+ void moveAndUpdate(Common::Point newPos);
+
+ void defaultDraw();
+
+ Feature *_next, *_prev;
+
+ Module::FeatureProc _drawProc;
+ Module::FeatureProc _moveProc;
+ Module::FeatureProc _doneProc;
+ Module::FeatureProc _frameProc;
+ Module::BooleanProc _timeProc;
+
+ uint16 _region; // TODO
+ uint16 _id;
+ uint16 _scrbId;
+ uint16 _storedScrbId; // old
+ uint32 _flags;
+ uint32 _nextTime;
+ uint32 _delayTime;
+ uint16 _dirty; // byte in old
+ byte _needsReset;
+ byte _justReset; // old
+ byte _notifyDone; // old
+ byte _done; // new
+
+ FeatureData _data;
+
+protected:
+ View *_view;
+
+ virtual void resetScript() = 0;
+ virtual void finishResetFeatureScript() = 0;
+};
+
+class OldFeature : public Feature {
+public:
+ OldFeature(View *view);
+ ~OldFeature();
+
+ void resetFrame();
+ void resetFeatureScript(uint16 enabled, uint16 scrbId);
+
+protected:
+ void resetScript();
+ void finishResetFeatureScript();
+};
+
+class NewFeature : public Feature {
+public:
+ NewFeature(View *view);
+ ~NewFeature();
+
+ void resetFrame();
+ void resetFeatureScript(uint16 enabled, uint16 scrbId);
+
+ uint32 _unknown168;
+
+ // Drag/drop variables.
+ Module::PickupProc _pickupProc;
+ Module::FeatureProc _dropProc;
+ Module::FeatureProc _dragMoveProc;
+ Module::FeatureProc _oldMoveProc;
+ uint32 _dragFlags;
+ uint32 _oldFlags;
+ Common::Point _oldPos;
+ Common::Point _posDiff;
+ Common::Point _currDragPos;
+
+protected:
+ void resetScript();
+ void finishResetFeatureScript();
+};
+
+#define NUM_SYNC_CHANNELS 17
+struct SyncChannel {
+ uint16 masterId;
+ byte state;
+ bool alternate;
+};
+
+class View {
+public:
+ View(MohawkEngine *vm);
+ virtual ~View();
+
+ virtual void idleView();
+
+ void setModule(Module *module);
+ Module *getCurrentModule() { return _currentModule; }
+ GraphicsManager *getGfx() { return _gfx; }
+
+ Common::Array<uint16> getSHPL(uint16 id);
+ void installBG(uint16 id);
+ void setColors(Common::SeekableReadStream *tpalStream);
+ void copyFadeColors(uint start, uint count);
+
+ uint16 getCompoundSHAPId(uint16 shapIndex);
+
+ void installGroupOfSCRBs(bool main, uint base, uint size, uint count = 0);
+ virtual void freeScripts();
+ void installFeatureShapes(bool regs, uint groupId, uint16 resourceBase);
+ void freeFeatureShapes();
+
+ uint16 getGroupFromBaseId(uint16 baseId);
+ void getnthScriptSetGroup(uint16 &scrbIndex, uint16 &shapIndex, uint16 scrbId);
+ Common::SeekableReadStream *getSCRB(uint16 index, uint16 id = 0xffff);
+
+ Feature *getFeaturePtr(uint16 id);
+ uint16 getNewFeatureId();
+ void removeFeature(Feature *feature, bool free);
+ void insertUnderCursor(Feature *feature);
+ Feature *pointOnFeature(bool topdown, uint32 flags, Common::Point pos);
+ void sortView();
+
+ uint32 _lastIdleTime;
+ SyncChannel _syncChannels[NUM_SYNC_CHANNELS];
+
+ virtual uint32 getTime() = 0;
+
+ bool _needsUpdate;
+
+protected:
+ MohawkEngine *_vm;
+ GraphicsManager *_gfx;
+ void setGraphicsManager(GraphicsManager *gfx) { _gfx = gfx; } // TODO
+ Module *_currentModule;
+
+ uint16 _backgroundId;
+
+ Feature *_rootNode, *_cursorNode;
+
+ uint16 _numSCRBGroups;
+ uint16 _SCRBGroupBases[14];
+ uint16 _SCRBGroupSizes[14];
+ Common::Array<uint16> _SCRBEntries;
+ //uint16 _numCompoundSHAPGroups;
+ uint16 _compoundSHAPGroups[14];
+
+ Feature *sortOneList(Feature *root);
+ Feature *mergeLists(Feature *root, Feature *mergeRoot);
+
+ virtual void finishDraw() { }
+};
+
+} // End of namespace Mohawk
+
+#endif