2016-05-24 19:03:21 +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.
|
|
|
|
*
|
|
|
|
*/
|
2016-05-25 22:16:29 +00:00
|
|
|
|
2016-05-24 19:03:21 +00:00
|
|
|
#include "director/score.h"
|
|
|
|
#include "common/stream.h"
|
|
|
|
#include "common/debug.h"
|
2016-06-07 13:45:02 +00:00
|
|
|
#include "common/file.h"
|
|
|
|
#include "common/config-manager.h"
|
2016-05-24 19:03:21 +00:00
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
#include "common/system.h"
|
|
|
|
#include "director/dib.h"
|
|
|
|
#include "director/resource.h"
|
2016-06-09 22:59:05 +00:00
|
|
|
#include "director/lingo/lingo.h"
|
2016-06-11 16:29:23 +00:00
|
|
|
#include "director/sound.h"
|
2016-05-25 22:16:29 +00:00
|
|
|
|
|
|
|
#include "graphics/palette.h"
|
|
|
|
#include "common/events.h"
|
|
|
|
#include "engines/util.h"
|
2016-05-31 17:49:05 +00:00
|
|
|
#include "graphics/managed_surface.h"
|
2016-05-25 22:16:29 +00:00
|
|
|
|
2016-05-24 19:03:21 +00:00
|
|
|
namespace Director {
|
|
|
|
|
2016-06-17 12:08:05 +00:00
|
|
|
Score::Score(DirectorEngine *vm) {
|
|
|
|
_vm = vm;
|
2016-05-31 17:49:05 +00:00
|
|
|
_surface = new Graphics::ManagedSurface;
|
2016-06-13 16:22:11 +00:00
|
|
|
_trailSurface = new Graphics::ManagedSurface;
|
2016-06-17 12:08:05 +00:00
|
|
|
_movieArchive = _vm->getMainArchive();
|
|
|
|
_lingo = _vm->getLingo();
|
|
|
|
_soundManager = _vm->getSoundManager();
|
2016-06-09 16:08:44 +00:00
|
|
|
_lingo->processEvent(kEventPrepareMovie, 0);
|
2016-06-16 12:17:28 +00:00
|
|
|
_movieScriptCount = 0;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-07 13:45:02 +00:00
|
|
|
if (_movieArchive->hasResource(MKTAG('M','C','N','M'), 0)) {
|
|
|
|
_macName = _movieArchive->getName(MKTAG('M','C','N','M'), 0).c_str();
|
|
|
|
}
|
|
|
|
|
2016-06-01 17:13:36 +00:00
|
|
|
if (_movieArchive->hasResource(MKTAG('V','W','L','B'), 1024)) {
|
|
|
|
loadLabels(*_movieArchive->getResource(MKTAG('V','W','L','B'), 1024));
|
|
|
|
}
|
2016-06-16 15:20:13 +00:00
|
|
|
}
|
2016-06-01 18:33:23 +00:00
|
|
|
|
2016-06-16 15:20:13 +00:00
|
|
|
void Score::loadArchive() {
|
2016-06-17 12:26:41 +00:00
|
|
|
Common::Array<uint16> clutList = _movieArchive->getResourceIDList(MKTAG('C','L','U','T'));
|
|
|
|
|
|
|
|
if (clutList.size() > 1)
|
|
|
|
error("More than one palette was found");
|
|
|
|
|
|
|
|
if (clutList.size() == 0)
|
|
|
|
error("CLUT not found");
|
|
|
|
|
|
|
|
Common::SeekableReadStream *pal = _movieArchive->getResource(MKTAG('C', 'L', 'U', 'T'), clutList[0]);
|
|
|
|
|
|
|
|
loadPalette(*pal);
|
|
|
|
g_system->getPaletteManager()->setPalette(_vm->getPalette(), 0, _vm->getPaletteColorCount());
|
2016-06-18 11:55:40 +00:00
|
|
|
|
2016-06-16 15:20:13 +00:00
|
|
|
assert(_movieArchive->hasResource(MKTAG('V','W','S','C'), 1024));
|
|
|
|
assert(_movieArchive->hasResource(MKTAG('V','W','C','F'), 1024));
|
|
|
|
assert(_movieArchive->hasResource(MKTAG('V','W','C','R'), 1024));
|
|
|
|
loadFrames(*_movieArchive->getResource(MKTAG('V','W','S','C'), 1024));
|
|
|
|
loadConfig(*_movieArchive->getResource(MKTAG('V','W','C','F'), 1024));
|
|
|
|
loadCastData(*_movieArchive->getResource(MKTAG('V','W','C','R'), 1024));
|
2016-06-17 12:26:41 +00:00
|
|
|
|
2016-06-01 18:33:23 +00:00
|
|
|
if (_movieArchive->hasResource(MKTAG('V','W','A','C'), 1024)) {
|
|
|
|
loadActions(*_movieArchive->getResource(MKTAG('V','W','A','C'), 1024));
|
|
|
|
}
|
2016-06-03 16:07:30 +00:00
|
|
|
|
2016-06-06 16:11:20 +00:00
|
|
|
if (_movieArchive->hasResource(MKTAG('V','W','F','I'), 1024)) {
|
|
|
|
loadFileInfo(*_movieArchive->getResource(MKTAG('V','W','F','I'), 1024));
|
|
|
|
}
|
2016-06-06 14:20:19 +00:00
|
|
|
|
2016-06-06 16:56:41 +00:00
|
|
|
if (_movieArchive->hasResource(MKTAG('V','W','F','M'), 1024)) {
|
|
|
|
loadFontMap(*_movieArchive->getResource(MKTAG('V','W','F','M'), 1024));
|
|
|
|
}
|
|
|
|
|
2016-06-06 14:20:19 +00:00
|
|
|
Common::Array<uint16> vwci = _movieArchive->getResourceIDList(MKTAG('V','W','C','I'));
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-06 14:20:19 +00:00
|
|
|
if (vwci.size() > 0) {
|
|
|
|
Common::Array<uint16>::iterator iterator;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-06 14:20:19 +00:00
|
|
|
for (iterator = vwci.begin(); iterator != vwci.end(); ++iterator)
|
2016-06-11 14:27:19 +00:00
|
|
|
loadCastInfo(*_movieArchive->getResource(MKTAG('V','W','C','I'), *iterator), *iterator);
|
2016-06-06 14:20:19 +00:00
|
|
|
}
|
|
|
|
|
2016-06-15 16:34:00 +00:00
|
|
|
Common::Array<uint16> stxt = _movieArchive->getResourceIDList(MKTAG('S','T','X','T'));
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 16:34:00 +00:00
|
|
|
if (stxt.size() > 0) {
|
|
|
|
Common::Array<uint16>::iterator iterator;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 16:34:00 +00:00
|
|
|
for (iterator = stxt.begin(); iterator != stxt.end(); ++iterator) {
|
|
|
|
loadScriptText(*_movieArchive->getResource(MKTAG('S','T','X','T'), *iterator));
|
|
|
|
}
|
|
|
|
}
|
2016-06-01 14:38:09 +00:00
|
|
|
}
|
|
|
|
|
2016-06-10 16:27:35 +00:00
|
|
|
Score::~Score() {
|
|
|
|
_surface->free();
|
2016-06-13 16:22:11 +00:00
|
|
|
_trailSurface->free();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-10 16:27:35 +00:00
|
|
|
delete _surface;
|
2016-06-13 16:22:11 +00:00
|
|
|
delete _trailSurface;
|
2016-06-10 16:27:35 +00:00
|
|
|
|
|
|
|
_movieArchive->close();
|
|
|
|
delete _movieArchive;
|
|
|
|
}
|
|
|
|
|
2016-06-17 12:08:05 +00:00
|
|
|
void Score::loadPalette(Common::SeekableReadStream &stream) {
|
|
|
|
uint16 steps = stream.size() / 6;
|
|
|
|
uint16 index = (steps * 3) - 1;
|
|
|
|
uint16 _paletteColorCount = steps;
|
|
|
|
byte *_palette = new byte[index];
|
|
|
|
|
|
|
|
for (uint8 i = 0; i < steps; i++) {
|
|
|
|
_palette[index - 2] = stream.readByte();
|
|
|
|
stream.readByte();
|
|
|
|
|
|
|
|
_palette[index - 1] = stream.readByte();
|
|
|
|
stream.readByte();
|
|
|
|
|
|
|
|
_palette[index] = stream.readByte();
|
|
|
|
stream.readByte();
|
|
|
|
index -= 3;
|
|
|
|
}
|
|
|
|
_vm->setPalette(_palette, _paletteColorCount);
|
|
|
|
}
|
|
|
|
|
2016-06-01 14:38:09 +00:00
|
|
|
void Score::loadFrames(Common::SeekableReadStream &stream) {
|
2016-05-24 19:03:21 +00:00
|
|
|
uint32 size = stream.readUint32BE();
|
|
|
|
size -= 4;
|
|
|
|
uint16 channelSize;
|
|
|
|
uint16 channelOffset;
|
|
|
|
|
2016-06-17 12:26:41 +00:00
|
|
|
Frame *initial = new Frame(_vm);
|
2016-05-25 22:16:29 +00:00
|
|
|
_frames.push_back(initial);
|
2016-05-28 15:39:33 +00:00
|
|
|
|
2016-05-24 19:03:21 +00:00
|
|
|
while (size != 0) {
|
|
|
|
uint16 frameSize = stream.readUint16BE();
|
|
|
|
size -= frameSize;
|
|
|
|
frameSize -= 2;
|
2016-05-25 22:16:29 +00:00
|
|
|
Frame *frame = new Frame(*_frames.back());
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
while (frameSize != 0) {
|
2016-05-24 19:03:21 +00:00
|
|
|
channelSize = stream.readByte() * 2;
|
|
|
|
channelOffset = stream.readByte() * 2;
|
|
|
|
frame->readChannel(stream, channelOffset, channelSize);
|
|
|
|
frameSize -= channelSize + 2;
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
_frames.push_back(frame);
|
2016-05-24 19:03:21 +00:00
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-24 19:03:21 +00:00
|
|
|
//remove initial frame
|
2016-05-25 22:16:29 +00:00
|
|
|
_frames.remove_at(0);
|
|
|
|
}
|
|
|
|
|
2016-05-26 18:05:34 +00:00
|
|
|
void Score::loadConfig(Common::SeekableReadStream &stream) {
|
|
|
|
/*uint16 unk1 = */ stream.readUint16BE();
|
|
|
|
/*ver1 = */ stream.readUint16BE();
|
2016-05-28 15:07:21 +00:00
|
|
|
_movieRect = Score::readRect(stream);
|
2016-05-26 18:05:34 +00:00
|
|
|
|
|
|
|
_castArrayStart = stream.readUint16BE();
|
|
|
|
_castArrayEnd = stream.readUint16BE();
|
2016-05-27 19:10:43 +00:00
|
|
|
_currentFrameRate = stream.readByte();
|
2016-05-26 18:05:34 +00:00
|
|
|
stream.skip(9);
|
2016-06-09 16:08:44 +00:00
|
|
|
_stageColor = stream.readUint16BE();
|
2016-05-26 18:05:34 +00:00
|
|
|
}
|
|
|
|
|
2016-05-26 11:51:51 +00:00
|
|
|
void Score::readVersion(uint32 rid) {
|
|
|
|
_versionMinor = rid & 0xffff;
|
|
|
|
_versionMajor = rid >> 16;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
|
|
|
debug("Version: %d.%d", _versionMajor, _versionMinor);
|
2016-05-26 11:51:51 +00:00
|
|
|
}
|
|
|
|
|
2016-05-26 18:05:34 +00:00
|
|
|
void Score::loadCastData(Common::SeekableReadStream &stream) {
|
2016-05-31 18:35:57 +00:00
|
|
|
for (uint16 id = _castArrayStart; id <= _castArrayEnd; id++) {
|
2016-05-26 18:05:34 +00:00
|
|
|
byte size = stream.readByte();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-27 14:00:57 +00:00
|
|
|
if (size == 0)
|
|
|
|
continue;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-27 14:00:57 +00:00
|
|
|
uint8 castType = stream.readByte();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-27 14:00:57 +00:00
|
|
|
switch (castType) {
|
|
|
|
case kCastBitmap:
|
2016-05-28 15:07:21 +00:00
|
|
|
_casts[id] = new BitmapCast(stream);
|
2016-05-27 14:00:57 +00:00
|
|
|
_casts[id]->type = kCastBitmap;
|
|
|
|
break;
|
|
|
|
case kCastText:
|
2016-05-28 15:07:21 +00:00
|
|
|
_casts[id] = new TextCast(stream);
|
2016-05-27 14:00:57 +00:00
|
|
|
_casts[id]->type = kCastText;
|
|
|
|
break;
|
|
|
|
case kCastShape:
|
2016-05-28 15:07:21 +00:00
|
|
|
_casts[id] = new ShapeCast(stream);
|
2016-05-27 14:00:57 +00:00
|
|
|
_casts[id]->type = kCastShape;
|
|
|
|
break;
|
|
|
|
case kCastButton:
|
2016-05-28 15:07:21 +00:00
|
|
|
_casts[id] = new ButtonCast(stream);
|
2016-05-27 14:00:57 +00:00
|
|
|
_casts[id]->type = kCastButton;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
warning("Unhandled cast type: %d", castType);
|
|
|
|
stream.skip(size - 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-27 14:00:57 +00:00
|
|
|
//Set cast pointers to sprites
|
|
|
|
for (uint16 i = 0; i < _frames.size(); i++) {
|
|
|
|
for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) {
|
|
|
|
byte castId = _frames[i]->_sprites[j]->_castId;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-27 17:29:10 +00:00
|
|
|
if (_casts.contains(castId))
|
|
|
|
_frames[i]->_sprites[j]->_cast = _casts.find(castId)->_value;
|
2016-05-26 18:05:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-01 17:13:36 +00:00
|
|
|
void Score::loadLabels(Common::SeekableReadStream &stream) {
|
|
|
|
uint16 count = stream.readUint16BE() + 1;
|
|
|
|
uint16 offset = count * 4 + 2;
|
|
|
|
|
|
|
|
uint16 frame = stream.readUint16BE();
|
|
|
|
uint16 stringPos = stream.readUint16BE() + offset;
|
|
|
|
|
|
|
|
for (uint16 i = 0; i < count; i++) {
|
|
|
|
uint16 nextFrame = stream.readUint16BE();
|
|
|
|
uint16 nextStringPos = stream.readUint16BE() + offset;
|
|
|
|
uint16 streamPos = stream.pos();
|
|
|
|
|
|
|
|
stream.seek(stringPos);
|
|
|
|
|
|
|
|
for (uint16 j = stringPos; j < nextStringPos; j++) {
|
|
|
|
_labels[frame] += stream.readByte();
|
|
|
|
}
|
|
|
|
|
|
|
|
stream.seek(streamPos);
|
|
|
|
|
|
|
|
frame = nextFrame;
|
|
|
|
stringPos = nextStringPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::HashMap<uint16, Common::String>::iterator j;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-01 17:13:36 +00:00
|
|
|
for (j = _labels.begin(); j != _labels.end(); ++j) {
|
|
|
|
debug("Frame %d, Label %s", j->_key, j->_value.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-01 18:33:23 +00:00
|
|
|
void Score::loadActions(Common::SeekableReadStream &stream) {
|
|
|
|
uint16 count = stream.readUint16BE() + 1;
|
|
|
|
uint16 offset = count * 4 + 2;
|
|
|
|
|
|
|
|
byte id = stream.readByte();
|
|
|
|
/*byte subId = */ stream.readByte(); //I couldn't find how it used in continuity (except print). Frame actionId = 1 byte.
|
|
|
|
uint16 stringPos = stream.readUint16BE() + offset;
|
|
|
|
|
|
|
|
for (uint16 i = 0; i < count; i++) {
|
|
|
|
uint16 nextId = stream.readByte();
|
|
|
|
/*byte subId = */ stream.readByte();
|
|
|
|
uint16 nextStringPos = stream.readUint16BE() + offset;
|
|
|
|
uint16 streamPos = stream.pos();
|
|
|
|
|
|
|
|
stream.seek(stringPos);
|
|
|
|
|
|
|
|
for (uint16 j = stringPos; j < nextStringPos; j++) {
|
2016-06-16 19:16:27 +00:00
|
|
|
byte ch = stream.readByte();
|
|
|
|
if (ch == 0x0d) {
|
|
|
|
ch = '\n';
|
|
|
|
}
|
|
|
|
_actions[id] += ch;
|
2016-06-01 18:33:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
stream.seek(streamPos);
|
|
|
|
|
|
|
|
id = nextId;
|
|
|
|
stringPos = nextStringPos;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-08 12:09:38 +00:00
|
|
|
if (stringPos == stream.size())
|
|
|
|
break;
|
2016-06-01 18:33:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Common::HashMap<uint16, Common::String>::iterator j;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-14 17:03:19 +00:00
|
|
|
for (j = _actions.begin(); j != _actions.end(); ++j)
|
2016-06-16 19:16:27 +00:00
|
|
|
if (j->_value != "")
|
|
|
|
_lingo->addCode(j->_value, kFrameScript, j->_key);
|
2016-06-07 13:45:02 +00:00
|
|
|
|
|
|
|
if (!ConfMan.getBool("dump_scripts"))
|
|
|
|
return;
|
|
|
|
|
2016-06-01 18:33:23 +00:00
|
|
|
for (j = _actions.begin(); j != _actions.end(); ++j) {
|
2016-06-16 19:16:27 +00:00
|
|
|
if (j->_value != "")
|
|
|
|
dumpScript(j->_key, kFrameScript, j->_value);
|
2016-06-07 13:45:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-15 16:34:00 +00:00
|
|
|
void Score::loadScriptText(Common::SeekableReadStream &stream) {
|
|
|
|
/*uint32 unk1 = */ stream.readUint32BE();
|
|
|
|
uint32 strLen = stream.readUint32BE();
|
|
|
|
/*uin32 dataLen = */ stream.readUint32BE();
|
|
|
|
Common::String script;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 16:34:00 +00:00
|
|
|
for (uint32 i = 0; i < strLen; i++) {
|
|
|
|
byte ch = stream.readByte();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
|
|
|
if (ch == 0x0d) {
|
2016-06-15 16:34:00 +00:00
|
|
|
//in old Mac systems \r was the code for end-of-line instead.
|
|
|
|
ch = '\n';
|
|
|
|
}
|
|
|
|
script += ch;
|
|
|
|
}
|
2016-06-16 19:16:27 +00:00
|
|
|
if (script != "")
|
|
|
|
_lingo->addCode(script, kMovieScript, _movieScriptCount);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-16 19:16:27 +00:00
|
|
|
if (ConfMan.getBool("dump_scripts") && (script != "")) {
|
2016-06-16 12:17:28 +00:00
|
|
|
dumpScript(_movieScriptCount, kMovieScript, script);
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-16 12:17:28 +00:00
|
|
|
_movieScriptCount++;
|
2016-06-15 16:34:00 +00:00
|
|
|
}
|
|
|
|
|
2016-06-15 13:00:10 +00:00
|
|
|
void Score::dumpScript(uint16 id, ScriptType type, Common::String script) {
|
2016-06-07 13:45:02 +00:00
|
|
|
Common::DumpFile out;
|
|
|
|
Common::String typeName;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case kFrameScript:
|
|
|
|
typeName = "frame";
|
|
|
|
break;
|
|
|
|
case kMovieScript:
|
|
|
|
typeName = "movie";
|
|
|
|
break;
|
|
|
|
case kSpriteScript:
|
|
|
|
typeName = "sprite";
|
|
|
|
break;
|
2016-06-01 18:33:23 +00:00
|
|
|
}
|
2016-06-07 13:45:02 +00:00
|
|
|
|
2016-06-07 14:02:56 +00:00
|
|
|
sprintf(buf, "./dumps/%s-%s-%d.txt", _macName.c_str(), typeName.c_str(), id);
|
2016-06-07 13:45:02 +00:00
|
|
|
|
2016-06-07 14:02:56 +00:00
|
|
|
if (!out.open(buf)) {
|
|
|
|
warning("Can not open dump file %s", buf);
|
|
|
|
return;
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-07 13:45:02 +00:00
|
|
|
out.writeString(script);
|
|
|
|
|
|
|
|
out.flush();
|
|
|
|
out.close();
|
2016-06-01 18:33:23 +00:00
|
|
|
}
|
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
void Score::loadCastInfo(Common::SeekableReadStream &stream, uint16 id) {
|
2016-06-06 14:20:19 +00:00
|
|
|
uint32 entryType = 0;
|
|
|
|
Common::Array<Common::String> castStrings = loadStrings(stream, entryType);
|
2016-06-11 14:27:19 +00:00
|
|
|
CastInfo *ci = new CastInfo();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
ci->script = castStrings[0];
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 13:00:10 +00:00
|
|
|
if (ci->script != "") {
|
|
|
|
_lingo->addCode(ci->script, kSpriteScript, id);
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-16 12:17:28 +00:00
|
|
|
if (!ConfMan.getBool("dump_scripts")) {
|
|
|
|
dumpScript(id, kSpriteScript, ci->script);
|
|
|
|
}
|
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
ci->name = getString(castStrings[1]);
|
|
|
|
ci->directory = getString(castStrings[2]);
|
|
|
|
ci->fileName = getString(castStrings[3]);
|
|
|
|
ci->type = castStrings[4];
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
_castsInfo[id] = ci;
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::String Score::getString(Common::String str) {
|
|
|
|
if (str.size() == 0) {
|
|
|
|
return str;
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
uint8 f = static_cast<uint8>(str.firstChar());
|
|
|
|
|
|
|
|
if (f == 0) {
|
|
|
|
return "";
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
str.deleteChar(0);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
if (str.lastChar() == '\x00') {
|
|
|
|
str.deleteLastChar();
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
return str;
|
2016-06-06 14:20:19 +00:00
|
|
|
}
|
|
|
|
|
2016-06-06 16:11:20 +00:00
|
|
|
void Score::loadFileInfo(Common::SeekableReadStream &stream) {
|
|
|
|
Common::Array<Common::String> fileInfoStrings = loadStrings(stream, _flags);
|
|
|
|
_script = fileInfoStrings[0];
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 13:00:10 +00:00
|
|
|
if (_script != "") {
|
2016-06-16 12:17:28 +00:00
|
|
|
_lingo->addCode(_script, kMovieScript, _movieScriptCount);
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-16 12:17:28 +00:00
|
|
|
if (!ConfMan.getBool("dump_scripts")) {
|
|
|
|
dumpScript(_movieScriptCount, kMovieScript, _script);
|
2016-06-15 13:00:10 +00:00
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-16 12:17:28 +00:00
|
|
|
_movieScriptCount++;
|
2016-06-06 16:11:20 +00:00
|
|
|
_changedBy = fileInfoStrings[1];
|
|
|
|
_createdBy = fileInfoStrings[2];
|
|
|
|
_directory = fileInfoStrings[3];
|
|
|
|
}
|
|
|
|
|
2016-06-06 14:20:19 +00:00
|
|
|
Common::Array<Common::String> Score::loadStrings(Common::SeekableReadStream &stream, uint32 &entryType, bool hasHeader) {
|
|
|
|
Common::Array<Common::String> strings;
|
|
|
|
uint32 offset = 0;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-06 14:20:19 +00:00
|
|
|
if (hasHeader) {
|
|
|
|
offset = stream.readUint32BE();
|
|
|
|
/*uint32 unk1 = */ stream.readUint32BE();
|
|
|
|
/*uint32 unk2 = */ stream.readUint32BE();
|
|
|
|
entryType = stream.readUint32BE();
|
|
|
|
stream.seek(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16 count = stream.readUint16BE();
|
2016-06-06 16:11:20 +00:00
|
|
|
offset += (count + 1) * 4 + 2; //positions info + uint16 count
|
2016-06-06 14:20:19 +00:00
|
|
|
uint32 startPos = stream.readUint32BE() + offset;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-06 14:20:19 +00:00
|
|
|
for (uint16 i = 0; i < count; i++) {
|
|
|
|
Common::String entryString;
|
|
|
|
uint32 nextPos = stream.readUint32BE() + offset;
|
|
|
|
uint32 streamPos = stream.pos();
|
|
|
|
|
|
|
|
stream.seek(startPos);
|
|
|
|
|
|
|
|
while (startPos != nextPos) {
|
|
|
|
entryString += stream.readByte();
|
|
|
|
++startPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
strings.push_back(entryString);
|
|
|
|
|
|
|
|
stream.seek(streamPos);
|
|
|
|
startPos = nextPos;
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-06 14:20:19 +00:00
|
|
|
return strings;
|
|
|
|
}
|
|
|
|
|
2016-06-06 16:56:41 +00:00
|
|
|
void Score::loadFontMap(Common::SeekableReadStream &stream) {
|
|
|
|
uint16 count = stream.readUint16BE();
|
|
|
|
uint32 offset = (count * 2) + 2;
|
|
|
|
uint16 currentRawPosition = offset;
|
|
|
|
|
|
|
|
for (uint16 i = 0; i < count; i++) {
|
|
|
|
uint16 id = stream.readUint16BE();
|
|
|
|
uint32 positionInfo = stream.pos();
|
|
|
|
|
|
|
|
stream.seek(currentRawPosition);
|
|
|
|
|
|
|
|
uint16 size = stream.readByte();
|
|
|
|
Common::String font;
|
|
|
|
|
|
|
|
for (uint16 k = 0; k < size; k++) {
|
|
|
|
font += stream.readByte();
|
|
|
|
}
|
|
|
|
|
|
|
|
_fontMap[id] = font;
|
|
|
|
currentRawPosition = stream.pos();
|
|
|
|
stream.seek(positionInfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 15:07:21 +00:00
|
|
|
BitmapCast::BitmapCast(Common::SeekableReadStream &stream) {
|
2016-05-26 18:05:34 +00:00
|
|
|
/*byte flags = */ stream.readByte();
|
2016-06-03 19:56:23 +00:00
|
|
|
uint16 someFlaggyThing = stream.readUint16BE();
|
2016-05-28 15:07:21 +00:00
|
|
|
initialRect = Score::readRect(stream);
|
|
|
|
boundingRect = Score::readRect(stream);
|
|
|
|
regY = stream.readUint16BE();
|
|
|
|
regX = stream.readUint16BE();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-03 19:56:23 +00:00
|
|
|
if (someFlaggyThing & 0x8000) {
|
|
|
|
/*uint16 unk1 =*/ stream.readUint16BE();
|
|
|
|
/*uint16 unk2 =*/ stream.readUint16BE();
|
|
|
|
}
|
2016-05-26 18:05:34 +00:00
|
|
|
}
|
|
|
|
|
2016-05-28 15:07:21 +00:00
|
|
|
TextCast::TextCast(Common::SeekableReadStream &stream) {
|
2016-05-26 18:05:34 +00:00
|
|
|
/*byte flags =*/ stream.readByte();
|
2016-05-28 15:07:21 +00:00
|
|
|
borderSize = stream.readByte();
|
|
|
|
gutterSize = stream.readByte();
|
|
|
|
boxShadow = stream.readByte();
|
|
|
|
textType = stream.readByte();
|
|
|
|
textAlign = stream.readUint16BE();
|
2016-05-26 18:05:34 +00:00
|
|
|
stream.skip(6); //palinfo
|
|
|
|
/*uint32 unk1 = */ stream.readUint32BE();
|
2016-05-28 15:07:21 +00:00
|
|
|
initialRect = Score::readRect(stream);
|
|
|
|
textShadow = stream.readByte();
|
|
|
|
textFlags = stream.readByte();
|
2016-05-26 18:05:34 +00:00
|
|
|
/*uint16 unk2 =*/ stream.readUint16BE();
|
|
|
|
}
|
|
|
|
|
2016-05-28 15:07:21 +00:00
|
|
|
ShapeCast::ShapeCast(Common::SeekableReadStream &stream) {
|
2016-05-26 18:05:34 +00:00
|
|
|
/*byte flags = */ stream.readByte();
|
|
|
|
/*unk1 = */ stream.readByte();
|
2016-05-28 15:07:21 +00:00
|
|
|
shapeType = stream.readByte();
|
|
|
|
initialRect = Score::readRect(stream);
|
|
|
|
pattern = stream.readUint16BE();
|
|
|
|
fgCol = stream.readByte();
|
|
|
|
bgCol = stream.readByte();
|
|
|
|
fillType = stream.readByte();
|
|
|
|
lineThickness = stream.readByte();
|
|
|
|
lineDirection = stream.readByte();
|
2016-05-26 18:05:34 +00:00
|
|
|
}
|
|
|
|
|
2016-05-27 14:00:57 +00:00
|
|
|
Common::Rect Score::readRect(Common::SeekableReadStream &stream) {
|
2016-05-27 17:29:10 +00:00
|
|
|
Common::Rect *rect = new Common::Rect();
|
|
|
|
rect->top = stream.readUint16BE();
|
|
|
|
rect->left = stream.readUint16BE();
|
|
|
|
rect->bottom = stream.readUint16BE();
|
|
|
|
rect->right = stream.readUint16BE();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-27 17:29:10 +00:00
|
|
|
return *rect;
|
2016-05-27 14:00:57 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:08:44 +00:00
|
|
|
void Score::startLoop() {
|
2016-05-31 19:41:20 +00:00
|
|
|
initGraphics(_movieRect.width(), _movieRect.height(), true);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-31 19:41:20 +00:00
|
|
|
_surface->create(_movieRect.width(), _movieRect.height());
|
2016-06-13 16:22:11 +00:00
|
|
|
_trailSurface->create(_movieRect.width(), _movieRect.height());
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-13 16:22:11 +00:00
|
|
|
if (_stageColor == 0)
|
|
|
|
_trailSurface->clear(15);
|
|
|
|
else
|
|
|
|
_trailSurface->clear(_stageColor);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-28 12:27:33 +00:00
|
|
|
_currentFrame = 0;
|
2016-05-27 19:10:43 +00:00
|
|
|
_stopPlay = false;
|
2016-05-28 12:27:33 +00:00
|
|
|
_nextFrameTime = 0;
|
2016-06-09 16:08:44 +00:00
|
|
|
|
|
|
|
_lingo->processEvent(kEventStartMovie, 0);
|
2016-06-14 13:34:52 +00:00
|
|
|
_frames[_currentFrame]->prepareFrame(this);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-31 19:41:20 +00:00
|
|
|
while (!_stopPlay && _currentFrame < _frames.size() - 2) {
|
2016-06-09 16:08:44 +00:00
|
|
|
update();
|
2016-05-27 19:10:43 +00:00
|
|
|
processEvents();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-28 12:27:33 +00:00
|
|
|
g_system->updateScreen();
|
2016-05-27 19:10:43 +00:00
|
|
|
g_system->delayMillis(10);
|
|
|
|
}
|
|
|
|
}
|
2016-05-25 22:16:29 +00:00
|
|
|
|
2016-06-09 16:08:44 +00:00
|
|
|
void Score::update() {
|
2016-05-27 19:10:43 +00:00
|
|
|
if (g_system->getMillis() < _nextFrameTime)
|
|
|
|
return;
|
2016-06-13 16:22:11 +00:00
|
|
|
|
|
|
|
_surface->clear();
|
|
|
|
_surface->copyFrom(*_trailSurface);
|
2016-05-25 22:16:29 +00:00
|
|
|
|
2016-06-10 15:51:54 +00:00
|
|
|
//Enter and exit from previous frame (Director 4)
|
|
|
|
_lingo->processEvent(kEventEnterFrame, _currentFrame);
|
|
|
|
_lingo->processEvent(kEventExitFrame, _currentFrame);
|
|
|
|
//TODO Director 6 - another order
|
2016-06-09 16:08:44 +00:00
|
|
|
|
|
|
|
|
2016-06-09 22:59:05 +00:00
|
|
|
//TODO Director 6 step: send beginSprite event to any sprites whose span begin in the upcoming frame
|
|
|
|
//for (uint16 i = 0; i < CHANNEL_COUNT; i++) {
|
|
|
|
// if (_frames[_currentFrame]->_sprites[i]->_enabled)
|
|
|
|
// _lingo->processEvent(kEventBeginSprite, i);
|
|
|
|
//}
|
|
|
|
|
|
|
|
//TODO Director 6 step: send prepareFrame event to all sprites and the script channel in upcoming frame
|
|
|
|
//_lingo->processEvent(kEventPrepareFrame, _currentFrame);
|
2016-06-10 15:51:54 +00:00
|
|
|
_currentFrame++;
|
2016-06-14 13:34:52 +00:00
|
|
|
_frames[_currentFrame]->prepareFrame(this);
|
2016-06-09 16:08:44 +00:00
|
|
|
//Stage is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell)
|
|
|
|
|
2016-05-27 19:10:43 +00:00
|
|
|
byte tempo = _frames[_currentFrame]->_tempo;
|
2016-06-09 16:08:44 +00:00
|
|
|
|
2016-05-27 19:10:43 +00:00
|
|
|
if (tempo) {
|
|
|
|
if (tempo > 161) {
|
|
|
|
//Delay
|
|
|
|
_nextFrameTime = g_system->getMillis() + (256 - tempo) * 1000;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-09 22:59:05 +00:00
|
|
|
return;
|
2016-06-04 19:24:30 +00:00
|
|
|
} else if (tempo <= 60) {
|
2016-05-27 19:10:43 +00:00
|
|
|
//FPS
|
|
|
|
_nextFrameTime = g_system->getMillis() + (float)tempo / 60 * 1000;
|
|
|
|
_currentFrameRate = tempo;
|
2016-06-04 19:24:30 +00:00
|
|
|
} else if (tempo >= 136) {
|
|
|
|
//TODO Wait for channel tempo - 135
|
|
|
|
} else if (tempo == 128) {
|
|
|
|
//TODO Wait for Click/Key
|
|
|
|
} else if (tempo == 135) {
|
2016-06-13 20:07:48 +00:00
|
|
|
//Wait for sound channel 1
|
|
|
|
while (_soundManager->isChannelActive(1)) {
|
|
|
|
processEvents();
|
|
|
|
g_system->delayMillis(10);
|
|
|
|
}
|
2016-06-04 19:24:30 +00:00
|
|
|
} else if (tempo == 134) {
|
2016-06-13 20:07:48 +00:00
|
|
|
//Wait for sound channel 2
|
|
|
|
while (_soundManager->isChannelActive(2)) {
|
|
|
|
processEvents();
|
|
|
|
g_system->delayMillis(10);
|
|
|
|
}
|
2016-05-25 22:16:29 +00:00
|
|
|
}
|
2016-05-27 19:10:43 +00:00
|
|
|
}
|
|
|
|
_nextFrameTime = g_system->getMillis() + (float)_currentFrameRate / 60 * 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Score::processEvents() {
|
2016-06-09 22:59:05 +00:00
|
|
|
if (_currentFrame > 0)
|
|
|
|
_lingo->processEvent(kEventIdle, _currentFrame - 1);
|
|
|
|
|
2016-05-27 19:10:43 +00:00
|
|
|
Common::Event event;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-27 19:10:43 +00:00
|
|
|
while (g_system->getEventManager()->pollEvent(event)) {
|
|
|
|
if (event.type == Common::EVENT_QUIT)
|
|
|
|
_stopPlay = true;
|
2016-06-10 15:51:54 +00:00
|
|
|
|
|
|
|
if (event.type == Common::EVENT_LBUTTONDOWN) {
|
|
|
|
Common::Point pos = g_system->getEventManager()->getMousePos();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-10 15:51:54 +00:00
|
|
|
//TODO there is dont send frame id
|
|
|
|
_lingo->processEvent(kEventMouseDown, _frames[_currentFrame]->getSpriteIDFromPos(pos));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.type == Common::EVENT_LBUTTONUP) {
|
|
|
|
Common::Point pos = g_system->getEventManager()->getMousePos();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-10 15:51:54 +00:00
|
|
|
_lingo->processEvent(kEventMouseUp, _frames[_currentFrame]->getSpriteIDFromPos(pos));
|
|
|
|
}
|
2016-05-25 22:16:29 +00:00
|
|
|
}
|
2016-05-24 19:03:21 +00:00
|
|
|
}
|
|
|
|
|
2016-06-17 12:26:41 +00:00
|
|
|
Frame::Frame(DirectorEngine *vm) {
|
|
|
|
_vm = vm;
|
2016-06-13 16:38:50 +00:00
|
|
|
_transDuration = 0;
|
2016-06-18 15:34:21 +00:00
|
|
|
_transType = kTransNone;
|
2016-06-13 16:38:50 +00:00
|
|
|
_transArea = 0;
|
2016-05-25 22:16:29 +00:00
|
|
|
_transChunkSize = 0;
|
|
|
|
_tempo = 0;
|
2016-06-03 14:44:41 +00:00
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
_sound1 = 0;
|
|
|
|
_sound2 = 0;
|
|
|
|
_soundType1 = 0;
|
|
|
|
_soundType2 = 0;
|
2016-06-03 14:44:41 +00:00
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
_actionId = 0;
|
|
|
|
_skipFrameFlag = 0;
|
|
|
|
_blend = 0;
|
2016-05-24 19:03:21 +00:00
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
_sprites.resize(CHANNEL_COUNT);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
for (uint16 i = 0; i < _sprites.size(); i++) {
|
|
|
|
Sprite *sp = new Sprite();
|
|
|
|
_sprites[i] = sp;
|
2016-05-24 19:03:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
Frame::Frame(const Frame &frame) {
|
2016-06-17 12:26:41 +00:00
|
|
|
_vm = frame._vm;
|
2016-05-25 22:16:29 +00:00
|
|
|
_actionId = frame._actionId;
|
2016-06-13 16:38:50 +00:00
|
|
|
_transArea = frame._transArea;
|
|
|
|
_transDuration = frame._transDuration;
|
2016-05-25 22:16:29 +00:00
|
|
|
_transType = frame._transType;
|
2016-06-08 12:50:21 +00:00
|
|
|
_transChunkSize = frame._transChunkSize;
|
2016-05-25 22:16:29 +00:00
|
|
|
_tempo = frame._tempo;
|
|
|
|
_sound1 = frame._sound1;
|
|
|
|
_sound2 = frame._sound2;
|
|
|
|
_soundType1 = frame._soundType1;
|
|
|
|
_soundType2 = frame._soundType2;
|
|
|
|
_skipFrameFlag = frame._skipFrameFlag;
|
|
|
|
_blend = frame._blend;
|
2016-06-13 20:07:48 +00:00
|
|
|
_palette = new PaletteInfo();
|
2016-05-24 19:03:21 +00:00
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
_sprites.resize(CHANNEL_COUNT);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-24 19:03:21 +00:00
|
|
|
for (uint16 i = 0; i < CHANNEL_COUNT; i++) {
|
2016-05-25 22:16:29 +00:00
|
|
|
_sprites[i] = new Sprite(*frame._sprites[i]);
|
2016-05-24 19:03:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Frame::~Frame() {
|
2016-05-25 22:16:29 +00:00
|
|
|
for (uint16 i = 0; i < _sprites.size(); i++) {
|
|
|
|
delete _sprites[i];
|
2016-05-24 19:03:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Frame::readChannel(Common::SeekableReadStream &stream, uint16 offset, uint16 size) {
|
|
|
|
if (offset >= 32) {
|
|
|
|
if (size <= 16)
|
|
|
|
readSprite(stream, offset, size);
|
|
|
|
else {
|
|
|
|
//read > 1 sprites channel
|
|
|
|
while (size > 16) {
|
|
|
|
byte spritePosition = (offset - 32) / 16;
|
|
|
|
uint16 nextStart = (spritePosition + 1) * 16 + 32;
|
|
|
|
uint16 needSize = nextStart - offset;
|
|
|
|
readSprite(stream, offset, needSize);
|
|
|
|
offset += needSize;
|
|
|
|
size -= needSize;
|
|
|
|
}
|
|
|
|
readSprite(stream, offset, size);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
readMainChannels(stream, offset, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Frame::readMainChannels(Common::SeekableReadStream &stream, uint16 offset, uint16 size) {
|
|
|
|
uint16 finishPosition = offset + size;
|
|
|
|
|
|
|
|
while (offset < finishPosition) {
|
|
|
|
switch(offset) {
|
|
|
|
case kScriptIdPosition:
|
2016-05-25 22:16:29 +00:00
|
|
|
_actionId = stream.readByte();
|
2016-05-24 19:03:21 +00:00
|
|
|
offset++;
|
|
|
|
break;
|
|
|
|
case kSoundType1Position:
|
2016-05-25 22:16:29 +00:00
|
|
|
_soundType1 = stream.readByte();
|
2016-05-24 19:03:21 +00:00
|
|
|
offset++;
|
|
|
|
break;
|
2016-06-13 16:38:50 +00:00
|
|
|
case kTransFlagsPosition: {
|
|
|
|
uint8 transFlags = stream.readByte();
|
|
|
|
if (transFlags & 0x80)
|
|
|
|
_transArea = 1;
|
|
|
|
else
|
|
|
|
_transArea = 0;
|
|
|
|
_transDuration = transFlags & 0x7f;
|
2016-05-24 19:03:21 +00:00
|
|
|
offset++;
|
2016-06-13 16:38:50 +00:00
|
|
|
}
|
2016-05-24 19:03:21 +00:00
|
|
|
break;
|
|
|
|
case kTransChunkSizePosition:
|
2016-05-25 22:16:29 +00:00
|
|
|
_transChunkSize = stream.readByte();
|
2016-05-24 19:03:21 +00:00
|
|
|
offset++;
|
|
|
|
break;
|
|
|
|
case kTempoPosition:
|
2016-05-25 22:16:29 +00:00
|
|
|
_tempo = stream.readByte();
|
2016-05-24 19:03:21 +00:00
|
|
|
offset++;
|
|
|
|
break;
|
|
|
|
case kTransTypePosition:
|
2016-06-15 13:00:10 +00:00
|
|
|
_transType = static_cast<TransitionType>(stream.readByte());
|
2016-05-24 19:03:21 +00:00
|
|
|
offset++;
|
|
|
|
break;
|
|
|
|
case kSound1Position:
|
2016-06-11 14:27:19 +00:00
|
|
|
_sound1 = stream.readUint16LE();
|
2016-05-24 19:03:21 +00:00
|
|
|
offset+=2;
|
|
|
|
break;
|
|
|
|
case kSkipFrameFlagsPosition:
|
2016-05-25 22:16:29 +00:00
|
|
|
_skipFrameFlag = stream.readByte();
|
2016-05-24 19:03:21 +00:00
|
|
|
offset++;
|
|
|
|
break;
|
|
|
|
case kBlendPosition:
|
2016-05-25 22:16:29 +00:00
|
|
|
_blend = stream.readByte();
|
2016-05-24 19:03:21 +00:00
|
|
|
offset++;
|
|
|
|
break;
|
|
|
|
case kSound2Position:
|
2016-06-11 14:27:19 +00:00
|
|
|
_sound2 = stream.readUint16LE();
|
2016-05-24 19:03:21 +00:00
|
|
|
offset += 2;
|
|
|
|
break;
|
|
|
|
case kSound2TypePosition:
|
2016-05-25 22:16:29 +00:00
|
|
|
_soundType2 = stream.readByte();
|
2016-05-24 19:03:21 +00:00
|
|
|
offset += 1;
|
|
|
|
break;
|
|
|
|
case kPaletePosition:
|
2016-06-13 20:07:48 +00:00
|
|
|
if (stream.readUint16LE())
|
|
|
|
readPaletteInfo(stream);
|
2016-05-24 19:03:21 +00:00
|
|
|
offset += 16;
|
|
|
|
default:
|
|
|
|
offset++;
|
|
|
|
stream.readByte();
|
|
|
|
debug("Field Position %d, Finish Position %d", offset, finishPosition);
|
|
|
|
break;
|
|
|
|
}
|
2016-05-25 22:16:29 +00:00
|
|
|
}
|
2016-05-24 19:03:21 +00:00
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-13 20:07:48 +00:00
|
|
|
void Frame::readPaletteInfo(Common::SeekableReadStream &stream) {
|
|
|
|
_palette->firstColor = stream.readByte();
|
|
|
|
_palette->lastColor = stream.readByte();
|
|
|
|
_palette->flags = stream.readByte();
|
|
|
|
_palette->speed = stream.readByte();
|
|
|
|
_palette->frameCount = stream.readUint16LE();
|
|
|
|
stream.skip(8); //unknown
|
|
|
|
}
|
2016-05-24 19:03:21 +00:00
|
|
|
|
|
|
|
void Frame::readSprite(Common::SeekableReadStream &stream, uint16 offset, uint16 size) {
|
|
|
|
uint16 spritePosition = (offset - 32) / 16;
|
|
|
|
uint16 spriteStart = spritePosition * 16 + 32;
|
2016-05-25 22:16:29 +00:00
|
|
|
|
2016-05-24 19:03:21 +00:00
|
|
|
uint16 fieldPosition = offset - spriteStart;
|
|
|
|
uint16 finishPosition = fieldPosition + size;
|
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
Sprite &sprite = *_sprites[spritePosition];
|
2016-05-24 19:03:21 +00:00
|
|
|
|
|
|
|
while (fieldPosition < finishPosition) {
|
|
|
|
switch (fieldPosition) {
|
|
|
|
case kSpritePositionUnk1:
|
|
|
|
/*byte x1 = */ stream.readByte();
|
|
|
|
fieldPosition++;
|
|
|
|
break;
|
|
|
|
case kSpritePositionEnabled:
|
2016-05-25 22:16:29 +00:00
|
|
|
sprite._enabled = (stream.readByte() != 0);
|
2016-05-24 19:03:21 +00:00
|
|
|
fieldPosition++;
|
|
|
|
break;
|
|
|
|
case kSpritePositionUnk2:
|
|
|
|
/*byte x2 = */ stream.readUint16BE();
|
|
|
|
fieldPosition += 2;
|
|
|
|
break;
|
|
|
|
case kSpritePositionFlags:
|
2016-05-25 22:16:29 +00:00
|
|
|
sprite._flags = stream.readUint16BE();
|
2016-06-15 13:00:10 +00:00
|
|
|
sprite._ink = static_cast<InkType>(sprite._flags & 0x3f);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-13 16:22:11 +00:00
|
|
|
if (sprite._flags & 0x40)
|
|
|
|
sprite._trails = 1;
|
|
|
|
else
|
|
|
|
sprite._trails = 0;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-24 19:03:21 +00:00
|
|
|
fieldPosition += 2;
|
|
|
|
break;
|
|
|
|
case kSpritePositionCastId:
|
2016-05-25 22:16:29 +00:00
|
|
|
sprite._castId = stream.readUint16BE();
|
2016-05-24 19:03:21 +00:00
|
|
|
fieldPosition += 2;
|
|
|
|
break;
|
|
|
|
case kSpritePositionY:
|
2016-05-25 22:16:29 +00:00
|
|
|
sprite._startPoint.y = stream.readUint16BE();
|
2016-05-24 19:03:21 +00:00
|
|
|
fieldPosition += 2;
|
|
|
|
break;
|
|
|
|
case kSpritePositionX:
|
2016-05-25 22:16:29 +00:00
|
|
|
sprite._startPoint.x = stream.readUint16BE();
|
2016-05-24 19:03:21 +00:00
|
|
|
fieldPosition += 2;
|
|
|
|
break;
|
|
|
|
case kSpritePositionWidth:
|
2016-06-02 14:32:37 +00:00
|
|
|
sprite._width = stream.readUint16BE();
|
2016-05-24 19:03:21 +00:00
|
|
|
fieldPosition += 2;
|
|
|
|
break;
|
|
|
|
case kSpritePositionHeight:
|
2016-06-02 14:32:37 +00:00
|
|
|
sprite._height = stream.readUint16BE();
|
2016-05-24 19:03:21 +00:00
|
|
|
fieldPosition += 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//end cycle, go to next sprite channel
|
|
|
|
readSprite(stream, spriteStart + 16, finishPosition - fieldPosition);
|
|
|
|
fieldPosition = finishPosition;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-14 13:34:52 +00:00
|
|
|
void Frame::prepareFrame(Score *score) {
|
|
|
|
renderSprites(*score->_movieArchive, *score->_surface, score->_movieRect, false);
|
|
|
|
renderSprites(*score->_movieArchive, *score->_trailSurface, score->_movieRect, true);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-09 16:08:44 +00:00
|
|
|
if (_transType != 0)
|
2016-06-13 18:30:11 +00:00
|
|
|
//TODO Handle changing area case
|
2016-06-14 13:34:52 +00:00
|
|
|
playTransition(score);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
if (_sound1 != 0 || _sound2 != 0) {
|
|
|
|
playSoundChannel();
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-14 13:34:52 +00:00
|
|
|
g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, score->_surface->getBounds().width(), score->_surface->getBounds().height());
|
2016-06-09 16:08:44 +00:00
|
|
|
}
|
|
|
|
|
2016-06-11 14:27:19 +00:00
|
|
|
void Frame::playSoundChannel() {
|
|
|
|
debug(0, "Sound2 %d", _sound2);
|
|
|
|
debug(0, "Sound1 %d", _sound1);
|
2016-06-09 16:08:44 +00:00
|
|
|
}
|
|
|
|
|
2016-06-14 13:34:52 +00:00
|
|
|
void Frame::playTransition(Score *score) {
|
2016-06-13 18:30:11 +00:00
|
|
|
uint16 duration = _transDuration * 250; // _transDuration in 1/4 of sec
|
|
|
|
duration = (duration == 0 ? 250 : duration); // director support transition duration = 0, but animation play like value = 1, idk.
|
2016-06-17 12:46:07 +00:00
|
|
|
|
|
|
|
if (_transChunkSize == 0)
|
|
|
|
_transChunkSize = 1; //equal 1 step
|
|
|
|
|
2016-06-13 18:30:11 +00:00
|
|
|
uint16 stepDuration = duration / _transChunkSize;
|
|
|
|
uint16 steps = duration / stepDuration;
|
|
|
|
|
|
|
|
switch (_transType) {
|
2016-06-16 13:31:46 +00:00
|
|
|
case kTransCoverDown:
|
|
|
|
{
|
2016-06-14 13:34:52 +00:00
|
|
|
uint16 stepSize = score->_movieRect.height() / steps;
|
|
|
|
Common::Rect r = score->_movieRect;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-13 18:30:11 +00:00
|
|
|
for (uint16 i = 1; i < steps; i++) {
|
|
|
|
r.setHeight(stepSize * i);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-13 18:30:11 +00:00
|
|
|
g_system->delayMillis(stepDuration);
|
2016-06-14 13:34:52 +00:00
|
|
|
score->processEvents();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-14 13:34:52 +00:00
|
|
|
g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, r.width(), r.height());
|
2016-06-13 18:30:11 +00:00
|
|
|
g_system->updateScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2016-06-16 13:31:46 +00:00
|
|
|
case kTransCoverUp:
|
|
|
|
{
|
2016-06-14 13:34:52 +00:00
|
|
|
uint16 stepSize = score->_movieRect.height() / steps;
|
|
|
|
Common::Rect r = score->_movieRect;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-13 18:30:11 +00:00
|
|
|
for (uint16 i = 1; i < steps; i++) {
|
2016-06-15 15:08:08 +00:00
|
|
|
r.setHeight(stepSize * i);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->delayMillis(stepDuration);
|
|
|
|
score->processEvents();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, score->_movieRect.height() - stepSize * i, r.width(), r.height());
|
|
|
|
g_system->updateScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kTransCoverRight: {
|
|
|
|
uint16 stepSize = score->_movieRect.width() / steps;
|
|
|
|
Common::Rect r = score->_movieRect;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
for (uint16 i = 1; i < steps; i++) {
|
|
|
|
r.setWidth(stepSize * i);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->delayMillis(stepDuration);
|
|
|
|
score->processEvents();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, r.width(), r.height());
|
|
|
|
g_system->updateScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kTransCoverLeft: {
|
|
|
|
uint16 stepSize = score->_movieRect.width() / steps;
|
|
|
|
Common::Rect r = score->_movieRect;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
for (uint16 i = 1; i < steps; i++) {
|
|
|
|
r.setWidth(stepSize * i);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->delayMillis(stepDuration);
|
|
|
|
score->processEvents();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, score->_movieRect.width() - stepSize * i, 0, r.width(), r.height());
|
|
|
|
g_system->updateScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kTransCoverUpLeft: {
|
|
|
|
uint16 stepSize = score->_movieRect.width() / steps;
|
|
|
|
Common::Rect r = score->_movieRect;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
for (uint16 i = 1; i < steps; i++) {
|
|
|
|
r.setWidth(stepSize * i);
|
|
|
|
r.setHeight(stepSize * i);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->delayMillis(stepDuration);
|
|
|
|
score->processEvents();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, score->_movieRect.width() - stepSize * i, score->_movieRect.height() - stepSize * i, r.width(), r.height());
|
|
|
|
g_system->updateScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kTransCoverUpRight: {
|
|
|
|
uint16 stepSize = score->_movieRect.width() / steps;
|
|
|
|
Common::Rect r = score->_movieRect;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
for (uint16 i = 1; i < steps; i++) {
|
|
|
|
r.setWidth(stepSize * i);
|
|
|
|
r.setHeight(stepSize * i);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-13 18:30:11 +00:00
|
|
|
g_system->delayMillis(stepDuration);
|
2016-06-14 13:34:52 +00:00
|
|
|
score->processEvents();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-14 13:34:52 +00:00
|
|
|
g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, score->_movieRect.height() - stepSize * i, r.width(), r.height());
|
2016-06-13 18:30:11 +00:00
|
|
|
g_system->updateScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2016-06-15 15:08:08 +00:00
|
|
|
case kTransCoverDownLeft: {
|
|
|
|
uint16 stepSize = score->_movieRect.width() / steps;
|
|
|
|
Common::Rect r = score->_movieRect;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
for (uint16 i = 1; i < steps; i++) {
|
|
|
|
r.setWidth(stepSize * i);
|
|
|
|
r.setHeight(stepSize * i);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->delayMillis(stepDuration);
|
|
|
|
score->processEvents();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, score->_movieRect.width() - stepSize * i, 0, r.width(), r.height());
|
|
|
|
g_system->updateScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kTransCoverDownRight: {
|
|
|
|
uint16 stepSize = score->_movieRect.width() / steps;
|
|
|
|
Common::Rect r = score->_movieRect;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
for (uint16 i = 1; i < steps; i++) {
|
|
|
|
r.setWidth(stepSize * i);
|
|
|
|
r.setHeight(stepSize * i);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->delayMillis(stepDuration);
|
|
|
|
score->processEvents();
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-15 15:08:08 +00:00
|
|
|
g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, r.width(), r.height());
|
|
|
|
g_system->updateScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2016-06-13 18:30:11 +00:00
|
|
|
default:
|
2016-06-15 15:08:08 +00:00
|
|
|
warning("Unhandled transition type %d %d %d", _transType, duration, _transChunkSize);
|
2016-06-13 18:30:11 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
2016-06-09 16:08:44 +00:00
|
|
|
}
|
2016-05-25 22:16:29 +00:00
|
|
|
|
2016-06-13 16:22:11 +00:00
|
|
|
void Frame::renderSprites(Archive &_movie, Graphics::ManagedSurface &surface, Common::Rect movieRect, bool renderTrail) {
|
2016-05-25 22:16:29 +00:00
|
|
|
for (uint16 i = 0; i < CHANNEL_COUNT; i++) {
|
|
|
|
if (_sprites[i]->_enabled) {
|
2016-06-13 16:22:11 +00:00
|
|
|
if ((_sprites[i]->_trails == 0 && renderTrail) || (_sprites[i]->_trails == 1 && !renderTrail))
|
|
|
|
continue;
|
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
DIBDecoder img;
|
2016-05-27 17:29:10 +00:00
|
|
|
uint32 imgId = 1024 + _sprites[i]->_castId;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-05-31 18:35:57 +00:00
|
|
|
if (!_movie.hasResource(MKTAG('D', 'I', 'B', ' '), imgId)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-05-28 15:39:33 +00:00
|
|
|
img.loadStream(*_movie.getResource(MKTAG('D', 'I', 'B', ' '), imgId));
|
2016-05-31 17:49:05 +00:00
|
|
|
|
2016-05-27 17:29:10 +00:00
|
|
|
uint32 regX = static_cast<BitmapCast *>(_sprites[i]->_cast)->regX;
|
|
|
|
uint32 regY = static_cast<BitmapCast *>(_sprites[i]->_cast)->regY;
|
|
|
|
uint32 rectLeft = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.left;
|
|
|
|
uint32 rectTop = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.top;
|
|
|
|
|
|
|
|
int x = _sprites[i]->_startPoint.x - regX + rectLeft;
|
|
|
|
int y = _sprites[i]->_startPoint.y - regY + rectTop;
|
|
|
|
int height = _sprites[i]->_height;
|
|
|
|
int width = _sprites[i]->_width;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-01 12:54:40 +00:00
|
|
|
Common::Rect drawRect = Common::Rect(x, y, x + width, y + height);
|
2016-06-10 15:51:54 +00:00
|
|
|
_drawRects.push_back(drawRect);
|
2016-06-01 12:54:40 +00:00
|
|
|
|
2016-06-02 14:32:37 +00:00
|
|
|
switch (_sprites[i]->_ink) {
|
2016-06-01 12:54:40 +00:00
|
|
|
case kInkTypeCopy:
|
|
|
|
surface.blitFrom(*img.getSurface(), Common::Point(x, y));
|
|
|
|
break;
|
|
|
|
case kInkTypeBackgndTrans:
|
|
|
|
drawBackgndTransSprite(surface, *img.getSurface(), drawRect);
|
|
|
|
break;
|
|
|
|
case kInkTypeMatte:
|
|
|
|
drawMatteSprite(surface, *img.getSurface(), drawRect);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
warning("Unhandled ink type %d", _sprites[i]->_ink);
|
|
|
|
surface.blitFrom(*img.getSurface(), Common::Point(x, y));
|
|
|
|
break;
|
|
|
|
}
|
2016-05-25 22:16:29 +00:00
|
|
|
}
|
|
|
|
}
|
2016-06-09 16:08:44 +00:00
|
|
|
}
|
|
|
|
|
2016-06-01 12:54:40 +00:00
|
|
|
void Frame::drawBackgndTransSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) {
|
2016-06-16 12:52:48 +00:00
|
|
|
uint8 skipColor = 15; //FIXME is it always white (last entry in pallette) ?
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-01 12:54:40 +00:00
|
|
|
for (int ii = 0; ii < sprite.h; ii++) {
|
|
|
|
const byte *src = (const byte *)sprite.getBasePtr(0, ii);
|
|
|
|
byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii);
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-01 12:54:40 +00:00
|
|
|
for (int j = 0; j < drawRect.width(); j++) {
|
|
|
|
if (*src != skipColor)
|
|
|
|
*dst = *src;
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-01 12:54:40 +00:00
|
|
|
src++;
|
|
|
|
dst++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Frame::drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) {
|
|
|
|
//Like background trans, but all white pixels NOT ENCLOSED by coloured pixels are transparent
|
2016-06-03 14:04:35 +00:00
|
|
|
Graphics::Surface tmp;
|
|
|
|
tmp.copyFrom(sprite);
|
|
|
|
|
2016-06-17 12:10:48 +00:00
|
|
|
// Searching white color in the corners
|
|
|
|
int whiteColor = -1;
|
|
|
|
|
|
|
|
for (int corner = 0; corner < 4; corner++) {
|
|
|
|
int x = (corner & 0x1) ? tmp.w - 1 : 0;
|
|
|
|
int y = (corner & 0x2) ? tmp.h - 1 : 0;
|
|
|
|
|
|
|
|
byte color = *(byte *)tmp.getBasePtr(x, y);
|
|
|
|
|
|
|
|
if (_vm->getPalette()[color * 3 + 0] == 0xff &&
|
|
|
|
_vm->getPalette()[color * 3 + 1] == 0xff &&
|
|
|
|
_vm->getPalette()[color * 3 + 2] == 0xff) {
|
|
|
|
whiteColor = color;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (whiteColor == -1) {
|
|
|
|
warning("No white color for Matte image");
|
|
|
|
whiteColor = *(byte *)tmp.getBasePtr(0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Graphics::FloodFill ff(&tmp, whiteColor, 0, true);
|
2016-06-03 14:04:35 +00:00
|
|
|
|
|
|
|
for (int yy = 0; yy < tmp.h; yy++) {
|
|
|
|
ff.addSeed(0, yy);
|
|
|
|
ff.addSeed(tmp.w - 1, yy);
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-03 14:04:35 +00:00
|
|
|
for (int xx = 0; xx < tmp.w; xx++) {
|
|
|
|
ff.addSeed(xx, 0);
|
|
|
|
ff.addSeed(xx, tmp.h - 1);
|
|
|
|
}
|
2016-06-03 14:44:41 +00:00
|
|
|
ff.fillMask();
|
2016-06-03 14:04:35 +00:00
|
|
|
|
|
|
|
for (int yy = 0; yy < tmp.h; yy++) {
|
|
|
|
const byte *src = (const byte *)tmp.getBasePtr(0, yy);
|
2016-06-03 14:44:41 +00:00
|
|
|
const byte *mask = (const byte *)ff.getMask()->getBasePtr(0, yy);
|
2016-06-03 14:04:35 +00:00
|
|
|
byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + yy);
|
2016-06-03 14:44:41 +00:00
|
|
|
|
|
|
|
for (int xx = 0; xx < drawRect.width(); xx++, src++, dst++, mask++)
|
|
|
|
if (*mask == 0)
|
2016-06-03 14:04:35 +00:00
|
|
|
*dst = *src;
|
2016-06-01 12:54:40 +00:00
|
|
|
}
|
2016-06-03 14:04:35 +00:00
|
|
|
|
|
|
|
tmp.free();
|
2016-06-01 12:54:40 +00:00
|
|
|
}
|
|
|
|
|
2016-06-10 15:51:54 +00:00
|
|
|
uint16 Frame::getSpriteIDFromPos(Common::Point pos) {
|
|
|
|
//Find first from top to bottom
|
|
|
|
for (uint16 i = _drawRects.size() - 1; i > 0; i--) {
|
|
|
|
if (_drawRects[i].contains(pos))
|
|
|
|
return i;
|
|
|
|
}
|
2016-06-16 13:31:46 +00:00
|
|
|
|
2016-06-10 15:51:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-03 14:44:41 +00:00
|
|
|
Sprite::Sprite() {
|
2016-05-25 22:16:29 +00:00
|
|
|
_enabled = false;
|
2016-06-18 11:55:40 +00:00
|
|
|
_trails = 0;
|
2016-05-25 22:16:29 +00:00
|
|
|
_width = 0;
|
2016-05-28 16:54:31 +00:00
|
|
|
_ink = kInkTypeCopy;
|
2016-05-25 22:16:29 +00:00
|
|
|
_flags = 0;
|
|
|
|
_height = 0;
|
|
|
|
_castId = 0;
|
|
|
|
_castId = 0;
|
2016-05-24 19:03:21 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
Sprite::Sprite(const Sprite &sprite) {
|
|
|
|
_enabled = sprite._enabled;
|
|
|
|
_castId = sprite._castId;
|
|
|
|
_flags = sprite._flags;
|
2016-06-18 11:55:40 +00:00
|
|
|
_trails = sprite._trails;
|
2016-05-28 16:54:31 +00:00
|
|
|
_ink = sprite._ink;
|
2016-05-25 22:16:29 +00:00
|
|
|
_width = sprite._width;
|
|
|
|
_height = sprite._height;
|
|
|
|
_startPoint.x = sprite._startPoint.x;
|
|
|
|
_startPoint.y = sprite._startPoint.y;
|
2016-05-24 19:03:21 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 22:16:29 +00:00
|
|
|
} //End of namespace Director
|