scummvm/engines/director/score.cpp

759 lines
20 KiB
C++
Raw Normal View History

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-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
#include "common/system.h"
#include "director/dib.h"
#include "director/resource.h"
#include "graphics/palette.h"
#include "common/events.h"
#include "engines/util.h"
#include "graphics/managed_surface.h"
2016-05-24 19:03:21 +00:00
namespace Director {
Score::Score(Archive &movie) {
_surface = new Graphics::ManagedSurface;
_movieArchive = &movie;
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-01 17:13:36 +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-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
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'));
if (vwci.size() > 0) {
Common::Array<uint16>::iterator iterator;
for (iterator = vwci.begin(); iterator != vwci.end(); ++iterator)
loadCastInfo(*_movieArchive->getResource(MKTAG('V','W','C','I'), *iterator));
}
DIBDecoder palette;
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]);
palette.loadPalette(*pal);
g_system->getPaletteManager()->setPalette(palette.getPalette(), 0, 255);
}
void Score::loadFrames(Common::SeekableReadStream &stream) {
2016-05-24 19:03:21 +00:00
uint32 size = stream.readUint32BE();
size -= 4;
uint16 channelSize;
uint16 channelOffset;
Frame *initial = new Frame();
_frames.push_back(initial);
2016-05-24 19:03:21 +00:00
while (size != 0) {
uint16 frameSize = stream.readUint16BE();
size -= frameSize;
frameSize -= 2;
Frame *frame = new Frame(*_frames.back());
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;
}
_frames.push_back(frame);
2016-05-24 19:03:21 +00:00
}
//remove initial frame
_frames.remove_at(0);
}
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);
_castArrayStart = stream.readUint16BE();
_castArrayEnd = stream.readUint16BE();
_currentFrameRate = stream.readByte();
stream.skip(9);
/*uint16 stageColor = */ stream.readUint16BE();
}
2016-05-26 11:51:51 +00:00
void Score::readVersion(uint32 rid) {
_versionMinor = rid & 0xffff;
_versionMajor = rid >> 16;
debug("%d.%d", _versionMajor, _versionMinor);
}
void Score::loadCastData(Common::SeekableReadStream &stream) {
2016-05-31 18:35:57 +00:00
for (uint16 id = _castArrayStart; id <= _castArrayEnd; id++) {
byte size = stream.readByte();
2016-05-27 14:00:57 +00:00
if (size == 0)
continue;
uint8 castType = stream.readByte();
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;
}
}
//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-05-27 17:29:10 +00:00
if (_casts.contains(castId))
_frames[i]->_sprites[j]->_cast = _casts.find(castId)->_value;
}
}
}
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;
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) {
2016-06-07 13:45:02 +00:00
2016-06-01 18:33:23 +00:00
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++) {
_actions[id] += stream.readByte();
}
stream.seek(streamPos);
id = nextId;
stringPos = nextStringPos;
}
Common::HashMap<uint16, Common::String>::iterator j;
2016-06-07 13:45:02 +00:00
debug("%d", ConfMan.getBool("dump_scripts"));
if (!ConfMan.getBool("dump_scripts"))
return;
2016-06-01 18:33:23 +00:00
for (j = _actions.begin(); j != _actions.end(); ++j) {
2016-06-07 13:45:02 +00:00
dumpScript(j->_key, kFrameScript, j->_value);
}
}
void Score::dumpScript(uint16 id, scriptType type, Common::String script) {
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
sprintf(buf, "./dumps/%s-%s-%d.txt", _macName.c_str(), typeName.c_str(), id);
2016-06-07 13:45:02 +00:00
if (!out.open(buf)) {
warning("Can not open dump file %s", buf);
return;
}
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-06 14:20:19 +00:00
void Score::loadCastInfo(Common::SeekableReadStream &stream) {
uint32 entryType = 0;
Common::Array<Common::String> castStrings = loadStrings(stream, entryType);
CastInfo ci;
ci.script = castStrings[0];
ci.name = castStrings[1];
ci.directory = castStrings[2];
ci.fileName = castStrings[3];
ci.type = castStrings[4];
//TODO storage in array, and use this info
}
void Score::loadFileInfo(Common::SeekableReadStream &stream) {
Common::Array<Common::String> fileInfoStrings = loadStrings(stream, _flags);
_script = fileInfoStrings[0];
_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;
if (hasHeader) {
offset = stream.readUint32BE();
/*uint32 unk1 = */ stream.readUint32BE();
/*uint32 unk2 = */ stream.readUint32BE();
entryType = stream.readUint32BE();
stream.seek(offset);
}
uint16 count = stream.readUint16BE();
offset += (count + 1) * 4 + 2; //positions info + uint16 count
2016-06-06 14:20:19 +00:00
uint32 startPos = stream.readUint32BE() + offset;
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;
}
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) {
/*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-03 19:56:23 +00:00
if (someFlaggyThing & 0x8000) {
/*uint16 unk1 =*/ stream.readUint16BE();
/*uint16 unk2 =*/ stream.readUint16BE();
}
}
2016-05-28 15:07:21 +00:00
TextCast::TextCast(Common::SeekableReadStream &stream) {
/*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();
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();
/*uint16 unk2 =*/ stream.readUint16BE();
}
2016-05-28 15:07:21 +00:00
ShapeCast::ShapeCast(Common::SeekableReadStream &stream) {
/*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-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();
return *rect;
2016-05-27 14:00:57 +00:00
}
void Score::play() {
2016-05-31 19:41:20 +00:00
initGraphics(_movieRect.width(), _movieRect.height(), true);
_surface->create(_movieRect.width(), _movieRect.height());
2016-05-28 12:27:33 +00:00
_currentFrame = 0;
_stopPlay = false;
2016-05-28 12:27:33 +00:00
_nextFrameTime = 0;
2016-05-31 19:41:20 +00:00
while (!_stopPlay && _currentFrame < _frames.size() - 2) {
display();
processEvents();
2016-05-28 12:27:33 +00:00
g_system->updateScreen();
g_system->delayMillis(10);
}
}
void Score::display() {
if (g_system->getMillis() < _nextFrameTime)
return;
_frames[_currentFrame]->display(*_movieArchive, *_surface, _movieRect);
_currentFrame++;
byte tempo = _frames[_currentFrame]->_tempo;
if (tempo) {
if (tempo > 161) {
//Delay
_nextFrameTime = g_system->getMillis() + (256 - tempo) * 1000;
} else if (tempo <= 60) {
//FPS
_nextFrameTime = g_system->getMillis() + (float)tempo / 60 * 1000;
_currentFrameRate = tempo;
} else if (tempo >= 136) {
//TODO Wait for channel tempo - 135
} else if (tempo == 128) {
//TODO Wait for Click/Key
} else if (tempo == 135) {
//TODO Wait for sound channel 1
} else if (tempo == 134) {
//TODO Wait for sound channel 2
}
}
_nextFrameTime = g_system->getMillis() + (float)_currentFrameRate / 60 * 1000;
}
void Score::processEvents() {
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
if (event.type == Common::EVENT_QUIT)
_stopPlay = true;
}
2016-05-24 19:03:21 +00:00
}
Frame::Frame() {
_transFlags = 0;
_transChunkSize = 0;
_tempo = 0;
_sound1 = 0;
_sound2 = 0;
_soundType1 = 0;
_soundType2 = 0;
_actionId = 0;
_skipFrameFlag = 0;
_blend = 0;
2016-05-24 19:03:21 +00:00
_sprites.resize(CHANNEL_COUNT);
for (uint16 i = 0; i < _sprites.size(); i++) {
Sprite *sp = new Sprite();
_sprites[i] = sp;
2016-05-24 19:03:21 +00:00
}
}
Frame::Frame(const Frame &frame) {
_actionId = frame._actionId;
_transFlags = frame._transFlags;
_transType = frame._transType;
_tempo = frame._tempo;
_sound1 = frame._sound1;
_sound2 = frame._sound2;
_soundType1 = frame._soundType1;
_soundType2 = frame._soundType2;
_skipFrameFlag = frame._skipFrameFlag;
_blend = frame._blend;
2016-05-24 19:03:21 +00:00
_sprites.resize(CHANNEL_COUNT);
2016-05-24 19:03:21 +00:00
for (uint16 i = 0; i < CHANNEL_COUNT; i++) {
_sprites[i] = new Sprite(*frame._sprites[i]);
2016-05-24 19:03:21 +00:00
}
}
Frame::~Frame() {
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:
_actionId = stream.readByte();
2016-05-24 19:03:21 +00:00
offset++;
break;
case kSoundType1Position:
_soundType1 = stream.readByte();
2016-05-24 19:03:21 +00:00
offset++;
break;
case kTransFlagsPosition:
_transFlags = stream.readByte();
2016-05-24 19:03:21 +00:00
offset++;
break;
case kTransChunkSizePosition:
_transChunkSize = stream.readByte();
2016-05-24 19:03:21 +00:00
offset++;
break;
case kTempoPosition:
_tempo = stream.readByte();
2016-05-24 19:03:21 +00:00
offset++;
break;
case kTransTypePosition:
_transType = stream.readByte();
2016-05-24 19:03:21 +00:00
offset++;
break;
case kSound1Position:
_sound1 = stream.readUint16BE();
2016-05-24 19:03:21 +00:00
offset+=2;
break;
case kSkipFrameFlagsPosition:
_skipFrameFlag = stream.readByte();
2016-05-24 19:03:21 +00:00
offset++;
break;
case kBlendPosition:
_blend = stream.readByte();
2016-05-24 19:03:21 +00:00
offset++;
break;
case kSound2Position:
_sound2 = stream.readUint16BE();
2016-05-24 19:03:21 +00:00
offset += 2;
break;
case kSound2TypePosition:
_soundType2 = stream.readByte();
2016-05-24 19:03:21 +00:00
offset += 1;
break;
case kPaletePosition:
//TODO palette channel
stream.skip(16);
offset += 16;
default:
offset++;
stream.readByte();
debug("Field Position %d, Finish Position %d", offset, finishPosition);
break;
}
}
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-24 19:03:21 +00:00
uint16 fieldPosition = offset - spriteStart;
uint16 finishPosition = fieldPosition + size;
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:
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:
sprite._flags = stream.readUint16BE();
2016-05-28 16:54:31 +00:00
sprite._ink = static_cast<inkType>(sprite._flags & 0x3f); //TODO more flags?
2016-05-24 19:03:21 +00:00
fieldPosition += 2;
break;
case kSpritePositionCastId:
sprite._castId = stream.readUint16BE();
2016-05-24 19:03:21 +00:00
fieldPosition += 2;
break;
case kSpritePositionY:
sprite._startPoint.y = stream.readUint16BE();
2016-05-24 19:03:21 +00:00
fieldPosition += 2;
break;
case kSpritePositionX:
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;
}
}
}
void Frame::display(Archive &_movie, Graphics::ManagedSurface &surface, Common::Rect moviRect) {
surface.clear();
for (uint16 i = 0; i < CHANNEL_COUNT; i++) {
if (_sprites[i]->_enabled) {
DIBDecoder img;
2016-05-27 14:00:57 +00:00
//TODO check cast type
2016-05-27 17:29:10 +00:00
uint32 imgId = 1024 + _sprites[i]->_castId;
2016-05-31 18:35:57 +00:00
//TODO looks like bad file?
if (!_movie.hasResource(MKTAG('D', 'I', 'B', ' '), imgId)) {
continue;
}
img.loadStream(*_movie.getResource(MKTAG('D', 'I', 'B', ' '), imgId));
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-05-27 17:29:10 +00:00
if (x < 0) {
width += x;
x = 0;
}
if (y < 0) {
height += y;
y = 0;
}
Common::Rect drawRect = Common::Rect(x, y, x + width, y + height);
2016-06-02 14:32:37 +00:00
switch (_sprites[i]->_ink) {
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-31 19:41:20 +00:00
g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, surface.getBounds().width(), surface.getBounds().height());
}
void Frame::drawBackgndTransSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) {
uint8 skipColor = 15; //FIXME is it always white (last entry in pallette) ?
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);
for (int j = 0; j < drawRect.width(); j++) {
if (*src != skipColor)
*dst = *src;
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
Graphics::Surface tmp;
tmp.copyFrom(sprite);
2016-06-03 22:29:36 +00:00
Graphics::FloodFill ff(&tmp, *(byte *)tmp.getBasePtr(0, 0), 0);
for (int yy = 0; yy < tmp.h; yy++) {
ff.addSeed(0, yy);
ff.addSeed(tmp.w - 1, yy);
}
for (int xx = 0; xx < tmp.w; xx++) {
ff.addSeed(xx, 0);
ff.addSeed(xx, tmp.h - 1);
}
ff.fillMask();
for (int yy = 0; yy < tmp.h; yy++) {
const byte *src = (const byte *)tmp.getBasePtr(0, yy);
const byte *mask = (const byte *)ff.getMask()->getBasePtr(0, yy);
byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + yy);
for (int xx = 0; xx < drawRect.width(); xx++, src++, dst++, mask++)
if (*mask == 0)
*dst = *src;
}
tmp.free();
}
Sprite::Sprite() {
_enabled = false;
_width = 0;
2016-05-28 16:54:31 +00:00
_ink = kInkTypeCopy;
_flags = 0;
_height = 0;
_castId = 0;
_castId = 0;
2016-05-24 19:03:21 +00:00
}
Sprite::Sprite(const Sprite &sprite) {
_enabled = sprite._enabled;
_castId = sprite._castId;
_flags = sprite._flags;
2016-05-28 16:54:31 +00:00
_ink = sprite._ink;
_width = sprite._width;
_height = sprite._height;
_startPoint.x = sprite._startPoint.x;
_startPoint.y = sprite._startPoint.y;
2016-05-24 19:03:21 +00:00
}
} //End of namespace Director