diff options
| author | Sven Hesse | 2012-07-07 13:21:07 +0200 | 
|---|---|---|
| committer | Sven Hesse | 2012-07-30 01:44:45 +0200 | 
| commit | e17d4a5c0c66b890014efa62d207406fd5b887ef (patch) | |
| tree | 0a4f26989b01e1ce3fa3bf02f97a348d5d957344 | |
| parent | 0b030dd341b00007b969805ff6d488a51a1a97c7 (diff) | |
| download | scummvm-rg350-e17d4a5c0c66b890014efa62d207406fd5b887ef.tar.gz scummvm-rg350-e17d4a5c0c66b890014efa62d207406fd5b887ef.tar.bz2 scummvm-rg350-e17d4a5c0c66b890014efa62d207406fd5b887ef.zip | |
GOB: Implement GCT drawing
| -rw-r--r-- | engines/gob/module.mk | 1 | ||||
| -rw-r--r-- | engines/gob/pregob/gctfile.cpp | 306 | ||||
| -rw-r--r-- | engines/gob/pregob/gctfile.h | 149 | ||||
| -rw-r--r-- | engines/gob/pregob/pregob.cpp | 13 | ||||
| -rw-r--r-- | engines/gob/pregob/pregob.h | 7 | 
5 files changed, 476 insertions, 0 deletions
| diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 1b3f400684..15351848de 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -80,6 +80,7 @@ MODULE_OBJS := \  	detection/detection.o \  	pregob/pregob.o \  	pregob/txtfile.o \ +	pregob/gctfile.o \  	pregob/onceupon/onceupon.o \  	pregob/onceupon/abracadabra.o \  	pregob/onceupon/babayaga.o \ diff --git a/engines/gob/pregob/gctfile.cpp b/engines/gob/pregob/gctfile.cpp new file mode 100644 index 0000000000..08c32cda76 --- /dev/null +++ b/engines/gob/pregob/gctfile.cpp @@ -0,0 +1,306 @@ +/* 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/random.h" +#include "common/stream.h" + +#include "gob/surface.h" +#include "gob/video.h" + +#include "gob/pregob/gctfile.h" + +namespace Gob { + +GCTFile::Chunk::Chunk() : type(kChunkTypeNone) { +} + + +GCTFile::GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd) : _rnd(&rnd), +	_areaLeft(0), _areaTop(0), _areaRight(0), _areaBottom(0), _currentItem(0xFFFF) { + +	load(gct); +} + +GCTFile::~GCTFile() { +} + +void GCTFile::load(Common::SeekableReadStream &gct) { +	gct.skip(4); // Required buffer size +	gct.skip(2); // Unknown + +	// Read the selector and line counts for each item +	const uint16 itemCount = gct.readUint16LE(); +	_items.resize(itemCount); + +	for (Items::iterator i = _items.begin(); i != _items.end(); ++i) { +		const uint16 selector  = gct.readUint16LE(); +		const uint16 lineCount = gct.readUint16LE(); + +		i->selector = selector; +		i->lines.resize(lineCount); +	} + +	// Read all item lines +	for (Items::iterator i = _items.begin(); i != _items.end(); ++i) { +		for (Lines::iterator l = i->lines.begin(); l != i->lines.end(); ++l) { +			const uint16 lineSize = gct.readUint16LE(); + +			readLine(gct, *l, lineSize); +		} +	} + +	if (gct.err()) +		error("GCTFile::load(): Failed reading GCT"); +} + +void GCTFile::readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const { +	line.chunks.push_back(Chunk()); + +	while (lineSize > 0) { +		byte c = gct.readByte(); +		lineSize--; + +		if (c == 0) { +			// Command byte + +			if (lineSize == 0) +				break; + +			byte cmd = gct.readByte(); +			lineSize--; + +			// Line end command +			if (cmd == 0) +				break; + +			// Item reference command +			if (cmd == 1) { +				if (lineSize < 2) { +					warning("GCTFile::readLine(): Item reference command is missing parameters"); +					break; +				} + +				const uint32 itemRef = gct.readUint16LE(); +				lineSize -= 2; + +				line.chunks.push_back(Chunk()); +				line.chunks.back().type = kChunkTypeItem; +				line.chunks.back().item = itemRef; + +				line.chunks.push_back(Chunk()); +				continue; +			} + +			warning("GCTFile::readLine(): Invalid command 0x%02X", cmd); +			break; +		} + +		// Text +		line.chunks.back().type = kChunkTypeString; +		line.chunks.back().text += (char)c; +	} + +	// Skip bytes we didn't read (because of errors) +	gct.skip(lineSize); + +	// Remove empty chunks from the end of the list +	while (!line.chunks.empty() && (line.chunks.back().type == kChunkTypeNone)) +		line.chunks.pop_back(); +} + +uint16 GCTFile::getLineCount(uint item) const { +	if (item >= _items.size()) +		return 0; + +	return _items[item].lines.size(); +} + +void GCTFile::selectLine(uint item, uint16 line) { +	if ((item >= _items.size()) && (item != kSelectorAll) && (item != kSelectorRandom)) +		return; + +	_items[item].selector = line; +} + +void GCTFile::setText(uint item, uint16 line, const Common::String &text) { +	if ((item >= _items.size()) || (line >= _items[item].lines.size())) +		return; + +	_items[item].lines[line].chunks.clear(); +	_items[item].lines[line].chunks.push_back(Chunk()); + +	_items[item].lines[line].chunks.back().type = kChunkTypeString; +	_items[item].lines[line].chunks.back().text = text; +} + +void GCTFile::setText(uint item, const Common::String &text) { +	if (item >= _items.size()) +		return; + +	_items[item].selector = 0; + +	_items[item].lines.resize(1); + +	setText(item, 0, text); +} + +void GCTFile::reset() { +	_currentItem = 0xFFFF; +	_currentText.clear(); +} + +Common::String GCTFile::getLineText(const Line &line) const { +	Common::String text; + +	// Go over all chunks in this line +	for (Chunks::const_iterator c = line.chunks.begin(); c != line.chunks.end(); ++c) { +		// A chunk is either a direct string, or a reference to another item + +		if        (c->type == kChunkTypeItem) { +			Common::List<Common::String> lines; + +			getItemText(c->item, lines); +			if (lines.empty()) +				continue; + +			if (lines.size() > 1) +				warning("GCTFile::getLineText(): Referenced item has multiple lines"); + +			text += lines.front(); +		} else if (c->type == kChunkTypeString) +			text += c->text; +	} + +	return text; +} + +void GCTFile::getItemText(uint item, Common::List<Common::String> &text) const { +	text.clear(); + +	if ((item >= _items.size()) || _items[item].lines.empty()) +		return; + +	uint16 line = _items[item].selector; + +	// Draw all lines +	if (line == kSelectorAll) { +		for (Lines::const_iterator l = _items[item].lines.begin(); l != _items[item].lines.end(); ++l) +			text.push_back(getLineText(*l)); + +		return; +	} + +	// Draw random line +	if (line == kSelectorRandom) +		line = _rnd->getRandomNumber(_items[item].lines.size() - 1); + +	if (line >= _items[item].lines.size()) +		return; + +	text.push_back(getLineText(_items[item].lines[line])); +} + +void GCTFile::setArea(int16 left, int16 top, int16 right, int16 bottom) { +	trashBuffer(); + +	_hasArea = false; + +	const int16 width  = right  - left + 1; +	const int16 height = bottom - top  + 1; +	if ((width <= 0) || (height <= 0)) +		return; + +	_areaLeft   = left; +	_areaTop    = top; +	_areaRight  = right; +	_areaBottom = bottom; + +	_hasArea = true; + +	resizeBuffer(width, height); +} + +bool GCTFile::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { +	return restoreScreen(dest, left, top, right, bottom); +} + +bool GCTFile::fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom) { +	left   = _areaLeft; +	top    = _areaTop; +	right  = _areaRight; +	bottom = _areaBottom; + +	if (!hasSavedBackground()) +		saveScreen(dest, left, top, right, bottom); + +	dest.fillRect(left, top, right, bottom, color); + +	return true; +} + +bool GCTFile::finished() const { +	return (_currentItem != 0xFFFF) && _currentText.empty(); +} + +bool GCTFile::draw(Surface &dest, uint16 item, const Font &font, uint8 color, +                   int16 &left, int16 &top, int16 &right, int16 &bottom) { + +	if ((item >= _items.size()) || !_hasArea) +		return false; + +	left   = _areaLeft; +	top    = _areaTop; +	right  = _areaRight; +	bottom = _areaBottom; + +	const int16 width  = right  - left + 1; +	const int16 height = bottom - top  + 1; + +	const uint lineCount = height / font.getCharHeight(); +	if (lineCount == 0) +		return false; + +	if (!hasSavedBackground()) +		saveScreen(dest, left, top, right, bottom); + +	if (item != _currentItem) { +		_currentItem = item; + +		getItemText(_currentItem, _currentText); +	} + +	if (_currentText.empty()) +		return false; + +	int16 y = top; +	for (uint i = 0; (i < lineCount) && !_currentText.empty(); i++, y += font.getCharHeight()) { +		const Common::String &line = _currentText.front(); +		const int16 x = left + ((width - (line.size() * font.getCharWidth())) / 2); + +		font.drawString(line, x, y, color, 0, true, dest); +		_currentText.pop_front(); +	} + +	return true; +} + +} // End of namespace Gob diff --git a/engines/gob/pregob/gctfile.h b/engines/gob/pregob/gctfile.h new file mode 100644 index 0000000000..ed6351b7a8 --- /dev/null +++ b/engines/gob/pregob/gctfile.h @@ -0,0 +1,149 @@ +/* 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. + * + */ + +#ifndef GOB_PREGOB_GCTFILE_H +#define GOB_PREGOB_GCTFILE_H + +#include "common/str.h" +#include "common/array.h" +#include "common/list.h" + +#include "gob/backbuffer.h" + +namespace Common { +	class RandomSource; +	class SeekableReadStream; +} + +namespace Gob { + +class Surface; +class Font; + +class GCTFile : public BackBuffer { +public: +	static const uint16 kSelectorAll    = 0xFFFE; ///< Print all lines. +	static const uint16 kSelectorRandom = 0xFFFF; ///< Print a random line. + + +	GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd); +	~GCTFile(); + +	/** Return the number of lines in an item. */ +	uint16 getLineCount(uint item) const; + +	/** Set the area the text will be printed in. */ +	void setArea(int16 left, int16 top, int16 right, int16 bottom); + +	/** Set which line of this item should be printed. */ +	void selectLine(uint item, uint16 line); + +	/** Change the text of an items' line. */ +	void setText(uint item, uint16 line, const Common::String &text); +	/** Change the item into one one line and set that line's text. */ +	void setText(uint item, const Common::String &text); + +	/** Reset the item drawing state. */ +	void reset(); + +	/** Clear the drawn text, restoring the original content. */ +	bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + +	/** Fill the text area with a color. */ +	bool fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom); + +	/** Draw an item onto the surface, until all text has been drawn or the area is filled. */ +	bool draw(Surface &dest, uint16 item, const Font &font, uint8 color, +	          int16 &left, int16 &top, int16 &right, int16 &bottom); + +	/** Did we draw all text? */ +	bool finished() const; + +private: +	/** The type of a chunk. */ +	enum ChunkType { +		kChunkTypeNone   = 0, ///< Do nothing. +		kChunkTypeString    , ///< A direct string. +		kChunkTypeItem        ///< A reference to an item to print instead. +	}; + +	/** A chunk in an item text line. */ +	struct Chunk { +		ChunkType type; ///< The type of the chunk. + +		Common::String text; ///< Text to print. + +		int item; ///< Item to print instead. + +		Chunk(); +	}; + +	typedef Common::List<Chunk> Chunks; + +	/** A line in an item. */ +	struct Line { +		Chunks chunks; ///< The chunks that make up the line. +	}; + +	typedef Common::Array<Line> Lines; + +	/** A GCT item. */ +	struct Item { +		Lines  lines;    ///< The text lines in the item +		uint16 selector; ///< Which line to print. +	}; + +	typedef Common::Array<Item> Items; + + +	Common::RandomSource *_rnd; + +	Items _items; ///< All GCT items. + +	// The area on which to print +	bool  _hasArea; +	int16 _areaLeft; +	int16 _areaTop; +	int16 _areaRight; +	int16 _areaBottom; + +	/** Index of the current item we're drawing. */ +	uint16 _currentItem; +	/** Text left to draw. */ +	Common::List<Common::String> _currentText; + + +	// -- Loading helpers -- + +	void load(Common::SeekableReadStream &gct); +	void readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const; + + +	// -- Draw helpers -- + +	Common::String getLineText(const Line &line) const; +	void getItemText(uint item, Common::List<Common::String> &text) const; +}; + +} // End of namespace Gob + +#endif // GOB_PREGOB_GCTFILE_H diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp index 4ee5430de7..033eea89f2 100644 --- a/engines/gob/pregob/pregob.cpp +++ b/engines/gob/pregob/pregob.cpp @@ -35,6 +35,7 @@  #include "gob/sound/sound.h"  #include "gob/pregob/pregob.h" +#include "gob/pregob/gctfile.h"  namespace Gob { @@ -341,4 +342,16 @@ TXTFile *PreGob::loadTXT(const Common::String &txtFile, TXTFile::Format format)  void PreGob::fixTXTStrings(TXTFile &txt) const {  } +GCTFile *PreGob::loadGCT(const Common::String &gctFile) const { +	Common::SeekableReadStream *gctStream = _vm->_dataIO->getFile(gctFile); +	if (!gctStream) +		error("PreGob::loadGCT(): Failed to open \"%s\"", gctFile.c_str()); + +	GCTFile *gct = new GCTFile(*gctStream, _vm->_rnd); + +	delete gctStream; + +	return gct; +} +  } // End of namespace Gob diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h index f1728036ab..686727b08b 100644 --- a/engines/gob/pregob/pregob.h +++ b/engines/gob/pregob/pregob.h @@ -38,6 +38,8 @@ namespace Gob {  class GobEngine;  class Surface; +class GCTFile; +  class PreGob {  public:  	PreGob(GobEngine *vm); @@ -164,6 +166,11 @@ protected:  	virtual void fixTXTStrings(TXTFile &txt) const; +	// -- GCT helpers -- + +	GCTFile *loadGCT(const Common::String &gctFile) const; + +  	GobEngine *_vm;  private: | 
