Initial commit
This commit is contained in:
836
engines/mohawk/view.cpp
Normal file
836
engines/mohawk/view.cpp
Normal file
@@ -0,0 +1,836 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mohawk/view.h"
|
||||
#include "mohawk/resource.h"
|
||||
#include "mohawk/graphics.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/system.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/paletteman.h"
|
||||
|
||||
namespace Mohawk {
|
||||
|
||||
Module::Module() {
|
||||
}
|
||||
|
||||
Module::~Module() {
|
||||
}
|
||||
|
||||
Feature::Feature(View *view) : _view(view) {
|
||||
_next = _prev = nullptr;
|
||||
_drawProc = nullptr;
|
||||
_moveProc = nullptr;
|
||||
_doneProc = nullptr;
|
||||
_frameProc = nullptr;
|
||||
_timeProc = nullptr;
|
||||
_region = 0;
|
||||
_id = 0;
|
||||
_scrbId = 0;
|
||||
_storedScrbId = 0;
|
||||
_flags = 0;
|
||||
_nextTime = 0;
|
||||
_delayTime = 0;
|
||||
_dirty = false;
|
||||
_needsReset = false;
|
||||
_justReset = false;
|
||||
_done = false;
|
||||
}
|
||||
|
||||
Feature::~Feature() {
|
||||
}
|
||||
|
||||
void Feature::setNodeDefaults(Feature *prev, Feature *next) {
|
||||
_prev = prev;
|
||||
_next = next;
|
||||
|
||||
_moveProc = nullptr;
|
||||
_drawProc = nullptr;
|
||||
_doneProc = nullptr;
|
||||
_frameProc = nullptr;
|
||||
|
||||
_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 = true;
|
||||
_needsReset = true;
|
||||
_justReset = false; // old
|
||||
_done = false; // 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 = true;
|
||||
|
||||
finishResetFeatureScript();
|
||||
|
||||
_needsReset = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = true;
|
||||
// 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 = true;
|
||||
|
||||
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) {
|
||||
_unknown168 = 0;
|
||||
_pickupProc = nullptr;
|
||||
_dropProc = nullptr;
|
||||
_dragMoveProc = nullptr;
|
||||
_oldMoveProc = nullptr;
|
||||
_dragFlags = 0;
|
||||
_oldFlags = 0;
|
||||
}
|
||||
|
||||
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 = false;
|
||||
}
|
||||
|
||||
View::View(MohawkEngine *vm) : _vm(vm) {
|
||||
_currentModule = nullptr;
|
||||
|
||||
_backgroundId = 0xffff;
|
||||
|
||||
for (uint i = 0; i < 14; i++) { // used to be 8
|
||||
_compoundSHAPGroups[i] = 0;
|
||||
}
|
||||
_numSCRBGroups = 0;
|
||||
|
||||
_lastIdleTime = 0;
|
||||
_needsUpdate = false;
|
||||
_gfx = nullptr;
|
||||
_rootNode = nullptr;
|
||||
_cursorNode = nullptr;
|
||||
}
|
||||
|
||||
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 = false;
|
||||
}
|
||||
|
||||
if (_needsUpdate) {
|
||||
finishDraw();
|
||||
_vm->_system->updateScreen();
|
||||
_needsUpdate = false;
|
||||
if (_backgroundId != 0xffff)
|
||||
_gfx->copyAnimImageToScreen(_backgroundId);
|
||||
}
|
||||
}
|
||||
|
||||
void View::setModule(Module *module) {
|
||||
if (_currentModule) {
|
||||
_currentModule->shutdown();
|
||||
delete _currentModule;
|
||||
}
|
||||
|
||||
_currentModule = nullptr;
|
||||
|
||||
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 * 3];
|
||||
|
||||
for (uint16 i = 0; i < colorCount; i++) {
|
||||
palette[i * 3 + 0] = tpalStream->readByte();
|
||||
palette[i * 3 + 1] = tpalStream->readByte();
|
||||
palette[i * 3 + 2] = tpalStream->readByte();
|
||||
tpalStream->readByte();
|
||||
}
|
||||
|
||||
// TODO: copy into temporary buffer
|
||||
_vm->_system->getPaletteManager()->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 nullptr;
|
||||
}
|
||||
|
||||
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 = nullptr;
|
||||
feature->_prev = nullptr;
|
||||
|
||||
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 nullptr;
|
||||
}
|
||||
|
||||
void View::sortView() {
|
||||
Feature *base = _rootNode;
|
||||
Feature *next = base->_next;
|
||||
Feature *otherRoot = nullptr;
|
||||
Feature *otherBase = nullptr;
|
||||
Feature *objectRoot = nullptr;
|
||||
Feature *objectBase = nullptr;
|
||||
Feature *staticRoot = nullptr;
|
||||
Feature *staticBase = nullptr;
|
||||
|
||||
// Remove all features.
|
||||
base->_next = nullptr;
|
||||
|
||||
// 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 = nullptr;
|
||||
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 = nullptr;
|
||||
staticBase = curr;
|
||||
} else {
|
||||
staticBase = curr;
|
||||
staticRoot = curr;
|
||||
curr->_prev = nullptr;
|
||||
curr->_next = nullptr;
|
||||
}
|
||||
} 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 = nullptr;
|
||||
objectBase = curr;
|
||||
} else {
|
||||
objectBase = curr;
|
||||
objectRoot = curr;
|
||||
curr->_prev = nullptr;
|
||||
curr->_next = nullptr;
|
||||
}
|
||||
} 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 = nullptr;
|
||||
otherBase = curr;
|
||||
} else {
|
||||
otherBase = curr;
|
||||
otherRoot = curr;
|
||||
curr->_prev = nullptr;
|
||||
curr->_next = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = nullptr;
|
||||
}
|
||||
|
||||
// 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 nullptr;
|
||||
|
||||
// Save the next feature and then clear the list.
|
||||
Feature *curr = root->_next;
|
||||
root->_next = nullptr;
|
||||
root->_prev = nullptr;
|
||||
|
||||
// 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 = nullptr;
|
||||
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 = nullptr;
|
||||
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 = nullptr;
|
||||
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
|
||||
Reference in New Issue
Block a user