[Scummvm-cvs-logs] CVS: scummvm-new/scumm/smush blitter.cpp,NONE,1.1 blitter.h,NONE,1.1 brenderer.cpp,NONE,1.1 brenderer.h,NONE,1.1 channel.h,NONE,1.1 chunck.cpp,NONE,1.1 chunck.h,NONE,1.1 chunck_type.h,NONE,1.1 codec1.cpp,NONE,1.1 codec1.h,NONE,1.1 codec37.cpp,NONE,1.1 codec37.h,NONE,1.1 codec44.cpp,NONE,1.1 codec44.h,NONE,1.1 codec47.cpp,NONE,1.1 codec47.h,NONE,1.1 color.cpp,NONE,1.1 color.h,NONE,1.1 config.h,NONE,1.1 decoder.h,NONE,1.1 frenderer.cpp,NONE,1.1 frenderer.h,NONE,1.1 imuse_channel.cpp,NONE,1.1 mixer.h,NONE,1.1 palette.cpp,NONE,1.1 palette.h,NONE,1.1 player.cpp,NONE,1.1 player.h,NONE,1.1 rect.cpp,NONE,1.1 rect.h,NONE,1.1 renderer.h,NONE,1.1 saud_channel.cpp,NONE,1.1 scumm_renderer.cpp,NONE,1.1 scumm_renderer.h,NONE,1.1

Pawe? Ko?odziejski aquadran at users.sourceforge.net
Sat Aug 24 08:32:04 CEST 2002


Update of /cvsroot/scummvm/scummvm-new/scumm/smush
In directory usw-pr-cvs1:/tmp/cvs-serv7048/scumm/smush

Added Files:
	blitter.cpp blitter.h brenderer.cpp brenderer.h channel.h 
	chunck.cpp chunck.h chunck_type.h codec1.cpp codec1.h 
	codec37.cpp codec37.h codec44.cpp codec44.h codec47.cpp 
	codec47.h color.cpp color.h config.h decoder.h frenderer.cpp 
	frenderer.h imuse_channel.cpp mixer.h palette.cpp palette.h 
	player.cpp player.h rect.cpp rect.h renderer.h 
	saud_channel.cpp scumm_renderer.cpp scumm_renderer.h 
Log Message:
synced with scummvm

--- NEW FILE: blitter.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/blitter.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "blitter.h"
#include "chunck.h"

#include <assert.h>
#include <string.h> // for memcpy

#ifndef min
#define min(x, y) ((x) > (y) ? (y) : (x))
#endif

Blitter::Blitter(char * ptr, const Point & dstsize, const Rect & src) : 
			_ptr(ptr), 
			_clip(dstsize), 
			_src(src),
			_cur(src.left(), src.top()),
			_outside(false) {
#ifdef DEBUG_CLIPPER
	_clipped = 0;
	_clippedBlock = 0;
#endif
	assert(_ptr);
	assert(_clip.getX() > 0 && _clip.getY() > 0);
	assert(_src.width() > 0 && _src.height() > 0);
	assert(_src.left() < _clip.getX() && _src.right() <= _clip.getX());
	assert(_src.top() < _clip.getY() && _src.bottom() <= _clip.getY());
	_offset = _ptr + _clip.getX() * _cur.getY()  + _cur.getX();
}

Blitter::~Blitter() {
#ifdef DEBUG_CLIPPER
	if(_clipped || _clippedBlock) {
		debug(3, "blitter clipped %d pixels and %d blocks", _clipped, _clippedBlock);
	}
#endif
}

void Blitter::advance(int x, int y) {
	if(y != 0) {
		_cur.set(_src.left() + x, _cur.getY() + y);
	} else {
		_cur.getX() += x;
		if(_cur.getX() >= _src.right()) {
			_cur.set(_src.left(), _cur.getY()+1);
		}
	}
	_offset = _ptr + _clip.getX() * _cur.getY()  + _cur.getX();
	_outside = ! _src.isInside(_cur); 
}

void Blitter::advanceBlock(int x, int y) {
	advance(x*4, y*4);
}

void Blitter::put(char data) {
	if(!_outside) {
		*_offset = data;
		advance();
	}
#ifdef DEBUG_CLIPPER
	else	_clipped ++;
#endif
}

void Blitter::put(char data, unsigned int len) {
	while(len) {
		if(_outside) {
#ifdef DEBUG_CLIPPER
			_clipped += len;
#endif
			break;
		}
		int l = min((int)len, min(_clip.getX() - _cur.getX(), _src.right() - _cur.getX()));
		len -= l;
		memset(_offset, data, l);
		advance(l);
	}
}

void Blitter::blit(char * ptr, unsigned int len) {
	while(len) {
		if(_outside) {
#ifdef DEBUG_CLIPPER
			_clipped += len;
#endif
			break;
		}
		int l = min((int)len, min(_clip.getX() - _cur.getX(), _src.right() - _cur.getX()));
		len -= l;
		memcpy(_offset, ptr, l);
		ptr += l;
		advance(l);
	}
}

void Blitter::blit(Chunck & src, unsigned int len) {
	while(len) {
		if(_outside) {
#ifdef DEBUG_CLIPPER
			_clipped += len;
#endif
			break;
		}
		int l = min((int)len, min(_clip.getX() -_cur.getX(), _src.right() - _cur.getX()));
		len -= l;
		src.read(_offset, l);
		advance(l);
	}
}

void Blitter::putBlock(unsigned int data) {
	if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping
		assert((_clip.getX() & 3) == 0);
		unsigned int * dst = (unsigned int *)_offset;
		int line_size = _clip.getX() >> 2;

		*dst = data; dst += line_size;
		*dst = data; dst += line_size;
		*dst = data; dst += line_size;
		*dst = data;

#ifdef DEBUG_CLIPPER
	} else {
		_clippedBlock ++;
#endif
	}
	advanceBlock();
}

void Blitter::putBlock(unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4) {
	if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping
		assert((_clip.getX() & 3) == 0);
		unsigned int * dst = (unsigned int *)_offset;
		int line_size = _clip.getX() >> 2;

		*dst = d4; dst += line_size;
		*dst = d3; dst += line_size;
		*dst = d2; dst += line_size;
		*dst = d1;

#ifdef DEBUG_CLIPPER
	} else {
		_clippedBlock ++;
#endif
	}
	advanceBlock();
}

void Blitter::putBlock(unsigned char * data) {
	if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping
		assert((_clip.getX() & 3) == 0);
		unsigned int * dst =  (unsigned int *)_offset;
		int line_size = _clip.getX() >> 2;
		unsigned int * src =  (unsigned int *)data;
		*dst = *src++; dst += line_size; 
		*dst = *src++; dst += line_size;
		*dst = *src++; dst += line_size;
		*dst = *src++;
#ifdef DEBUG_CLIPPER
	} else {
		_clippedBlock ++;
#endif
	}
	advanceBlock();
}

void Blitter::putBlock(Chunck & src) {
	if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping
		assert((_clip.getX() & 3) == 0);
		unsigned int * dst =  (unsigned int *)_offset;
		int line_size = _clip.getX() >> 2;
		*dst = src.getDword(); dst += line_size;
		*dst = src.getDword(); dst += line_size;
		*dst = src.getDword(); dst += line_size;
		*dst = src.getDword();
#ifdef DEBUG_CLIPPER
	} else {
		_clippedBlock ++;
#endif
	}
	advanceBlock();
}

void Blitter::blockCopy(int offset) {
	if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) {// This is clipping
		char  * dst = _offset;
		*((unsigned int *)dst) = *((unsigned int *)(dst + offset));
		dst += _clip.getX();
		*((unsigned int *)dst) = *((unsigned int *)(dst + offset));
		dst += _clip.getX();
		*((unsigned int *)dst) = *((unsigned int *)(dst + offset));
		dst += _clip.getX();
		*((unsigned int *)dst) = *((unsigned int *)(dst + offset));
#ifdef DEBUG_CLIPPER
	} else {
		_clippedBlock ++;
#endif
	}
	advanceBlock();
}

--- NEW FILE: blitter.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/blitter.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __BLITTER_H_
#define __BLITTER_H_

#include "config.h"

#ifdef DEBUG
# ifndef NO_DEBUG_CLIPPER
#  define DEBUG_CLIPPER
# endif
#else
# ifdef DEBUG_CLIPPER
#  error DEBUG_CLIPPER defined without DEBUG
# endif
#endif

#include "rect.h"

class Chunck;
/*! 	@brief class for handling blitting on a frame buffer

	This class allows to perform secure blitting to a frame buffer in several ways.
	This means that clipping is performed, so that only the part that you want to modify can be modified.
*/
class Blitter {
private:
	char * _ptr;	//!< This is the pointer to the start of the frame buffer
	char * _offset;	//!< This is the current pointer in the frame buffer
	Point _clip;		//!<  This is the size of the frame buffer (width/height)
	Rect _src; 		//!< This is the size and position of the destination rectangle
	Point _cur; 		//!< This is the current position in the destination rectangle
	bool _outside;	//!< flag that is set to \c true when the blitter reach the end of the destination rectangle
#ifdef DEBUG_CLIPPER
	int _clipped;
	int _clippedBlock;
#endif
public:
	/*!	@brief constructor

		@param buffer the frame buffer to blit to
		@param dstsize the size of the frame buffer
		@param src the rectangle to blit to
	*/
	Blitter(char * buffer, const Point & dstsize, const Rect & src);
	virtual ~Blitter();
	void blit(char *, unsigned int); //!< This method allows to blit directly some data from a buffer
	void blit(Chunck &, unsigned int); //!< This method allows to blit directly some data from a chunck
	void put(char); //!< This method allows to blit one byte
	void put(char, unsigned int); //!< This method allows to blit one byte several times
	void advance(int = 1, int = 0); //!< This method allows to advance the current position in the blitter
	void advanceBlock(int = 1, int = 0); //!< This method allows to advance the current position in the blitter in terms of blocks
	void putBlock(unsigned int); //!< This method allows to blit one block from an int value repeated 4 time
	void putBlock(Chunck &); //!< This method allows to blit one block directly read from a chunck
	void putBlock(unsigned char *); //!< This method allows to blit one block directly from a buffer
	void putBlock(unsigned int, unsigned int, unsigned int, unsigned int); //!< This method allows to blit one block from a 4 int value
	void blockCopy(int); //!< This method allows to copy one block from another separated by the given offset
};

#endif

--- NEW FILE: brenderer.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/brenderer.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "brenderer.h"

#include <assert.h>

void BaseRenderer::clean() {
	if(_data) {
		delete[] _data;
		_data = 0;
		_width = _height = 0;
	}
}

BaseRenderer::BaseRenderer() : 
		_data(0), 
		_frame(0), 
		_nbframes(0), 
		_width(0), 
		_height(0) {
}

BaseRenderer::~BaseRenderer() { 
	clean(); 
}

bool BaseRenderer::initFrame(const Point & p) {
	clean();
	_width = p.getX();
	_height = p.getY();
	assert(_width && _height);
	_data = new char[_width * _height];
	if(!_data) error("base_renderer unable to allocate frame buffer");
	return true;
}

char * BaseRenderer::lockFrame(int frame) {
	_frame = frame; 
	if(!_data) error("no allocated image buffer in lock_frame");
	return _data;
}

bool BaseRenderer::unlockFrame() {
	return true;
}

bool BaseRenderer::flipFrame() { 
	save();
	return true;
}

bool BaseRenderer::setPalette(const Palette & pal) { 
	_pal = pal; 
	return true;
}

--- NEW FILE: brenderer.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/brenderer.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __BRENDERER_H_
#define __BRENDERER_H_

#include "config.h"

#include "renderer.h"
#include "palette.h"
#include "rect.h"

/*! 	@brief base class for easily creating ::renderer instances

	This class implements some function available in the ::renderer abstract class, so that 
	creation of subclasses of ::renderer is easier.
*/
class BaseRenderer : public Renderer {
private:
	Palette _pal;		//!< The current palette
	char * _data;		//!< The current frame buffer
	int _frame;			//!< The current frame number
	int _nbframes;		//!< The number of frames in the animation
	int _width;			//!< The current frame's width
	int _height;		//!< The current frame's height
	const char * _fname;	//!< The filename of the animation being played
protected:
	virtual void save(int frame = -1) = 0;

protected:
	const char * getFilename() const { return _fname; };	//!< accessor for animation filename
	int getNbframes() const { return _nbframes; };	//!< accessor for number of frames
	int getWidth() const { return _width; };	//!< accessor for current width
	int getHeight() const { return _height; };	//!< accessor for current height
	const Palette & pal() const { return _pal; };	//!< accessor for current palette
	const char * data() const { return _data; };	//!< accessor for current frame buffer
	void clean();	//!< memory cleanup (deletes frame buffer)
	void setFrame(int f) { _frame = f; };	//!< allows to change the frame number
public:
	int getFrame() const { return _frame; };	//!< accessor for current frame number
	BaseRenderer();
	virtual ~BaseRenderer();

	virtual bool initFrame(const Point & size);
	virtual char * lockFrame(int frame);
	virtual bool unlockFrame();
	virtual bool flipFrame();
	virtual bool setPalette(const Palette & pal);
	virtual bool startDecode(const char * fname, int version, int nbframes) { _fname = fname; _nbframes = nbframes; return true; }
	virtual Mixer * getMixer() { return 0; };
	virtual bool prematureClose() { return false; };
};

/*! 	@brief A null ::renderer

	This class completely implements ::renderer, without actually doing anything.
	This class is useful for performance measurements.
*/
class NullRenderer : public BaseRenderer {
protected:
	void save(int frame = -1) {};
public:
	NullRenderer() {};
	virtual ~NullRenderer() {};
	bool wait(int ms) { return true; };
};

#endif

--- NEW FILE: channel.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/channel.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __CHANNEL_H_
#define __CHANNEL_H_

#include "config.h"

#ifdef DEBUG
# ifndef NO_DEBUG_CHANNEL
#  define DEBUG_CHANNEL
# endif
#else
# ifdef DEBUG_CHANNEL
#  error DEBUG_CHANNEL defined without DEBUG
# endif
#endif

class Chunck;
class ContChunck;
	
/*! 	@brief interface for a sound channel (a track)

	This is the interface for sound channels. 
*/
class _Channel {
public:
	virtual ~_Channel() {};
	// called by the smush_player
	virtual bool appendData(Chunck & b, int size) = 0;
	virtual bool setParameters(int, int, int, int) = 0;
	virtual bool checkParameters(int, int, int, int, int) = 0;
	// called by the mixer
	virtual bool isTerminated() const = 0;
	virtual int availableSoundData() const = 0;
	virtual void getSoundData(short * sound_buffer, int size) = 0; // size is in sample 
	virtual void getSoundData(char * sound_buffer, int size) = 0;
	virtual bool getParameters(int &rate, bool &stereo, bool &is_16bit) = 0;
	virtual int getTrackIdentifier() const = 0;
};

class SaudChannel : public _Channel {
private:
	int _track;				//!< The track identifier
	int _nbframes;			//!< number of frames of the track (unused)
	int _dataSize;			//!< the size of the sound buffer
	int _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
	int _flags;				//!< current flags of the track (unused)
	int _volume;			//!< the current track volume
	int _balance;			//!< the current track balance
	int _index;				//!< the current PSAD index (for coherency checking)
	short _voltable[2][256];	//!< the precalculated volume table (stereo 16 bits)
	unsigned char * _tbuffer;	//!< data temporary buffer
	int _tbufferSize;			//!< temporary buffer size
	unsigned char * _sbuffer;	//!< sound buffer
	int _sbufferSize;			//!< sound buffer size

protected:
	void handleStrk(Chunck & c);
	void handleSmrk(Chunck & c);
	void handleShdr(Chunck & c);
	bool handleSubTags(int & offset);
	bool processBuffer();
	void recalcVolumeTable();

public:
	SaudChannel(int track, int freq);
	virtual ~SaudChannel();
	bool isTerminated() const;
	bool setParameters(int duration, int flags, int vol1, int vol2);
	bool checkParameters(int index, int duration, int flags, int vol1, int vol2);
	bool appendData(Chunck & b, int size);
	int availableSoundData() const;
	void getSoundData(short * sound_buffer, int size);
	void getSoundData(char * sound_buffer, int size) { error("16bit request for SAUD channel should never happen"); };
	bool getParameters(int &rate, bool &stereo, bool &is_16bit) { 
		rate = _frequency;
		stereo = true;
		is_16bit = true;
		return true;
	};
	virtual int 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 {
private:
	int _track;				//!< the track number
	unsigned char * _tbuffer;	//!< data temporary buffer
	int _tbufferSize;			//!< temporary buffer size
	unsigned char * _sbuffer;	//!< sound buffer
	int _sbufferSize;			//!< sound buffer size
	int _srbufferSize;
	int _frequency;			//!< the target frequency of the ::mixer
	int _dataSize;			//!< remaining size of sound data in the iMUS buffer
	bool _inData;

	int _bitsize;			//!< the bitsize of the original data
	int _rate;				//!< the sampling rate of the original data
	int _channels;			//!< the number of channels of the original data

protected:
	int decode(int size, int &ret);
	void decode();
	bool processBuffer();
	bool handleMap(Chunck &);
	bool handleFormat(Chunck &);
	bool handleText(Chunck &);
	bool handleRegion(Chunck &);
	bool handleStop(Chunck &);
	bool handleSubTags(int & offset);

public:
	ImuseChannel(int track, int freq);
	virtual ~ImuseChannel();
	bool isTerminated() const;
	bool setParameters(int nbframes, int size, int unk1, int unk2);
	bool checkParameters(int index, int nbframes, int size, int unk1, int unk2);
	bool appendData(Chunck & b, int size);
	int availableSoundData() const;
	void getSoundData(short * sound_buffer, int size);
	void getSoundData(char * sound_buffer, int size);
	bool getParameters(int &rate, bool &stereo, bool &is_16bit) {
		rate = _frequency;
		stereo = (_channels == 2);
		is_16bit = (_bitsize > 8);
		return true;
	};
	virtual int getTrackIdentifier() const { return _track; };
};

#endif

--- NEW FILE: chunck.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/chunck.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "chunck.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_chunck does not leak memory !
*/
class FilePtr {
	char * _filename;
	FILE * _ifs;
	int _refcount;
	int _curPos;
public:
	FilePtr(const char * fname) : _refcount(1), _curPos(0) {
		debug(9, "FilePtr created for %s", fname);
		_filename = strdup(fname);
		_ifs  = fopen(fname, "rb");
		if(_ifs == NULL) error("FilePtr unable to read file \"%s\"", fname);
	}
	~FilePtr() {
		debug(9, "FilePtr destroyed for %s", _filename);
		free(_filename);
		fclose(_ifs);
	}
	int tell() {
		return _curPos;
	}
	bool seek(int pos) {
		if(pos != _curPos) {
			fseek(_ifs, pos, SEEK_SET);
			_curPos = pos;
		}
		return true;
	}
	bool read(void * ptr, int size) {
		fread(ptr, size, 1, _ifs);
		_curPos += size;
		return true;
	}
	void incRef() {
		_refcount++;
	}
	void decRef() {
		if(--_refcount == 0)
			delete this;
	}
};

const char * Chunck::ChunckString(Chunck::type t) {
	static char data[5];
	data[0] = (char)((t >> 24) & 0xFF);
	data[1] = (char)((t >> 16) & 0xFF);
	data[2] = (char)((t >> 8) & 0xFF);
	data[3] = (char)((t >> 0) & 0xFF);
	data[4] = 0;
	return data;
}

FileChunck::FileChunck() : _data(0), _type(0), _size(0), _curPos(0) {
}

FileChunck::~FileChunck() {
	if(_data) _data->decRef();
}

FileChunck::FileChunck(const char * fname) {
	_data = new FilePtr(fname);
	_data->read(&_type, 4);
	_type = TO_BE_32(_type);
	_data->read(&_size, 4);
	_size = TO_BE_32(_size);
	_offset = _data->tell();
	_curPos = 0;
}

Chunck::type FileChunck::getType() const { 
	return _type; 
}

unsigned int FileChunck::getSize() const { 
	return _size; 
}

Chunck * FileChunck::subBlock() {
	FileChunck * ptr = new FileChunck;
	ptr->_data = _data;
	_data->incRef();
	_data->seek(_offset + _curPos);
	unsigned int temp;
	_data->read(&temp, 4);
	ptr->_type = TO_BE_32(temp);
	_data->read(&temp, 4);
	ptr->_size = TO_BE_32(temp);
	ptr->_offset = _offset + _curPos + 8;
	ptr->_curPos = 0;
	seek(8 + ptr->getSize());
	return ptr;
}

bool FileChunck::eof() const { 
	return _curPos >= _size; 
}

unsigned int FileChunck::tell() const { 
	return _curPos; 
}

bool FileChunck::seek(int delta, seek_type dir) {
	switch(dir) {
		case seek_cur:
			_curPos += delta;
			break;
		case seek_start:
			if(delta < 0) error("invalid seek request");
			_curPos = (unsigned int)delta;
			break;
		case seek_end:
			if(delta > 0 || (_size + delta) < 0) error("invalid seek request");
			_curPos = (unsigned int)(_size + delta);
			break;
	}
	if(_curPos > _size) {
		error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta);
	}
	return true;
}

bool FileChunck::read(void * buffer, unsigned int size) {
	if(size <= 0 || (_curPos + size) > _size) error("invalid buffer read request");
	_data->seek(_offset + _curPos);
	_data->read(buffer, size);
	_curPos += size;
	return true;
}

char FileChunck::getChar() {
	if(_curPos >= _size) error("invalid char read request");
	_data->seek(_offset + _curPos);
	char buffer;
	_data->read(&buffer, sizeof(buffer));
	_curPos+= sizeof(buffer);
	return buffer;
}

unsigned char FileChunck::getByte() {
	if(_curPos >= _size) error("invalid byte read request");
	_data->seek(_offset + _curPos);
	unsigned char buffer;
	_data->read(&buffer, sizeof(buffer));
	_curPos+= sizeof(buffer);
	return buffer;
}

short FileChunck::getShort() {
	unsigned short buffer = getWord();
	return *((short*)&buffer);
}

unsigned short FileChunck::getWord() {
	if(_curPos >= _size - 1) error("invalid word read request");
	_data->seek(_offset + _curPos);
	unsigned short buffer;
	_data->read(&buffer, sizeof(buffer));
	_curPos+= sizeof(buffer);
	return TO_LE_16(buffer);
}

unsigned int FileChunck::getDword() {
	if(_curPos >= _size - 3) error("invalid dword read request");
	_data->seek(_offset + _curPos);
	unsigned int buffer;
	_data->read(&buffer, sizeof(buffer));
	_curPos+= sizeof(buffer);
	return TO_LE_32(buffer);
}

ContChunck::ContChunck(char * data) {
	if(data == 0) error("Chunck() called with NULL pointer");
	_type = (Chunck::type)READ_BE_UINT32(data);
	_size = READ_BE_UINT32(data+4);
	_data = data + sizeof(Chunck::type) + sizeof(unsigned int);
	_curPos = 0;
}

Chunck::type ContChunck::getType() const { 
	return _type; 
}

unsigned int ContChunck::getSize() const { 
	return _size; 
}

Chunck * ContChunck::subBlock() {
	ContChunck * ptr = new ContChunck(_data + _curPos);
	seek(sizeof(Chunck::type) + sizeof(unsigned int) + ptr->getSize());
	return ptr;
}

bool ContChunck::eof() const { 
	return _curPos >= _size; 
}

unsigned int ContChunck::tell() const { 
	return _curPos; 
}

bool ContChunck::seek(int delta, seek_type dir) {
	switch(dir) {
		case seek_cur:
			_curPos += delta;
			break;
		case seek_start:
			if(delta < 0) error("invalid seek request");
			_curPos = (unsigned int)delta;
			break;
		case seek_end:
			if(delta > 0 || (_size + delta) < 0) error("invalid seek request");
			_curPos = (unsigned int)(_size + delta);
			break;
	}
	if(_curPos > _size) {
		error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta);
	}
	return true;
}

bool ContChunck::read(void * buffer, unsigned int size) {
	if(size <= 0 || (_curPos + size) > _size) error("invalid buffer read request");
	memcpy(buffer, _data + _curPos, size);
	_curPos += size;
	return true;
}

char ContChunck::getChar() {
	if(_curPos >= _size) error("invalid char read request");
	return _data[_curPos++];
}

unsigned char ContChunck::getByte() {
	if(_curPos >= _size) error("invalid byte read request");
	unsigned char * ptr = (unsigned char *)(_data + _curPos);
	_curPos += 1;
	return *ptr;
}

short ContChunck::getShort() {
	if(_curPos >= _size - 1) error("invalid short read request");
	unsigned short buffer = getWord();
	return *((short*)&buffer);
}

unsigned short ContChunck::getWord() {
	if(_curPos >= _size - 1) error("invalid word read request");
	unsigned short * ptr = (unsigned short *)(_data + _curPos);
	_curPos += 2;
	return READ_LE_UINT16(ptr);
}

unsigned int ContChunck::getDword() {
	if(_curPos >= _size - 3) error("invalid dword read request");
	unsigned int * ptr = (unsigned int *)(_data + _curPos);
	_curPos += 4;
	return READ_LE_UINT32(ptr);
}

--- NEW FILE: chunck.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/chunck.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __CHUNCK_H_
#define __CHUNCK_H_

#include "config.h"

/*! 	@brief Interface for chunck handling

	This class is an interface for reading from a chunck.

	\todo handle big endian system.
*/
class Chunck {
public:
	enum seek_type { seek_start, seek_end, seek_cur };
	virtual ~Chunck() {};
	typedef unsigned int type;			//!< type of a chunck (i.e. The first 4byte field of the chunck 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 * ChunckString(type t);

	virtual type getType() const = 0;	//!< return the type of the chunck
	virtual unsigned int getSize() const = 0;	//!< return the size of the chunck
	virtual Chunck * subBlock() = 0; //!< extract a subchunck from the current read position
	virtual bool eof() const = 0;	//!< is the chunck completely read ?
	virtual unsigned int tell() const = 0;	//!< get the chunck current read position
	virtual bool seek(int delta, seek_type dir = seek_cur) = 0;	//!< move the current read position inside the chunck
	virtual bool read(void * buffer, unsigned int size) = 0;		//!< read some data for the current read position
	virtual char getChar() = 0;							//!< extract the character at the current read position
	virtual unsigned char getByte() = 0;					//!< extract the byte at the current read position
	virtual short getShort() = 0;						//!< extract the short at the current read position
	virtual unsigned short getWord() = 0;					//!< extract the word at the current read position
	virtual unsigned int getDword()= 0;					//!< extract the dword at the current read position
};

class FilePtr;

/*! 	@brief file based ::chunck

	This class is an implementation of ::chunck that handles file.

*/
class FileChunck : public Chunck {
private:
	FilePtr * _data;
	type _type;
	unsigned int _size;
	unsigned int _offset;
	unsigned int _curPos;
protected:
	FileChunck();
public:
	FileChunck(const char * fname);
	virtual ~FileChunck();
	type getType() const;
	unsigned int getSize() const;
	Chunck * subBlock();
	bool eof() const;
	unsigned int tell() const;
	bool seek(int delta, seek_type dir = seek_cur);
	bool read(void * buffer, unsigned int size);
	char getChar();
	unsigned char getByte();
	short getShort();
	unsigned short getWord();
	unsigned int getDword();
};

/*! 	@brief memory based ::chunck

	This class is an implementation of ::chunck that handles a memory buffer.
*/
class ContChunck : public Chunck {
private:
	char * _data;
	Chunck::type _type;
	unsigned int _size;
	unsigned int _curPos;
public:
	ContChunck(char * data);
	Chunck::type getType() const;
	unsigned int getSize() const;
	Chunck * subBlock();
	bool eof() const;
	unsigned int tell() const;
	bool seek(int delta, seek_type dir = seek_cur);
	bool read(void * buffer, unsigned int size);
	char getChar();
	unsigned char getByte();
	short getShort();
	unsigned short getWord();
	unsigned int getDword();
};

#endif

--- NEW FILE: chunck_type.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/chunck_type.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __CHUNCK_TYPE_H
#define __CHUNCK_TYPE_H

#include "chunck.h"

#define MAKE_TYPE(a,b,c,d) (Chunck::type)( ((a) << 24) | ((b) << 16) | ((c) << 8) | (d) )

static const Chunck::type TYPE_ANIM = MAKE_TYPE('A', 'N', 'I', 'M');
static const Chunck::type TYPE_AHDR = MAKE_TYPE('A', 'H', 'D', 'R');
static const Chunck::type TYPE_FRME = MAKE_TYPE('F', 'R', 'M', 'E');
static const Chunck::type TYPE_NPAL = MAKE_TYPE('N', 'P', 'A', 'L');
static const Chunck::type TYPE_FOBJ = MAKE_TYPE('F', 'O', 'B', 'J');
static const Chunck::type TYPE_PSAD = MAKE_TYPE('P', 'S', 'A', 'D');
static const Chunck::type TYPE_TRES = MAKE_TYPE('T', 'R', 'E', 'S');
static const Chunck::type TYPE_XPAL = MAKE_TYPE('X', 'P', 'A', 'L');
static const Chunck::type TYPE_IACT = MAKE_TYPE('I', 'A', 'C', 'T');
static const Chunck::type TYPE_STOR = MAKE_TYPE('S', 'T', 'O', 'R');
static const Chunck::type TYPE_FTCH = MAKE_TYPE('F', 'T', 'C', 'H');
static const Chunck::type TYPE_SKIP = MAKE_TYPE('S', 'K', 'I', 'P');
static const Chunck::type TYPE_STRK = MAKE_TYPE('S', 'T', 'R', 'K');
static const Chunck::type TYPE_SMRK = MAKE_TYPE('S', 'M', 'R', 'K');
static const Chunck::type TYPE_SHDR = MAKE_TYPE('S', 'H', 'D', 'R');
static const Chunck::type TYPE_SDAT = MAKE_TYPE('S', 'D', 'A', 'T');
static const Chunck::type TYPE_SAUD = MAKE_TYPE('S', 'A', 'U', 'D');
static const Chunck::type TYPE_iMUS = MAKE_TYPE('i', 'M', 'U', 'S');
static const Chunck::type TYPE_FRMT = MAKE_TYPE('F', 'R', 'M', 'T');
static const Chunck::type TYPE_TEXT = MAKE_TYPE('T', 'E', 'X', 'T');
static const Chunck::type TYPE_REGN = MAKE_TYPE('R', 'E', 'G', 'N');
static const Chunck::type TYPE_STOP = MAKE_TYPE('S', 'T', 'O', 'P');
static const Chunck::type TYPE_MAP_ = MAKE_TYPE('M', 'A', 'P', ' ');
static const Chunck::type TYPE_DATA = MAKE_TYPE('D', 'A', 'T', 'A');
static const Chunck::type TYPE_ETRS = MAKE_TYPE('E', 'T', 'R', 'S');

#undef MAKE_TYPE

#endif

--- NEW FILE: codec1.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/codec1.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "codec1.h"
#include "chunck.h"
#include "blitter.h"

Codec1Decoder::~Codec1Decoder() {
}

bool Codec1Decoder::decode(Blitter & dst, Chunck & src) {
	int val;
	int size_line;
	int code, length;
	int h, height = getRect().height();

	for(h = 0; h < height; h++) {
		size_line = src.getWord(); // size of compressed line !
#ifdef DEBUG_CODEC1
		debug(7, "codec1 : h == %d, size_line == %d", h, size_line);
#endif
		while(size_line > 0) {
			code = src.getByte();
			size_line --;
			length = (code >> 1) + 1;
#ifdef DEBUG_CODEC1
			debug(7, "codec1 : length == %d", length);
#endif
			if(code & 1) {
				val = src.getByte();
				size_line --;
				if(val) dst.put(val, length);
				else dst.advance(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.getByte();
					if(val) dst.put(val);
					else dst.advance();
				}
			}
		}
	}
#ifdef DEBUG_CODEC1
	if(!src.eof()) {
		int len = src.getSize() - src.tell();
		debug(7, "codec1: remaining length after decode == %d", len);
	}
#endif
	return true;
}

--- NEW FILE: codec1.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/codec1.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __CODEC1_H_
#define __CODEC1_H_

#include "config.h"

#ifdef DEBUG
# ifndef NO_DEBUG_CODEC1
#  define DEBUG_CODEC1
# endif
#else
# ifdef DEBUG_CODEC1
#  error DEBUG_CODEC1 defined without DEBUG
# endif
#endif

#include "decoder.h"

/*!	@brief ::decoder for codec 1 and 3.

*/
class Codec1Decoder : public Decoder {
public:
	virtual ~Codec1Decoder();
	bool decode(Blitter &, Chunck &);
};

#endif

--- NEW FILE: codec37.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/codec37.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "codec37.h"
#include "chunck.h"
#include "blitter.h"

#include <assert.h>
#include <string.h> // for memset

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();
		int frame_size = getRect().width() * getRect().height();
		_deltaSize = frame_size * 2 + DELTA_ADD * 4;
		_deltaBuf = new  unsigned char[_deltaSize];
		if(_deltaBuf == 0) error("unable to allocate decoder buffer");
		_deltaBufs[0] = _deltaBuf + DELTA_ADD;
		_deltaBufs[1] = _deltaBuf + frame_size + DELTA_ADD * 3;
		_offsetTable = new short[255];
		if(_offsetTable == 0) error("unable to allocate decoder offset table");
		_tableLastPitch = -1;
		_tableLastIndex = -1;
		return true; 
	}
	return false;
}

Codec37Decoder::Codec37Decoder() {
	_deltaSize = 0;
	_deltaBuf = 0;
	_deltaBufs[0] = 0;
	_deltaBufs[1] = 0;
	_curtable = 0;
	_offsetTable = 0;
	_tableLastPitch = -1;
	_tableLastIndex = -1;
	_prevSeqNb = 32768; // Some invalid number
}

void Codec37Decoder::clean() {
	if(_offsetTable) {
		delete []_offsetTable;
		_offsetTable = 0;
		_tableLastPitch = -1;
		_tableLastIndex = -1;
	}
	if(_deltaBuf) {
		delete []_deltaBuf;
		_deltaSize = 0;
		_deltaBuf = 0;
		_deltaBufs[0] = 0;
		_deltaBufs[1] = 0;
	}
}

Codec37Decoder::~Codec37Decoder() {
	clean();
}

void Codec37Decoder::maketable(int pitch, int index) {
	static const char maketable_bytes[] = {
		0, 0, 1, 0, 2, 0, 3, 0, 5, 0, 8, 0, 13, 0, 21, 0,
		-1, 0, -2, 0, -3, 0, -5, 0, -8, 0, -13, 0, -17, 0, -21, 0,
		0, 1, 1, 1, 2, 1, 3, 1, 5, 1, 8, 1, 13, 1, 21, 1,
		-1, 1, -2, 1, -3, 1, -5, 1, -8, 1, -13, 1, -17, 1, -21, 1,
		0, 2, 1, 2, 2, 2, 3, 2, 5, 2, 8, 2, 13, 2, 21, 2,
		-1, 2, -2, 2, -3, 2, -5, 2, -8, 2, -13, 2, -17, 2, -21, 2,
		0, 3, 1, 3, 2, 3, 3, 3, 5, 3, 8, 3, 13, 3, 21, 3,
		-1, 3, -2, 3, -3, 3, -5, 3, -8, 3, -13, 3, -17, 3, -21, 3,
		0, 5, 1, 5, 2, 5, 3, 5, 5, 5, 8, 5, 13, 5, 21, 5,
		-1, 5, -2, 5, -3, 5, -5, 5, -8, 5, -13, 5, -17, 5, -21, 5,
		0, 8, 1, 8, 2, 8, 3, 8, 5, 8, 8, 8, 13, 8, 21, 8,
		-1, 8, -2, 8, -3, 8, -5, 8, -8, 8, -13, 8, -17, 8, -21, 8,
		0, 13, 1, 13, 2, 13, 3, 13, 5, 13, 8, 13, 13, 13, 21, 13,
		-1, 13, -2, 13, -3, 13, -5, 13, -8, 13, -13, 13, -17, 13, -21, 13,
		0, 21, 1, 21, 2, 21, 3, 21, 5, 21, 8, 21, 13, 21, 21, 21,
		-1, 21, -2, 21, -3, 21, -5, 21, -8, 21, -13, 21, -17, 21, -21, 21,
		0, -1, 1, -1, 2, -1, 3, -1, 5, -1, 8, -1, 13, -1, 21, -1,
		-1, -1, -2, -1, -3, -1, -5, -1, -8, -1, -13, -1, -17, -1, -21, -1,
		0, -2, 1, -2, 2, -2, 3, -2, 5, -2, 8, -2, 13, -2, 21, -2,
		-1, -2, -2, -2, -3, -2, -5, -2, -8, -2, -13, -2, -17, -2, -21, -2,
		0, -3, 1, -3, 2, -3, 3, -3, 5, -3, 8, -3, 13, -3, 21, -3,
		-1, -3, -2, -3, -3, -3, -5, -3, -8, -3, -13, -3, -17, -3, -21, -3,
		0, -5, 1, -5, 2, -5, 3, -5, 5, -5, 8, -5, 13, -5, 21, -5,
		-1, -5, -2, -5, -3, -5, -5, -5, -8, -5, -13, -5, -17, -5, -21, -5,
		0, -8, 1, -8, 2, -8, 3, -8, 5, -8, 8, -8, 13, -8, 21, -8,
		-1, -8, -2, -8, -3, -8, -5, -8, -8, -8, -13, -8, -17, -8, -21, -8,
		0, -13, 1, -13, 2, -13, 3, -13, 5, -13, 8, -13, 13, -13, 21, -13,
		-1, -13, -2, -13, -3, -13, -5, -13, -8, -13, -13, -13, -17, -13, -21, -13,
		0, -17, 1, -17, 2, -17, 3, -17, 5, -17, 8, -17, 13, -17, 21, -17,
		-1, -17, -2, -17, -3, -17, -5, -17, -8, -17, -13, -17, -17, -17, -21, -17,
		0, -21, 1, -21, 2, -21, 3, -21, 5, -21, 8, -21, 13, -21, 21, -21,
		-1, -21, -2, -21, -3, -21, -5, -21, -8, -21, -13, -21, -17, -21, 0, 0,
		-8, -29, 8, -29, -18, -25, 17, -25, 0, -23, -6, -22, 6, -22, -13, -19,
		12, -19, 0, -18, 25, -18, -25, -17, -5, -17, 5, -17, -10, -15, 10, -15,
		0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8, -11, -2, -11, 0, -11,
		2, -11, 8, -11, -15, -10, -4, -10, 4, -10, 15, -10, -6, -9, -1, -9,
		1, -9, 6, -9, -29, -8, -11, -8, -8, -8, -3, -8, 3, -8, 8, -8,
		11, -8, 29, -8, -5, -7, -2, -7, 0, -7, 2, -7, 5, -7, -22, -6,
		-9, -6, -6, -6, -3, -6, -1, -6, 1, -6, 3, -6, 6, -6, 9, -6,
		22, -6, -17, -5, -7, -5, -4, -5, -2, -5, 0, -5, 2, -5, 4, -5,
		7, -5, 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -1, -4, 0, -4,
		1, -4, 3, -4, 5, -4, 10, -4, 13, -4, -8, -3, -6, -3, -4, -3,
		-3, -3, -2, -3, -1, -3, 0, -3, 1, -3, 2, -3, 4, -3, 6, -3,
		8, -3, -11, -2, -7, -2, -5, -2, -3, -2, -2, -2, -1, -2, 0, -2,
		1, -2, 2, -2, 3, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1,
		-4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1,
		4, -1, 6, -1, 9, -1, -31, 0, -23, 0, -18, 0, -14, 0, -11, 0,
		-7, 0, -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0, -31, 1, 0,
		2, 0, 3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 14, 0, 18, 0,
		23, 0, 31, 0, -9, 1, -6, 1, -4, 1, -3, 1, -2, 1, -1, 1,
		0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 6, 1, 9, 1, -11, 2,
		-7, 2, -5, 2, -3, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2,
		3, 2, 5, 2, 7, 2, 11, 2, -8, 3, -6, 3, -4, 3, -2, 3,
		-1, 3, 0, 3, 1, 3, 2, 3, 3, 3, 4, 3, 6, 3, 8, 3,
		-13, 4, -10, 4, -5, 4, -3, 4, -1, 4, 0, 4, 1, 4, 3, 4,
		5, 4, 10, 4, 13, 4, -17, 5, -7, 5, -4, 5, -2, 5, 0, 5,
		2, 5, 4, 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6,
		-1, 6, 1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7,
		0, 7, 2, 7, 5, 7, -29, 8, -11, 8, -8, 8, -3, 8, 3, 8,
		8, 8, 11, 8, 29, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10,
		-4, 10, 4, 10, 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11,
		19, 12, -19, 13, -4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5, 17,
		5, 17, 25, 17, -25, 18, 0, 18, -12, 19, 13, 19, -6, 22, 6, 22,
		0, 23, -17, 25, 18, 25, -8, 29, 8, 29, 0, 31, 0, 0, -6, -22,
		6, -22, -13, -19, 12, -19, 0, -18, -5, -17, 5, -17, -10, -15, 10, -15,
		0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8, -11, -2, -11, 0, -11,
		2, -11, 8, -11, -15, -10, -4, -10, 4, -10, 15, -10, -6, -9, -1, -9,
		1, -9, 6, -9, -11, -8, -8, -8, -3, -8, 0, -8, 3, -8, 8, -8,
		11, -8, -5, -7, -2, -7, 0, -7, 2, -7, 5, -7, -22, -6, -9, -6,
		-6, -6, -3, -6, -1, -6, 1, -6, 3, -6, 6, -6, 9, -6, 22, -6,
		-17, -5, -7, -5, -4, -5, -2, -5, -1, -5, 0, -5, 1, -5, 2, -5,
		4, -5, 7, -5, 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -2, -4,
		-1, -4, 0, -4, 1, -4, 2, -4, 3, -4, 5, -4, 10, -4, 13, -4,
		-8, -3, -6, -3, -4, -3, -3, -3, -2, -3, -1, -3, 0, -3, 1, -3,
		2, -3, 3, -3, 4, -3, 6, -3, 8, -3, -11, -2, -7, -2, -5, -2,
		-4, -2, -3, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 3, -2,
		4, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1, -5, -1, -4, -1,
		-3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1,
		5, -1, 6, -1, 9, -1, -23, 0, -18, 0, -14, 0, -11, 0, -7, 0,
		-5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0, -23, 1, 0, 2, 0,
		3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 14, 0, 18, 0, 23, 0,
		-9, 1, -6, 1, -5, 1, -4, 1, -3, 1, -2, 1, -1, 1, 0, 1,
		1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 9, 1, -11, 2,
		-7, 2, -5, 2, -4, 2, -3, 2, -2, 2, -1, 2, 0, 2, 1, 2,
		2, 2, 3, 2, 4, 2, 5, 2, 7, 2, 11, 2, -8, 3, -6, 3,
		-4, 3, -3, 3, -2, 3, -1, 3, 0, 3, 1, 3, 2, 3, 3, 3,
		4, 3, 6, 3, 8, 3, -13, 4, -10, 4, -5, 4, -3, 4, -2, 4,
		-1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 5, 4, 10, 4, 13, 4,
		-17, 5, -7, 5, -4, 5, -2, 5, -1, 5, 0, 5, 1, 5, 2, 5,
		4, 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6, -1, 6,
		1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7, 0, 7,
		2, 7, 5, 7, -11, 8, -8, 8, -3, 8, 0, 8, 3, 8, 8, 8,
		11, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10, -4, 10, 4, 10,
		15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11, 19, 12, -19, 13,
		-4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5, 17, 5, 17, 0, 18,
		-12, 19, 13, 19, -6, 22, 6, 22, 0, 23,
	};

	if (_tableLastPitch == pitch && _tableLastIndex == index)
		return;
#ifdef DEBUG_CODEC37
	debug(7, "codec37::maketable(%d, %d) called", pitch, index);
#endif
	_tableLastPitch = pitch;
	_tableLastIndex = index;
	index *= 255;
	assert(index + 254 < (int)(sizeof(maketable_bytes) / 2));

	for (int i = 0; i < 255; i++) {
		int j = (i + index) << 1; // * 2
		_offsetTable[i] = maketable_bytes[j + 1] * pitch + maketable_bytes[j];
	}
}

void Codec37Decoder::proc1(Blitter & dst, Chunck & src, int next_offs, int bw, int bh, int size) {
	unsigned char * decoded = new unsigned char[size];
	int w = 0;
	while(!src.eof()) {
		int code = src.getByte();
		int length = (code >> 1) + 1;
		if (code & 1) {
			unsigned char val = src.getByte();
			while(length--)
				decoded[w++] = val;
		} else {
			while(length--) {
				decoded[w++] = src.getByte();
			}
		}
	}
	assert(w == size);
	w = 0;
	// Now we have our stream ready...
	for(int i = 0; i < size; i++) {
		if(decoded[i] == 0xFF) {
			dst.putBlock(decoded + i + 1);
			i += 16;
		} else {
			dst.blockCopy(_offsetTable[decoded[i]] + next_offs);
		}
		if(++w == bw) {
			w = 0;
			dst.advance(0, 3);
		}
	}
	delete []decoded;
}

void Codec37Decoder::proc2(Blitter & dst, Chunck & src, int size) { // This is codec1 like...
#ifdef DEBUG_CODEC37_PROC2
	int decoded_size = 0;
	int coded_size = 0;
#endif
	do {
		int code = src.getByte();
		int length = (code >> 1) + 1;
		size -= length;
#ifdef DEBUG_CODEC37_PROC2
		decoded_size += length;
		coded_size += 1 + ((code & 1) ? 1 : length);

		debug(7, "proc2() : code == %d : length == %d : decoded_size == %d : coded_size == %d : seek - header == %d : size == %d",
			code, length, decoded_size, coded_size, src.tell() - 31, size + decoded_size);
#endif
		if (code & 1)
			dst.put(src.getChar(), length);
		else
			// while(length--) dst.put(src.get_char());
			dst.blit(src, length);
	} while (size);
}

void Codec37Decoder::proc3WithFDFE(Blitter & dst, Chunck & src, int next_offs, int bw, int bh) {
	do {
		int i = bw;
		do {
			int code = src.getByte();
			if (code == 0xFD) {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(1));
#else
				dst.putBlock(expand(src.getByte()));
#endif
			} else if (code == 0xFE) {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(2));
#else
				dst.putBlock(expand(src.getByte()), expand(src.getByte()), expand(src.getByte()), expand(src.getByte()));
#endif
			} else if (code == 0xFF) {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(3));
#else
				dst.putBlock(src);
#endif
			} else {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(4));
#else
				dst.blockCopy(_offsetTable[code] + next_offs); // copy from an offset !
#endif
			}
		} while (--i);
		dst.advance(0, 3); // advance 3 lines
	} while (--bh);
}

void Codec37Decoder::proc3WithoutFDFE(Blitter & dst, Chunck & src, int next_offs, int bw, int bh) {
	do {
		int i = bw;
		do {
			int code = src.getByte();
			if (code == 0xFF) {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(5));
#else
				dst.putBlock(src);
#endif
			} else {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(6));
#else
				dst.blockCopy(_offsetTable[code] + next_offs); // copy from an offset !
#endif
			}
		} while (--i);
		dst.advance(0, 3); // advance 3 lines
	} while (--bh);
}

void Codec37Decoder::proc4(Blitter & dst, Chunck & src, int next_offs, int bw, int bh) {
#ifdef DEBUG_CODEC37_PROC4
	int b_nb = 0;
#endif
	do {
		int i = bw;
		do {
			int code = src.getByte();
			if (code == 0xFD) {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(7));
#else
				dst.putBlock(expand(src.getByte()));
#endif
			} else if (code == 0xFE) {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(8));
#else
				dst.putBlock(expand(src.getByte()), expand(src.getByte()), expand(src.getByte()), expand(src.getByte()));
#endif
			} else if (code == 0xFF) {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(9));
#else
				dst.putBlock(src);
#endif
			} else if (code == 0x00) {
				int length = src.getByte() + 1;
				for (int l = 0; l < length; l++) {
#ifdef USE_COLOR_CODE_FOR_BLOCK
					dst.putBlock(expand(10));
#else
					dst.blockCopy(next_offs);
#endif
					i--;
					if (i == 0) {
						dst.advance(0, 3); // advance 3 lines
						bh--;
						i = bw;
					}
				}
				if(bh == 0) return;
				i++;
			} else {
#ifdef USE_COLOR_CODE_FOR_BLOCK
				dst.putBlock(expand(11));
#else
				dst.blockCopy(_offsetTable[code] + next_offs); // copy from an offset !
#endif
			}
		} while (--i);
		dst.advance(0, 3); // advance 3 lines
	} while (--bh);
}

bool Codec37Decoder::decode(Blitter & dst, Chunck & src) {
	int width = getRect().width();
	int height = getRect().height();
	int bw = (width + 3) >> 2, bh = (height + 3) >> 2;
	int pitch = bw << 2;
#ifdef DEBUG_CODEC37
	debug(7, "codec37::decode() : width == %d : height == %d : pitch == %d : _prevSeqNb == %d",
		width, height, pitch, _prevSeqNb);
#endif
	int code = src.getByte();			// 0 -> 1	(1)
	int index = src.getByte();			// 1 -> 2	(1)
	unsigned short seq_nb	= src.getWord();	// 2 -> 4	(2)
	unsigned int decoded_size = src.getDword();	// 4 -> 8	(4)
#ifdef DEBUG_CODEC37
	unsigned int coded_size	= src.getDword();	// 8 -> 12	(4)
#else
	src.seek(4);
#endif
	unsigned int mask_flag	= src.getDword();	// 12 -> 16	(4)
#ifdef DEBUG_CODEC37
	debug(7, "codec37::decode() : code == %d : index == %d : seq_nb == %d : decoded_size == %d : coded_size == %d : mask_flag == %d",
		code, index, seq_nb, decoded_size, coded_size, mask_flag);
#endif
	maketable(pitch, index);
	if(code == 3 || code == 4 || code == 1) {
		assert(seq_nb && _prevSeqNb + 1 == seq_nb);
		if (seq_nb & 1 || !(mask_flag & 1)) _curtable ^= 1;
	}
	Blitter blit((char *)_deltaBufs[_curtable], Point(width, height), Rect(0, 0, width, height));
	switch(code) {
	case 0:
		memset(_deltaBuf, 0, _deltaBufs[_curtable] - _deltaBuf);
		memset(_deltaBufs[_curtable] + decoded_size, 0, _deltaBuf + _deltaSize - _deltaBufs[_curtable] - decoded_size);
		blit.blit(src, decoded_size);
		break;
	case 1:
		proc1(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh, decoded_size);
		break;
	case 2:
		memset(_deltaBuf, 0, _deltaBufs[_curtable] - _deltaBuf);
		memset(_deltaBufs[_curtable] + decoded_size, 0, _deltaBuf + _deltaSize - _deltaBufs[_curtable] - decoded_size);
		proc2(blit, src, decoded_size);
		break;
	case 3:
		if(mask_flag & 1)
			proc3WithFDFE(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh);
		else
			proc3WithoutFDFE(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh);
		break;
	case 4:
		proc4(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh);
		break;
	default:
#ifdef DEBUG_CODEC37
		error("codec37::decode() received an invalid code : %d", code);
#endif
		break;
	}
	dst.blit((char*)_deltaBufs[_curtable], width * height);
	_prevSeqNb = seq_nb;
	return true;
}


--- NEW FILE: codec37.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/codec37.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __CODEC37_H_
#define __CODEC37_H_

#include "config.h"

#ifdef DEBUG
# ifndef NO_DEBUG_CODEC37
#  define DEBUG_CODEC37
# endif
#else
# ifdef DEBUG_CODEC37
#  error DEBUG_CODEC37 defined without DEBUG
# endif
#endif

#ifdef DEBUG_CODEC37
# ifndef NO_DEBUG_CODEC37_PROCS
#  define DEBUG_CODEC37_PROC1
#  define DEBUG_CODEC37_PROC2
#  define DEBUG_CODEC37_PROC3
#  define DEBUG_CODEC37_PROC4
# endif
#endif

#include "decoder.h"

/*!	@brief ::decoder for codec 37.

*/

#define DELTA_ADD 0x3E00	// what is this 0x3E00 ?? == 320*200/4 - 128
				// It looks like it is a safe-guarding protection from bugs., but maybe not...

class Codec37Decoder : public Decoder {
private:
	int _deltaSize;
	unsigned char * _deltaBufs[2];
	unsigned char * _deltaBuf;
	short * _offsetTable;
	int _curtable;
	unsigned short _prevSeqNb;
	int _tableLastPitch;
	int _tableLastIndex;

public:
	bool initSize(const Point &, const Rect &);
	Codec37Decoder();
	void clean();
	virtual ~Codec37Decoder();
protected:
	static inline unsigned int expand(unsigned char b) {
		unsigned int r = b | (b << 8);
		return r | (r << 16);
	}
	void maketable(int, int);
	void proc1(Blitter &, Chunck &, int, int, int, int);
	void proc2(Blitter &, Chunck &, int);
	void proc3WithFDFE(Blitter &, Chunck &, int, int, int);
	void proc3WithoutFDFE(Blitter &, Chunck &, int, int, int);
	void proc4(Blitter &, Chunck &, int, int, int);
public:
	bool decode(Blitter &, Chunck &);
};

#endif

--- NEW FILE: codec44.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/codec44.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "codec44.h"
#include "chunck.h"
#include "blitter.h"

bool Codec44Decoder::decode(Blitter & dst, Chunck & src) {
	int size_line;
	int num;
	int w, width = getRect().width() + 1;
	int h, height = getRect().height() + 1;
	bool zero;
#ifdef DEBUG_CODEC44
	debug(7, "codec44 : %dx%d", width, height);
#endif

	for(h = 0; h < height - 1; h++) {
		w = width;
		size_line = src.getWord(); // size of compressed line !
#ifdef DEBUG_CODEC44
		debug(7, "codec44 : h == %d, size_line == %d", h, size_line);
#endif
		zero = true;
		while(size_line > 1) {
			num = src.getWord();
			size_line -= 2;
			if(zero) {
#ifdef DEBUG_CODEC44
				debug(7, "codec44 : zeroing %d, entries", num);
#endif
				if(w == num)
					num--;
				w -= num;
				if(num)
					dst.put(0, num);
			} else {
				num += 1;
#ifdef DEBUG_CODEC44
				debug(7, "codec44 : blitting %d, entries", num);
#endif
				if(w == num)
					num--;
				w -= num;
				dst.blit(src, num);
				size_line -= num;
			}
			zero = !zero;
		}
	}
	return true;
}

--- NEW FILE: codec44.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/codec44.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __CODEC44_H_
#define __CODEC44_H_

#include "config.h"

#ifdef DEBUG
# ifndef NO_DEBUG_CODEC44
#  define DEBUG_CODEC44
# endif
#else
# ifdef DEBUG_CODEC44
#  error DEBUG_CODEC44 defined without DEBUG
# endif
#endif

#include "decoder.h"

/*!	@brief ::decoder for codec 21 and 44.

*/
class Codec44Decoder : public Decoder {
public:
	bool decode(Blitter & dst, Chunck & src);
};

#endif

--- NEW FILE: codec47.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/codec47.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "codec47.h"
#include "chunck.h"
#include "blitter.h"

DumpDecoder::~DumpDecoder() {
}

bool DumpDecoder::decode(Blitter & dst, Chunck & src) {
	int n = 0, i = 0;
	int seq = src.getWord();
	int codec = src.getByte();
	int flags = src.getByte();
	int unknown[22];
	for(i = 0; i < 0; i++) {
		unknown[i] = src.getByte();
	}
	if(codec == 5 || codec == 1) {
		do {
			int code = src.getByte();
			int length = (code >> 1) + 1;
			if (code & 1)
				dst.put(src.getChar(), length);
			else
				dst.blit(src, length);
		} while (!src.eof());
	}

	return true;
}

--- NEW FILE: codec47.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/codec47.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __CODEC_47_H_
#define __CODEC_47_H_

#include "config.h"

#include "decoder.h"

/*!	@brief ::decoder for debugging purpose.

*/
class DumpDecoder : public Decoder {
public:
	virtual ~DumpDecoder();
	bool decode(Blitter &, Chunck &);
};

#endif

--- NEW FILE: color.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/color.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "color.h"

Color::Color() : _r(0), _g(0), _b(0) {
}

Color::Color(value_type r, value_type g, value_type b) : _r(r), _g(g), _b(b) {
}

Color::Color(const Color & c) : _r(c._r), _g(c._g), _b(c._b) {
}

Color & Color::operator=(const Color & c) {
	_r = c._r;
	_g = c._g;
	_b = c._b;
	return *this;
}

Color::~Color() {
}

Color::value_type Color::red() const { 
	return _r; 
}

Color::value_type Color::green() const { 
	return _g; 
}

Color::value_type Color::blue() const { 
	return _b;
}

void Color::delta(short * ptr) {
	// This is a very specific method for XPALs.
	int t;
#define UPDATE_COLOR(c, inc) (((int)((c)) << 7) + (c) + (inc)) >> 7
#define CHECK_BOUNDS(c) (((c) > 255) ? 255 : (((c) < 0) ? 0 : (c)))
	t = UPDATE_COLOR(_r, ptr[0]);
	_r = CHECK_BOUNDS(t);
	t = UPDATE_COLOR(_g, ptr[1]);
	_g = CHECK_BOUNDS(t);
	t = UPDATE_COLOR(_b, ptr[2]);
	_b = CHECK_BOUNDS(t);
#undef UPDATE_COLOR
#undef CHECK_BOUNDS
}

--- NEW FILE: color.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/color.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __COLOR_H_
#define __COLOR_H_

#include "config.h"

/*! 	@brief simple class for handling a color.

	This small class is an helper for colors.
*/
class Color {
public:
	typedef unsigned char value_type;	//!< The type of the color components.
private:
	value_type _r;	//!< The red component.
	value_type _g;	//!< The green component.
	value_type _b;	//!< The blue component.
public:
	Color();
	Color(value_type, value_type, value_type);
	Color(const Color &);
	Color & operator=(const Color &);
	virtual ~Color();
	value_type red() const;
	value_type green() const;
	value_type blue() const;
	/*!	@brief handle delta palette modification

		This method is used specifically by player::handleDeltaPalette().
		It updates the color component using delta values given as short.

		@param ptr pointer to a table of 3 shorts that contain delta values to use.
	*/
	void delta(short * ptr);
};

#endif

--- NEW FILE: config.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/config.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __CONFIG_H_
#define __CONFIG_H_

#include <stdafx.h>
#include <scumm.h>

#ifndef NDEBUG
#define DEBUG
#endif

//~ #define NO_DEBUG_MIXER
//~ #define NO_DEBUG_CHANNEL
//~ #define NO_DEBUG_CLIPPER
#define NO_DEBUG_CODEC1
#define NO_DEBUG_CODEC37
#define NO_DEBUG_CODEC44
//~ #define NO_DEBUG_WIN32
//~ #define NO_DEBUG_FONT_RENDERER


#endif

--- NEW FILE: decoder.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/decoder.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __DECODER_H_
#define __DECODER_H_

#include "config.h"

#include "rect.h"

class Blitter;
class Chunck;

/*!	@brief base class for codec decompression.

	This class provides an interface for codec decompression.

*/
class Decoder {
private:
	Rect _r;			//!< current size of the frame object to decode
	Point _p;			//!< position of the frame object to decode
protected:
	const Rect & getRect() const{ return _r; }
	const Point & getSize() const { return _p; }
public:
	Decoder() {};
	virtual ~Decoder() {};
	virtual bool initSize(const Point & p, const Rect & r) { _p = p; _r = r; return true; };
	virtual bool decode(Blitter &, Chunck &) = 0;
};

#endif

--- NEW FILE: frenderer.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/frenderer.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "frenderer.h"
#include "rect.h"

#include <assert.h>
#include <string.h> // for memcpy, strcat, strdup

#ifndef max
#define max(x, y) ((x) > (y) ? (x) : (y))
#endif

FontRenderer::FontRenderer(bool use_original_colors) : _nbChars(0), _color(-1), _original(use_original_colors) {
}

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

void FontRenderer::save(int frame) {
	_chars[_nbChars].width = getWidth();
	_chars[_nbChars].height = getHeight();
	int size = getWidth() * getHeight();
	_chars[_nbChars].chr = new char[size];
	memcpy(_chars[_nbChars].chr, data(), size);
	_nbChars++;
}

int FontRenderer::charWidth(int v) const {
	if(v < 0) v = 256 + v;
	if(v < 0 || v >= _nbChars) error("invalid character in FontRenderer::charWidth : %d (%d)", v, _nbChars);
	return _chars[v].width;
}

int FontRenderer::charHeight(int v) const {
	if(v < 0) v = 256 + v;
	if(v < 0 || v >= _nbChars) error("invalid character in FontRenderer::charHeight : %d (%d)", v, _nbChars);
	return _chars[v].height;
}

int FontRenderer::stringWidth(const char * str) const {
	int ret = 0;

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

	return ret;
}

int FontRenderer::stringHeight(const char * str) const {
	int ret = 0;

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

	return ret;
}

int FontRenderer::drawChar(char * buffer, const Point & size, int x, int y, int chr) const {
	int w = _chars[chr].width;
	int h = _chars[chr].height;
	char * src = _chars[chr].chr;
	char * dst = buffer + size.getX() * y + x;

	if(_original) {
		for(int j = 0; j < h; j++) {
			for(int i = 0; i < w; i++) {
				int value = *src++;
				if(value) dst[i] = value;
			}
			dst += size.getX();
		}
	} else {
		int color = (_color != -1) ? _color : 1;
		for(int j = 0; j < h; j++) {
			for(int i = 0; i < w; i++) {
				int value = *src++;
				if(value == 1) {
					dst[i] = color;
				} else if(value) {
					dst[i] = 0;
				}
			}
			dst += size.getX();
		}
	}
	return w;
}

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

	while(j != NULL) {
		assert(n < 30);
		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 FontRenderer::drawSubstring(const unsigned char * str, char * buffer, const Point & size, int x, int y) const {
	for(int i = 0; str[i] != 0; i++)
		x += drawChar(buffer, size, x, y, str[i]);
}

bool FontRenderer::drawStringAbsolute(const char * str, char * buffer, const Point & size, int x, int y) const {
	debug(9, "FontRenderer::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((const unsigned char *)line, buffer, size, x, y);
		y += stringHeight(line);
	}
	return true;
}

bool FontRenderer::drawStringCentered(const char * str, char * buffer, const Point & size, int y, int xmin, int width, int offset) const {
	debug(9, "FontRenderer::drawStringCentered(%s, %d, %d)", str, xmin, y);
	assert(strchr(str, '\n') == 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] = stringWidth(words[i]);

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

	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 += stringHeight(substr);
	}

	delete []sizes;
	for(i = 0; i < nb_sub; i++) {
		delete []words[i];
	}
	delete []words;
	
	max_width = (max_width + 1) >> 1;
	// we have a box from 0 -> max_width
	// we want a box from (xmin + offset) - max_width / 2, (xmin + offset) + max_width / 2
	int x = xmin + width / 2;
	x += offset - size.getX() / 2;

	if(x < max_width) x = max_width;
	if(x + max_width > size.getX()) {
		x = size.getX() - max_width;
	}

	if(y + height > size.getY()) {
		y = size.getY() - height;
	}

	for(i = 0; i < nb_subs; i++) {
		int substr_width = substr_widths[i];
		drawSubstring((const unsigned char *)substrings[i], buffer, size, x - substr_width / 2, y);
		y += stringHeight(substrings[i]);
		delete []substrings[i];
	}

	delete []substr_widths;
	delete []substrings;
	return true;
}

--- NEW FILE: frenderer.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/frenderer.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __FRENDERER_H_
#define __FRENDERER_H_

#include "config.h"

#ifdef DEBUG
# ifndef NO_DEBUG_FONT_RENDERER
#  define DEBUG_FONT_RENDERER
# endif
#else
# ifdef DEBUG_FONT_RENDERER
#  error DEBUG_FONT_RENDERER defined without DEBUG
# endif
#endif

#include "brenderer.h"
#include "rect.h"
#include "blitter.h"

/*!	@brief ::renderer implementation specifically designed for font files.

	This class is a valid ::renderer implementation. The frames are kept in memory, as bitmap representing characters, so that 
	they can be rendered again in another frame as strings. 
	
	This class also contains some functions useful for printing strings. This is used to show subtitles and more generally texts
	in animations.
	
	@todo update the mehod to use the ::blitter class, instead of direct pointers.
*/
class FontRenderer : public BaseRenderer {
private:
	int _nbChars;	//!< The number of frames in the font
	int _color;		//!< A color parameter used for font printing.
	bool _original;	//!< flag for color selection
	struct {
		int width;
		int height;
		char * chr;
	} _chars[256]; //!< array that contains the size of the different frames (i.e. characters) of the font.
public:
	/*!	@brief font_renderer constructor
		
		@param use_original_colors	flag to indicate if the font use it's own color, or if the base color are set at runtime.
	*/
	FontRenderer(bool use_original_colors = false);
	virtual ~FontRenderer();
	virtual bool wait(int ms) { return true; };
protected:
	virtual void save(int frame = -1);
	/*!	@brief get the width of a character.
		
		@param c	the character we want the width from.

		@return the width of the character
	*/
	int charWidth(int c) const;
	/*!	@brief get the width of a string.
		
		@param str	the string we want the width from.

		@return the complete width of the string
	*/
	int stringWidth(const char * str) const;
	/*!	@brief get the height of a character.
		
		@param c	the character we want the height from.

		@return the height of the character
	*/
	int charHeight(int c) const;
	/*!	@brief get the height of a string.
		
		@param str	the string we want the height from.

		@return the complete height of the string
	*/
	int stringHeight(const char * str) const;
	/*!	@brief draw a character in the given frame buffer.
		
		@param buffer	the frame buffer to draw into.
		@param size		the size of the frame buffer.
		@param x		the horizontal position of the topleft corner of the character.
		@param y		the vertical position of the topleft corner of the character.
		@param c		the character to draw.
		
		@bug	This method does not clip. This is not really a bug, as it should always be correctly called, but some asserts would be welcome.

		@return the width of the character
	*/
	int drawChar(char * buffer, const Point & size, int x, int y, int c) const;
	/*!	@brief draw a string in the given frame buffer.
		
		@param str		the string to draw.
		@param buffer	the frame buffer to draw into.
		@param size		the size of the frame buffer.
		@param x		the horizontal position of the topleft corner of the string.
		@param y		the vertical position of the topleft corner of the string.

		@bug	This method does not clip. This is not really a bug, as it should always be correctly called, but some asserts would be welcome.
	*/
	void drawSubstring(const unsigned char * str, char * buffer, const Point & size, int x, int y) const;
public:
	/*!	@brief change the programmable color of the font.
		
		@param c		the new color to use.

		@return \c true if everything went fine, \c false otherwise
	*/
	bool setColor(int c) { _color = c; return true; }
	/*!	@brief draw a centered and possibly using multiple lines string.
	
		This method performs calculation of the string size before choosing where to draw it.
		As I still not have figured out exactly what is the meaning of the fields in the TRES chunck, 
		the real meaning of the parameters can be quite difficult to understand.
	
		@remark	The current implementation is incorrect in the sense that it does not conform to the original game.
		@todo	rewrite and rethink this to better match the original implementation.
		
		@param str		the string to draw.
		@param buffer	the frame buffer to draw into.
		@param size		the size of the frame buffer.
		@param y		the vertical position of the topleft corner of the string. This position may be changed if it is too low to be correctly drawn.
		@param xmin		the minimum horizontal position of the topleft corner of the string.
		@param width		the maximum width of the string. If the string is too long, it will wrap.
		@param offset	offset to give to the horizontal position.

		@return \c true if everything went fine, \c false otherwise
	*/
	bool drawStringCentered(const char * str, char * buffer, const Point & size, int y, int xmin, int width, int offset) const;
	/*!	@brief draw a string at an absolute position.
	
		@param str		the string to draw.
		@param buffer	the frame buffer to draw into.
		@param size		the size of the frame buffer.
		@param x		the horizontal position of the topleft corner of the string.
		@param y		the vertical position of the topleft corner of the string. This position may be changed if it is too low to be correctly drawn.

		@return \c true if everything went fine, \c false otherwise
	*/
	bool drawStringAbsolute(const char * str, char * buffer, const Point & size, int x, int y) const;
};

#endif

--- NEW FILE: imuse_channel.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/imuse_channel.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "channel.h"
#include "chunck.h"
#include "chunck_type.h"

#include <assert.h>
#include <string.h> // for memcpy.h
#ifndef min
#define min(x, y) ((x) > (y) ? (y) : (x))
#endif

ImuseChannel::ImuseChannel(int track, int freq) : 
			_track(track), 
			_tbuffer(0), 
			_tbufferSize(0), 
			_sbuffer(0), 
			_sbufferSize(0), 
			_frequency(freq), 
			_dataSize(-1),
			_inData(false) {
}

ImuseChannel::~ImuseChannel() {
	if(_tbuffer) {
		delete []_tbuffer; 
	}
	if(_sbuffer) {
		warning("_sbuffer should be 0 !!!");
		delete []_sbuffer; 
	}
}

bool ImuseChannel::isTerminated() const {
	return (_dataSize <= 0 && _sbuffer == 0);
}

bool ImuseChannel::setParameters(int nbframes, int size, int unk1, int unk2) {
	return true;
}

bool ImuseChannel::checkParameters(int index, int nbframes, int size, int unk1, int unk2) {
	return true;
}

bool ImuseChannel::appendData(Chunck & b, int size) {
	if(_dataSize == -1) { // First call
		assert(size > 8);
		Chunck::type imus_type = b.getDword(); imus_type = TO_BE_32(imus_type);
		unsigned int imus_size = b.getDword(); imus_size = TO_BE_32(imus_size);
		if(imus_type != TYPE_iMUS) error("Invalid CHUNCK for imuse_channel");
		size -= 8;
		_tbufferSize = size;
		assert(_tbufferSize);
		_tbuffer = new unsigned char[_tbufferSize];
		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
	} else {
		if(_tbuffer) { // remaining from last call
			unsigned char * old = _tbuffer;
			int new_size = size + _tbufferSize;
			_tbuffer = new unsigned char[new_size];
			if(!_tbuffer)  error("imuse_channel failed to allocate memory");
			memcpy(_tbuffer, old, _tbufferSize);
			delete []old;
			b.read(_tbuffer + _tbufferSize, size);
			_tbufferSize += size;
		} else {
			_tbufferSize = size;
			_tbuffer = new unsigned char[_tbufferSize];
			if(!_tbuffer)  error("imuse_channel failed to allocate memory");
			b.read(_tbuffer, size);
		}
	}
	return processBuffer();
}

bool ImuseChannel::handleFormat(Chunck & src) {
	if(src.getSize() != 20) error("invalid size for FRMT chunck");
	unsigned imuse_start = src.getDword();
	imuse_start = TO_BE_32(imuse_start);
	src.seek(4);
	_bitsize = src.getDword();
	_bitsize = TO_BE_32(_bitsize);
	_rate = src.getDword();
	_rate = TO_BE_32(_rate);
	_channels = src.getDword();
	_channels = TO_BE_32(_channels);
	assert(_channels == 1 || _channels == 2);
	return true;
}

bool ImuseChannel::handleText(Chunck & src) {
	return true;
}

bool ImuseChannel::handleRegion(Chunck & src) {
	if(src.getSize() != 8) error("invalid size for REGN chunck");
	return true;
}

bool ImuseChannel::handleStop(Chunck & src) {
	if(src.getSize() != 4) error("invalid size for STOP chunck");
	return true;
}

bool ImuseChannel::handleMap(Chunck & map) {
	while(!map.eof()) {
		Chunck * sub = map.subBlock();
		switch(sub->getType()) {
			case TYPE_FRMT:
				handleFormat(*sub);
				break;
			case TYPE_TEXT:
				handleText(*sub);
				break;
			case TYPE_REGN:
				handleRegion(*sub);
				break;
			case TYPE_STOP:
				handleStop(*sub);
				break;
			default:
				error("Unknown iMUS subchunck found : %s, %d", Chunck::ChunckString(sub->getType()), sub->getSize());
		}
		delete sub;
	}
	return true;
}

void ImuseChannel::decode() {
	int remaining_size = _sbufferSize % 3;
	if(remaining_size) {
		_srbufferSize -= remaining_size;
		assert(_inData);
		if(_tbuffer == 0) {
			_tbuffer = new unsigned char[remaining_size];
			memcpy(_tbuffer, _sbuffer + _sbufferSize - remaining_size, remaining_size);
			_tbufferSize = remaining_size;
			_sbufferSize -= remaining_size;
		} else {
			warning("impossible ! : %p, %d, %d, %p(%d), %p(%d, %d)",
				this, _dataSize, _inData, _tbuffer, _tbufferSize, _sbuffer, _sbufferSize, _srbufferSize);
			unsigned char * old = _tbuffer;
			int new_size = remaining_size + _tbufferSize;
			_tbuffer = new unsigned char[new_size];
			if(!_tbuffer)  error("imuse_channel failed to allocate memory");
			memcpy(_tbuffer, old, _tbufferSize);
			delete []old;
			memcpy(_tbuffer + _tbufferSize, _sbuffer + _sbufferSize - remaining_size, remaining_size);
			_tbufferSize += remaining_size;
		}
	}
	int loop_size = _sbufferSize / 3;
	int new_size = loop_size * 2;
	short * keep, * decoded;
	keep = decoded = new short[new_size];
	assert(keep);
	unsigned char * source = _sbuffer;
	while(loop_size--) {
		int v1 =  *source++;
		int v2 =  *source++;
		int v3 =  *source++;
		int value = (((v2 & 0x0f) << 12) | (v1 << 4)) - 0x8000;
		*decoded++ = (short)value;
		value = (((v2 & 0xf0) << 8) | (v3 << 4)) - 0x8000;		
		*decoded++ = (short)value;
	}
	delete []_sbuffer;
	_sbuffer = (unsigned char*)keep;
	_sbufferSize = new_size * sizeof(short);
}

bool ImuseChannel::handleSubTags(int & offset) {
	int available_size = _tbufferSize - offset;
	if(available_size >= 8) {
		Chunck::type type = READ_BE_UINT32(_tbuffer + offset);
		unsigned int size = READ_BE_UINT32(_tbuffer + offset + 4);
		switch(type) {
			case TYPE_MAP_: 
				_inData = false;
				if(available_size >= (size + 8)) {
					ContChunck c((char*)_tbuffer + offset);
					handleMap(c);
				}
				break;
			case TYPE_DATA: // Sound data !!!
				_inData = true;
				_dataSize = size;
				offset += 8;
				{
					int reqsize = 1;
					if(_channels == 2) reqsize *= 2;
					if(_bitsize == 16) reqsize *= 2;
					else if(_bitsize == 12) {
						if(reqsize > 1)
							reqsize = reqsize * 3 / 2;
						else reqsize = 3;
					}
					if((size % reqsize) != 0) {
						warning("Invalid iMUS sound data size : (%d %% %d) != 0, correcting...", size, reqsize);
						size += 3 - (size % reqsize);
					}
				}
				return false;
			default:
				error("unknown chunck in iMUS track : %s ", Chunck::ChunckString(type));
		}
		offset += size + 8;
		return true;
	}
	return false;
}

bool ImuseChannel::processBuffer() {
	// see comments in saud_channel::processBuffer for an explanation
	assert(_tbuffer != 0);
	assert(_tbufferSize != 0);
	assert(_sbuffer == 0);
	assert(_sbufferSize == 0);
	
	if(_inData) {
		if(_dataSize < _tbufferSize) {			
			int offset= _dataSize;
			while(handleSubTags(offset));
			_sbufferSize = _dataSize;
			_sbuffer = _tbuffer;
			if(offset < _tbufferSize) { // there is still some unprocessed data
				int new_size = _tbufferSize - offset;
				_tbuffer = new unsigned char[new_size];
				if(!_tbuffer)  error("imuse_channel failed to allocate memory");
				memcpy(_tbuffer, _sbuffer + offset, new_size);
				_tbufferSize = new_size;
			} else {
				_tbuffer = 0;
				_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;
			_tbuffer = 0;
		}
	} else {
		int offset = 0;
		while(handleSubTags(offset));
		if(_inData) {
			//~ unsigned char * old = _tbuffer;
			_sbufferSize = _tbufferSize - offset;
			assert(_sbufferSize);
			_sbuffer = new unsigned char[_sbufferSize];
			if(!_sbuffer)  error("imuse_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;
				int new_size = _tbufferSize - offset;
				_tbuffer = new unsigned char[new_size];
				if(!_tbuffer)  error("imuse_channel failed to allocate memory");
				memcpy(_tbuffer, old + offset, new_size);
				_tbufferSize = new_size;
				delete []old;
			}
		}
	}
	_srbufferSize = _sbufferSize;
	if(_sbuffer && _bitsize == 12) decode();
	return true;
}

int ImuseChannel::availableSoundData(void) const {
	int ret = _sbufferSize;
	if(_channels == 2) ret /= 2;
	if(_bitsize > 8) ret /= 2;
	return ret;
}

void ImuseChannel::getSoundData(short * snd, int size) {
	if(_dataSize <= 0 || _bitsize <= 8) error("invalid call to imuse_channel::read_sound_data()");
	if(_channels == 2) size *= 2;
	for(int i = 0; i < size; i++)
		snd[i] = READ_BE_UINT16(_sbuffer + 2 * i);
	delete []_sbuffer;
	assert(_sbufferSize == 2 * size);
	_sbuffer = 0;
	_sbufferSize = 0;
	_dataSize -= _srbufferSize;
}

void ImuseChannel::getSoundData(char * snd, int size) {
	if(_dataSize <= 0 || _bitsize > 8) error("invalid call to imuse_channel::read_sound_data()");
	if(_channels == 2) size *= 2;
	for(int i = 0; i < size; i++)
		snd[i] = _sbuffer[i];
	delete []_sbuffer;
	_sbuffer = 0;
	_sbufferSize = 0;
	_dataSize -= _srbufferSize;
}

--- NEW FILE: mixer.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/mixer.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __MIXER_H_
#define __MIXER_H_

#include "config.h"

#ifdef DEBUG
# ifndef NO_DEBUG_MIXER
#  define DEBUG_MIXER
# endif
#else
# ifdef DEBUG_MIXER
#  error DEBUG_MIXER defined without DEBUG
# endif
#endif

class _Channel;

class SoundRenderer;

/*! 	@brief The class for the player's sound mixer

	This class is used for sound mixing.
	It contains a list of current track and request them to mix.
	It then sends the mixed sound samples to the sound renderer.

*/
class Mixer {
public:
	virtual ~Mixer() {};
	virtual bool init() = 0;
	virtual _Channel * findChannel(int track) = 0;
	virtual bool addChannel(_Channel * c) = 0;
	virtual bool handleFrame() = 0;
	virtual bool stop() = 0;
};

#endif

--- NEW FILE: palette.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/palette.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "palette.h"
#include "assert.h"

Palette::Palette() {
}

Palette::Palette(unsigned char * ptr) {
	for(int i = 0; i < 256; i++) {
		_colors[i] = Color(ptr[3 * i + 0], ptr[3 * i + 1], ptr[3 * i + 2]);
	}
}

Palette::Palette(const Palette & p) {
	for(int i = 0; i < 256; i++) {
		_colors[i] = p._colors[i];
	}
}

const Color & Palette::operator[](int a) const {
	assert(a >= 0 && a < 256);
	return _colors[a];
}

Color & Palette::operator[](int a) {
	assert(a >= 0 && a < 256);
	return _colors[a];
}

Palette & Palette::operator=(const Palette & p) {
	for(int i = 0; i < 256; i++) {
		_colors[i] = p._colors[i];
	}
	return *this;
}

--- NEW FILE: palette.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/palette.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __PALETTE_H_
#define __PALETTE_H_

#include "config.h"

#include "color.h"

/*! 	@brief simple class for handling a palette.

	This small class is an helper for palettes.
*/
class Palette {
private:
	Color _colors[256];
public:
	Palette();
	Palette(unsigned char *);
	Palette(const Palette &);
	const Color & operator[](int) const;
	Color & operator[](int);
	Palette & operator=(const Palette &);
};

#endif

--- NEW FILE: player.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/player.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "player.h"

#include "renderer.h"
#include "channel.h"
#include "chunck_type.h"
#include "rect.h"
#include "blitter.h"

#include <assert.h>
#include <stdlib.h> // for atoi
#include <stdio.h> // for FILE, fopen, fclose, fread, fseek, ftell
#include <string.h> // for strchr, strrchr
#include <ctype.h> // for isdigit

#ifndef max
#define max(x, y) ((x) > (y) ? (x) : (y))
#endif

const int WAIT = 100;

/*!	@brief parser and map of string resources

	This class implements a parser for the string resource format of SMUSH animations.
	It then allows the player to get the string corresponding to a particular identifier.
	
	@bug some of The Dig strings are not completely parsed (in titles)
*/

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(int i = 0; i < _nbStrings; i++) {
			delete []_strings[i].string;
		}
	}
	/*!	@brief parse the given buffer

		@param buffer the buffer that contain the resource (in lucasart format)
		@param length the length of the buffer

		@return \c true if the parsing went fine, \c false otherwise
	*/
	bool init(char * buffer, int length) {
		debug(9, "parsing string resources...");
		char * def_start = strchr(buffer, '#');
		while(def_start != NULL) {
			char * def_end = strchr(def_start, '\n');
			assert(def_end != NULL); // def_end is just before the start of the string [def_start,def_end] correspond to the definition text
			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--;
			// [id_start-id_end] is the id number
			char idstring[32];
			memcpy(idstring, id_start, id_end - id_start);
			idstring[id_end - id_start] = 0;
			int id = atoi(idstring);
			//~ assert(id != LONG_MIN && id != 0 && id != LONG_MAX);
			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;
#ifdef DEBUG
			debug(9, "Inserting (%s)%d == \"%s\"", idstring, id, value);
#endif				
			_strings[_nbStrings].id = id;
			_strings[_nbStrings].string = value;
			_nbStrings ++;
			def_start = strchr(data_end + 2, '#');
		}
		return true;
	}
	/*!	@brief extract a string

		@param id the resource identifier

		@return the corresponding string.
	*/
	const 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;
	}
};

void SmushPlayer::show(const char * p) {
	if(strcmp(p, "subtitles") == 0)
		_subtitles = true;
	else if(strcmp(p, "bgmusic") == 0)
		_bgmusic = true;
	else if(strcmp(p, "voices") == 0)
		_voices = true;
	else {
		int id = atoi(p);
		if(id < 0 || id > 36) error("invalid parameter to show");
		_skips[id] = true;
	}
}

void SmushPlayer::hide(const char * p) {
	if(strcmp(p, "subtitles") == 0)
		_subtitles = false;
	else if(strcmp(p, "bgmusic") == 0)
		_bgmusic = false;
	else if(strcmp(p, "voices") == 0)
		_voices = false;
	else {
		int id = atoi(p);
		if(id < 0 || id > 36) error("invalid parameter to hide");
		_skips[id] = false;
	}
}

SmushPlayer::SmushPlayer(Renderer * renderer, bool wait, bool sound) :
							_version(-1),
							_secondaryVersion(0),
							_soundFrequency(0),
							_nbframes(0),
							_mixer(0),
							_renderer(renderer),
							_strings(0),
							_frameSize(-1, -1),
							_frame(0),
							_outputSound(sound),
							_wait(wait),
							_alreadyInit(false),
							_codec37Called(false),
							_skipNext(false),
							_subtitles(true),
							_bgmusic(true),
							_voices(true) {
	_fr[0] = _fr[1] = _fr[2] = _fr[3] = 0;
	assert(_renderer != 0);
}

SmushPlayer::~SmushPlayer() {
	clean();
	//~ if(_mixer) delete _mixer;
}

void SmushPlayer::updatePalette(void) { 
	_renderer->setPalette(_pal); 
}

void SmushPlayer::clean() {
	if(_strings) 
		delete _strings;
	if(_fr[0]) delete _fr[0];
	if(_fr[1]) delete _fr[1];
	if(_fr[2]) delete _fr[2];
	if(_fr[3]) delete _fr[3];
}

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

void SmushPlayer::handleSoundBuffer(int track_id, int index, int max_frames, int flags, int vol, int bal, Chunck & b, int size) {
	debug(6, "smush_player::handleSoundBuffer(%d)", track_id);
	if(!_voices && (flags & 128) == 128) return;
	if(!_bgmusic && (flags & 64) == 64) return;
	_Channel * c = _mixer->findChannel(track_id);
	if(c == 0) {
		c = new SaudChannel(track_id,  _soundFrequency);
		_mixer->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(Chunck & b) {
	checkBlock(b, TYPE_PSAD);
	debug(6, "SmushPlayer::handleSoundFrame()");
	if(!_outputSound) return;
	int track_id = b.getWord();
	int index = b.getWord();
	int max_frames = b.getWord();
	int flags = b.getWord();
	int vol = b.getByte();
	int 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
	int size = b.getSize() - 10;
	handleSoundBuffer(track_id, index, max_frames, flags, vol, bal, b, size);
}

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

void SmushPlayer::handleStore(Chunck & b) {
	checkBlock(b, TYPE_STOR, 4);
	debug(6, "SmushPlayer::handleStore()");
}

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

void SmushPlayer::handleImuseBuffer(int track_id, int index, int nbframes, int size, int unk1, int unk2, Chunck & b, int bsize) {
	_Channel * c = _mixer->findChannel(track_id);
	if(c == 0) {
		c = new ImuseChannel(track_id, _soundFrequency);
		_mixer->addChannel(c);
	}
	if(index == 0)
		c->setParameters(nbframes, size, unk1, unk2);
	else
		c->checkParameters(index, nbframes, size, unk1, unk2);
	c->appendData(b, bsize);
}

void SmushPlayer::handleImuseAction8(Chunck & b, int flags, int unknown, int track_id) {
	assert(flags == 46 && unknown == 0);
	int unknown2 = b.getWord();
	track_id |= unknown2 << 16;
	int index = b.getWord();
	int nbframes = b.getWord();
	int size = b.getDword();
	int bsize = b.getSize() - 18;
	handleImuseBuffer(track_id, index, nbframes, size, unknown, unknown2, b, bsize);
}

void SmushPlayer::handleImuseAction(Chunck & b) {
	checkBlock(b, TYPE_IACT, 8);
	debug(6, "SmushPlayer::handleImuseAction()");
	if(!_outputSound) return;
	int code = b.getWord();
	int flags = b.getWord();
	int unknown = b.getShort();
	int track_id = b.getWord();
#ifdef DEBUG
	debug(5, "handleImuseAction(%d, %d, %d, %d)", code, flags, unknown, track_id);
#endif
	switch(code) {
		case 8:
			handleImuseAction8(b, flags, unknown, track_id);
			break;
#ifdef DEBUG
		default: {
				debug(9, "%5.5d %d %8.8d %4.4d", track_id, flags, unknown);
			}
#endif
	}
}

void SmushPlayer::handleTextResource(Chunck & b) {
	checkBlock(b, TYPE_TRES, 18); 
	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();
	int height = b.getShort();
	int unk2 = b.getWord();
	int string_id = b.getWord();
	debug(6, "SmushPlayer::handleTextResource(%d)", string_id);
	if(!_strings) return;

	// if subtitles disabled and bit 3 is set, then do not draw
	if((!_subtitles) && ((flags & 8) == 8)) return;
	const char * str = _strings->get(string_id);

	FontRenderer * fr = _fr[0];
	int color = 15;
	while(*str == '/') str++; // For Full Throttle text resources
	while(str[0] == '^') {
		switch(str[1]) {
		case 'f':
			{
#if 0
				// This cause trouble if the next character is a digit.
				int id = atoi(str+2);
#else
				// assume ASCII like character set...
				int id = str[3] - '0';
#endif
				str += 4;
				fr = _fr[id]; 
			} break;
		case 'c':
			{
				//~ int id = atoi(str+2);
				color = str[4] - '0' + 10 *(str[3] - '0');
				str += 5;
			} break;
		default:
			error("invalid escape code in text string");
		}
	}
	assert(fr != 0);
	fr->setColor(color);
	if(!_curBuffer) { _curBuffer = _renderer->lockFrame(_frame); }
	if(flags == 0 || flags == 4) {
		fr->drawStringAbsolute(str, _curBuffer, _frameSize, pos_x, pos_y);
	} else {
		fr->drawStringCentered(str, _curBuffer, _frameSize, max(pos_y, top), left, width, pos_x);
	}
}

void SmushPlayer::readPalette(Palette & out, Chunck & in) {
	unsigned char buffer[768];
	in.read(buffer, 768);
	out = Palette(buffer);
}

void SmushPlayer::handleDeltaPalette(Chunck & b) {
	checkBlock(b, TYPE_XPAL);
	debug(6, "SmushPlayer::handleDeltaPalette()");
	if(b.getSize() == 768 * 3 + 4) {
		int unk1, num;
		unk1 = b.getWord();
		num = b.getWord();
		for(int i = 0; i < 768; i++) {
			_deltaPal[i] = b.getWord();
		}
		readPalette(_pal, b);
		updatePalette();
	} else if(b.getSize() == 6) {
		int unk1, num, unk2;
		unk1 = b.getWord();
		num = b.getWord();
		unk2 = b.getWord();
		for(int i = 0; i < 256; i++) {
			_pal[i].delta(_deltaPal + 3 * i);
		}
		updatePalette();
	} else {
		error("wrong size for DeltaPalette");
	}
}

void SmushPlayer::handleNewPalette(Chunck & b) {
	checkBlock(b, TYPE_NPAL, 768);
	debug(6, "SmushPlayer::handleNewPalette()");
	readPalette(_pal, b);
	updatePalette();
}

void SmushPlayer::decodeCodec(Chunck & b, const Rect & r, Decoder & codec) {
	assert(_curBuffer);
	Blitter blit(_curBuffer, _frameSize, r);
	codec.decode(blit, b);
}

void SmushPlayer::initSize(const Rect & r, bool always, bool transparent) {
	if(_codec37Called) _alreadyInit = true;
		
	if(!_alreadyInit || _frameSize.getX() < r.right() || _frameSize.getY() < r.bottom() || always) {
		if(_curBuffer) {
			_renderer->unlockFrame();
			_curBuffer = 0;
		}
		_frameSize = r.bottomRight();
		_renderer->initFrame(_frameSize);
	}

	if(_curBuffer) {
		_renderer->unlockFrame();
		_curBuffer = 0;
	}

	_curBuffer = _renderer->lockFrame(_frame);
	if(!_alreadyInit && transparent) {
		memset(_curBuffer, 0, _frameSize.getX()*_frameSize.getY());
	}

	_codec1.initSize(_frameSize, r);
	_codec37.initSize(_frameSize, r);
	_codec44.initSize(_frameSize, r);
	_codecd.initSize(_frameSize, r);
	_alreadyInit = true;
}

void SmushPlayer::handleFrameObject(Chunck & b) {
	checkBlock(b, TYPE_FOBJ, 14);
	if(_skipNext) {
		_skipNext = false;
		return;
	}
	int codec = b.getWord();
	debug(6, "SmushPlayer::handleFrameObject(%d)", codec);
	unsigned short left = b.getWord();
	unsigned short top = b.getWord();
	unsigned short width = b.getWord();
	unsigned short height = b.getWord();
	Rect r(left, top, left + width, top + height);
	unsigned short data[2];
	data[1] = b.getWord();
	data[0] = b.getWord();
#ifdef DEBUG
	debug(5, "Frame pos : %d, %d", left, top);
	debug(5, "Frame size : %dx%d", width, height);
	debug(5, "Codec : %d", codec);
#endif
	switch (codec) {
	case 3:
	case 1:
		initSize(r, false, true);
		decodeCodec(b, r, _codec1);
		break;
	case 37:
		assert(left == 0 && top == 0);
		initSize(r, true, false);
		decodeCodec(b, r, _codec37);
		_codec37Called = true;
		break;
	case 47:
		initSize(r, false, true);
		decodeCodec(b, r, _codecd);
		break;
	case 21:
	case 44:
		initSize(r, true, true);
		decodeCodec(b, r, _codec44);
		break;
	default:
		error("Invalid codec for frame object : %d", (int)codec);
	}
}

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

	while(!b.eof()) {
		Chunck * 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;
			default:
				error("Unknown frame subchunck found : %s, %d", Chunck::ChunckString(sub->getType()), sub->getSize());
		}
		delete sub;
	}
	if(_curBuffer) {
		_renderer->unlockFrame();
		_curBuffer = 0;
	}
	if(_outputSound)
		_mixer->handleFrame();
#ifdef DEBUG
	debug(5, "===================END OF FRAME========================");
#endif
	_renderer->flipFrame();
	if(_wait)
		_renderer->wait(WAIT);
	_frame++;
}

void SmushPlayer::handleAnimHeader(Chunck & b) {
	checkBlock(b, TYPE_AHDR, 774);
	debug(6, "SmushPlayer::handleAnimHeader()");
	_version = b.getWord();
	_nbframes = b.getWord();
	int unknown = b.getWord();
#ifdef DEBUG
	debug(5, "SMUSH HEADER : version == %d, nbframes == %d, unknown == %d", _version, _nbframes, unknown);
#else
	unknown = unknown;
#endif
	_renderer->startDecode(_fname, _version, _nbframes);
	readPalette(_pal, b);
	updatePalette();
	if(_version == 1) {
		_soundFrequency = 22050;
	}
	if(_version == 2) {
		_secondaryVersion = b.getDword();
		int unknown2 = b.getDword();
		_soundFrequency = b.getDword();
#ifdef DEBUG
		debug(5, "SMUSH HEADER : secondary version == %d, unknown2 == %d, sound frequency == %d", _secondaryVersion, unknown2, _soundFrequency);
		int i = 0, c;
		while(!b.eof()) {
			c = b.getByte();
			if(c) debug(9, "SMUSH HEADER : remaining bytes : %d == %d", i, c);
			i++;
		}
#else
		unknown2 = unknown2;
#endif
		if(_secondaryVersion != 10 && _secondaryVersion != 0 && _secondaryVersion != 12 && _secondaryVersion != 15 && _secondaryVersion != 14)
			error("Wrong secondary version number for SMUSH animation");
		if(_soundFrequency != 0 && _soundFrequency != 11025 && _soundFrequency != 22050)
			error("Wrong _sound_frequency number for SMUSH animation");
	}else if(_version > 2) {
		error("Wrong primary version number for SMUSH animation");
	}
	if(_outputSound && _soundFrequency) {
		if(_soundFrequency != 22050) _soundFrequency = 22050;
		_mixer = _renderer->getMixer();
		if(_mixer) {
			_mixer->init();
		} else {
			_outputSound = false;
		}
	}
}

static StringResource * getStrings(const char * file, bool is_encoded) {
	debug(7, "trying to read text ressources from %s", file);
	FILE * is;
	is = fopen(file, "rb");
	if(is == NULL) return 0;
	fseek(is, 0, SEEK_END);
	int length = ftell(is);
	fseek(is, 0, SEEK_SET);
	char * filebuffer = new char [length + 1];
	assert(filebuffer);
	fread (filebuffer, length, 1, is);
	filebuffer[length] = 0;
	fclose(is);
	if(is_encoded) {
		static const int ETRS_HEADER_LENGTH = 16;
		assert(length > ETRS_HEADER_LENGTH);
		Chunck::type type = READ_BE_UINT32(filebuffer);
		if(type != TYPE_ETRS) error("invalid type for file"); // mem leak !!!
		char * old = filebuffer;
		filebuffer = new char[length - ETRS_HEADER_LENGTH];
		for(int i = ETRS_HEADER_LENGTH; i < length; i++)
			filebuffer[i - ETRS_HEADER_LENGTH] = old[i] ^ 0xCC;
		delete []old;
		length -= ETRS_HEADER_LENGTH;
	}
	StringResource * sr = new StringResource;
	assert(sr);
	sr->init(filebuffer, length);
	delete []filebuffer;
	return sr;
}

bool SmushPlayer::readString(const char * file, bool & ft) {
	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, false)) != 0) {
		ft = true;
		return true;
	}
	i = strrchr(file, '\\');
	if(i == NULL) i = strrchr(file, '/');
	else {
		char * j = strrchr(file, '/');
		if(j > i) i = j;
	}
	if(i == NULL) error("invalid filename : %s", file);

	memcpy(fname, file, i - file + 1);
	strcpy(fname + (i - file + 1), "digtxt.trs");
	if((_strings = getStrings(fname, true)) != 0) {
		ft = false;
		return true;
	}
	return false;
}

static FontRenderer * loadFont(const char * file, bool original = false) {
#ifdef DEBUG
	debug(5, "loading font from \"%s\"", file);
#endif
	FontRenderer * fr = new FontRenderer(original);
	SmushPlayer p(fr, false, false);
	p.play(file);
	return fr;
}

bool SmushPlayer::play(const char * file) {
#ifdef DEBUG
	debug(5, "start of animation : %s", file);
#endif	
	char * i = strrchr(file, '\\');
	if(i == NULL)
	{
		i = strrchr(file, '/');
	} else {
		char * j = strrchr(i, '/');
		if(j != NULL)
			i = j;
	}
	char directory[260];
	if(i != NULL) {
		strcpy(directory, file);
		directory[i-file] = 0;
		//! @todo remove this...
		_fname = strdup(i);
	} else {
		directory[0] = 0;
		_fname = strdup(file);
	}
	clean();
	
	if(_wait) {
		bool isFullthrottle;
		if(!readString(file, isFullthrottle))
			warning("unable to read text information for \"%s\"", file);
		if(_strings) {
			if(isFullthrottle) {
				if(strcmp(directory, "") == 0) {
					strcpy(directory, "../data/");
				} else {
					char * i = strrchr(directory, '\\');
					char * j = strrchr(directory, '/');
					if(j > i) i = j;
					if(i == NULL) {
						strcpy(directory, "data/");
					} else {
						*i = 0;
						strcat(directory, "/data/");
					}
				}
				char file[260];
				strcpy(file, directory); strcat(file, "scummfnt.nut");
				_fr[0] = loadFont(file, true);
				strcpy(file, directory); strcat(file, "titlfnt.nut");
				_fr[2] = loadFont(file, true);
			} else {
				for(int i = 0; i < 4; i++) {
					char file[260];
					sprintf(file, "%s/font%d.nut",directory, i);
					_fr[i] = loadFont(file, i != 0);
				}
			}
		}
	}
	FileChunck base = FileChunck(file);

	checkBlock(base, TYPE_ANIM); 

	while(!base.eof()) {
		Chunck * sub = base.subBlock();
		switch(sub->getType()) {
			case TYPE_AHDR:
				handleAnimHeader(*sub);
				break;
			case TYPE_FRME:
				handleFrame(*sub);
				break;
			default:
				error("Unknown chunck found : %d, %d", sub->getType(), sub->getSize());
		}
		delete sub;
		if(_renderer->prematureClose())
			break;
	}
#ifdef DEBUG
	debug(5, "end of animation");
#endif	
	if(_outputSound) {
		_mixer->stop();
	}
	return true;
}

--- NEW FILE: player.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/player.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __PLAYER_H_
#define __PLAYER_H_

#include "config.h"

#include "rect.h"
#include "mixer.h"
#include "chunck.h"
#include "palette.h"
#include "codec1.h"
#include "codec37.h"
#include "codec44.h"
#include "codec47.h"
#include "frenderer.h"

class Renderer;

class StringResource;

/*!	@brief the SMUSH player class

	This class is the player itself. 
*/
class SmushPlayer {
private:
	char * _fname;			//!< the name of the animation file being played
	int _version;			//!< the version of the animation file being played
	int _secondaryVersion;	//!< the secondary version number of the animation file being played
	int _soundFrequency;		//!< the sound frequency of the animation file being played
	int _nbframes;			//!< the number of frames in the animation file
	Mixer * _mixer;			//!< the sound mixer
	Palette _pal;			//!< the current palette
	short _deltaPal[768];		//!< the delta palette information set by an xpal
	Renderer * _renderer;		//!< pointer to the ::renderer
	StringResource * _strings;	//!< pointer to the string resources associated with the animation
	FontRenderer * _fr[4];		//!< pointers to the fonts for the animation
	Codec1Decoder _codec1;	//!< the ::decoder for codec 1 and 3
	Codec37Decoder _codec37;	//!< the ::decoder for codec 37
	Codec44Decoder _codec44;	//!< the ::decoder for codec 21 and 44
	DumpDecoder _codecd;	//!< the ::decoder for codec 21 and 44
	Point _frameSize;		//!< the current frame size of the animation
	int _frame;				//!< the current frame number of the animation
	bool _outputSound;		//!< should we handle sound ?
	bool _wait;				//!< should we synchronise the player ?
	bool _alreadyInit;		//!< has the player already been initialized for the current frame
	bool _codec37Called;		//!< has the codec 37 already been called once for this animation
	bool _skipNext;			//!< should the player skip the next frame object ?
	bool _subtitles;			//!< should the player handle subtitles ?
	bool _bgmusic;			//!< should the player output the background music ?
	bool _voices;			//!< should the player output the voice ?
	bool _skips[37];			//!< mapping of frame object identifier to show or hide
	char * _curBuffer;		//!< pointer to the current frame
public:
	SmushPlayer(Renderer *, bool wait = true, bool output_sound = true);
	virtual ~SmushPlayer();
	bool play(const char *);
	void updatePalette(void);
	void show(const char *);
	void hide(const char *);
protected:
	bool readString(const char * file, bool &);
	void clean();
	void checkBlock(const Chunck &, Chunck::type, unsigned int = 0);
	void handleAnimHeader(Chunck &);
	void handleFrame(Chunck &);
	void handleNewPalette(Chunck &);
	void handleFrameObject(Chunck &);
	void handleSoundBuffer(int, int, int, int, int, int, Chunck &, int);
	void handleImuseBuffer(int, int, int, int, int, int, Chunck &, int);
	void handleSoundFrame(Chunck &);
	void handleSkip(Chunck &);
	void handleStore(Chunck &);
	void handleFetch(Chunck &);
	void handleImuseAction8(Chunck &, int flags, int unknown, int track_id);
	void handleImuseAction(Chunck &);
	void handleTextResource(Chunck &);
	void handleDeltaPalette(Chunck &);
	void decodeCodec(Chunck &, const Rect &, Decoder &);
	void readPalette(Palette &, Chunck &);
	void initSize(const Rect &, bool, bool);
};

#endif

--- NEW FILE: rect.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/rect.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "rect.h"

Rect::Rect() : _topLeft(0, 0), _bottomRight(0,0) { 
}

Rect::Rect(int x, int y) : _topLeft(0, 0), _bottomRight(x, y) {
	check();
}

Rect::Rect(int x1, int y1, int x2, int y2) : _topLeft(x1, y1), _bottomRight(x2, y2) { 
	check(); 
}

Rect::Rect(const Rect & r) : _topLeft(r._topLeft), _bottomRight(r._bottomRight) {
}

Rect & Rect::operator=(const Rect & r) {
	_topLeft = r._topLeft;
	_bottomRight = r._bottomRight;
	return *this;
}

bool Rect::operator==(const Rect & r) const {
	return _topLeft == r._topLeft && _bottomRight == r._bottomRight;
}

void Rect::check() {
	if ((_topLeft.getX() < 0) || (_bottomRight.getX() < _topLeft.getX())  || (_topLeft.getY() < 0) || (_bottomRight.getY() < _topLeft.getY())) {
		error("Invalid rect");
	}
}

bool Rect::isInside(int x, int y) const {
	return _topLeft.getX() >= x && _bottomRight.getX() < x && _topLeft.getY() >= y && _bottomRight.getY() < y;
}

bool Rect::isInside(const Point & p) const {
	return (left() <= p.getX()) && (right() > p.getX()) && (top() <= p.getY()) && (bottom() > p.getY());
}


--- NEW FILE: rect.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/rect.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __RECT_H_
#define __RECT_H_

#include "config.h"

/*! 	@brief simple class for handling both 2D position and size

	This small class is an helper for position and size values.
*/
class Point {
private:
	int _x;	//!< The horizontal part of the point
	int _y;	//!< The vertical part of the point
public:
	Point() : _x(0), _y(0) {};
	Point(const Point & p) : _x(p.getX()), _y(p.getY()) {};
	explicit Point(int x, int y) : _x(x), _y(y) {};
	Point & operator=(const Point & p) { _x = p.getX(); _y = p.getY(); return *this; };
	bool operator==(const Point & p) const { return _x == p.getX() && _y == p.getY(); };
	const int & getX() const { return _x; };
	const int & getY() const { return _y; };
	int & getX() { return _x; };
	int & getY() { return _y; };
	Point operator+(const Point & p) const { return Point(_x + p.getX(), _y+p.getY()); };
	Point operator-(const Point & p) const { return Point(_x - p.getX(), _y-p.getY()); };
	Point & operator+=(const Point & p) { _x += p.getX(); _y += p.getY(); return *this; };
	Point & operator-=(const Point & p) { _x -= p.getX(); _y -= p.getY(); return *this; };
	bool isOrigin() const { return *this == Point(0, 0); };
	void set(int x, int y) { _x = x; _y = y; }
};

/*! 	@brief simple class for handling a rectangular zone.

	This small class is an helper for rectangles.
	It is mostly used by the blitter class.
*/
class Rect {
private:
	Point _topLeft;		//!< The point at the top left of the rectangle
	Point _bottomRight;	//!< The point at the bottom right of the rectangle
protected:
	void check();
public:
	Rect();
	Rect(int x, int y);
	explicit Rect(const Point & size);
	Rect(int x1, int y1, int x2, int y2);
	Rect(const Point & topleft, const Point & bottomright);
	Rect(const Rect & r);
	Rect & operator=(const Rect & r);
	bool operator==(const Rect & r) const;
	Point size() const { return (_bottomRight - _topLeft); };
	int width() const { return size().getX(); }
	int height() const { return size().getY(); }
	int left() const { return _topLeft.getX(); }
	int right() const { return _bottomRight.getX(); }
	int top() const { return _topLeft.getY(); }
	int bottom() const { return _bottomRight.getY(); }
	const Point & topLeft() const { return _topLeft; }
	const Point & bottomRight() const { return _bottomRight; }

	/*!	@brief check if given position is inside the rectangle
		
		@param x the horizontal position to check
		@param y the vertical position to check	
		
		@return true if the given position is inside the rectangle, false otherwise
	*/
	bool isInside(int x, int y) const;
	/*!	@brief check if given point is inside the rectangle
		
		@param p the point to check
		
		@return true if the given point is inside the rectangle, false otherwise
	*/
	bool isInside(const Point & p) const;
	bool clip(Rect & r) const;
};

#endif

--- NEW FILE: renderer.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/renderer.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __RENDERER_H_
#define __RENDERER_H_

#include "config.h"

#include "rect.h"

class Palette;
class Mixer;
	
/*! 	@brief interface for general output (rendering)

	This is the interface for frame output. 
	Several implementations of these interface exist, each having a particular
	application.
*/
class Renderer {
public:
	virtual ~Renderer() {};
	/*!	@brief start of animation output
		
		This is called by the animation player when output is going to start.
		
		@param fname name of the animation being played.
		@param version version number of the animation
		@param nbframes total number of frames of the animation.
		
		@return true if initialisation was ok, false otherwise
	*/
	virtual bool startDecode(const char * fname, int version, int nbframes) = 0;
	/*!	@brief start of animation output
		
		This is called by the animation player when the frame size is changing.
		
		@param size new size of the frames.
		
		@return true if everything went fine, false otherwise
	*/
	virtual bool initFrame(const Point & size) = 0;
	/*!	@brief set a new palette
		
		This is called by the animation player when the palette is changing.
		
		@param pal new palette.
		
		@return true if everything went fine, false otherwise
	*/
	virtual bool setPalette(const Palette & pal) = 0;
	/*!	@brief lock a frame buffer
		
		This is called by the animation player when a frame is going to be decoded.
		
		@param frame the frame number.
		
		@return a pointer to the frame buffer to output data to.
	*/
	virtual char * lockFrame(int frame) = 0;
	/*!	@brief unlock a frame buffer
		
		This is called by the animation player when a frame has been decoded.
		
		@return true if everything went fine, false otherwise
	*/
	virtual bool unlockFrame() = 0;
	/*!	@brief flip a frame buffer
		
		This is called by the animation player when the current frame should be shown.
		
		@return true if everything went fine, false otherwise
	*/
	virtual bool flipFrame() = 0;
	/*!	@brief wait for some time
		
		This is called by the animation player when the animation should stay idle.
		
		@param ms number of millisecond to wait.
		
		@return true if everything went fine, false otherwise
	*/
	virtual bool wait(int ms) = 0;
	/*!	@brief does the renderer want a premature end of the animation ?
		
		This is called by the animation player after each frame.
		
		@return true if playing should be stopped, false otherwise.
	*/
	virtual bool prematureClose() = 0;
	/*!	@brief request for a mixer
		
		This is called by the animation player when sound output is required by the animation.
		
		@return a valid pointer to an uninitialized mixer instance, or null if none is available.
	*/
	virtual Mixer * getMixer() = 0;
	/*!	@brief debugging function : do not use
		
		@return true if everything went fine, false otherwise
	*/
	virtual bool saveCurrent() { return false; };
};

#endif

--- NEW FILE: saud_channel.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/saud_channel.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "channel.h"
#include "chunck.h"
#include "chunck_type.h"

#include <assert.h>
#include <string.h> // for memcpy.h
#ifndef min
#define min(x, y) ((x) > (y) ? (y) : (x))
#endif

void SaudChannel::handleStrk(Chunck & b) {
	int size = b.getSize();
	if(size != 14 && size != 10) {
		error("STRK has a invalid size : %d", size);
	}
}

void SaudChannel::handleSmrk(Chunck & b) {
	_markReached = true;
}

void SaudChannel::handleShdr(Chunck & b) {
	int size = b.getSize();
	if(size != 4) warning("SMRK has a invalid size : %d", size);
}

bool SaudChannel::handleSubTags(int & offset) {
	int available_size = _tbufferSize - offset;
	if(available_size >= 8) {
		Chunck::type type = READ_BE_UINT32(_tbuffer + offset);
		unsigned int size = READ_BE_UINT32(_tbuffer + offset + 4);

		switch(type) {
			case TYPE_STRK:
				_inData = false;
				if(available_size >= (size + 8)) {
					ContChunck c((char*)_tbuffer + offset);
					handleStrk(c);
				}
				else
					return false;
				break;
			case TYPE_SMRK:
				_inData = false;
				if(available_size >= (size + 8)) {
					ContChunck c((char*)_tbuffer + offset);
					handleSmrk(c);
				}
				else
					return false;
				break;
			case TYPE_SHDR:
				_inData = false;
				if(available_size >= (size + 8)) {
					ContChunck c((char*)_tbuffer + offset);
					handleShdr(c);
				}
				else
					return false;
				break;
			case TYPE_SDAT: 
				_inData = true;
				_dataSize = size;
				offset += 8;
				return false;
			default:
				error("unknown chunck in SAUD track : %s ", Chunck::ChunckString(type));
		}
		offset += size + 8;
		return true;
	}
	return false;
}

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);
	assert(_sbufferSize == 0);
	
	if(_inData) {
		if(_dataSize < _tbufferSize) {
			// I can't assume that the channel is finished after data is received... (this assumption failed in realride.san)
			int offset= _dataSize;
			while(handleSubTags(offset));
			_sbufferSize = _dataSize;
			_sbuffer = _tbuffer;
			if(offset < _tbufferSize) { // there is still some unprocessed data
				int new_size = _tbufferSize - offset;
				_tbuffer = new unsigned char[new_size];
				if(!_tbuffer)  error("SaudChannel failed to allocate memory");
				memcpy(_tbuffer, _sbuffer + offset, new_size);
				_tbufferSize = new_size;
			} else {
				_tbuffer = 0;
				_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;
			_tbuffer = 0;
		}
	} else {
		int offset = 0;
		while(handleSubTags(offset));
		if(_inData) {
			_sbufferSize = _tbufferSize - offset;
			assert(_sbufferSize);
			_sbuffer = new unsigned char[_sbufferSize];
			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;
				int new_size = _tbufferSize - offset;
				_tbuffer = new unsigned char[new_size];
				if(!_tbuffer)  error("SaudChannel failed to allocate memory");
				memcpy(_tbuffer, old + offset, new_size);
				_tbufferSize = new_size;
				delete []old;
			}
		}
	}
	return true;
}

SaudChannel::SaudChannel(int track, int freq) : 
			_track(track), 
			_nbframes(0),
			_dataSize(-1),
			_tbuffer(0), 
			_sbuffer(0), 
			_frequency(freq),
			_tbufferSize(0), 
			_sbufferSize(0), 
			_inData(false),
			_markReached(false)
			{
}

SaudChannel::~SaudChannel() {
	if(_tbuffer) delete []_tbuffer;
	if(_sbuffer) {
		warning("this should never happen !!!! (_sbuffer not NULL here)");
		delete []_sbuffer;
	}
}

bool SaudChannel::isTerminated() const {
	return (_markReached && _dataSize == 0 && _sbuffer == 0);
}

void SaudChannel::recalcVolumeTable() {
	const int MAX_BALANCE = 100;
	int volume_left, volume_right;
	if(_balance < -MAX_BALANCE || _balance > MAX_BALANCE) {
		error("balance is out of range ! : %d", _balance);
	}
	int left_multiplier = MAX_BALANCE - _balance;
	int 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;
	for(int i = 0; i < 256; i++) {
		int value = volume_left * (signed char)i;
		_voltable[0][i] = TO_BE_16(value);
		value = volume_right * (signed char)i;
		_voltable[1][i] = TO_BE_16(value);
	}
}

bool SaudChannel::setParameters(int nb, int flags, int volume, int balance) {
	_nbframes = nb;
	_flags = flags; // bit 7 == IS_VOICE, bit 6 == IS_BACKGROUND_MUSIC, other ??
	_volume = volume;
	_balance = balance;
	_index = 0;
	recalcVolumeTable();
	return true;
}

bool SaudChannel::checkParameters(int index, int nb, int flags, int volume, int 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(_volume != volume || _balance != balance) {
		_volume = volume;
		_balance = balance;
		recalcVolumeTable();
	}
	return true;
}

bool SaudChannel::appendData(Chunck & b, int size) {
	if(_dataSize == -1) { // First call
		assert(size > 8);
		Chunck::type saud_type = b.getDword(); saud_type = TO_BE_32(saud_type);
		unsigned int saud_size = b.getDword(); saud_size = TO_BE_32(saud_size);
		if(saud_type != TYPE_SAUD) error("Invalid CHUNCK for SaudChannel : %X", saud_type);
		size -= 8;
		_dataSize = -2; // We don't get here again...
	}
	if(_tbuffer) {
		unsigned char * old = _tbuffer;
		_tbuffer = new unsigned char[_tbufferSize + size];
		if(!_tbuffer)  error("saud_channel failed to allocate memory");
		memcpy(_tbuffer, old, _tbufferSize);
		delete []old;
		b.read(_tbuffer + _tbufferSize, size);
		_tbufferSize += size;
	} else {
		_tbufferSize = size;
		_tbuffer = new unsigned char[_tbufferSize];
		if(!_tbuffer)  error("saud_channel failed to allocate memory");
		b.read(_tbuffer, _tbufferSize);
	}
	return processBuffer();
}

int SaudChannel::availableSoundData(void) const {
	return _sbufferSize;
}

void SaudChannel::getSoundData(short * snd, int size) {
	for(int i = 0; i < size; i++) {
		snd[2 * i] = _voltable[0][_sbuffer[i] ^ 0x80];
		snd[2 * i + 1] = _voltable[1][_sbuffer[i] ^ 0x80];
	}
	_dataSize -= size;
	delete []_sbuffer;
	_sbuffer = 0;
	_sbufferSize = 0;
}

--- NEW FILE: scumm_renderer.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/scumm_renderer.cpp,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#include <stdafx.h>
#include "scumm_renderer.h"
#include "channel.h"

class scumm_mixer : public Mixer {
private:
	SoundMixer * _mixer; //!< pointer to the SoundMixer instance
	struct {
		int id;
		_Channel * chan;
		bool first;
		int mixer_index;
	} _channels[SoundMixer::NUM_CHANNELS];		//!< The map of track and channels
	int _nextIndex;
public:
	scumm_mixer(SoundMixer *);
	virtual ~scumm_mixer();
	bool init();
	_Channel * findChannel(int track);
	bool addChannel(_Channel * c);
	bool handleFrame();
	bool stop();
	bool update();
};

scumm_mixer::scumm_mixer(SoundMixer * m) : _mixer(m), _nextIndex(0) {
	for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
		_channels[i].id = -1;
		_channels[i].chan = 0;
		_channels[i].first = true;
	}
}

scumm_mixer::~scumm_mixer() {
}

bool scumm_mixer::init() {
	debug(9, "scumm_mixer::init()");
	return true;
}

_Channel * scumm_mixer::findChannel(int track) {
	debug(9, "scumm_mixer::findChannel(%d)", track);
	for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
		if(_channels[i].id == track)
			return _channels[i].chan;
	}
	return 0;
}

bool scumm_mixer::addChannel(_Channel * c) {
	int track = c->getTrackIdentifier();
	int i;

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

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

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

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

	fprintf(stderr, "_nextIndex == %d\n", _nextIndex);

	for(i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
		fprintf(stderr, "channel %d : %p(%d, %d) %d %d\n", i, _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("mixer::add_channel() : no more channel available");
	return false;
}

bool scumm_mixer::handleFrame() {
	debug(9, "scumm_mixer::handleFrame()");
	for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
		if(_channels[i].id != -1) {
			debug(9, "updating channel %d (%p)", _channels[i].id, _channels[i].chan);
			if(_channels[i].chan->isTerminated()) {
				debug(9, "channel %d has terminated (%p)", _channels[i].id, _channels[i].chan);
				delete _channels[i].chan;
				_channels[i].id = -1;
				_channels[i].chan = 0;
			} else {
				int rate;
				bool stereo, is_short;

				_channels[i].chan->getParameters(rate, stereo, is_short);
				int size = _channels[i].chan->availableSoundData();
				debug(9, "channel %d : %d, %s, %d bits, %d", _channels[i].id, rate, stereo ? "stereo" : "mono", is_short ? 16 : 8, size);
				int flags = stereo ? SoundMixer::FLAG_STEREO : 0;

				if(is_short) {
					// FIXME this is one more data copy... we could get rid of it...
					short * data = new short[size * (stereo ? 2 : 1)];
					_channels[i].chan->getSoundData(data, size);
					size *= stereo ? 4 : 2;

					// append to _sound
					if(_channels[i].first) {
						_channels[i].mixer_index = _mixer->playStream(NULL, -1, data, size, rate, flags | SoundMixer::FLAG_16BITS);
						debug(5, "channel %d bound to mixer_index %d", _channels[i].id, _channels[i].mixer_index);
						_channels[i].first = false;
					} else {
						_mixer->append(_channels[i].mixer_index, data, size, rate, flags | SoundMixer::FLAG_16BITS);
					}

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

					// append to _sound
					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 scumm_mixer::stop() {
	debug(9, "scumm_mixer::stop()");
	for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
		if(_channels[i].id != -1) {
				delete _channels[i].chan;
				_channels[i].id = -1;
				_channels[i].chan = 0;
		}
	}
	//~ _mixer->stopAll();
	return true;
}

ScummRenderer::ScummRenderer(Scumm * scumm) : _scumm(scumm), _smixer(0) {
}

static ScummRenderer * s_renderer;

static void smush_handler(Scumm * scumm) {
	s_renderer->update();
}

Mixer * ScummRenderer::getMixer() {
	if(_smixer == 0) {
		_scumm->_sound->pauseBundleMusic(true);
		_smixer = new scumm_mixer(_scumm->_mixer);
		if(!_smixer) error("unable to allocate a smush mixer");
		s_renderer = this;
		_scumm->_timer->installProcedure(&smush_handler, 75);
	}
	return _smixer;
}

ScummRenderer::~ScummRenderer() {
	_scumm->_insaneState = 0;
	_scumm->exitCutscene();
	if(_smixer) {
		_scumm->_timer->releaseProcedure(&smush_handler);
		delete _smixer;
		_smixer = 0;
	}
	_scumm->_sound->pauseBundleMusic(false);
}

bool ScummRenderer::wait(int ms) {
	while(_wait) {
		_scumm->waitForTimer(1);
	}
	return true; 
}

bool ScummRenderer::startDecode(const char * fname, int version, int nbframes) {
	_scumm->_sound->pauseBundleMusic(true);
	_scumm->videoFinished = 0;
	_scumm->_insaneState = 1;
	return true;
}

bool ScummRenderer::setPalette(const Palette & pal) {
	int i;
	byte palette_colors[1024];
	byte *p = palette_colors;

	for (i = 0; i < 256; i++, p += 4) {
		p[0] = pal[i].red();
		p[1] = pal[i].green();
		p[2] = pal[i].blue();
		p[3] = 0;
	}

	_scumm->_system->set_palette(palette_colors, 0, 256);
	_scumm->setDirtyColors(0, 255);
	return BaseRenderer::setPalette(pal); // For compatibility with possible subclass...
}

void ScummRenderer::save(int frame) {
	int width = min(getWidth(), _scumm->_realWidth); 
	int height = min(getHeight(), _scumm->_realHeight);
	
	_scumm->_system->copy_rect((const byte *)data(), getWidth(), 0, 0, width, height);
	_scumm->_system->update_screen();
	_scumm->processKbd();
	_wait = true;
}

bool ScummRenderer::prematureClose() { 
	return _scumm->videoFinished; 
}

bool ScummRenderer::update() {
	_wait = false;
	return true;
}


--- NEW FILE: scumm_renderer.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001/2002 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-new/scumm/smush/scumm_renderer.h,v 1.1 2002/08/24 15:31:37 aquadran Exp $
 *
 */

#ifndef __SCUMM_RENDERER_H_
#define __SCUMM_RENDERER_H_

#include "config.h"

#ifdef DEBUG
# ifndef NO_DEBUG_SCUMM_RENDERER
#  define DEBUG_SCUMM_RENDERER
# endif
#else
# ifdef DEBUG_SCUMM_RENDERER
#  error DEBUG_SCUMM_RENDERER defined without DEBUG
# endif
#endif

#include "brenderer.h"
#include "mixer.h"
#include "rect.h"
#include "blitter.h"

#ifndef min
#define min(x, y) ((x) > (y) ? (y) : (x))
#endif

class scumm_mixer;

class ScummRenderer : public BaseRenderer {
private:
	Scumm * _scumm;
	scumm_mixer * _smixer;
	volatile bool _wait;
public:
	ScummRenderer(Scumm * scumm);
	virtual ~ScummRenderer();
	virtual bool wait(int ms);
	bool update();
protected:
	virtual bool startDecode(const char * fname, int version, int nbframes);
	virtual bool setPalette(const Palette & pal);
	virtual void save(int frame = -1);
	virtual Mixer * getMixer();
	virtual bool prematureClose();
};

#endif





More information about the Scummvm-git-logs mailing list