mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-10 20:01:25 +00:00
447 lines
12 KiB
C++
447 lines
12 KiB
C++
/* 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.
|
|
*
|
|
*/
|
|
|
|
#include "common/substream.h"
|
|
#include "graphics/surface.h"
|
|
#include "graphics/macgui/maceditabletext.h"
|
|
#include "image/image_decoder.h"
|
|
|
|
#include "director/director.h"
|
|
#include "director/cachedmactext.h"
|
|
#include "director/cast.h"
|
|
#include "director/score.h"
|
|
#include "director/sound.h"
|
|
#include "director/stxt.h"
|
|
|
|
namespace Director {
|
|
|
|
Cast::Cast() {
|
|
_type = kCastTypeNull;
|
|
_surface = nullptr;
|
|
_widget = nullptr;
|
|
|
|
_img = nullptr;
|
|
|
|
_modified = true;
|
|
}
|
|
|
|
Cast::~Cast() {
|
|
if (_img)
|
|
delete _img;
|
|
}
|
|
|
|
BitmapCast::BitmapCast(Common::ReadStreamEndian &stream, uint32 castTag, uint16 version) {
|
|
_type = kCastBitmap;
|
|
|
|
if (version < 4) {
|
|
_pitch = 0;
|
|
_flags = stream.readByte(); // region: 0 - auto, 1 - matte, 2 - disabled
|
|
_bytes = stream.readUint16();
|
|
_initialRect = Score::readRect(stream);
|
|
_boundingRect = Score::readRect(stream);
|
|
_regY = stream.readUint16();
|
|
_regX = stream.readUint16();
|
|
|
|
if (_bytes & 0x8000) {
|
|
_bitsPerPixel = stream.readUint16();
|
|
_clut = stream.readUint16();
|
|
} else {
|
|
_bitsPerPixel = 1;
|
|
_clut = 0;
|
|
}
|
|
|
|
_pitch = _initialRect.width();
|
|
if (_pitch % 16)
|
|
_pitch += 16 - (_initialRect.width() % 16);
|
|
} else if (version == 4) {
|
|
_pitch = stream.readUint16();
|
|
_pitch &= 0x0fff;
|
|
|
|
_flags = 0;
|
|
_bytes = 0;
|
|
_clut = 0;
|
|
|
|
_initialRect = Score::readRect(stream);
|
|
_boundingRect = Score::readRect(stream);
|
|
_regY = stream.readUint16();
|
|
_regX = stream.readUint16();
|
|
|
|
_bitsPerPixel = stream.readUint16();
|
|
if (_bitsPerPixel == 0)
|
|
_bitsPerPixel = 1;
|
|
|
|
if (_bitsPerPixel == 1)
|
|
_pitch *= 8;
|
|
|
|
int tail = 0;
|
|
|
|
while (!stream.eos()) {
|
|
stream.readByte();
|
|
tail++;
|
|
}
|
|
|
|
warning("BitmapCast: %d bytes left", tail);
|
|
} else if (version == 5) {
|
|
_bytes = 0;
|
|
_pitch = 0;
|
|
uint16 count = stream.readUint16();
|
|
for (uint16 cc = 0; cc < count; cc++)
|
|
stream.readUint32();
|
|
|
|
uint32 stringLength = stream.readUint32();
|
|
for (uint32 s = 0; s < stringLength; s++)
|
|
stream.readByte();
|
|
|
|
/*uint16 width =*/ stream.readUint16LE(); //maybe?
|
|
_initialRect = Score::readRect(stream);
|
|
|
|
/*uint32 somethingElse =*/ stream.readUint32();
|
|
_boundingRect = Score::readRect(stream);
|
|
|
|
_bitsPerPixel = stream.readUint16();
|
|
|
|
_regX = 0;
|
|
_regY = 0;
|
|
_clut = 0;
|
|
|
|
stream.readUint32();
|
|
}
|
|
_tag = castTag;
|
|
}
|
|
|
|
SoundCast::SoundCast(Common::ReadStreamEndian &stream, uint16 version) {
|
|
_type = kCastSound;
|
|
_audio = nullptr;
|
|
_looping = 0;
|
|
|
|
if (version == 4) {
|
|
for (int i = 0; i < 0xe; i++) {
|
|
stream.readByte();
|
|
}
|
|
_looping = stream.readByte() & 0x10 ? 0 : 1;
|
|
}
|
|
}
|
|
|
|
TextCast::TextCast(Common::ReadStreamEndian &stream, uint16 version, int32 bgcolor) {
|
|
_type = kCastText;
|
|
|
|
_bgcolor = bgcolor;
|
|
_borderSize = kSizeNone;
|
|
_gutterSize = kSizeNone;
|
|
_boxShadow = kSizeNone;
|
|
|
|
_flags = 0;
|
|
_textFlags = 0;
|
|
_fontId = 0;
|
|
_fontSize = 12;
|
|
_textType = kTextTypeFixed;
|
|
_textAlign = kTextAlignLeft;
|
|
_textShadow = kSizeNone;
|
|
_textSlant = 0;
|
|
_palinfo1 = _palinfo2 = _palinfo3 = 0;
|
|
|
|
if (version <= 3) {
|
|
_flags = stream.readByte(); // region: 0 - auto, 1 - matte, 2 - disabled
|
|
_borderSize = static_cast<SizeType>(stream.readByte());
|
|
_gutterSize = static_cast<SizeType>(stream.readByte());
|
|
_boxShadow = static_cast<SizeType>(stream.readByte());
|
|
byte pad1 = stream.readByte();
|
|
_textAlign = static_cast<TextAlignType>(stream.readUint16());
|
|
_palinfo1 = stream.readUint16();
|
|
_palinfo2 = stream.readUint16();
|
|
_palinfo3 = stream.readUint16();
|
|
|
|
uint32 pad2;
|
|
uint16 pad3;
|
|
uint16 pad4 = 0;
|
|
uint16 totalTextHeight;
|
|
|
|
if (version == 2) {
|
|
pad2 = stream.readUint16();
|
|
if (pad2 != 0) { // In D2 there are values
|
|
warning("TextCast: pad2: %x", pad2);
|
|
}
|
|
|
|
_initialRect = Score::readRect(stream);
|
|
pad3 = stream.readUint16();
|
|
|
|
_textShadow = static_cast<SizeType>(stream.readByte());
|
|
_textFlags = stream.readByte();
|
|
if (_textFlags & 0xf8)
|
|
warning("Unprocessed text cast flags: %x", _textFlags & 0xf8);
|
|
|
|
totalTextHeight = stream.readUint16();
|
|
} else {
|
|
pad2 = stream.readUint16();
|
|
_initialRect = Score::readRect(stream);
|
|
pad3 = stream.readUint16();
|
|
pad4 = stream.readUint16();
|
|
totalTextHeight = stream.readUint16();
|
|
}
|
|
|
|
debugC(2, kDebugLoading, "TextCast(): flags1: %d, border: %d gutter: %d shadow: %d pad1: %x align: %04x",
|
|
_flags, _borderSize, _gutterSize, _boxShadow, pad1, _textAlign);
|
|
debugC(2, kDebugLoading, "TextCast(): rgb: 0x%04x 0x%04x 0x%04x, pad2: %x pad3: %d pad4: %d shadow: %d flags: %d totHeight: %d",
|
|
_palinfo1, _palinfo2, _palinfo3, pad2, pad3, pad4, _textShadow, _textFlags, totalTextHeight);
|
|
if (debugChannelSet(2, kDebugLoading)) {
|
|
_initialRect.debugPrint(2, "TextCast(): rect:");
|
|
}
|
|
} else if (version == 4) {
|
|
_borderSize = static_cast<SizeType>(stream.readByte());
|
|
_gutterSize = static_cast<SizeType>(stream.readByte());
|
|
_boxShadow = static_cast<SizeType>(stream.readByte());
|
|
_textType = static_cast<TextType>(stream.readByte());
|
|
_textAlign = static_cast<TextAlignType>(stream.readSint16()); // this is because 'right' is -1? or should that be 255?
|
|
stream.readUint16();
|
|
stream.readUint16();
|
|
stream.readUint16();
|
|
stream.readUint16();
|
|
|
|
_fontId = 1; // this is in STXT
|
|
|
|
_initialRect = Score::readRect(stream);
|
|
stream.readUint16();
|
|
_textShadow = static_cast<SizeType>(stream.readByte());
|
|
byte flags = stream.readByte();
|
|
|
|
if (flags)
|
|
warning("Unprocessed text cast flags: %x", flags);
|
|
|
|
_fontSize = stream.readUint16();
|
|
_textSlant = 0;
|
|
} else {
|
|
_fontId = 1;
|
|
_fontSize = 12;
|
|
|
|
stream.readUint32();
|
|
stream.readUint32();
|
|
stream.readUint32();
|
|
stream.readUint32();
|
|
uint16 skip = stream.readUint16();
|
|
for (int i = 0; i < skip; i++)
|
|
stream.readUint32();
|
|
|
|
stream.readUint32();
|
|
stream.readUint32();
|
|
stream.readUint32();
|
|
stream.readUint32();
|
|
stream.readUint32();
|
|
stream.readUint32();
|
|
|
|
_initialRect = Score::readRect(stream);
|
|
_boundingRect = Score::readRect(stream);
|
|
|
|
stream.readUint32();
|
|
stream.readUint16();
|
|
stream.readUint16();
|
|
}
|
|
|
|
_cachedMacText = new CachedMacText(this, _bgcolor, version, -1, g_director->_wm);
|
|
|
|
_modified = false;
|
|
}
|
|
|
|
TextCast::~TextCast() {
|
|
delete _cachedMacText;
|
|
}
|
|
|
|
void TextCast::importStxt(const Stxt *stxt) {
|
|
_fontId = stxt->_fontId;
|
|
_textSlant = stxt->_textSlant;
|
|
_fontSize = stxt->_fontSize;
|
|
_palinfo1 = stxt->_palinfo1;
|
|
_palinfo2 = stxt->_palinfo2;
|
|
_palinfo3 = stxt->_palinfo3;
|
|
_ftext = stxt->_ftext;
|
|
_ptext = stxt->_ptext;
|
|
|
|
_cachedMacText->setStxt(this);
|
|
}
|
|
|
|
void TextCast::importRTE(byte *text) {
|
|
//assert(rteList.size() == 3);
|
|
//child0 is probably font data.
|
|
//child1 is the raw text.
|
|
_ptext = _ftext = Common::String((char*)text);
|
|
//child2 is positional?
|
|
}
|
|
|
|
void TextCast::setText(const char *text) {
|
|
// Do nothing if text did not change
|
|
if (_ftext.equals(text))
|
|
return;
|
|
|
|
_ptext = _ftext = text;
|
|
|
|
_cachedMacText->forceDirty();
|
|
|
|
if (_widget) {
|
|
((Graphics::MacEditableText *)_widget)->clearText();
|
|
((Graphics::MacEditableText *)_widget)->appendTextDefault(_ftext);
|
|
}
|
|
}
|
|
|
|
Common::String TextCast::getText() {
|
|
if (_widget)
|
|
_ptext = ((Graphics::MacEditableText *)_widget)->getEditedString().encode();
|
|
|
|
return _ptext;
|
|
}
|
|
|
|
ShapeCast::ShapeCast(Common::ReadStreamEndian &stream, uint16 version) {
|
|
_type = kCastShape;
|
|
|
|
byte flags, unk1;
|
|
|
|
_ink = kInkTypeCopy;
|
|
|
|
if (version < 4) {
|
|
flags = stream.readByte();
|
|
unk1 = stream.readByte();
|
|
_shapeType = static_cast<ShapeType>(stream.readByte());
|
|
_initialRect = Score::readRect(stream);
|
|
_pattern = stream.readUint16BE();
|
|
// Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
|
|
_fgCol = g_director->transformColor((128 + stream.readByte()) & 0xff);
|
|
_bgCol = g_director->transformColor((128 + stream.readByte()) & 0xff);
|
|
_fillType = stream.readByte();
|
|
_ink = static_cast<InkType>(_fillType & 0x3f);
|
|
_lineThickness = stream.readByte();
|
|
_lineDirection = stream.readByte();
|
|
} else if (version == 4) {
|
|
flags = 0;
|
|
unk1 = stream.readByte();
|
|
_shapeType = static_cast<ShapeType>(stream.readByte());
|
|
_initialRect = Score::readRect(stream);
|
|
_pattern = stream.readUint16BE();
|
|
_fgCol = g_director->transformColor((uint8)stream.readByte());
|
|
_bgCol = g_director->transformColor((uint8)stream.readByte());
|
|
_fillType = stream.readByte();
|
|
_ink = static_cast<InkType>(_fillType & 0x3f);
|
|
_lineThickness = stream.readByte();
|
|
_lineDirection = stream.readByte();
|
|
} else {
|
|
flags = stream.readByte();
|
|
unk1 = stream.readByte();
|
|
|
|
_initialRect = Score::readRect(stream);
|
|
_boundingRect = Score::readRect(stream);
|
|
|
|
_shapeType = kShapeRectangle;
|
|
_pattern = 0;
|
|
_fgCol = _bgCol = 0;
|
|
_fillType = 0;
|
|
_lineThickness = 1;
|
|
_lineDirection = 0;
|
|
}
|
|
_modified = false;
|
|
|
|
debugC(3, kDebugLoading, "ShapeCast: fl: %x unk1: %x type: %d pat: %d fg: %d bg: %d fill: %d thick: %d dir: %d",
|
|
flags, unk1, _shapeType, _pattern, _fgCol, _bgCol, _fillType, _lineThickness, _lineDirection);
|
|
|
|
if (debugChannelSet(3, kDebugLoading))
|
|
_initialRect.debugPrint(0, "ShapeCast: rect:");
|
|
}
|
|
|
|
ButtonCast::ButtonCast(Common::ReadStreamEndian &stream, uint16 version) : TextCast(stream, version, 0xff) {
|
|
_type = kCastButton;
|
|
|
|
if (version < 4) {
|
|
_buttonType = static_cast<ButtonType>(stream.readUint16BE() - 1);
|
|
} else {
|
|
stream.readByte();
|
|
stream.readByte();
|
|
|
|
// This has already been populated in the super TextCast constructor
|
|
//initialRect = Score::readRect(stream);
|
|
//boundingRect = Score::readRect(stream);
|
|
|
|
_buttonType = static_cast<ButtonType>(stream.readUint16BE());
|
|
}
|
|
}
|
|
|
|
ScriptCast::ScriptCast(Common::ReadStreamEndian &stream, uint16 version) {
|
|
_type = kCastLingoScript;
|
|
_scriptType = kNoneScript;
|
|
|
|
if (version < 4) {
|
|
error("Unhandled Script cast");
|
|
} else if (version == 4) {
|
|
byte unk1 = stream.readByte();
|
|
byte type = stream.readByte();
|
|
|
|
switch (type) {
|
|
case 1:
|
|
_scriptType = kScoreScript;
|
|
break;
|
|
case 3:
|
|
_scriptType = kMovieScript;
|
|
break;
|
|
default:
|
|
error("ScriptCast: Unprocessed script type: %d", type);
|
|
}
|
|
|
|
_initialRect = Score::readRect(stream);
|
|
_boundingRect = Score::readRect(stream);
|
|
|
|
_id = stream.readUint32();
|
|
|
|
debugC(4, kDebugLoading, "CASt: Script id: %d type: %s (%d) unk1: %d", _id, scriptType2str(_scriptType), type, unk1);
|
|
|
|
stream.readByte(); // There should be no more data
|
|
assert(stream.eos());
|
|
} else if (version > 4) {
|
|
stream.readByte();
|
|
stream.readByte();
|
|
|
|
_initialRect = Score::readRect(stream);
|
|
_boundingRect = Score::readRect(stream);
|
|
|
|
_id = stream.readUint32();
|
|
|
|
debugC(4, kDebugLoading, "CASt: Script id: %d", _id);
|
|
|
|
// WIP need to complete this!
|
|
}
|
|
}
|
|
|
|
RTECast::RTECast(Common::ReadStreamEndian &stream, uint16 version, int32 bgcolor) : TextCast(stream, version, bgcolor) {
|
|
|
|
_type = kCastRTE;
|
|
}
|
|
|
|
void RTECast::loadChunks() {
|
|
//TODO: Actually load RTEs correctly, don't just make fake STXT.
|
|
#if 0
|
|
Common::SeekableReadStream *rte1 = _movieArchive->getResource(res->children[child].tag, res->children[child].index);
|
|
byte *buffer = new byte[rte1->size() + 2];
|
|
rte1->read(buffer, rte1->size());
|
|
buffer[rte1->size()] = '\n';
|
|
buffer[rte1->size() + 1] = '\0';
|
|
_loadedText->getVal(id)->importRTE(buffer);
|
|
|
|
delete rte1;
|
|
#endif
|
|
}
|
|
|
|
} // End of namespace Director
|