[Scummvm-cvs-logs] CVS: scummvm/scumm/smush smush_font.cpp,NONE,1.1 smush_font.h,NONE,1.1 smush_mixer.cpp,NONE,1.1 smush_mixer.h,NONE,1.1 smush_player.cpp,NONE,1.1 smush_player.h,NONE,1.1 channel.h,1.9,1.10 chunk.cpp,1.10,1.11 chunk.h,1.7,1.8 codec1.cpp,1.8,1.9 codec37.cpp,1.17,1.18 codec37.h,1.10,1.11 codec47.cpp,1.44,1.45 codec47.h,1.13,1.14 imuse_channel.cpp,1.13,1.14 saud_channel.cpp,1.10,1.11 brenderer.cpp,1.6,NONE brenderer.h,1.10,NONE codec1.h,1.6,NONE codec44.cpp,1.9,NONE codec44.h,1.8,NONE color.cpp,1.4,NONE color.h,1.6,NONE config.h,1.6,NONE decoder.h,1.8,NONE frenderer.cpp,1.18,NONE frenderer.h,1.13,NONE mixer.h,1.5,NONE palette.h,1.6,NONE player.cpp,1.43,NONE player.h,1.15,NONE renderer.h,1.8,NONE scumm_renderer.cpp,1.30,NONE scumm_renderer.h,1.14,NONE

Pawel Kolodziejski aquadran at users.sourceforge.net
Mon Mar 17 04:30:35 CET 2003


Update of /cvsroot/scummvm/scummvm/scumm/smush
In directory sc8-pr-cvs1:/tmp/cvs-serv7190

Modified Files:
	channel.h chunk.cpp chunk.h codec1.cpp codec37.cpp codec37.h 
	codec47.cpp codec47.h imuse_channel.cpp saud_channel.cpp 
Added Files:
	smush_font.cpp smush_font.h smush_mixer.cpp smush_mixer.h 
	smush_player.cpp smush_player.h 
Removed Files:
	brenderer.cpp brenderer.h codec1.h codec44.cpp codec44.h 
	color.cpp color.h config.h decoder.h frenderer.cpp frenderer.h 
	mixer.h palette.h player.cpp player.h renderer.h 
	scumm_renderer.cpp scumm_renderer.h 
Log Message:
reorg/clenup, changed main loop in smush code

--- NEW FILE: smush_font.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2002-2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/smush/smush_font.cpp,v 1.1 2003/03/17 12:28:50 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "common/util.h"
#include "common/engine.h"
#include "common/file.h"
#include "scumm/scumm.h"

#include "smush_font.h"

SmushFont::SmushFont(bool use_original_colors, bool new_colors) :
	_nbChars(0),
	_color(-1),
	_new_colors(new_colors),
	_original(use_original_colors) {
	for(int i = 0; i < 256; i++)
		_chars[i].chr = NULL;
}

SmushFont::~SmushFont() {
	for(int i = 0; i < _nbChars; i++) {
		if(_chars[i].chr)
			delete []_chars[i].chr;
	}
}

bool SmushFont::loadFont(const char *filename, const char *directory) {
	debug(2, "SmushFont::loadFont() called");

	File file;
	file.open(filename, directory);
	if (file.isOpen() == false) {
		warning("SmushFont::loadFont() Can't open font file: %s/%s", directory, filename);
		return false;
	}

	uint32 tag = file.readUint32BE();
	if (tag != 'ANIM') {
		debug(2, "SmushFont::loadFont() there is no ANIM chunk in font header");
		return false;
	}

	if (_dataSrc != NULL) {
		free(_dataSrc);
		_dataSrc = NULL;
	}

	uint32 length = file.readUint32BE();
	_dataSrc = (byte *)malloc(length);
	file.read(_dataSrc, length);
	file.close();

	if (READ_BE_UINT32(_dataSrc) != 'AHDR') {
		debug(2, "SmushFont::loadFont() there is no AHDR chunk in font header");
		free(_dataSrc);
		_dataSrc = NULL;
		return false;
	}
	
	_nbChars = READ_LE_UINT16(_dataSrc + 10);
	int32 offset = READ_BE_UINT32(_dataSrc + 4) + 8;
	for (int l = 0; l < _nbChars; l++) {
		if (READ_BE_UINT32(_dataSrc + offset) == 'FRME') {
			offset += 8;
			if (READ_BE_UINT32(_dataSrc + offset) == 'FOBJ') {
				_chars[l].width = READ_LE_UINT16(_dataSrc + offset + 14);
				_chars[l].height = READ_LE_UINT16(_dataSrc + offset + 16);
				_chars[l].chr = new byte[_chars[l].width * _chars[l].height + 1000];
				decodeCodec(_chars[l].chr, _dataSrc + offset + 22, READ_BE_UINT32(_dataSrc + offset + 4) - 14);
				offset += READ_BE_UINT32(_dataSrc + offset + 4) + 8;
			} else {
				debug(2, "SmushFont::loadFont(%s, %s) there is no FOBJ chunk in FRME chunk %d (offset %x)", filename, directory, l, offset);
				break;
			}
		} else {
			debug(2, "SmushFont::loadFont(%s, %s) there is no FRME chunk %d (offset %x)", filename, directory, l, offset);
			break;
		}
	}

	free(_dataSrc);
	_dataSrc = NULL;
	return true;
}

int SmushFont::getCharWidth(byte v) {
	if(v >= _nbChars)
		error("invalid character in SmushFont::charWidth : %d (%d)", v, _nbChars);

	return _chars[v].width;
}

int SmushFont::getCharHeight(byte v) {
	if(v >= _nbChars)
		error("invalid character in SmushFont::charHeight : %d (%d)", v, _nbChars);

	return _chars[v].height;
}

int SmushFont::getStringWidth(char *str) {
	int ret = 0;

	while(*str) {
		ret += getCharWidth(*str++);
	}

	return ret;
}

int SmushFont::getStringHeight(char *str) {
	int ret = 0;

	for(int i = 0; str[i] != 0; i++) {
		int h = getCharHeight(str[i]);
		ret = MAX(ret, h);
	}

	return ret;
}

void SmushFont::decodeCodec(byte *dst, byte *src, int length) {
	int size_line, num;
	byte *src2 = src;
	byte *dst2 = dst;
	byte val;

	do {
		size_line = READ_LE_UINT16(src2);
		src2 += 2;
		length -= 2;

		while (size_line != 0) {
			num = *src2++;
			val = *src2++;
			memset(dst2, val, num);
			dst2 += num;
			length -= 2;
			size_line -= 2;
			if (size_line != 0) {
				num = READ_LE_UINT16(src2) + 1;
				src2 += 2;
				memcpy(dst2, src2, num);
				dst2 += num;
				src2 += num;
				length -= num + 2;
				size_line -= num + 2;
			}
		}
		dst2--;

	} while (length > 1);
}

int SmushFont::drawChar(byte *buffer, int dst_width, int x, int y, byte chr) {
	int w = _chars[chr].width;
	int h = _chars[chr].height;
	byte *src = _chars[chr].chr;
	byte *dst = buffer + dst_width * y + x;

	if(_original) {
		for(int32 j = 0; j < h; j++) {
			for(int32 i = 0; i < w; i++) {
				char value = *src++;
				if(value) dst[i] = value;
			}
			dst += dst_width;
		}
	} else {
		char color = (_color != -1) ? _color : 1;
		if (_new_colors == true) {
			for(int j = 0; j < h; j++) {
				for(int i = 0; i < w; i++) {
					char value = *src++;
					if(value == -color) {
						dst[i] = 0xFF;
					} else if(value == -31) {
						dst[i] = 0;
					} else if(value) {
						dst[i] = value;
					}
				}
				dst += dst_width;
			}
		} else {
			for(int j = 0; j < h; j++) {
				for(int i = 0; i < w; i++) {
					char value = *src++;
					if(value == 1) {
						dst[i] = color;
					} else if(value) {
						dst[i] = 0;
					}
				}
				dst += dst_width;
			}
		}
	}
	return w;
}

static char **split(char *str, char sep) {
	char **ret = new char *[62];
	int n = 0;
	const char *i = str;
	char *j = strchr(i, sep);

	while(j != NULL) {
		assert(n < 60);
		ret[n] = new char[j - i + 1];
		memcpy(ret[n], i, j - i);
		ret[n++][j - i] = 0;
		i = j + 1;
		j = strchr(i, sep);
	}

	ret[n] = new char[strlen(i) + 1];
	memcpy(ret[n], i, strlen(i));
	ret[n++][strlen(i)] = 0;
	ret[n] = 0;

	return ret;
}

void SmushFont::drawSubstring(char *str, byte *buffer, int dst_width, int x, int y) {
	for(int i = 0; str[i] != 0; i++)
		x += drawChar(buffer, dst_width, x, y, str[i]);
}

void SmushFont::drawStringAbsolute(char *str, byte *buffer, int dst_width, int x, int y) {
	debug(9, "SmushFont::drawStringAbsolute(%s, %d, %d)", str, x, y);

	while(str) {
		char line[256];
		char *pos = strchr(str, '\n');
		if(pos) {
			memcpy(line, str, pos - str - 1);
			line[pos - str - 1] = 0;
			str = pos + 1;
		} else {
			strcpy(line, str);
			str = 0;
		}
		drawSubstring(line, buffer, dst_width, x, y);
		y += getStringHeight(line);
	}
}

void SmushFont::drawStringCentered(char *str, byte *buffer, int dst_width, int dst_height, int y, int xmin, int width, int offset) {
	debug(9, "SmushFont::drawStringCentered(%s, %d, %d)", str, xmin, y);

	if ((strchr(str, '\n') != 0)) {
		char *z = strchr(str, '\n');
		*z = 0;
	}
	char **words = split(str, ' ');
	int nb_sub = 0;

	while(words[nb_sub])
		nb_sub++;

	int *sizes = new int[nb_sub];
	int i = 0, max_width = 0, height = 0, nb_subs = 0;

	for(i = 0; i < nb_sub; i++)
		sizes[i] = getStringWidth(words[i]);

	char **substrings = new char *[nb_sub];
	int *substr_widths = new int[nb_sub];
	int space_width = getCharWidth(' ');

	i = 0;
	while(i < nb_sub) {
		int substr_width = sizes[i];
		char *substr = new char[1000];
		strcpy(substr, words[i]);
		int j = i + 1;

		while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
			substr_width += sizes[j++] + space_width;
		}

		for(int k = i + 1; k < j; k++) {
			strcat(substr, " ");
			strcat(substr, words[k]);
		}

		substrings[nb_subs] = substr;
		substr_widths[nb_subs++] = substr_width;
		if(substr_width > max_width)
			max_width = substr_width;
		i = j;
		height += getStringHeight(substr);
	}

	delete []sizes;
	for(i = 0; i < nb_sub; i++) {
		delete []words[i];
	}
	delete []words;
	
	max_width = (max_width + 1) >> 1;
	int x = xmin + width / 2;
	x += offset - dst_width / 2;

	if(x < max_width) x = max_width;
	if(x + max_width > dst_width) {
		x = dst_width - max_width;
	}

	if(y + height > dst_height) {
		y = dst_height - height;
	}

	for(i = 0; i < nb_subs; i++) {
		int substr_width = substr_widths[i];
		drawSubstring(substrings[i], buffer, dst_width, x - substr_width / 2, y);
		y += getStringHeight(substrings[i]);
		delete []substrings[i];
	}

	delete []substr_widths;
	delete []substrings;
}

void SmushFont::drawStringWrap(char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int width) {
	debug(9, "SmushFont::drawStringWrap(%s, %d, %d)", str, x, y);

	if ((strchr(str, '\n') != 0)) {
		char *z = strchr(str, '\n');
		*z = 0;
	}
	char ** words = split(str, ' ');
	int nb_sub = 0;

	while(words[nb_sub])
		nb_sub++;

	int *sizes = new int[nb_sub];
	int i = 0, max_width = 0, height = 0, nb_subs = 0, left_x;

	for(i = 0; i < nb_sub; i++)
		sizes[i] = getStringWidth(words[i]);

	char **substrings = new char *[nb_sub];
	int *substr_widths = new int[nb_sub];
	int space_width = getCharWidth(' ');

	i = 0;
	while(i < nb_sub) {
		int substr_width = sizes[i];
		char *substr = new char[1000];
		strcpy(substr, words[i]);
		int j = i + 1;

		while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
			substr_width += sizes[j++] + space_width;
		}

		for(int k = i + 1; k < j; k++) {
			strcat(substr, " ");
			strcat(substr, words[k]);
		}

		substrings[nb_subs] = substr;
		substr_widths[nb_subs++] = substr_width;
		i = j;
		height += getStringHeight(substr);
	}

	delete []sizes;
	for(i = 0; i < nb_sub; i++) {
		delete []words[i];
	}
	delete []words;

	if(y + height > dst_height) {
		y = dst_height - height;
	}

	for(i = 0; i < nb_subs; i++)
		max_width = MAX(max_width, substr_widths[i]);

	if(max_width + x > dst_width)
		left_x = dst_width - max_width + getCharWidth(' ');
	else
		left_x = x;

	if(max_width + left_x > dst_height)
		left_x = dst_width - max_width;

	for(i = 0; i < nb_subs; i++) {
		drawSubstring(substrings[i], buffer, dst_width, left_x, y);
		y += getStringHeight(substrings[i]);
		delete []substrings[i];
	}

	delete []substr_widths;
	delete []substrings;
}

void SmushFont::drawStringWrapCentered(char *str, byte *buffer, int dst_width, int dst_height, int x, int32 y, int width) {
	debug(9, "SmushFont::drawStringWrapCentered(%s, %d, %d)", str, x, y);
	
	int max_substr_width = 0;
	if ((strchr(str, '\n') != 0)) {
		char *z = strchr(str, '\n');
		*z = 0;
	}
	char **words = split(str, ' ');
	int nb_sub = 0;

	while(words[nb_sub])
		nb_sub++;

	int *sizes = new int[nb_sub];
	int i = 0, height = 0, nb_subs = 0;

	for(i = 0; i < nb_sub; i++)
		sizes[i] = getStringWidth(words[i]);

	char **substrings = new char *[nb_sub];
	int *substr_widths = new int[nb_sub];
	int space_width = getCharWidth(' ');

	i = 0;
	width = MIN(width, dst_width);
	while(i < nb_sub) {
		int substr_width = sizes[i];
		char *substr = new char[1000];
		strcpy(substr, words[i]);
		int j = i + 1;

		while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
			substr_width += sizes[j++] + space_width;
		}

		for(int k = i + 1; k < j; k++) {
			strcat(substr, " ");
			strcat(substr, words[k]);
		}

		substrings[nb_subs] = substr;
		substr_widths[nb_subs++] = substr_width;
		max_substr_width = MAX(substr_width, max_substr_width);
		i = j;
		height += getStringHeight(substr);
	}

	delete []sizes;
	for(i = 0; i < nb_sub; i++) {
		delete []words[i];
	}
	delete []words;

	if(y + height > dst_height) {
		y = dst_height - height;
	}

	x = (dst_width - max_substr_width) / 2;

	for(i = 0; i < nb_subs; i++) {
		int substr_width = substr_widths[i];
		drawSubstring(substrings[i], buffer, dst_width, x + (max_substr_width - substr_width) / 2, y);
		y += getStringHeight(substrings[i]);
		delete []substrings[i];
	}

	delete []substr_widths;
	delete []substrings;
}

--- NEW FILE: smush_font.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2002-2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/smush/smush_font.h,v 1.1 2003/03/17 12:28:50 aquadran Exp $
 *
 */

#ifndef SMUSH_FONT_H
#define SMUSH_FONT_H

#include "common/scummsys.h"

class SmushFont {
private:

	int _nbChars;
	byte _color;
	bool _new_colors;
	bool _original;
	byte *_dataSrc;
	
	struct {
		int width;
		int height;
		byte *chr;
	} _chars[256];

public:

	SmushFont(bool use_original_colors, bool new_colors);
	~SmushFont();

protected:

	int getCharWidth(byte c);
	int getStringWidth(char *str);
	int getCharHeight(byte c);
	int getStringHeight(char *str);
	int drawChar(byte *buffer, int dst_width, int x, int y, byte chr);
	void drawSubstring(char *str, byte *buffer, int dst_width, int x, int y);
	void decodeCodec(byte *dst, byte *src, int length);

public:

	bool loadFont(const char *filename, const char *directory);
	void setColor(byte c) { _color = c; }
	void drawStringCentered(char *str, byte *buffer, int dst_width, int dst_height, int y, int xmin, int width, int offset);
	void drawStringWrap(char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int width);
	void drawStringWrapCentered(char *str, byte *buffer, int dst_width, int dst_height, int x, int32 y, int width);
	void drawStringAbsolute(char *str, byte *buffer, int dst_width, int x, int y);
};

#endif

--- NEW FILE: smush_mixer.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2002-2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/smush/smush_mixer.cpp,v 1.1 2003/03/17 12:28:50 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "common/util.h"
#include "smush_mixer.h"
#include "channel.h"
#include "sound/mixer.h"
#include "scumm/scumm.h"
#include "scumm/sound.h"
#include "scumm/imuse.h"

SmushMixer::SmushMixer(SoundMixer *m) :
	_mixer(m),
	_soundFrequency(22050),
	_nextIndex(_mixer->_beginSlots)	{
	for(int32 i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
		_channels[i].id = -1;
		_channels[i].chan = NULL;
		_channels[i].first = true;
	}
}

SmushMixer::~SmushMixer() {
}

SmushChannel *SmushMixer::findChannel(int32 track) {
	debug(9, "SmushMixer::findChannel(%d)", track);
	for(int32 i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
		if(_channels[i].id == track)
			return _channels[i].chan;
	}
	return NULL;
}

bool SmushMixer::addChannel(SmushChannel *c) {
	int32 track = c->getTrackIdentifier();
	int i;

	debug(9, "SmushMixer::addChannel(%d)", track);

	for(i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
		if(_channels[i].id == track)
			warning("SmushMixer::addChannel(%d) : channel already exist !", track);
	}
	if(_nextIndex >= SoundMixer::NUM_CHANNELS)
		_nextIndex = _mixer->_beginSlots;

	for(i = _nextIndex; i < SoundMixer::NUM_CHANNELS; i++) {
		if(_channels[i].chan == NULL || _channels[i].id == -1) {
			_channels[i].chan = c;
			_channels[i].id = track;
			_channels[i].first = true;
			_nextIndex = i + 1;
			return true;
		}
	}

	for(i = _mixer->_beginSlots; i < _nextIndex; i++) {
		if(_channels[i].chan == NULL || _channels[i].id == -1)	{
			_channels[i].chan = c;
			_channels[i].id = track;
			_channels[i].first = true;
			_nextIndex = i + 1;
			return true;
		}
	}

	warning("_nextIndex == %d\n", _nextIndex);

	for(i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
		warning("channel %d : %p(%d, %d) %d %d\n", i, (void *)_channels[i].chan, 
			_channels[i].chan ? _channels[i].chan->getTrackIdentifier() : -1, 
			_channels[i].chan ? _channels[i].chan->isTerminated() : 1, 
			_channels[i].first, _channels[i].mixer_index);
	}

	error("SmushMixer::add_channel() : no more channel available");
	return false;
}

bool SmushMixer::handleFrame() {
	debug(9, "SmushMixer::handleFrame()");
	for(int i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
		if(_channels[i].id != -1) {
			if(_channels[i].chan->isTerminated()) {
				delete _channels[i].chan;
				_channels[i].id = -1;
				_channels[i].chan = NULL;
			} else {
				int32 rate;
				bool stereo, is_short;

				_channels[i].chan->getParameters(rate, stereo, is_short);
				int32 size = _channels[i].chan->availableSoundData();
				int32 flags = stereo ? SoundMixer::FLAG_STEREO : 0;

				if(is_short) {
					short *data = new int16[size * (stereo ? 2 : 1) * 2];
					_channels[i].chan->getSoundData(data, size);
					if(_channels[i].chan->getRate() == 11025) size *= 2;
					size *= stereo ? 4 : 2;

					if(_silentMixer == false) {
						if(_channels[i].first) {
							_channels[i].mixer_index = _mixer->playStream(NULL, -1, data, size, rate, flags | SoundMixer::FLAG_16BITS);
							_channels[i].first = false;
						} else {
							_mixer->append(_channels[i].mixer_index, data, size, rate, flags | SoundMixer::FLAG_16BITS);
						}
					}

					delete []data;
				} else {
					int8 *data = new int8[size * (stereo ? 2 : 1) * 2];
					_channels[i].chan->getSoundData(data, size);
					if(_channels[i].chan->getRate() == 11025) size *= 2;
					size *= stereo ? 2 : 1;

					if(_silentMixer == false) {
						if(_channels[i].first) {
							_channels[i].mixer_index = _mixer->playStream(NULL, -1, data, size, rate, flags | SoundMixer::FLAG_UNSIGNED);
							_channels[i].first = false;
						} else {
							_mixer->append(_channels[i].mixer_index, data, size, rate, flags | SoundMixer::FLAG_UNSIGNED);
						}
					}

					delete []data;
				}
			}
		}
	}
	return true;
}

bool SmushMixer::stop() {
	debug(9, "SmushMixer::stop()");
	for(int i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
		if(_channels[i].id != -1) {
			delete _channels[i].chan;
			_channels[i].id = -1;
			_channels[i].chan = NULL;
		}
	}
	return true;
}


--- NEW FILE: smush_mixer.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2002-2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/smush/smush_mixer.h,v 1.1 2003/03/17 12:28:50 aquadran Exp $
 *
 */

#include <stdafx.h>

#include "sound/mixer.h"

class SmushChannel;

class SmushMixer {
private:

	SoundMixer *_mixer;
	struct {
		int id;
		SmushChannel *chan;
		bool first;
		int mixer_index;
	} _channels[SoundMixer::NUM_CHANNELS];

	int _nextIndex;
	int _soundFrequency;

public:

	SmushMixer(SoundMixer *);
	virtual ~SmushMixer();
	SmushChannel *findChannel(int32 track);
	bool addChannel(SmushChannel *c);
	bool handleFrame();
	bool stop();
	bool update();
	bool _silentMixer;
};

--- NEW FILE: smush_player.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2002-2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/smush/smush_player.cpp,v 1.1 2003/03/17 12:28:50 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "common/file.h"
#include "common/util.h"
#include "common/engine.h"
#include "scumm/scumm.h"
#include "scumm/sound.h"
#include "scumm/imuse.h"
#include "sound/mixer.h"
#include "smush_player.h"
#include "smush_mixer.h"
#include "smush_font.h"
#include "channel.h"
#include "chunk.h"
#include "chunk_type.h"

const int MAX_STRINGS = 200;

class StringResource {
private:

	struct {
		int id;
		char *string;
	} _strings[MAX_STRINGS];

	int _nbStrings;
	int _lastId;
	char *_lastString;

public:

	StringResource() :
		_nbStrings(0),
		_lastId(-1) {
	};
	~StringResource() {
		for(int32 i = 0; i < _nbStrings; i++) {
			delete []_strings[i].string;
		}
	}

	bool init(char *buffer, int32 length) {
		char *def_start = strchr(buffer, '#');
		while(def_start != NULL) {
			char *def_end = strchr(def_start, '\n');
			assert(def_end != NULL);

			char *id_end = def_end;
			while(id_end >= def_start && !isdigit(*(id_end-1))) { 
				id_end--;
			}

			assert(id_end > def_start);
			char *id_start = id_end;
			while(isdigit(*(id_start - 1))) {
				id_start--;
			}

			char idstring[32];
			memcpy(idstring, id_start, id_end - id_start);
			idstring[id_end - id_start] = 0;
			int32 id = atoi(idstring);
			char *data_start = def_end;

			while(*data_start == '\n' || *data_start == '\r') {
				data_start++;
			}
			char *data_end = data_start;

			while(1) {
				if(data_end[-2] == '\r' && data_end[1] == '\n' && data_end[-1] == '\n' && data_end[0] == '\r') {
					break;
				}
				data_end++;
				if(data_end >= buffer + length) {
					data_end = buffer + length;
					break;
				}
			}

			data_end -= 2;
			assert(data_end > data_start);
			char *value = new char[data_end - data_start + 1];
			assert(value);
			memcpy(value, data_start, data_end - data_start);
			value[data_end - data_start] = 0;
			char *line_start = value;
			char *line_end;

			while ((line_end = strchr(line_start, '\n'))) {
				line_start = line_end+1;
				if (line_start[0] == '/' && line_start[1] == '/') {
					line_start += 2;
					if	(line_end[-1] == '\r')
						line_end[-1] = ' ';
					else
						*line_end++ = ' ';
					memmove(line_end, line_start, strlen(line_start)+1);
				}
			}
			_strings[_nbStrings].id = id;
			_strings[_nbStrings].string = value;
			_nbStrings ++;
			def_start = strchr(data_end + 2, '#');
		}
		return true;
	}

	char *get(int id) {
		if(id == _lastId) {
			return _lastString;
		}
		for(int i = 0; i < _nbStrings; i++) {
			if(_strings[i].id == id) {
				_lastId = id;
				_lastString = _strings[i].string;
				return _strings[i].string;
			}
		}
		warning("invalid string id : %d", id);
		_lastId = -1;
		_lastString = "unknown string";
		return _lastString;
	}
};

static StringResource *getStrings(const char *file, const char *directory, bool is_encoded) {
	debug(7, "trying to read text ressources from %s", file);
	File theFile;

	theFile.open(file, directory);
	if (!theFile.isOpen()) {
		return 0;
	}
	int32 length = theFile.size();
	char *filebuffer = new char [length + 1];
	assert(filebuffer);
	theFile.read(filebuffer, length);
	filebuffer[length] = 0;

	if(is_encoded) {
		static const int32 ETRS_HEADER_LENGTH = 16;
		assert(length > ETRS_HEADER_LENGTH);
		Chunk::type type = READ_BE_UINT32(filebuffer);

		if(type != TYPE_ETRS) {
			delete [] filebuffer;
			return getStrings(file, directory, false);
		}

		char *old = filebuffer;
		filebuffer = new char[length - ETRS_HEADER_LENGTH + 1];
		for(int32 i = ETRS_HEADER_LENGTH; i < length; i++) {
			filebuffer[i - ETRS_HEADER_LENGTH] = old[i] ^ 0xCC;
		}
		filebuffer[length - ETRS_HEADER_LENGTH] = '\0';
		delete []old;
		length -= ETRS_HEADER_LENGTH;
	}
	StringResource *sr = new StringResource;
	assert(sr);
	sr->init(filebuffer, length);
	delete []filebuffer;
	return sr;
}

SmushPlayer *player;

void smush_callback(void *ptr) {
	player->_smushProcessFrame = true;
	player->parseNextFrame();
	player->_smushProcessFrame = false;
}

SmushPlayer::SmushPlayer(Scumm *scumm, int speed, bool subtitles) {
	player = this;
	_version = -1;
	_nbframes = 0;
	_smixer = 0;
	_strings = NULL;
	_skipNext = false;
	_data = NULL;
	_storeFrame = false;
	_width = 0;
	_height = 0;
	_frameBuffer = NULL;
	_sf[0] = NULL;
	_sf[1] = NULL;
	_sf[2] = NULL;
	_sf[3] = NULL;
	_sf[4] = NULL;
	_scumm = scumm;
	_IACTchannel = -1,
	_IACTpos = 0;
	_soundFrequency = 22050;
	_speed = speed;
	_subtitles = subtitles;
	_smushProcessFrame = false;
}

SmushPlayer::~SmushPlayer() {
	deinit();
}

void SmushPlayer::init() {

	_frame = 0;

	_scumm->_sound->pauseBundleMusic(true);
	if (_scumm->_imuseDigital) {
		_scumm->_imuseDigital->pause(true);
	}
	_scumm->_videoFinished = false;
	_scumm->_insaneState = true;

	_smixer = new SmushMixer(_scumm->_mixer);

	_scumm->setDirtyColors(0, 255);
	_smixer->_silentMixer = _scumm->_silentDigitalImuse;
	_scumm->_smushPlay = true;
	_data = _scumm->virtscr[0].screenPtr + _scumm->virtscr[0].xstart;
	_scumm->_timer->installProcedure(&smush_callback, _speed);

	_alreadyInit = false;
}

void SmushPlayer::deinit() {
	_scumm->_smushPlay = false;
	_scumm->_timer->releaseProcedure(&smush_callback);
	while (_smushProcessFrame) {}

	for(int i = 0; i < 5; i++) {
		if (_sf[i]) {
			delete _sf[i];
			_sf[i] = NULL;
		}
	}

	if(_strings) {
		delete _strings;
		_strings = NULL;
	}

	if(_smixer) {
		_smixer->stop();
		delete _smixer;
		_smixer = NULL;
	}

	_scumm->_insaneState = false;
	_scumm->exitCutscene();
	if (_scumm->_imuseDigital) {
		_scumm->_imuseDigital->pause(false);
	}
	_scumm->_sound->pauseBundleMusic(false);
	_scumm->_fullRedraw = 1;
}

void SmushPlayer::checkBlock(const Chunk &b, Chunk::type type_expected, uint32 min_size) {
	if(type_expected != b.getType()) {
		error("Chunk type is different from expected : %d != %d", b.getType(), type_expected);
	}
	if(min_size > b.getSize()) {
		error("Chunk size is inferior than minimum required size : %d < %d", b.getSize(), min_size);
	}
}

void SmushPlayer::handleSoundBuffer(int32 track_id, int32 index, int32 max_frames, int32 flags, int32 vol, int32 bal, Chunk &b, int32 size) {
	debug(6, "SmushPlayer::handleSoundBuffer(%d)", track_id);
//	if((flags & 128) == 128) {
//		return;
//	}
//	if((flags & 64) == 64) {
//		return;
//	}
	SmushChannel *c = _smixer->findChannel(track_id);
	if(c == NULL) {
		c = new SaudChannel(track_id, _soundFrequency);
		_smixer->addChannel(c);
	}
	if(index == 0) {
		c->setParameters(max_frames, flags, vol, bal);
	}	else {
		c->checkParameters(index, max_frames, flags, vol, bal);
	}
	c->appendData(b, size);
}

void SmushPlayer::handleSoundFrame(Chunk &b) {
	checkBlock(b, TYPE_PSAD);
	debug(6, "SmushPlayer::handleSoundFrame()");

	int32 track_id = b.getWord();
	int32 index = b.getWord();
	int32 max_frames = b.getWord();
	int32 flags = b.getWord();
	int32 vol = b.getByte();
	int32 bal = b.getChar();
#ifdef DEBUG
	if(index == 0) {
		debug(5, "track_id == %d, max_frames == %d, %d, %d, %d", track_id, max_frames, flags, vol, bal);
	}
#endif
	int32 size = b.getSize() - 10;
	handleSoundBuffer(track_id, index, max_frames, flags, vol, bal, b, size);
}

void SmushPlayer::handleSkip(Chunk &b) {
	checkBlock(b, TYPE_SKIP, 4);
	int32 code = b.getDword();
	debug(6, "SmushPlayer::handleSkip(%d)", code);
	if(code >= 0 && code < 37)
		_skipNext = _skips[code];
	else
		_skipNext = true;
}

void SmushPlayer::handleStore(Chunk &b) {
	debug(6, "SmushPlayer::handleStore()");
	checkBlock(b, TYPE_STOR, 4);
	_storeFrame = true;
}

void SmushPlayer::handleFetch(Chunk &b) {
	debug(6, "SmushPlayer::handleFetch()");
	checkBlock(b, TYPE_FTCH, 6);

	if (_frameBuffer != NULL) {
		memcpy(_data, _frameBuffer, _width * _height);
	}
}

void SmushPlayer::handleImuseBuffer(int32 track_id, int32 index, int32 nbframes, int32 size, int32 unk1, int32 track_flags, Chunk &b, int32 bsize) {
	int32 track = (track_flags << 16) | track_id;

	SmushChannel *c = _smixer->findChannel(track);
	if(c == 0) {
		c = new ImuseChannel(track, _soundFrequency);
		_smixer->addChannel(c);
	}
	if(index == 0)
		c->setParameters(nbframes, size, track_flags, unk1);
	else
		c->checkParameters(index, nbframes, size, track_flags, unk1);
	c->appendData(b, bsize);
}

void SmushPlayer::handleImuseAction(Chunk &b) {
	checkBlock(b, TYPE_IACT, 8);
	debug(6, "SmushPlayer::handleImuseAction()");

	int code = b.getWord();
	int flags = b.getWord();
	int unknown = b.getShort();
	int track_flags = b.getWord();

	assert(flags == 46 && unknown == 0);
	int track_id = b.getWord();
	int index = b.getWord();
	int nbframes = b.getWord();
	int32 size = b.getDword();
	int32 bsize = b.getSize() - 18;

	if (g_scumm->_gameId != GID_CMI) {
		handleImuseBuffer(track_id, index, nbframes, size, unknown, track_flags, b, bsize);
	} else {
		byte output_data[4096];
		byte *src = (byte *)malloc(bsize);
		b.read(src, bsize);
		byte *d_src = src;
		byte value;

		do {
			if (bsize == 0)
				break;
			if (_IACTpos >= 2) {
				int32 len = READ_BE_UINT16(_IACToutput) + 2;
				len -= _IACTpos;
				if (len > bsize) {
					memcpy(_IACToutput + _IACTpos, d_src, bsize);
					_IACTpos += bsize;
					bsize = 0;
				} else {
					memcpy(_IACToutput + _IACTpos, d_src, len);
					byte *dst = output_data;
					byte *d_src2 = _IACToutput;
					d_src2 += 2;
					int32 count = 1024;
					byte variable1 = *d_src2++;
					byte variable2 = variable1 >> 4;
					variable1 &= 0x0f;
					do {
						value = *(d_src2++);
						if (value == 0x80) {
							*dst++ = *d_src2++;
							*dst++ = *d_src2++;
						} else {
							int16 val = (int8)value << variable2;
							*dst++ = val>> 8;
							*dst++ = (byte)(val);
						}
						value = *(d_src2++);
						if (value == 0x80) {
							*dst++ = *d_src2++;
							*dst++ = *d_src2++;
						} else {
							int16 val = (int8)value << variable1;
							*dst++ = val>> 8;
							*dst++ = (byte)(val);
						}
					} while (--count);

					if (_IACTchannel == -1) {
						_IACTchannel = _scumm->_mixer->playStream(NULL, -1, output_data, 0x1000, 22050,
															SoundMixer::FLAG_STEREO | SoundMixer::FLAG_16BITS, -1, 200000);
					} else {
						_scumm->_mixer->append(_IACTchannel, output_data, 0x1000, 22050,
															SoundMixer::FLAG_STEREO | SoundMixer::FLAG_16BITS);
					}

					bsize -= len;
					d_src += len;
					_IACTpos = 0;
				}
			} else {
				if (bsize == 1) {
					if (_IACTpos != 0) {
						*(_IACToutput + 1) = *d_src++;
						_IACTpos = 2;
						bsize--;
						continue;
					}
					bsize = 0;
					*(_IACToutput + 0) = *d_src;
					_IACTpos = 1;
					continue;
				} else if (_IACTpos == 0) {
					*(_IACToutput + 0) = *d_src++;
					bsize--;
				}
				*(_IACToutput + 1) = *d_src++;
				_IACTpos = 2;
				bsize--;
			}	
		} while (bsize != 0);
	
		free(src);
	}
}

void SmushPlayer::handleTextResource(Chunk &b) {
	int pos_x = b.getShort();
	int pos_y = b.getShort();
	int flags = b.getShort();
	int left = b.getShort();
	int top = b.getShort();
	int width = b.getShort();
	/*int32 height =*/ b.getShort();
	/*int32 unk2 =*/ b.getWord();

	char *str, *string = NULL, *string2 = NULL;
	if (b.getType() == TYPE_TEXT) {
		string = (char *)malloc(b.getSize() - 16);
		str = string;
		b.read(string, b.getSize() - 16);
	} else {
		int string_id = b.getWord();
		if(!_strings)
			return;
		str = _strings->get(string_id);
	}

	// if subtitles disabled and bit 3 is set, then do not draw
	if((!_subtitles) && ((flags & 8) == 8))
		return;

	SmushFont *sf = _sf[0];
	int color = 15;
	while(*str == '/') {
		str++; // For Full Throttle text resources
	}

	if (_scumm->_gameId == GID_CMI) {
		_scumm->translateText((byte*)str - 1, _scumm->_transText);
		while(*str++ != '/');
		string2 = (char *)_scumm->_transText;

		// If string2 contains formatting information there probably
		// wasn't any translation for it in the language.tab file. In
		// that case, pretend there is no string2.
		if (string2[0] == '^')
			string2[0] = 0;
	}

	while(str[0] == '^') {
		switch(str[1]) {
		case 'f':
			{
				int id = str[3] - '0';
				str += 4;
				sf = _sf[id]; 
			}
			break;
		case 'c':
			{
				color = str[4] - '0' + 10 *(str[3] - '0');
				str += 5;
			}
			break;
		default:
			error("invalid escape code in text string");
		}
	}

	assert(sf != NULL);
	sf->setColor(color);

	if (_scumm->_gameId != GID_CMI) {
		string2 = str;
	}
	if (_scumm->_gameId == GID_CMI) {
		if (string2[0] == 0) {
			string2 = str;
		}
	}

	// flags:
	// bit 0 - center				1
	// bit 1 - not used			2
	// bit 2 - ???					4
	// bit 3 - wrap around	8
	switch (flags) {
		case 0: 
			sf->drawStringAbsolute(string2, _data, _width, pos_x, pos_y);
			break;
		case 1:
			sf->drawStringCentered(string2, _data, _width, _height, MAX(pos_y, top), left, width, pos_x);
			break;
		case 4:
			sf->drawStringAbsolute(string2, _data, _width, pos_x, pos_y);
			break;
		case 5:
			sf->drawStringCentered(string2, _data, _width, _height, MAX(pos_y, top), left, width, pos_x);
			break;
		case 8:
			sf->drawStringWrap(string2, _data, _width, _height, pos_x, MAX(pos_y, top), width);
			break;
		case 9:
			sf->drawStringCentered(string2, _data, _width, _height, MAX(pos_y, top), left, width, pos_x);
			break;
		case 12:
			sf->drawStringWrap(string2, _data, _width, _height, pos_x, MAX(pos_y, top), width);
			break;
		case 13:
			sf->drawStringWrapCentered(string2, _data, _width, _height, pos_x, MAX(pos_y, top), width);
			break;
		default:
			warning("SmushPlayer::handleTextResource. Not handled flags: %d\n", flags);
	}

	if (string != NULL) {
		free (string);
	}
}

bool SmushPlayer::readString(const char *file, const char *directory) {
	const char *i = strrchr(file, '.');
	if(i == NULL) {
		error("invalid filename : %s", file);
	}
	char fname[260];
	memcpy(fname, file, i - file);
	strcpy(fname + (i - file), ".trs");
	if((_strings = getStrings(fname, directory, false)) != 0) {
		return true;
	}

	if((_strings = getStrings("digtxt.trs", directory, true)) != 0) {
		return true;
	}
	return false;
}

void SmushPlayer::readPalette(byte *out, Chunk &in) {
	in.read(out, 0x300);
}

static byte delta_color(byte org_color, int16 delta_color) {
	int16 t;
	t = (((int32)(org_color) << 7) + org_color + delta_color) >> 7;
	if (t > 255)
		t = 255;
	if (t < 0)
		t = 0;
	return (byte)t;
}

void SmushPlayer::handleDeltaPalette(Chunk &b) {
	checkBlock(b, TYPE_XPAL);
	debug(6, "SmushPlayer::handleDeltaPalette()");

	if(b.getSize() == 0x300 * 3 + 4) {

		b.getWord();
		b.getWord();

		for(int i = 0; i < 0x300; i++) {
			_deltaPal[i] = b.getWord();
		}
		readPalette(_pal, b);
		setPalette(_pal);
	} else if(b.getSize() == 6) {

		b.getWord();
		b.getWord();
		b.getWord();

		for(int i = 0; i < 0x300; i++) {
			_pal[i] = delta_color(_pal[i], _deltaPal[i]);
		}
		setPalette(_pal);
	} else {
		error("SmushPlayer::handleDeltaPalette() Wrong size for DeltaPalette");
	}
}

void SmushPlayer::handleNewPalette(Chunk &b) {
	checkBlock(b, TYPE_NPAL, 0x300);
	debug(6, "SmushPlayer::handleNewPalette()");

	readPalette(_pal, b);
	setPalette(_pal);
}

void SmushPlayer::initCodecs() {
}

extern void smush_decode_codec1(byte *dst, byte *src, int height);

void SmushPlayer::handleFrameObject(Chunk &b) {
	checkBlock(b, TYPE_FOBJ, 14);
	if(_skipNext) {
		_skipNext = false;
		return;
	}

	int codec = b.getWord();
	b.getWord(); // left
	b.getWord(); // top
	int width = b.getWord();
	int height = b.getWord();

	// hack for spontanic changing resolution
	// differ than width scumm screen, and pass only one width 384x242
	if((height != _scumm->_realHeight) && (height != 242))
		return;
	if (height == 242)
		return;
	if((width != _scumm->_realWidth) && (width != 384))
		return;
	if (width == 384)
		return;

	if(_alreadyInit == false) {
		_codec37.init(width, height);
		_codec47.init(width, height);
		_alreadyInit = true;
	}

	_width = width;
	_height = height;
	b.getWord();
	b.getWord();


	int32 chunk_size = b.getSize() - 14;
	byte *chunk_buffer = (byte *)malloc(chunk_size);
	assert(chunk_buffer);
	b.read(chunk_buffer, chunk_size);

	switch (codec) {
	case 1:
	case 3:
		smush_decode_codec1(_data, chunk_buffer, _height);
		break;
	case 37:
		_codec37.decode(_data, chunk_buffer);
		break;
	case 47:
		_codec47.decode(_data, chunk_buffer);
		break;
	default:
		error("Invalid codec for frame object : %d", (int)codec);
	}

	if (_storeFrame == true) {
		if (_frameBuffer == NULL) {
			_frameBuffer = (byte *)malloc(_width * _height);
		}
		memcpy(_frameBuffer, _data, _width * _height);
		_storeFrame = false;
	}

	free(chunk_buffer);
}

void SmushPlayer::handleFrame(Chunk &b) {
	checkBlock(b, TYPE_FRME);
	debug(6, "SmushPlayer::handleFrame(%d)", _frame);
	_skipNext = false;

	uint32 start_time, curr_time, start_update, end_update;
	start_time = _scumm->_system->get_msecs();

	while(!b.eof()) {
		Chunk *sub = b.subBlock();
		if(sub->getSize() & 1) b.seek(1);
		switch(sub->getType()) {
			case TYPE_NPAL:
				handleNewPalette(*sub);
				break;
			case TYPE_FOBJ:
				handleFrameObject(*sub);
				break;
			case TYPE_PSAD:
				handleSoundFrame(*sub);
				break;
			case TYPE_TRES:
				handleTextResource(*sub);
				break;
			case TYPE_XPAL:
				handleDeltaPalette(*sub);
				break;
			case TYPE_IACT:
				handleImuseAction(*sub);
				break;
			case TYPE_STOR:
				handleStore(*sub);
				break;
			case TYPE_FTCH:
				handleFetch(*sub);
				break;
			case TYPE_SKIP:
				handleSkip(*sub);
				break;
			case TYPE_TEXT:
				handleTextResource(*sub);
				break;
			default:
				error("Unknown frame subChunk found : %s, %d", Chunk::ChunkString(sub->getType()), sub->getSize());
		}
		delete sub;
	}

	curr_time = _scumm->_system->get_msecs();

	_smixer->handleFrame();

	start_update = _scumm->_system->get_msecs();
	if (curr_time < (start_time + _speed / 1000)) {
		updateScreen();
	} else {
		warning("SmushPlayer: skipping update frame %d", _frame);
	}
	end_update = _scumm->_system->get_msecs();
	debug(0, "Smush stats: FRME( %03d ),GFX_update( %03d ),FRME+GFX+SFX( %03d ),Limit(%d)",
		curr_time - start_time, end_update - start_update,
		end_update - start_time, _speed / 1000);

	_frame++;
}

void SmushPlayer::handleAnimHeader(Chunk &b) {
	checkBlock(b, TYPE_AHDR, 0x300 + 6);
	debug(6, "SmushPlayer::handleAnimHeader()");

	_version = b.getWord();
	_nbframes = b.getWord();
	b.getWord();
	readPalette(_pal, b);
	setPalette(_pal);
}

void SmushPlayer::setupAnim(const char *file, const char *directory) {
	_base = new FileChunk(file, directory);
	Chunk *sub = _base->subBlock();
	checkBlock(*sub, TYPE_AHDR);
	handleAnimHeader(*sub);

	readString(file, directory);

	if (_scumm->_gameId == GID_FT) {
		_sf[0] = new SmushFont(true, false);
		_sf[2] = new SmushFont(true, false);
		_sf[0]->loadFont("scummfnt.nut", directory);
		_sf[2]->loadFont("titlfnt.nut", directory);
	} else if (_scumm->_gameId == GID_DIG) {
		for(int i = 0; i < 4; i++) {
			char file_font[11];
			sprintf((char *)&file_font, "font%d.nut", i);
			_sf[i] = new SmushFont(i != 0, false);
			_sf[i]->loadFont(file_font, directory);
		}
	} else if (_scumm->_gameId == GID_CMI) {
		for(int i = 0; i < 5; i++) {
			char file_font[11];
			sprintf((char *)&file_font, "font%d.nut", i);
			_sf[i] = new SmushFont(false, true);
			_sf[i]->loadFont(file_font, directory);
		}
	} else {
		error("SmushPlayer::init() Unknown font setup for game");
	}	

	delete sub;
}

void SmushPlayer::parseNextFrame() {
	if (_scumm->_smushPlay == false)
		return;

	Chunk *sub = _base->subBlock();
	if (_base->eof()) {
		_scumm->_videoFinished = true;
		return;
	}

	switch(sub->getType()) {
		case TYPE_FRME:
			handleFrame(*sub);
			break;
		default:
			error("Unknown Chunk found : %d, %d", sub->getType(), sub->getSize());
	}
	delete sub;
}

void SmushPlayer::setPalette(byte *palette) {
	byte palette_colors[1024];
	byte *p = palette_colors;
	byte *data = palette;

	for (int i = 0; i != 256; i++, data += 3, p += 4) {
		p[0] = data[0]; // red
		p[1] = data[1]; // green
		p[2] = data[2]; // blue
		p[3] = 0;
	}

	_scumm->_system->set_palette(palette_colors, 0, 256);
}

void SmushPlayer::updateScreen() {
	int width = MIN(_width, _scumm->_realWidth);
	int height = MIN(_height, _scumm->_realHeight);

	_scumm->parseEvents();
	_scumm->_system->copy_rect(_data, _width, 0, 0, width, height);
	_scumm->_system->update_screen();
}

void SmushPlayer::play(const char *filename, const char *directory) {
	setupAnim(filename, directory);
	init();

	while (true) {
		_scumm->processKbd();
		_scumm->_system->delay_msecs(10);
		if (_scumm->_videoFinished == true)
			break;
		if (_scumm->_saveLoadFlag)
			break;
	};

	deinit();
}

--- NEW FILE: smush_player.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2002-2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/smush/smush_player.h,v 1.1 2003/03/17 12:28:50 aquadran Exp $
 *
 */

#ifndef SMUSH_PLAYER_H
#define SMUSH_PLAYER_H

#include "common/util.h"
#include "chunk.h"
#include "codec37.h"
#include "codec47.h"

class SmushFont;
class SmushMixer;
class StringResource;

class SmushPlayer {
private:

	Scumm *_scumm;
	int _version;
	int32 _nbframes;
	SmushMixer *_smixer;
	int16 _deltaPal[0x300];
	byte _pal[0x300];
	StringResource *_strings;
	SmushFont *_sf[5];
	Codec37Decoder _codec37;
	Codec47Decoder _codec47;
	int dst_width, dst_height;
	FileChunk *_base;
	byte *_frameBuffer;

	bool _codec37Called;
	bool _skipNext;
	bool _subtitles;
	bool _skips[37];
	int32 _frame;

	int _IACTchannel;
	byte _IACToutput[4096];
	int32 _IACTpos;
	bool _storeFrame;
	int _soundFrequency;
	bool _alreadyInit;
	int _speed;
	bool _outputSound;

public:

	int _width, _height;
	byte *_data;
	bool _smushProcessFrame;

	SmushPlayer(Scumm *, int, bool);
	~SmushPlayer();
	void updatePalette(void);
	void parseNextFrame();
	void init();
	void deinit();
	void setupAnim(const char *file, const char *directory);
	void initCodecs();
	void updateScreen();
	void play(const char *filename, const char *directory);
	void setPalette(byte *palette);

protected:

	bool readString(const char *file, const char *directory);
	void clean();
	void checkBlock(const Chunk &, Chunk::type, uint32 = 0);
	void handleAnimHeader(Chunk &);
	void handleFrame(Chunk &);
	void handleNewPalette(Chunk &);
	void handleFrameObject(Chunk &);
	void handleSoundBuffer(int32, int32, int32, int32, int32, int32, Chunk &, int32);
	void handleImuseBuffer(int32, int32, int32, int32, int32, int32, Chunk &, int32);
	void handleSoundFrame(Chunk &);
	void handleSkip(Chunk &);
	void handleStore(Chunk &);
	void handleFetch(Chunk &);
	void handleImuseAction(Chunk &);
	void handleTextResource(Chunk &);
	void handleDeltaPalette(Chunk &);
	void readPalette(byte *, Chunk &);
};

#endif

Index: channel.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/channel.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- channel.h	6 Mar 2003 21:46:35 -0000	1.9
+++ channel.h	17 Mar 2003 12:28:49 -0000	1.10
@@ -19,63 +19,47 @@
  *
  */
 
-#ifndef CHANNEL_H
-#define CHANNEL_H
-
-#include "config.h"
-#include "common/engine.h" // for debug, warning, error
+#ifndef SMUSH_CHANNEL_H
+#define SMUSH_CHANNEL_H
 
-#ifdef DEBUG
-# ifndef NO_DEBUG_CHANNEL
-#  define DEBUG_CHANNEL
-# endif
-#else
-# ifdef DEBUG_CHANNEL
-#  error DEBUG_CHANNEL defined without DEBUG
-# endif
-#endif
+#include "common/engine.h"
 
 class Chunk;
 class ContChunk;
 	
-/*! 	@brief int32erface for a sound channel (a track)
-
-	This is the int32erface for sound channels. 
-*/
-class _Channel {
+class SmushChannel {
 public:
-	virtual ~_Channel() {};
-	// called by the smush_player
+
+	virtual ~SmushChannel() {};
 	virtual bool appendData(Chunk &b, int32 size) = 0;
 	virtual bool setParameters(int32, int32, int32, int32) = 0;
 	virtual bool checkParameters(int32, int32, int32, int32, int32) = 0;
-	// called by the mixer
 	virtual bool isTerminated() const = 0;
 	virtual int32 availableSoundData() const = 0;
-	virtual void getSoundData(int16 *sound_buffer, int32 size) = 0; // size is in sample 
+	virtual void getSoundData(int16 *sound_buffer, int32 size) = 0;
 	virtual void getSoundData(int8 *sound_buffer, int32 size) = 0;
 	virtual int32 getRate() = 0;
 	virtual bool getParameters(int32 &rate, bool &stereo, bool &is_16bit) = 0;
 	virtual int32 getTrackIdentifier() const = 0;
 };
 
-class SaudChannel : public _Channel {
+class SaudChannel : public SmushChannel {
 private:
-	int32 _track;				//!< The track identifier
-	int32 _nbframes;			//!< number of frames of the track (unused)
-	int32 _dataSize;			//!< the size of the sound buffer
-	int32 _frequency;			//!< the frequency target of the track (always 22050)
-	bool _inData;			//!< are we processing data ?
-	bool _markReached;		//!< set to \c true when the SMRK tag is reached
-	int32 _flags;				//!< current flags of the track (unused)
-	int32 _volume;			//!< the current track volume
-	int32 _balance;			//!< the current track balance
-	int32 _index;				//!< the current PSAD index (for coherency checking)
-	int16 _voltable[2][256];	//!< the precalculated volume table (stereo 16 bits)
-	byte *_tbuffer;	//!< data temporary buffer
-	int32 _tbufferSize;			//!< temporary buffer size
-	byte *_sbuffer;	//!< sound buffer
-	int32 _sbufferSize;			//!< sound buffer size
+	int32 _track;
+	int32 _nbframes;
+	int32 _dataSize;
+	int32 _frequency;
+	bool _inData;
+	bool _markReached;
+	int32 _flags;
+	int32 _volume;
+	int32 _balance;
+	int32 _index;
+	int16 _voltable[2][256];
+	byte *_tbuffer;
+	int32 _tbufferSize;
+	byte *_sbuffer;
+	int32 _sbufferSize;
 
 protected:
 	void handleStrk(Chunk &c);
@@ -105,13 +89,7 @@
 	virtual int32 getTrackIdentifier() const { return _track; };
 };
 
-/*! 	@brief class for a IACT sound ::channel (a The Dig track)
-
-	This class implements a channel specifically for The Dig.
-
-	\bug for unknown reason, some sound have a too long duration, or repeat themselves.
-*/
-class ImuseChannel : public _Channel {
+class ImuseChannel : public SmushChannel {
 private:
 	int32 _track;				//!< the track number
 	byte *_tbuffer;	//!< data temporary buffer

Index: chunk.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/chunk.cpp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- chunk.cpp	6 Mar 2003 21:46:36 -0000	1.10
+++ chunk.cpp	17 Mar 2003 12:28:49 -0000	1.11
@@ -22,35 +22,34 @@
 #include <stdafx.h>
 #include "chunk.h"
 
-#include "common/engine.h" // for debug, warning, error
+#include "common/engine.h"
 #include "common/file.h"
 #include "common/str.h"
 
-#include <stdio.h> // for FILE, fopen, fclose, fseek and ftell
-#include <string.h> // for memcpy
-
-/*!	@brief very small and fast wrapper for a ifstream.
-
-	implements reference counting, so that ::file_Chunk does not leak memory !
-*/
 class FilePtr {
 	ScummVM::String _filename;
 	File _ifs;
 	int32 _refcount;
 	int32 _curPos;
 public:
-	FilePtr(const char *fname, const char *directory) : _filename(fname), _refcount(1), _curPos(0) {
-		debug(9, "FilePtr created for %s", fname);
-		_ifs.open(fname, directory);
-		if(_ifs.isOpen() == false) error("FilePtr unable to read file %s", fname);
-	}
+	FilePtr(const char *fname, const char *directory) :
+		_filename(fname),
+		_refcount(1),
+		_curPos(0) {
+			debug(9, "FilePtr created for %s", fname);
+			_ifs.open(fname, directory);
+			if(_ifs.isOpen() == false) error("FilePtr unable to read file %s", fname);
+		}
+
 	~FilePtr() {
 		debug(9, "FilePtr destroyed for %s", _filename.c_str());
 		_ifs.close();
 	}
+
 	int32 tell() {
 		return _curPos;
 	}
+
 	bool seek(int32 pos) {
 		if(pos != _curPos) {
 			_ifs.seek(pos, SEEK_SET);
@@ -58,14 +57,17 @@
 		}
 		return true;
 	}
+
 	bool read(void *ptr, int32 size) {
 		_ifs.read(ptr, size);
 		_curPos += size;
 		return true;
 	}
+
 	void incRef() {
 		_refcount++;
 	}
+
 	void decRef() {
 		if(--_refcount == 0)
 			delete this;
@@ -82,11 +84,16 @@
 	return data;
 }
 
-FileChunk::FileChunk() : _data(0), _type(0), _size(0), _curPos(0) {
+FileChunk::FileChunk() : 
+	_data(0),
+	_type(0),
+	_size(0),
+	_curPos(0) {
 }
 
 FileChunk::~FileChunk() {
-	if(_data) _data->decRef();
+	if(_data)
+		_data->decRef();
 }
 
 FileChunk::FileChunk(const char *fname, const char *directory) {
@@ -137,11 +144,15 @@
 			_curPos += delta;
 			break;
 		case seek_start:
-			if(delta < 0) error("invalid seek request");
+			if(delta < 0)
+				error("invalid seek request");
+
 			_curPos = (uint32)delta;
 			break;
 		case seek_end:
-			if(delta > 0 || (_size + delta) < 0) error("invalid seek request");
+			if(delta > 0 || (_size + delta) < 0)
+				error("invalid seek request");
+
 			_curPos = (uint32)(_size + delta);
 			break;
 	}
@@ -154,6 +165,7 @@
 bool FileChunk::read(void *buffer, uint32 size) {
 	if(size <= 0 || (_curPos + size) > _size)
 		error("invalid buffer read request");
+
 	_data->seek(_offset + _curPos);
 	_data->read(buffer, size);
 	_curPos += size;
@@ -163,6 +175,7 @@
 int8 FileChunk::getChar() {
 	if(_curPos >= _size)
 		error("invalid char read request");
+
 	_data->seek(_offset + _curPos);
 	int8 buffer;
 	_data->read(&buffer, sizeof(buffer));
@@ -173,6 +186,7 @@
 byte FileChunk::getByte() {
 	if(_curPos >= _size)
 		error("invalid byte read request");
+
 	_data->seek(_offset + _curPos);
 	byte buffer;
 	_data->read(&buffer, sizeof(buffer));
@@ -188,6 +202,7 @@
 uint16 FileChunk::getWord() {
 	if(_curPos >= _size - 1)
 		error("invalid word read request");
+
 	_data->seek(_offset + _curPos);
 	uint16 buffer;
 	_data->read(&buffer, sizeof(buffer));
@@ -198,6 +213,7 @@
 uint32 FileChunk::getDword() {
 	if(_curPos >= _size - 3)
 		error("invalid dword read request");
+
 	_data->seek(_offset + _curPos);
 	uint32 buffer;
 	_data->read(&buffer, sizeof(buffer));
@@ -207,7 +223,8 @@
 
 ContChunk::ContChunk(byte *data) {
 	if(data == 0)
-		error("Chunk() called with NULL point32er");
+		error("Chunk() called with NULL pointer");
+
 	_type = (Chunk::type)READ_BE_UINT32(data);
 	_size = READ_BE_UINT32(data + 4);
 	_data = data + sizeof(Chunk::type) + sizeof(uint32);
@@ -257,39 +274,51 @@
 }
 
 bool ContChunk::read(void *buffer, uint32 size) {
-	if(size <= 0 || (_curPos + size) > _size) error("invalid buffer read request");
+	if(size <= 0 || (_curPos + size) > _size)
+		error("invalid buffer read request");
+
 	memcpy(buffer, _data + _curPos, size);
 	_curPos += size;
 	return true;
 }
 
 int8 ContChunk::getChar() {
-	if(_curPos >= _size) error("invalid char read request");
+	if(_curPos >= _size)
+		error("invalid char read request");
+
 	return _data[_curPos++];
 }
 
 byte ContChunk::getByte() {
-	if(_curPos >= _size) error("invalid byte read request");
+	if(_curPos >= _size)
+		error("invalid byte read request");
+
 	byte *ptr = (byte *)(_data + _curPos);
 	_curPos += 1;
 	return *ptr;
 }
 
 int16 ContChunk::getShort() {
-	if(_curPos >= _size - 1) error("invalid int16 read request");
+	if(_curPos >= _size - 1)
+		error("invalid int16 read request");
+
 	int16 buffer = getWord();
 	return *((int16 *)&buffer);
 }
 
 uint16 ContChunk::getWord() {
-	if(_curPos >= _size - 1) error("invalid word read request");
+	if(_curPos >= _size - 1)
+		error("invalid word read request");
+
 	uint16 *ptr = (uint16 *)(_data + _curPos);
 	_curPos += 2;
 	return READ_LE_UINT16(ptr);
 }
 
 uint32 ContChunk::getDword() {
-	if(_curPos >= _size - 3) error("invalid dword read request");
+	if(_curPos >= _size - 3)
+		error("invalid dword read request");
+
 	uint32 *ptr = (uint32 *)(_data + _curPos);
 	_curPos += 4;
 	return READ_LE_UINT32(ptr);

Index: chunk.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/chunk.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- chunk.h	6 Mar 2003 21:46:37 -0000	1.7
+++ chunk.h	17 Mar 2003 12:28:49 -0000	1.8
@@ -22,69 +22,54 @@
 #ifndef CHUNK_H
 #define CHUNK_H
 
-#include "config.h"
-
-/*! 	@brief Interface for Chunk handling
-
-	This class is an interface for reading from a Chunk.
+#include "common/scummsys.h"
 
-	\todo handle big endian system.
-*/
 class Chunk {
 public:
-	enum seek_type { seek_start, seek_end, seek_cur };
-	virtual ~Chunk() {};
-	typedef uint32 type;			//!< type of a Chunk (i.e. The first 4byte field of the Chunk structure).
-	/*!	@brief convert a type to a string
-		
-		Utility function that convert a type to a string.
-		
-		@param t the type to convert to a string
-		
-		@return the converted string
-	*/
-	static const char * ChunkString(type t);
 
-	virtual type getType() const = 0;	//!< return the type of the Chunk
-	virtual uint32 getSize() const = 0;	//!< return the size of the Chunk
-	virtual Chunk * subBlock() = 0; //!< extract a subChunk from the current read position
-	virtual bool eof() const = 0;	//!< is the Chunk completely read ?
-	virtual uint32 tell() const = 0;	//!< get the Chunk current read position
-	virtual bool seek(int32 delta, seek_type dir = seek_cur) = 0;	//!< move the current read position inside the Chunk
-	virtual bool read(void * buffer, uint32 size) = 0;		//!< read some data for the current read position
-	virtual int8 getChar() = 0;							//!< extract the character at the current read position
-	virtual byte getByte() = 0;					//!< extract the byte at the current read position
-	virtual int16 getShort() = 0;						//!< extract the short at the current read position
-	virtual uint16 getWord() = 0;					//!< extract the word at the current read position
-	virtual uint32 getDword()= 0;					//!< extract the dword at the current read position
+	virtual ~Chunk() {};
+	enum seek_type { seek_start, seek_end, seek_cur };
+	typedef uint32 type;
+	static const char *ChunkString(type t);
+	virtual type getType() const = 0;
+	virtual uint32 getSize() const = 0;
+	virtual Chunk *subBlock() = 0;
+	virtual bool eof() const = 0;
+	virtual uint32 tell() const = 0;
+	virtual bool seek(int32 delta, seek_type dir = seek_cur) = 0;
+	virtual bool read(void *buffer, uint32 size) = 0;
+	virtual int8 getChar() = 0;
+	virtual byte getByte() = 0;
+	virtual int16 getShort() = 0;
+	virtual uint16 getWord() = 0;
+	virtual uint32 getDword()= 0;
 };
 
 class FilePtr;
 
-/*! 	@brief file based ::Chunk
-
-	This class is an implementation of ::Chunk that handles file.
-
-*/
 class FileChunk : public Chunk {
 private:
-	FilePtr * _data;
+	FilePtr *_data;
 	type _type;
 	uint32 _size;
 	uint32 _offset;
 	uint32 _curPos;
+
 protected:
+
 	FileChunk();
+
 public:
-	FileChunk(const char * fname, const char * directory);
+
+	FileChunk(const char *fname, const char *directory);
 	virtual ~FileChunk();
 	type getType() const;
 	uint32 getSize() const;
-	Chunk * subBlock();
+	Chunk *subBlock();
 	bool eof() const;
 	uint32 tell() const;
 	bool seek(int32 delta, seek_type dir = seek_cur);
-	bool read(void * buffer, uint32 size);
+	bool read(void *buffer, uint32 size);
 	int8 getChar();
 	byte getByte();
 	short getShort();
@@ -92,17 +77,16 @@
 	uint32 getDword();
 };
 
-/*! 	@brief memory based ::Chunk
-
-	This class is an implementation of ::Chunk that handles a memory buffer.
-*/
 class ContChunk : public Chunk {
 private:
+
 	byte *_data;
 	Chunk::type _type;
 	uint32 _size;
 	uint32 _curPos;
+
 public:
+
 	ContChunk(byte *data);
 	Chunk::type getType() const;
 	uint32 getSize() const;

Index: codec1.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/codec1.cpp,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- codec1.cpp	13 Mar 2003 01:24:02 -0000	1.8
+++ codec1.cpp	17 Mar 2003 12:28:49 -0000	1.9
@@ -20,44 +20,28 @@
  */
 
 #include <stdafx.h>
-#include "codec1.h"
-
-Codec1Decoder::~Codec1Decoder() {
-}
+#include "common/scummsys.h"
 
-bool Codec1Decoder::decode(byte *dst, const byte *src, int) {
-	byte val;
-	int32 size_line;
-	int32 code, length;
-	int32 h, height = getRect().height();
+void smush_decode_codec1(byte *dst, byte *src, int height) {
+	byte val, code;
+	int32 length;
+	int h = height, size_line;
 
 	for(h = 0; h < height; h++) {
-		size_line = READ_LE_UINT16(src); // size of compressed line !
+		size_line = READ_LE_UINT16(src);
 		src += 2;
-#ifdef DEBUG_CODEC1
-		debug(7, "codec1 : h == %d, size_line == %d", h, size_line);
-#endif
 		while(size_line > 0) {
 			code = *src++;
 			size_line--;
 			length = (code >> 1) + 1;
-#ifdef DEBUG_CODEC1
-			debug(7, "codec1 : length == %d", length);
-#endif
 			if(code & 1) {
 				val = *src++;
 				size_line--;
 				if (val)
 					memset(dst, val, length);
 				dst += length;
-#ifdef DEBUG_CODEC1
-			debug(7, "codec1 : blitting %d times %d", length, val);
-#endif
 			} else {
 				size_line -= length;
-#ifdef DEBUG_CODEC1
-				debug(7, "codec1 : blitting %d entries", length);
-#endif
 				while(length--) {
 					val = *src++;
 					if (val)
@@ -67,5 +51,4 @@
 			}
 		}
 	}
-	return true;
 }

Index: codec37.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/codec37.cpp,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- codec37.cpp	13 Mar 2003 01:24:02 -0000	1.17
+++ codec37.cpp	17 Mar 2003 12:28:49 -0000	1.18
@@ -24,35 +24,24 @@
 
 #include "common/engine.h"
 
-#include <assert.h>
-#include <string.h>
-
-bool Codec37Decoder::initSize(const Point &p, const Rect &r) {
-	if(r.width() != getRect().width() && r.height() != getRect().height()) {
-		if(
-			(r.width() != 320 || r.height() != 200) &&
-			(r.width() != 384 || r.height() != 242) &&
-			(r.width() != 640 || r.height() != 480)
-			)
-			return false;
-		Decoder::initSize(p, r);
-		clean();
-		int32 frame_size = getRect().width() * getRect().height();
-		_deltaSize = frame_size * 3 + 0x13600;
-		_deltaBuf = new byte[_deltaSize];
-		memset(_deltaBuf, 0, _deltaSize);
-		if(_deltaBuf == 0) error("unable to allocate decoder buffer");
-		_deltaBufs[0] = _deltaBuf + 0x4D80;
-		_deltaBufs[1] = _deltaBuf + 0xE880 + frame_size;
-		_offsetTable = new int16[255];
-		_curtable = 0;
-		if(_offsetTable == 0)
-			error("unable to allocate decoder offset table");
-		_tableLastPitch = -1;
-		_tableLastIndex = -1;
-		return true; 
-	}
-	return false;
+void Codec37Decoder::init(int width, int height) {
+	deinit();
+	_width = width;
+	_height = height;
+	_frameSize = _width * _height;
+	_deltaSize = _frameSize * 3 + 0x13600;
+	_deltaBuf = new byte[_deltaSize];
+	memset(_deltaBuf, 0, _deltaSize);
+	if(_deltaBuf == 0)
+		error("unable to allocate decoder buffer");
+	_deltaBufs[0] = _deltaBuf + 0x4D80;
+	_deltaBufs[1] = _deltaBuf + 0xE880 + _frameSize;
+	_offsetTable = new int16[255];
+	_curtable = 0;
+	if(_offsetTable == 0)
+		error("unable to allocate decoder offset table");
+	_tableLastPitch = -1;
+	_tableLastIndex = -1;
 }
 
 Codec37Decoder::Codec37Decoder() {
@@ -67,7 +56,7 @@
 	_prevSeqNb = 0;
 }
 
-void Codec37Decoder::clean() {
+void Codec37Decoder::deinit() {
 	if(_offsetTable) {
 		delete []_offsetTable;
 		_offsetTable = 0;
@@ -84,10 +73,10 @@
 }
 
 Codec37Decoder::~Codec37Decoder() {
-	clean();
+	deinit();
 }
 
-void Codec37Decoder::maketable(int32 pitch, int32 index) {
+void Codec37Decoder::maketable(int pitch, int index) {
 	static const int8 maketable_bytes[] = {
     0,   0,   1,   0,   2,   0,   3,   0,   5,   0,
     8,   0,  13,   0,  21,   0,  -1,   0,  -2,   0,
@@ -246,6 +235,7 @@
 
 	if (_tableLastPitch == pitch && _tableLastIndex == index)
 		return;
+
 	_tableLastPitch = pitch;
 	_tableLastIndex = index;
 	index *= 255;
@@ -368,7 +358,7 @@
 		dst += 4;						  \
 	} while(0)
 
-void Codec37Decoder::proc3WithFDFE(byte *dst, const byte *src, int32 next_offs, int32 bw, int32 bh, int32 pitch, int16 *offset_table) {
+void Codec37Decoder::proc3WithFDFE(byte *dst, const byte *src, int32 next_offs, int bw, int bh, int pitch, int16 *offset_table) {
 	do {
 		int32 i = bw;
 		do {
@@ -388,7 +378,7 @@
 	} while (--bh);
 }
 
-void Codec37Decoder::proc3WithoutFDFE(byte *dst, const byte *src, int32 next_offs, int32 bw, int32 bh, int32 pitch, int16 *offset_table) {
+void Codec37Decoder::proc3WithoutFDFE(byte *dst, const byte *src, int32 next_offs, int bw, int bh, int pitch, int16 *offset_table) {
 	do {
 		int32 i = bw;
 		do {
@@ -404,7 +394,7 @@
 	} while (--bh);
 }
 
-void Codec37Decoder::proc4WithFDFE(byte *dst, const byte *src, int32 next_offs, int32 bw, int32 bh, int32 pitch, int16 *offset_table) {
+void Codec37Decoder::proc4WithFDFE(byte *dst, const byte *src, int32 next_offs, int bw, int bh, int pitch, int16 *offset_table) {
 	do {
 		int32 i = bw;
 		do {
@@ -440,7 +430,7 @@
 	} while (--bh);
 }
 
-void Codec37Decoder::proc4WithoutFDFE(byte *dst, const byte *src, int32 next_offs, int32 bw, int32 bh, int32 pitch, int16 *offset_table) {
+void Codec37Decoder::proc4WithoutFDFE(byte *dst, const byte *src, int32 next_offs, int bw, int bh, int pitch, int16 *offset_table) {
 	do {
 		int32 i = bw;
 		do {
@@ -472,10 +462,8 @@
 	} while (--bh);
 }
 
-bool Codec37Decoder::decode(byte *dst, const byte *src, int length) {
-	int32 width = getRect().width();
-	int32 height = getRect().height();
-	int32 bw = (width + 3) >> 2, bh = (height + 3) >> 2;
+void Codec37Decoder::decode(byte *dst, const byte *src) {
+	int32 bw = (_width + 3) >> 2, bh = (_height + 3) >> 2;
 	int32 pitch = bw << 2;
 
 	int16 seq_nb = READ_LE_UINT16(src + 2);
@@ -543,8 +531,6 @@
 	}
 	_prevSeqNb = seq_nb;
 
-	memcpy(dst, _deltaBufs[_curtable], width * height);
-	
-	return true;
+	memcpy(dst, _deltaBufs[_curtable], _frameSize);
 }
 

Index: codec37.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/codec37.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- codec37.h	13 Mar 2003 01:24:02 -0000	1.10
+++ codec37.h	17 Mar 2003 12:28:49 -0000	1.11
@@ -19,36 +19,39 @@
  *
  */
 
-#ifndef CODEC37_H
-#define CODEC37_H
+#ifndef SMUSH_CODEC37_H
+#define SMUSH_CODEC37_H
 
-#include "decoder.h"
+#include "common/scummsys.h"
 
-class Codec37Decoder : public Decoder {
+class Codec37Decoder {
 private:
+
 	int32 _deltaSize;
 	byte *_deltaBufs[2];
 	byte *_deltaBuf;
 	int16 *_offsetTable;
-	int32 _curtable;
+	int _curtable;
 	uint16 _prevSeqNb;
-	int32 _tableLastPitch;
-	int32 _tableLastIndex;
+	int _tableLastPitch;
+	int _tableLastIndex;
+	int32 _frameSize;
+	int _width, _height;
 
 public:
-	bool initSize(const Point &, const Rect &);
 	Codec37Decoder();
-	void clean();
-	virtual ~Codec37Decoder();
+	~Codec37Decoder();
+	void init(int width, int height);
+	void deinit();
 protected:
-	void maketable(int32, int32);
+	void maketable(int, int);
 	void bompDecode(byte *dst, const byte *src, int len);
-	void proc3WithFDFE(byte *dst, const byte *src, int32, int32, int32, int32, int16 *);
-	void proc3WithoutFDFE(byte *dst, const byte *src, int32, int32, int32, int32, int16 *);
-	void proc4WithFDFE(byte *dst, const byte *src, int32, int32, int32, int32, int16 *);
-	void proc4WithoutFDFE(byte *dst, const byte *src, int32, int32, int32, int32, int16 *);
+	void proc3WithFDFE(byte *dst, const byte *src, int32, int, int, int, int16 *);
+	void proc3WithoutFDFE(byte *dst, const byte *src, int32, int, int, int, int16 *);
+	void proc4WithFDFE(byte *dst, const byte *src, int32, int, int, int, int16 *);
+	void proc4WithoutFDFE(byte *dst, const byte *src, int32, int, int, int, int16 *);
 public:
-	bool decode(byte *dst, const byte *src, int length);
+	void decode(byte *dst, const byte *src);
 };
 
 #endif

Index: codec47.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/codec47.cpp,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- codec47.cpp	13 Mar 2003 06:37:07 -0000	1.44
+++ codec47.cpp	17 Mar 2003 12:28:49 -0000	1.45
@@ -601,16 +601,16 @@
 	}
 }
 
-void Codec47Decoder::decode2(byte *dst, const byte *src, int32 width, int32 height, const byte *param_ptr) {
+void Codec47Decoder::decode2(byte *dst, const byte *src, int width, int height, const byte *param_ptr) {
 	_d_src = src;
 	_paramPtr = param_ptr - 0xf8;
-	int32 bw = (width + 7) >> 3;
-	int32 bh = (height + 7) >> 3;
-	int32 next_line = width * 7;
+	int bw = (width + 7) >> 3;
+	int bh = (height + 7) >> 3;
+	int next_line = width * 7;
 	_d_pitch = width;
 
 	do {
-		int32 tmp_bw = bw;
+		int tmp_bw = bw;
 		do {
 			level1(dst);
 			dst += 8;
@@ -619,35 +619,26 @@
 	} while (--bh);
 }
 
-bool Codec47Decoder::initSize(const Point &p, const Rect &r) {
-	if(r.width() != getRect().width() && r.height() != getRect().height()) {
-		if(
-			(r.width() != 640 || r.height() != 480)
-			)
-			return false;
-		Decoder::initSize(p, r);
-		clean();
-
-		makeTables37(4);
-		makeTables37(8);
-
-		int32 frame_size = getRect().width() * getRect().height();
-		_deltaSize = frame_size * 3;
-		_deltaBuf = new byte[_deltaSize];
-		_deltaBufs[0] = _deltaBuf;
-		_deltaBufs[1] = _deltaBuf + frame_size;
-		_curBuf = _deltaBuf + frame_size * 2;
+void Codec47Decoder::init(int width, int height) {
+	deinit();
+	_width = width;
+	_height = height;
+	makeTables37(4);
+	makeTables37(8);
 
-		return true;
-	}
-	return false;
+	_frameSize = _width * _height;
+	_deltaSize = _frameSize * 3;
+	_deltaBuf = new byte[_deltaSize];
+	_deltaBufs[0] = _deltaBuf;
+	_deltaBufs[1] = _deltaBuf + _frameSize;
+	_curBuf = _deltaBuf + _frameSize * 2;
 }
 
 Codec47Decoder::Codec47Decoder() {
 	_deltaBuf = 0;
 }
 
-void Codec47Decoder::clean() {
+void Codec47Decoder::deinit() {
 	_lastTableWidth = -1;
 	if(_deltaBuf) {
 		delete []_deltaBuf;
@@ -659,12 +650,10 @@
 }
 
 Codec47Decoder::~Codec47Decoder() {
-	clean();
+	deinit();
 }
 
-bool Codec47Decoder::decode(byte *dst, const byte *src, int length) {
-	int32 width = getRect().width();
-	int32 height = getRect().height();
+bool Codec47Decoder::decode(byte *dst, const byte *src) {
 	_offset1 = _deltaBufs[1] - _curBuf;
 	_offset2 = _deltaBufs[0] - _curBuf;
 
@@ -674,9 +663,9 @@
 	byte *tmp_ptr;
 
 	if (seq_nb == 0) {
-		makeTables47(width);
-		memset(_deltaBufs[0], src[12], width * height);
-		memset(_deltaBufs[1], src[13], width * height);
+		makeTables47(_width);
+		memset(_deltaBufs[0], src[12], _frameSize);
+		memset(_deltaBufs[1], src[13], _frameSize);
 		_prevSeqNb = -1;
 	}
 
@@ -686,28 +675,28 @@
 
 	switch(src[2]) {
 	case 0:
-		memcpy(_curBuf, gfx_data, width * height);
+		memcpy(_curBuf, gfx_data, _frameSize);
 		break;
 	case 1:
 		warning("codec47: not implemented decode1 proc");
 		break;
 	case 2:
 		if (seq_nb == _prevSeqNb + 1) {
-			decode2(_curBuf, gfx_data, width, height, src + 8);
+			decode2(_curBuf, gfx_data, _width, _height, src + 8);
 		}
 		break;
 	case 3:
-		memcpy(_curBuf, _deltaBufs[1], width * height);
+		memcpy(_curBuf, _deltaBufs[1], _frameSize);
 		break;
 	case 4:
-		memcpy(_curBuf, _deltaBufs[0], width * height);
+		memcpy(_curBuf, _deltaBufs[0], _frameSize);
 		break;
 	case 5:
 		bompDecode(_curBuf, gfx_data, READ_LE_UINT32(src + 14));
 		break;
 	}
 
-	memcpy(dst, _curBuf, width * height);
+	memcpy(dst, _curBuf, _frameSize);
 
 	if (seq_nb == _prevSeqNb + 1) {
 		if (src[3] == 1) {

Index: codec47.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/codec47.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- codec47.h	13 Mar 2003 01:24:02 -0000	1.13
+++ codec47.h	17 Mar 2003 12:28:50 -0000	1.14
@@ -19,27 +19,28 @@
  *
  */
 
-#ifndef CODEC_47_H
-#define CODEC_47_H
-
-#include "config.h"
+#ifndef SMUSH_CODEC_47_H
+#define SMUSH_CODEC_47_H
 
-#include "decoder.h"
+#include "common/scummsys.h"
 
-class Codec47Decoder : public Decoder {
+class Codec47Decoder {
 private:
+
 	int32 _deltaSize;
 	byte *_deltaBufs[2];
 	byte *_deltaBuf;
 	byte *_curBuf;
 	int32 _prevSeqNb;
-	int32 _lastTableWidth;
+	int _lastTableWidth;
 	const byte *_d_src, *_paramPtr;
-	int32 _d_pitch;
+	int _d_pitch;
 	int32 _offset1, _offset2;
 	byte _tableBig[99328];
 	byte _tableSmall[32768];
 	int16 _table[256];
+	int32 _frameSize;
+	int _width, _height;
 
 	void makeTables47(int32 width);
 	void makeTables37(int32 param);
@@ -47,14 +48,14 @@
 	void level1(byte *d_dst);
 	void level2(byte *d_dst);
 	void level3(byte *d_dst);
-	void decode2(byte *dst, const byte *src, int32 width, int32 height, const byte *param_ptr);
+	void decode2(byte *dst, const byte *src, int width, int height, const byte *param_ptr);
 
 public:
 	Codec47Decoder();
-	virtual ~Codec47Decoder();
-	bool initSize(const Point &, const Rect &);
-	void clean();
-	bool decode(byte *dst, const byte *src, int length);
+	~Codec47Decoder();
+	void init(int width, int height);
+	void deinit();
+	bool decode(byte *dst, const byte *src);
 };
 
 #endif

Index: imuse_channel.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/imuse_channel.cpp,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- imuse_channel.cpp	6 Mar 2003 21:46:44 -0000	1.13
+++ imuse_channel.cpp	17 Mar 2003 12:28:50 -0000	1.14
@@ -24,9 +24,6 @@
 #include "chunk.h"
 #include "chunk_type.h"
 
-#include <assert.h>
-#include <string.h>
-
 ImuseChannel::ImuseChannel(int32 track, int32 freq) : 
 	_track(track), 
 	_tbuffer(0), 
@@ -73,7 +70,7 @@
 }
 
 bool ImuseChannel::appendData(Chunk &b, int32 size) {
-	if(_dataSize == -1) { // First call
+	if(_dataSize == -1) {
 		assert(size > 8);
 		Chunk::type imus_type = b.getDword(); imus_type = SWAP_BYTES(imus_type);
 		uint32 imus_size = b.getDword(); imus_size = SWAP_BYTES(imus_size);
@@ -86,9 +83,9 @@
 		if(!_tbuffer)
 			error("imuse_channel failed to allocate memory");
 		b.read(_tbuffer, size);
-		_dataSize = -2; // even if _in_data does not get set, this won't be called again
+		_dataSize = -2;
 	} else {
-		if(_tbuffer) { // remaining from last call
+		if(_tbuffer) {
 			byte *old = _tbuffer;
 			int32 new_size = size + _tbufferSize;
 			_tbuffer = new byte[new_size];
@@ -223,7 +220,7 @@
 					handleMap(c);
 				}
 				break;
-			case TYPE_DATA: // Sound data !!!
+			case TYPE_DATA:
 				_inData = true;
 				_dataSize = size;
 				offset += 8;
@@ -254,7 +251,6 @@
 }
 
 bool ImuseChannel::processBuffer() {
-	// see comments in saud_channel::processBuffer for an explanation
 	assert(_tbuffer != 0);
 	assert(_tbufferSize != 0);
 	assert(_sbuffer == 0);
@@ -266,7 +262,7 @@
 			while(handleSubTags(offset));
 			_sbufferSize = _dataSize;
 			_sbuffer = _tbuffer;
-			if(offset < _tbufferSize) { // there is still some unprocessed data
+			if(offset < _tbufferSize) {
 				int32 new_size = _tbufferSize - offset;
 				_tbuffer = new byte[new_size];
 				if(!_tbuffer) error("imuse_channel failed to allocate memory");
@@ -277,12 +273,10 @@
 				_tbufferSize = 0;
 			}
 			if(_sbufferSize == 0) {
-				// this never happened yet, but who knows
 				delete []_sbuffer; 
 				_sbuffer = 0;
 			}
 		} else {
-			// easy, swap the buffer
 			_sbufferSize = _tbufferSize;
 			_sbuffer = _tbuffer;
 			_tbufferSize = 0;
@@ -301,7 +295,7 @@
 			_tbuffer = 0;
 			_tbufferSize = 0;
 		} else {
-			if(offset) { // maybe I should assert() this to avoid a lock...
+			if(offset) {
 				byte * old = _tbuffer;
 				int32 new_size = _tbufferSize - offset;
 				_tbuffer = new byte[new_size];

Index: saud_channel.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/smush/saud_channel.cpp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- saud_channel.cpp	6 Mar 2003 21:46:45 -0000	1.10
+++ saud_channel.cpp	17 Mar 2003 12:28:50 -0000	1.11
@@ -25,9 +25,6 @@
 #include "chunk.h"
 #include "chunk_type.h"
 
-#include <assert.h>
-#include <string.h>
-
 void SaudChannel::handleStrk(Chunk &b) {
 	int32 size = b.getSize();
 	if(size != 14 && size != 10) {
@@ -41,7 +38,8 @@
 
 void SaudChannel::handleShdr(Chunk &b) {
 	int32 size = b.getSize();
-	if(size != 4) warning("SMRK has a invalid size : %d", size);
+	if(size != 4)
+		warning("SMRK has a invalid size : %d", size);
 }
 
 bool SaudChannel::handleSubTags(int32 &offset) {
@@ -93,12 +91,6 @@
 }
 
 bool SaudChannel::processBuffer() {
-	// At the start of this function, we have _tbuffer[0.._tbuffersize] containing possible data...
-	// and _sbuffer is 0
-	// At the end we have :
-	// if(sound data) _sbuffer[0.._sbuffer_size] contains the sound data
-	// the unprocessed data is kept in _tbuffer[0.._tbuffersize] (which may have changed)
-	// if no unprocessed data, then _tbuffer is 0
 	assert(_tbuffer != 0);
 	assert(_tbufferSize != 0);
 	assert(_sbuffer == 0);
@@ -106,12 +98,11 @@
 	
 	if(_inData) {
 		if(_dataSize < _tbufferSize) {
-			// I can't assume that the channel is finished after data is received... (this assumption failed in realride.san)
 			int32 offset = _dataSize;
 			while(handleSubTags(offset));
 			_sbufferSize = _dataSize;
 			_sbuffer = _tbuffer;
-			if(offset < _tbufferSize) { // there is still some unprocessed data
+			if(offset < _tbufferSize) {
 				int new_size = _tbufferSize - offset;
 				_tbuffer = new byte[new_size];
 				if(!_tbuffer)  error("SaudChannel failed to allocate memory");
@@ -122,12 +113,10 @@
 				_tbufferSize = 0;
 			}
 			if(_sbufferSize == 0) {
-				// this never happened yet, but who knows
 				delete []_sbuffer; 
 				_sbuffer = 0;
 			}
 		} else {
-			// easy, swap the buffer
 			_sbufferSize = _tbufferSize;
 			_sbuffer = _tbuffer;
 			_tbufferSize = 0;
@@ -140,17 +129,19 @@
 			_sbufferSize = _tbufferSize - offset;
 			assert(_sbufferSize);
 			_sbuffer = new byte[_sbufferSize];
-			if(!_sbuffer)  error("saud_channel failed to allocate memory");
+			if(!_sbuffer)
+				error("saud_channel failed to allocate memory");
 			memcpy(_sbuffer, _tbuffer + offset, _sbufferSize);
 			delete []_tbuffer;
 			_tbuffer = 0;
 			_tbufferSize = 0;
 		} else {
-			if(offset) { // maybe I should assert() this to avoid a lock...
-				unsigned char *old = _tbuffer;
+			if(offset) {
+				byte *old = _tbuffer;
 				int32 new_size = _tbufferSize - offset;
 				_tbuffer = new byte[new_size];
-				if(!_tbuffer)  error("SaudChannel failed to allocate memory");
+				if(!_tbuffer)
+					error("SaudChannel failed to allocate memory");
 				memcpy(_tbuffer, old + offset, new_size);
 				_tbufferSize = new_size;
 				delete []old;
@@ -197,10 +188,14 @@
 	int32 right_multiplier = MAX_BALANCE + _balance;
 	volume_left = _volume * left_multiplier / (MAX_BALANCE * 2);
 	volume_right = _volume * right_multiplier / (MAX_BALANCE * 2);
-	if(volume_left < 0) volume_left = 0;
-	if(volume_left > 128) volume_left = 128;
-	if(volume_right < 0) volume_right = 0;
-	if(volume_right > 128) volume_right = 128;
+	if(volume_left < 0)
+		volume_left = 0;
+	if(volume_left > 128)
+		volume_left = 128;
+	if(volume_right < 0)
+		volume_right = 0;
+	if(volume_right > 128)
+		volume_right = 128;
 	for(int32 i = 0; i < 256; i++) {
 		int16 value = volume_left * (int8)i;
 		_voltable[0][i] = TO_BE_16(value);
@@ -220,9 +215,12 @@
 }
 
 bool SaudChannel::checkParameters(int32 index, int32 nb, int32 flags, int32 volume, int32 balance) {
-	if(++_index != index) error("invalid index in SaudChannel::checkParameters()");
-	if(_nbframes != nb) error("invalid duration in SaudChannel::checkParameters()");
-	if(_flags != flags) error("invalid flags in SaudChannel::checkParameters()");
+	if(++_index != index)
+		error("invalid index in SaudChannel::checkParameters()");
+	if(_nbframes != nb)
+		error("invalid duration in SaudChannel::checkParameters()");
+	if(_flags != flags)
+		error("invalid flags in SaudChannel::checkParameters()");
 	if(_volume != volume || _balance != balance) {
 		_volume = volume;
 		_balance = balance;
@@ -232,13 +230,13 @@
 }
 
 bool SaudChannel::appendData(Chunk &b, int32 size) {
-	if(_dataSize == -1) { // First call
+	if(_dataSize == -1) {
 		assert(size > 8);
 		Chunk::type saud_type = b.getDword(); saud_type = SWAP_BYTES(saud_type);
 		uint32 saud_size = b.getDword(); saud_size = SWAP_BYTES(saud_size);
 		if(saud_type != TYPE_SAUD) error("Invalid Chunk for SaudChannel : %X", saud_type);
 		size -= 8;
-		_dataSize = -2; // We don't get here again...
+		_dataSize = -2;
 	}
 	if(_tbuffer) {
 		byte *old = _tbuffer;

--- brenderer.cpp DELETED ---

--- brenderer.h DELETED ---

--- codec1.h DELETED ---

--- codec44.cpp DELETED ---

--- codec44.h DELETED ---

--- color.cpp DELETED ---

--- color.h DELETED ---

--- config.h DELETED ---

--- decoder.h DELETED ---

--- frenderer.cpp DELETED ---

--- frenderer.h DELETED ---

--- mixer.h DELETED ---

--- palette.h DELETED ---

--- player.cpp DELETED ---

--- player.h DELETED ---

--- renderer.h DELETED ---

--- scumm_renderer.cpp DELETED ---

--- scumm_renderer.h DELETED ---





More information about the Scummvm-git-logs mailing list