diff options
| -rw-r--r-- | graphics/flic_player.cpp | 264 | ||||
| -rw-r--r-- | graphics/flic_player.h | 100 | ||||
| -rw-r--r-- | graphics/module.mk | 1 | 
3 files changed, 365 insertions, 0 deletions
| diff --git a/graphics/flic_player.cpp b/graphics/flic_player.cpp new file mode 100644 index 0000000000..7a69762570 --- /dev/null +++ b/graphics/flic_player.cpp @@ -0,0 +1,264 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "flic_player.h" + +namespace Graphics { + +FlicPlayer::FlicPlayer(const char *fileName) +	: _paletteDirty(false), _offscreen(0), _currFrame(0) { + +	memset(&_flicInfo, 0, sizeof(_flicInfo)); +	_fileStream.open(fileName); + +	_flicInfo.size = _fileStream.readUint32LE(); +	_flicInfo.type = _fileStream.readUint16LE(); +	_flicInfo.numFrames = _fileStream.readUint16LE(); +	_flicInfo.width = _fileStream.readUint16LE(); +	_flicInfo.height = _fileStream.readUint16LE(); +	_fileStream.skip(4); +	_flicInfo.speed = _fileStream.readUint32LE(); + +	_fileStream.seek(80); +	_flicInfo.offsetFrame1 = _fileStream.readUint32LE(); +	_flicInfo.offsetFrame2 = _fileStream.readUint32LE(); + +	// Check FLC magic number +	if (_flicInfo.type != 0xAF12) { +		error("FlicPlayer::FlicPlayer(): attempted to load non-FLC data (type = 0x%04X)", _flicInfo.type); +	} + +	_offscreen = new uint8[_flicInfo.width * _flicInfo.height]; +	memset(_palette, 0, sizeof(_palette)); + +	// Seek to the first frame +	_fileStream.seek(_flicInfo.offsetFrame1); +} + +FlicPlayer::~FlicPlayer() { +	delete[] _offscreen; +} + +void FlicPlayer::redraw() { +	_dirtyRects.clear(); +	_dirtyRects.push_back(Common::Rect(0, 0, _flicInfo.width, _flicInfo.height)); +} + +ChunkHeader FlicPlayer::readChunkHeader() { +	ChunkHeader head; +	head.size = _fileStream.readUint32LE(); +	head.type = _fileStream.readUint16LE(); + +	/* XXX: You'll want to read the rest of the chunk here as well! */ + +	return head; +} + +FrameTypeChunkHeader FlicPlayer::readFrameTypeChunkHeader(ChunkHeader chunkHead) { +	FrameTypeChunkHeader head; + +	head.header = chunkHead; +	head.numChunks = _fileStream.readUint16LE(); +	head.delay = _fileStream.readUint16LE(); +	head.reserved = _fileStream.readUint16LE(); +	head.widthOverride = _fileStream.readUint16LE(); +	head.heightOverride = _fileStream.readUint16LE(); + +	return head; +} + +void FlicPlayer::decodeByteRun(uint8 *data) { +	uint8 *ptr = (uint8 *)_offscreen; +	while((ptr - _offscreen) < (_flicInfo.width * _flicInfo.height)) { +		uint8 chunks = *data++; +		while (chunks--) { +			int8 count = *data++; +			if (count > 0) { +				memset(ptr, *data++, count); +				ptr += count; +			} else { +				uint8 copyBytes = -count; +				memcpy(ptr, data, copyBytes); +				ptr += copyBytes; +				data += copyBytes; +			} +		} +	} + +	redraw(); +} + +#define OP_PACKETCOUNT   0 +#define OP_UNDEFINED     1 +#define OP_LASTPIXEL     2 +#define OP_LINESKIPCOUNT 3 + +void FlicPlayer::decodeDeltaFLC(uint8 *data) { +	uint16 linesInChunk = READ_LE_UINT16(data); data += 2; +	uint16 currentLine = 0; +	uint16 packetCount = 0; + +	while (linesInChunk--) { +		uint16 opcode; + +		// First process all the opcodes. +		do { +			opcode = READ_LE_UINT16(data); data += 2; + +			switch ((opcode >> 14) & 3) { +			case OP_PACKETCOUNT: +				packetCount = opcode; +				break; +			case OP_UNDEFINED: +				break; +			case OP_LASTPIXEL: +				*(uint8 *)(_offscreen + (currentLine * _flicInfo.width) + (_flicInfo.width - 1)) = (opcode & 0xFF); +				_dirtyRects.push_back(Common::Rect(_flicInfo.width - 1, currentLine, _flicInfo.width, currentLine + 1)); +				break; +			case OP_LINESKIPCOUNT: +				currentLine += -(int16)opcode; +				break; +			} +		} while (((opcode >> 14) & 3) != OP_PACKETCOUNT); + +		uint16 column = 0; + +		// Now interpret the RLE data +		while (packetCount--) { +			column += *data++; +			int8 rleCount = (int8)*data++; +			if (rleCount > 0) { +				memcpy((void *)(_offscreen + (currentLine * _flicInfo.width) + column), data, rleCount * 2); +				_dirtyRects.push_back(Common::Rect(column, currentLine, column + (rleCount * 2), currentLine + 1)); +				data += rleCount * 2; +				column += rleCount * 2; +			} else if (rleCount < 0) { +				uint16 dataWord = *(uint16 *)data; data += 2; +				for (int i = 0; i < -(int16)rleCount; ++i) { +					WRITE_LE_UINT16(_offscreen + (currentLine * _flicInfo.width) + column + (i * 2), dataWord); +				} +				_dirtyRects.push_back(Common::Rect(column, currentLine, column + (-(int16)rleCount * 2), currentLine + 1)); + +				column += (-(int16)rleCount) * 2; +			} else { // End of cutscene ? +				return; +			} +		} + +		currentLine++; +	} +} + +#define COLOR_256  4 +#define FLI_SS2    7 +#define FLI_BRUN   15 +#define PSTAMP     18 +#define FRAME_TYPE 0xF1FA + +void FlicPlayer::decodeFrame() { +	FrameTypeChunkHeader frameHeader; + +	// Read chunk +	ChunkHeader cHeader = readChunkHeader(); +	switch (cHeader.type) { +	case FRAME_TYPE: +		frameHeader = readFrameTypeChunkHeader(cHeader); +		_currFrame++; +		break; +	default: +		error("FlicPlayer::decodeFrame(): unknown main chunk type (type = 0x%02X)", cHeader.type); +		break; +	 } + +	// Read subchunks +	if (cHeader.type == FRAME_TYPE) { +		for (int i = 0; i < frameHeader.numChunks; ++i) { +			cHeader = readChunkHeader(); +			uint8 *data = new uint8[cHeader.size - 6]; +			_fileStream.read(data, cHeader.size - 6); +			switch (cHeader.type) { +			case COLOR_256: +				setPalette(data); +				_paletteDirty = true; +				break; +			case FLI_SS2: +				decodeDeltaFLC(data); +				break; +			case FLI_BRUN: +				decodeByteRun(data); +				break; +			case PSTAMP: +				/* PSTAMP - skip for now */ +				break; +			default: +				error("FlicPlayer::decodeFrame(): unknown subchunk type (type = 0x%02X)", cHeader.type); +				break; +			 } + +			delete[] data; +		} +	} + +	// If we just processed the ring frame, set the next frame +	if (_currFrame == _flicInfo.numFrames + 1) { +		_currFrame = 1; +		_fileStream.seek(_flicInfo.offsetFrame2); +	} +} + +void FlicPlayer::reset() { +	_fileStream.seek(_flicInfo.offsetFrame1); +} + +void FlicPlayer::setPalette(uint8 *mem) { +	uint16 numPackets = READ_LE_UINT16(mem); mem += 2; + +	if (0 == READ_LE_UINT16(mem)) { //special case +		mem += 2; +		for (int i = 0; i < 256; ++i) { +			for (int j = 0; j < 3; ++j) +				_palette[i * 4 + j] = (mem[i * 3 + j]); +			_palette[i * 4 + 3] = 0; +		} +	} else { +		uint8 palPos = 0; + +		while (numPackets--) { +			palPos += *mem++; +			uint8 change = *mem++; + +			for (int i = 0; i < change; ++i) { +				for (int j = 0; j < 3; ++j) +					_palette[(palPos + i) * 4 + j] = (mem[i * 3 + j]); +				_palette[(palPos + i) * 4 + 3] = 0; +			} + +			palPos += change; +			mem += (change * 3); +		} +	} +} + +} // End of namespace Graphics diff --git a/graphics/flic_player.h b/graphics/flic_player.h new file mode 100644 index 0000000000..64b29969c8 --- /dev/null +++ b/graphics/flic_player.h @@ -0,0 +1,100 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GRAPHICS_FLICPLAYER_H +#define GRAPHICS_FLICPLAYER_H + +#include "common/endian.h" +#include "common/list.h" +#include "common/rect.h" +#include "common/file.h" + +namespace Graphics { + +struct FlicHeader { +	uint32 size; +	uint16 type; +	uint16 numFrames; +	uint16 width; +	uint16 height; +	uint32 speed; +	uint16 offsetFrame1; +	uint16 offsetFrame2; +}; + +struct ChunkHeader { +	uint32 size; +	uint16 type; +}; + +struct FrameTypeChunkHeader { +	ChunkHeader header; +	uint16 numChunks; +	uint16 delay; +	uint16 reserved; // always zero +	uint16 widthOverride; +	uint16 heightOverride; +}; + +class FlicPlayer { +public: +	FlicPlayer(const char *fileName); +	~FlicPlayer(); + +	void decodeFrame(); +	int getWidth() const { return _flicInfo.width; } +	int getHeight() const { return _flicInfo.height; } +	bool hasFrames() const { return _flicInfo.numFrames > 0; } +	int getCurFrame() const { return _currFrame; } +	int getFrameCount() const { return _flicInfo.numFrames; } +	uint32 getSpeed() const { return _flicInfo.speed; } +	bool isPaletteDirty() const { return _paletteDirty; } +	const uint8 *getPalette() { _paletteDirty = false; return _palette; } +	const uint8 *getOffscreen() const { return _offscreen; } +	const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; } +	void clearDirtyRects() { _dirtyRects.clear(); } +	void redraw(); +	void reset(); + +protected: +	ChunkHeader readChunkHeader(); +	FrameTypeChunkHeader readFrameTypeChunkHeader(ChunkHeader chunkHead); +	void decodeByteRun(uint8 *data); +	void decodeDeltaFLC(uint8 *data); +	void setPalette(uint8 *mem); + +	Common::File _fileStream; +	bool _paletteDirty; +	uint8 *_offscreen; +	uint8 _palette[256 * 4]; +	FlicHeader _flicInfo; +	uint16 _currFrame; +	uint32 _lastFrameTime; +	Common::List<Common::Rect> _dirtyRects; +}; + +} // End of namespace Graphics + +#endif diff --git a/graphics/module.mk b/graphics/module.mk index 982711b608..70fb75fabe 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -3,6 +3,7 @@ MODULE := graphics  MODULE_OBJS := \  	cursorman.o \  	dxa_player.o \ +	flic_player.o \  	font.o \  	fontman.o \  	fonts/consolefont.o \ | 
