reorg/clenup, changed main loop in smush code

svn-id: r6817
This commit is contained in:
Paweł Kołodziejski 2003-03-17 12:28:50 +00:00
parent ee26752d2e
commit 06ef80fa61
32 changed files with 1491 additions and 2487 deletions

View file

@ -1,77 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include <stdafx.h>
#include "brenderer.h"
#include "common/engine.h" // for debug, warning, error
#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 byte[_width * _height];
if(!_data) error("base_renderer unable to allocate frame buffer");
return true;
}
byte *BaseRenderer::lockFrame(int32 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;
}

View file

@ -1,81 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef BRENDERER_H
#define BRENDERER_H
#include "config.h"
#include "renderer.h"
#include "palette.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 {
protected:
Palette _pal; //!< The current palette
byte *_data; //!< The current frame buffer
int32 _frame; //!< The current frame number
int32 _nbframes; //!< The number of frames in the animation
int32 _width; //!< The current frame's width
int32 _height; //!< The current frame's height
const char *_fname; //!< The filename of the animation being played
protected:
virtual void save() = 0;
protected:
const char *getFilename() const { return _fname; }; //!< accessor for animation filename
int32 getNbframes() const { return _nbframes; }; //!< accessor for number of frames
void clean(); //!< memory cleanup (deletes frame buffer)
void setFrame(int32 f) { _frame = f; }; //!< allows to change the frame number
public:
int32 getFrame() const { return _frame; }; //!< accessor for current frame number
BaseRenderer();
virtual ~BaseRenderer();
virtual bool initFrame(const Point &size);
virtual byte *lockFrame(int32 frame);
virtual bool unlockFrame();
virtual bool flipFrame();
virtual bool setPalette(const Palette &pal);
virtual bool startDecode(const char *fname, int32 version, int32 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() {};
public:
NullRenderer() {};
virtual ~NullRenderer() {};
bool wait(int32 ms) { return true; };
};
#endif

View file

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

View file

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

View file

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

View file

@ -20,44 +20,28 @@
*/
#include <stdafx.h>
#include "codec1.h"
#include "common/scummsys.h"
Codec1Decoder::~Codec1Decoder() {
}
bool Codec1Decoder::decode(byte *dst, const byte *src, int) {
byte val;
int32 size_line;
int32 code, length;
int32 h, height = getRect().height();
void smush_decode_codec1(byte *dst, byte *src, int height) {
byte val, code;
int32 length;
int h = height, size_line;
for(h = 0; h < height; h++) {
size_line = READ_LE_UINT16(src); // size of compressed line !
size_line = READ_LE_UINT16(src);
src += 2;
#ifdef DEBUG_CODEC1
debug(7, "codec1 : h == %d, size_line == %d", h, size_line);
#endif
while(size_line > 0) {
code = *src++;
size_line--;
length = (code >> 1) + 1;
#ifdef DEBUG_CODEC1
debug(7, "codec1 : length == %d", length);
#endif
if(code & 1) {
val = *src++;
size_line--;
if (val)
memset(dst, val, length);
dst += length;
#ifdef DEBUG_CODEC1
debug(7, "codec1 : blitting %d times %d", length, val);
#endif
} else {
size_line -= length;
#ifdef DEBUG_CODEC1
debug(7, "codec1 : blitting %d entries", length);
#endif
while(length--) {
val = *src++;
if (val)
@ -67,5 +51,4 @@ bool Codec1Decoder::decode(byte *dst, const byte *src, int) {
}
}
}
return true;
}

View file

@ -1,48 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#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(byte *dst, const byte *src, int length);
};
#endif

View file

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

View file

@ -19,36 +19,39 @@
*
*/
#ifndef CODEC37_H
#define CODEC37_H
#ifndef SMUSH_CODEC37_H
#define SMUSH_CODEC37_H
#include "decoder.h"
#include "common/scummsys.h"
class Codec37Decoder : public Decoder {
class Codec37Decoder {
private:
int32 _deltaSize;
byte *_deltaBufs[2];
byte *_deltaBuf;
int16 *_offsetTable;
int32 _curtable;
int _curtable;
uint16 _prevSeqNb;
int32 _tableLastPitch;
int32 _tableLastIndex;
int _tableLastPitch;
int _tableLastIndex;
int32 _frameSize;
int _width, _height;
public:
bool initSize(const Point &, const Rect &);
Codec37Decoder();
void clean();
virtual ~Codec37Decoder();
~Codec37Decoder();
void init(int width, int height);
void deinit();
protected:
void maketable(int32, int32);
void maketable(int, int);
void bompDecode(byte *dst, const byte *src, int len);
void proc3WithFDFE(byte *dst, const byte *src, int32, int32, int32, int32, int16 *);
void proc3WithoutFDFE(byte *dst, const byte *src, int32, int32, int32, int32, int16 *);
void proc4WithFDFE(byte *dst, const byte *src, int32, int32, int32, int32, int16 *);
void proc4WithoutFDFE(byte *dst, const byte *src, int32, int32, int32, int32, int16 *);
void proc3WithFDFE(byte *dst, const byte *src, int32, int, int, int, int16 *);
void proc3WithoutFDFE(byte *dst, const byte *src, int32, int, int, int, int16 *);
void proc4WithFDFE(byte *dst, const byte *src, int32, int, int, int, int16 *);
void proc4WithoutFDFE(byte *dst, const byte *src, int32, int, int, int, int16 *);
public:
bool decode(byte *dst, const byte *src, int length);
void decode(byte *dst, const byte *src);
};
#endif

View file

@ -1,62 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include <stdafx.h>
#include "codec44.h"
bool Codec44Decoder::decode(byte *dst, const byte *src, int length) {
int32 size_line, num;
int32 width = getRect().width();
int32 height = getRect().height();
const byte *src2 = src;
byte *dst2 = _buffer;
byte val;
do {
size_line = READ_LE_UINT16(src2);
src2 += 2;
length -= 2;
while (size_line != 0) {
num = *src2++;
val = *src2++;
memset(dst2, val, num);
dst2 += num;
length -= 2;
size_line -= 2;
if (size_line != 0) {
num = READ_LE_UINT16(src2) + 1;
src2 += 2;
memcpy(dst2, src2, num);
dst2 += num;
src2 += num;
length -= num + 2;
size_line -= num + 2;
}
}
dst2--;
} while (length > 1);
memcpy(dst, _buffer, width * height);
return true;
}

View file

@ -1,34 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef CODEC44_H
#define CODEC44_H
#include "decoder.h"
class Codec44Decoder : public Decoder {
byte _buffer[1000];
public:
bool decode(byte *dst, const byte *src, int length);
};
#endif

View file

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

View file

@ -19,27 +19,28 @@
*
*/
#ifndef CODEC_47_H
#define CODEC_47_H
#ifndef SMUSH_CODEC_47_H
#define SMUSH_CODEC_47_H
#include "config.h"
#include "common/scummsys.h"
#include "decoder.h"
class Codec47Decoder : public Decoder {
class Codec47Decoder {
private:
int32 _deltaSize;
byte *_deltaBufs[2];
byte *_deltaBuf;
byte *_curBuf;
int32 _prevSeqNb;
int32 _lastTableWidth;
int _lastTableWidth;
const byte *_d_src, *_paramPtr;
int32 _d_pitch;
int _d_pitch;
int32 _offset1, _offset2;
byte _tableBig[99328];
byte _tableSmall[32768];
int16 _table[256];
int32 _frameSize;
int _width, _height;
void makeTables47(int32 width);
void makeTables37(int32 param);
@ -47,14 +48,14 @@ private:
void level1(byte *d_dst);
void level2(byte *d_dst);
void level3(byte *d_dst);
void decode2(byte *dst, const byte *src, int32 width, int32 height, const byte *param_ptr);
void decode2(byte *dst, const byte *src, int width, int height, const byte *param_ptr);
public:
Codec47Decoder();
virtual ~Codec47Decoder();
bool initSize(const Point &, const Rect &);
void clean();
bool decode(byte *dst, const byte *src, int length);
~Codec47Decoder();
void init(int width, int height);
void deinit();
bool decode(byte *dst, const byte *src);
};
#endif

View file

@ -1,37 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include <stdafx.h>
#include "color.h"
#define UPDATE_COLOR(c, inc) (((int32)((c)) << 7) + (c) + (inc)) >> 7
#define CHECK_BOUNDS(c) (((c) > 255) ? 255 : (((c) < 0) ? 0 : (c)))
void Color::delta(int16 * ptr) {
// This is a very specific method for XPALs.
int16 t;
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);
}

View file

@ -1,55 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef COLOR_H
#define COLOR_H
#include "config.h"
/*! @brief simple class for handling a Chunk.
This small class is an helper for Chunks.
*/
class Color {
public:
typedef byte value_type; //!< The type of the Chunk components.
private:
value_type _r; //!< The red component.
value_type _g; //!< The green component.
value_type _b; //!< The blue component.
public:
Color() : _r(0), _g(0), _b(0) {}
Color(value_type r, value_type g, value_type b) : _r(r), _g(g), _b(b) {}
inline value_type red() const { return _r; }
inline value_type green() const { return _g; }
inline value_type blue() const { return _b; }
/*! @brief handle delta palette modification
This method is used specifically by player::handleDeltaPalette().
It updates the Chunk component using delta values given as short.
@param ptr pointer to a table of 3 shorts that contain delta values to use.
*/
void delta(int16 * ptr);
};
#endif

View file

@ -1,51 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef DECODER_H
#define DECODER_H
#include "config.h"
#include "common/rect.h"
using ScummVM::Point;
using ScummVM::Rect;
/*! @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(byte *dst, const byte *src, int length) = 0;
};
#endif

View file

@ -1,399 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include <stdafx.h>
#include "common/util.h"
#include "common/engine.h" // for debug, warning, error
#include "scumm/scumm.h"
#include "frenderer.h"
#include <assert.h>
#include <string.h>
FontRenderer::FontRenderer(bool use_original_colors) :
_nbChars(0),
_color(-1),
_original(use_original_colors) {
}
FontRenderer::~FontRenderer() {
for(int32 i = 0; i < _nbChars; i++) {
if(_chars[i].chr) delete []_chars[i].chr;
}
}
void FontRenderer::save() {
_chars[_nbChars].width = _width;
_chars[_nbChars].height = _height;
int size = _width * _height;
_chars[_nbChars].chr = new byte[size];
memcpy(_chars[_nbChars].chr, _data, size);
_nbChars++;
}
int32 FontRenderer::charWidth(int32 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;
}
int32 FontRenderer::charHeight(int32 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;
}
int32 FontRenderer::stringWidth(const char *str) const {
int32 ret = 0;
while(*str) {
ret += charWidth(*str++);
}
return ret;
}
int32 FontRenderer::stringHeight(const char *str) const {
int32 ret = 0;
for(int32 i = 0; str[i] != 0; i++) {
int32 h = charHeight(str[i]);
ret = MAX(ret, h);
}
return ret;
}
int32 FontRenderer::drawChar(byte *buffer, const Point &size, int32 x, int32 y, int32 chr) const {
int32 w = _chars[chr].width;
int32 h = _chars[chr].height;
byte *src = _chars[chr].chr;
byte *dst = buffer + size.getX() * y + x;
if(_original) {
for(int32 j = 0; j < h; j++) {
for(int32 i = 0; i < w; i++) {
char value = *src++;
if(value) dst[i] = value;
}
dst += size.getX();
}
} else {
char color = (_color != -1) ? _color : 1;
if (g_scumm->_gameId == GID_CMI) {
for(int32 j = 0; j < h; j++) {
for(int32 i = 0; i < w; i++) {
char value = *src++;
if(value == -color) {
dst[i] = 0xFF;
} else if(value == -31) {
dst[i] = 0;
} else if(value) {
dst[i] = value;
}
}
dst += size.getX();
}
} else {
for(int32 j = 0; j < h; j++) {
for(int32 i = 0; i < w; i++) {
char 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 *[62];
int32 n = 0;
const char *i = str, *j = strchr(i, sep);
while(j != NULL) {
assert(n < 60);
ret[n] = new char[j - i + 1];
memcpy(ret[n], i, j - i);
ret[n++][j - i] = 0;
i = j+1;
j = strchr(i, sep);
}
ret[n] = new char[strlen(i) + 1];
memcpy(ret[n], i, strlen(i));
ret[n++][strlen(i)] = 0;
ret[n] = 0;
return ret;
}
void FontRenderer::drawSubstring(const byte *str, byte *buffer, const Point &size, int32 x, int32 y) const {
for(int32 i = 0; str[i] != 0; i++)
x += drawChar(buffer, size, x, y, str[i]);
}
bool FontRenderer::drawStringAbsolute(const char *str, byte *buffer, const Point &size, int32 x, int32 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 byte *)line, buffer, size, x, y);
y += stringHeight(line);
}
return true;
}
bool FontRenderer::drawStringCentered(const char *str, byte *buffer, const Point &size, int32 y, int32 xmin, int32 width, int32 offset) const {
debug(9, "FontRenderer::drawStringCentered(%s, %d, %d)", str, xmin, y);
if ((strchr(str, '\n') != 0)) {
char *j = strchr(str, '\n');
*j = 0;
}
char **words = split(str, ' ');
int32 nb_sub = 0;
while(words[nb_sub]) nb_sub++;
int32 *sizes = new int32[nb_sub];
int32 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];
int32 *substr_widths = new int32[nb_sub];
int32 space_width = charWidth(' ');
i = 0;
while(i < nb_sub) {
int32 substr_width = sizes[i];
char *substr = new char[1000];
strcpy(substr, words[i]);
int32 j = i + 1;
while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
substr_width += sizes[j++] + space_width;
}
for(int32 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++) {
int32 substr_width = substr_widths[i];
drawSubstring((const byte *)substrings[i], buffer, size, x - substr_width / 2, y);
y += stringHeight(substrings[i]);
delete []substrings[i];
}
delete []substr_widths;
delete []substrings;
return true;
}
bool FontRenderer::drawStringWrap(const char *str, byte *buffer, const Point &size, int32 x, int32 y, int32 width) const {
debug(9, "FontRenderer::drawStringWrap(%s, %d, %d)", str, x, y);
if ((strchr(str, '\n') != 0)) {
char *j = strchr(str, '\n');
*j = 0;
}
char * * words = split(str, ' ');
int32 nb_sub = 0;
while(words[nb_sub]) nb_sub++;
int32 *sizes = new int32[nb_sub];
int32 i = 0, max_width = 0, height = 0, nb_subs = 0, left_x;
for(i = 0; i < nb_sub; i++)
sizes[i] = stringWidth(words[i]);
char **substrings = new char *[nb_sub];
int32 *substr_widths = new int32[nb_sub];
int32 space_width = charWidth(' ');
i = 0;
while(i < nb_sub) {
int32 substr_width = sizes[i];
char *substr = new char[1000];
strcpy(substr, words[i]);
int32 j = i + 1;
while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
substr_width += sizes[j++] + space_width;
}
for(int32 k = i + 1; k < j; k++) {
strcat(substr, " ");
strcat(substr, words[k]);
}
substrings[nb_subs] = substr;
substr_widths[nb_subs++] = substr_width;
i = j;
height += stringHeight(substr);
}
delete []sizes;
for(i = 0; i < nb_sub; i++) {
delete []words[i];
}
delete []words;
if(y + height > size.getY()) {
y = size.getY() - height;
}
for(i = 0; i < nb_subs; i++)
max_width = MAX(max_width, substr_widths[i]);
if(max_width + x > size.getX())
left_x = size.getX() - max_width + charWidth(' ');
else
left_x = x;
if(max_width + left_x > size.getX())
left_x = size.getX() - max_width;
for(i = 0; i < nb_subs; i++) {
drawSubstring((const byte *)substrings[i], buffer, size, left_x, y);
y += stringHeight(substrings[i]);
delete []substrings[i];
}
delete []substr_widths;
delete []substrings;
return true;
}
bool FontRenderer::drawStringWrapCentered(const char *str, byte *buffer, const Point &size, int32 x, int32 y, int32 width) const {
int32 max_substr_width = 0;
debug(9, "FontRenderer::drawStringWrapCentered(%s, %d, %d)", str, x, y);
if ((strchr(str, '\n') != 0)) {
char *j = strchr(str, '\n');
*j = 0;
}
char **words = split(str, ' ');
int32 nb_sub = 0;
while(words[nb_sub]) nb_sub++;
int32 *sizes = new int32[nb_sub];
int32 i = 0, height = 0, nb_subs = 0;
for(i = 0; i < nb_sub; i++)
sizes[i] = stringWidth(words[i]);
char **substrings = new char *[nb_sub];
int32 *substr_widths = new int32[nb_sub];
int32 space_width = charWidth(' ');
i = 0;
width = MIN(width, size.getX());
while(i < nb_sub) {
int32 substr_width = sizes[i];
char *substr = new char[1000];
strcpy(substr, words[i]);
int32 j = i + 1;
while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
substr_width += sizes[j++] + space_width;
}
for(int32 k = i + 1; k < j; k++) {
strcat(substr, " ");
strcat(substr, words[k]);
}
substrings[nb_subs] = substr;
substr_widths[nb_subs++] = substr_width;
max_substr_width = MAX(substr_width, max_substr_width);
i = j;
height += stringHeight(substr);
}
delete []sizes;
for(i = 0; i < nb_sub; i++) {
delete []words[i];
}
delete []words;
if(y + height > size.getY()) {
y = size.getY() - height;
}
x = (size.getX() - max_substr_width) / 2;
for(i = 0; i < nb_subs; i++) {
int32 substr_width = substr_widths[i];
drawSubstring((const byte *)substrings[i], buffer, size, x + (max_substr_width - substr_width) / 2, y);
y += stringHeight(substrings[i]);
delete []substrings[i];
}
delete []substr_widths;
delete []substrings;
return true;
}

View file

@ -1,165 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#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 "common/util.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:
int32 _nbChars; //!< The number of frames in the font
int32 _color; //!< A color parameter used for font printing.
bool _original; //!< flag for color selection
struct {
int32 width;
int32 height;
byte *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(int32 ms) { return true; };
protected:
virtual void save();
/*! @brief get the width of a character.
@param c the character we want the width from.
@return the width of the character
*/
int32 charWidth(int32 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
*/
int32 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
*/
int32 charHeight(int32 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
*/
int32 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
*/
int32 drawChar(byte *buffer, const Point &size, int32 x, int32 y, int32 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 byte *str, byte *buffer, const Point &size, int32 x, int32 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(int32 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 Chunk,
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, byte *buffer, const Point &size, int32 y, int32 xmin, int32 width, int32 offset) const;
bool drawStringWrap(const char *str, byte *buffer, const Point &size, int32 x, int32 y, int32 width) const;
bool drawStringWrapCentered(const char *str, byte *buffer, const Point &size, int32 x, int32 y, int32 width) 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, byte *buffer, const Point &size, int32 x, int32 y) const;
};
#endif

View file

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

View file

@ -1,58 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef SMUSH_MIXER_H
#define SMUSH_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(int32 track) = 0;
virtual bool addChannel(_Channel * c) = 0;
virtual bool handleFrame() = 0;
virtual bool stop() = 0;
};
#endif

View file

@ -1,57 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef SMUSH_PALETTE_H
#define SMUSH_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(byte *ptr)
{
for(int32 i = 0; i < 256; i++) {
_colors[i] = Color(ptr[3 * i + 0], ptr[3 * i + 1], ptr[3 * i + 2]);
}
}
const Color & operator[](int32 a) const
{
assert(a >= 0 && a < 256);
return _colors[a];
}
Color & operator[](int32 a)
{
assert(a >= 0 && a < 256);
return _colors[a];
}
};
#endif

View file

@ -1,109 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef PLAYER_H
#define PLAYER_H
#include "config.h"
#include "common/util.h"
#include "chunk.h"
#include "palette.h"
#include "codec1.h"
#include "codec37.h"
#include "codec44.h"
#include "codec47.h"
class FontRenderer;
class Mixer;
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
int32 _version; //!< the version of the animation file being played
int32 _secondaryVersion; //!< the secondary version number of the animation file being played
int32 _soundFrequency; //!< the sound frequency of the animation file being played
int32 _nbframes; //!< the number of frames in the animation file
Mixer *_mixer; //!< the sound mixer
Palette _pal; //!< the current palette
int16 _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[5]; //!< pointers to the fonts for the animation
Codec1Decoder _codec1; //!< the ::decoder for codec 1 and 3
Codec37Decoder _codec37; //!< the ::decoder for codec 37
Codec47Decoder _codec47; //!< the ::decoder for codec 47
Codec44Decoder _codec44; //!< the ::decoder for codec 21 and 44
Point _frameSize; //!< the current frame size of the animation
int32 _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
byte *_curBuffer; //!< pointer to the current frame
int32 _IACTchannel;
byte _IACToutput[4096];
int32 _IACTpos;
bool _storeFrame;
byte *_frameBuffer;
public:
SmushPlayer(Renderer *, bool wait = true, bool output_sound = true);
virtual ~SmushPlayer();
bool play(const char *, const char *directory);
void updatePalette(void);
void show(const char *);
void hide(const char *);
protected:
bool readString(const char *file, const char *directory, bool &);
void clean();
void checkBlock(const Chunk &, Chunk::type, uint32 = 0);
void handleAnimHeader(Chunk &);
void handleFrame(Chunk &);
void handleNewPalette(Chunk &);
void handleFrameObject(Chunk &);
void handleSoundBuffer(int32, int32, int32, int32, int32, int32, Chunk &, int32);
void handleImuseBuffer(int32, int32, int32, int32, int32, int32, Chunk &, int32);
void handleSoundFrame(Chunk &);
void handleSkip(Chunk &);
void handleStore(Chunk &);
void handleFetch(Chunk &);
void handleImuseAction8(Chunk &, int32 flags, int32 unknown, int32 track_id);
void handleImuseAction(Chunk &);
void handleTextResource(Chunk &);
void handleDeltaPalette(Chunk &);
void decodeCodec(Chunk &, const Rect &, Decoder &);
void readPalette(Palette &, Chunk &);
void initSize(const Rect &, bool, bool);
};
#endif

View file

@ -1,125 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef RENDERER_H
#define RENDERER_H
#include "config.h"
#include "palette.h"
#include "common/rect.h"
using ScummVM::Point;
using ScummVM::Rect;
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, int32 version, int32 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 byte *lockFrame(int32 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(int32 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

View file

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

View file

@ -1,320 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include <stdafx.h>
#include "common/util.h"
#include "scumm_renderer.h"
#include "channel.h"
#include "mixer.h"
#include "sound/mixer.h"
#include "scumm/scumm.h"
#include "scumm/sound.h"
#include "scumm/imuse.h"
class ScummMixer : 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:
ScummMixer(SoundMixer *);
virtual ~ScummMixer();
bool init();
_Channel *findChannel(int32 track);
bool addChannel(_Channel *c);
bool handleFrame();
bool stop();
bool update();
bool _silentMixer;
};
ScummMixer::ScummMixer(SoundMixer *m) : _mixer(m), _nextIndex(_mixer->_beginSlots) {
for(int32 i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
_channels[i].id = -1;
_channels[i].chan = 0;
_channels[i].first = true;
}
}
ScummMixer::~ScummMixer() {
}
bool ScummMixer::init() {
debug(9, "ScummMixer::init()");
return true;
}
_Channel *ScummMixer::findChannel(int32 track) {
debug(9, "scumm_mixer::findChannel(%d)", track);
for(int32 i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
if(_channels[i].id == track)
return _channels[i].chan;
}
return 0;
}
bool ScummMixer::addChannel(_Channel *c) {
int32 track = c->getTrackIdentifier();
int i;
debug(9, "ScummMixer::addChannel(%d)", track);
for(i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
if(_channels[i].id == track)
warning("mixer::addChannel(%d) : channel already exist !", track);
}
if(_nextIndex >= SoundMixer::NUM_CHANNELS) _nextIndex = _mixer->_beginSlots;
for(i = _nextIndex; i < SoundMixer::NUM_CHANNELS; i++) {
if(_channels[i].chan == 0 || _channels[i].id == -1) {
_channels[i].chan = c;
_channels[i].id = track;
_channels[i].first = true;
_nextIndex = i + 1;
return true;
}
}
for(i = _mixer->_beginSlots; i < _nextIndex; i++) {
if(_channels[i].chan == 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 = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
fprintf(stderr, "channel %d : %p(%d, %d) %d %d\n", i, (void *)_channels[i].chan,
_channels[i].chan ? _channels[i].chan->getTrackIdentifier() : -1,
_channels[i].chan ? _channels[i].chan->isTerminated() : 1,
_channels[i].first, _channels[i].mixer_index);
}
error("mixer::add_channel() : no more channel available");
return false;
}
bool ScummMixer::handleFrame() {
debug(9, "ScummMixer::handleFrame()");
for(int i = _mixer->_beginSlots; 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 {
int32 rate;
bool stereo, is_short;
_channels[i].chan->getParameters(rate, stereo, is_short);
int32 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);
int32 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 int16[size * (stereo ? 2 : 1) * 2];
_channels[i].chan->getSoundData(data, size);
if(_channels[i].chan->getRate() == 11025) size *= 2;
size *= stereo ? 4 : 2;
if(_silentMixer == false) {
// 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 {
int8 *data = new int8[size * (stereo ? 2 : 1) * 2];
_channels[i].chan->getSoundData(data, size);
if(_channels[i].chan->getRate() == 11025) size *= 2;
size *= stereo ? 2 : 1;
if(_silentMixer == false) {
// 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 ScummMixer::stop() {
debug(9, "ScummMixer::stop()");
for(int i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
if(_channels[i].id != -1) {
delete _channels[i].chan;
_channels[i].id = -1;
_channels[i].chan = 0;
}
}
return true;
}
ScummRenderer::ScummRenderer(Scumm *scumm, uint32 speed) :
_scumm(scumm),
_smixer(0),
_insaneSpeed(speed),
_pending_updates(0) {
}
static ScummRenderer *s_renderer;
static void smush_handler(void *engine) {
s_renderer->update();
}
bool ScummRenderer::initFrame(const Point &p) {
clean();
_width = p.getX();
_height = p.getY();
assert(_width && _height);
_data = _scumm->virtscr[0].screenPtr + _scumm->virtscr[0].xstart;
return true;
}
void ScummRenderer::clean() {
_data = 0;
_width = _height = 0;
}
byte *ScummRenderer::lockFrame(int32 frame) {
_frame = frame;
if(!_data) error("no allocated image buffer in lock_frame");
return _data;
}
Mixer *ScummRenderer::getMixer() {
if(_smixer == 0) {
_smixer = new ScummMixer(_scumm->_mixer);
if(!_smixer) error("unable to allocate a smush mixer");
_smixer->_silentMixer = _scumm->_silentDigitalImuse;
s_renderer = this;
_scumm->_timer->installProcedure(&smush_handler, _insaneSpeed);
}
return _smixer;
}
ScummRenderer::~ScummRenderer() {
clean();
_scumm->_insaneState = false;
_scumm->exitCutscene();
if(_smixer) {
_scumm->_timer->releaseProcedure(&smush_handler);
delete _smixer;
_smixer = 0;
}
if (_scumm->_imuseDigital) {
_scumm->_imuseDigital->pause(false);
}
_scumm->_sound->pauseBundleMusic(false);
_scumm->_fullRedraw = 1;
}
bool ScummRenderer::wait(int32 ms) {
// Because waitForTimer() also is the function that checks for user
// input we always want to call it at least once between frames, or
// the user may become unable to interrupt the movie.
do {
_scumm->waitForTimer(1);
} while(_pending_updates <= 0);
return true;
}
bool ScummRenderer::startDecode(const char *fname, int32 version, int32 nbframes) {
if (_scumm->_imuseDigital) {
_scumm->_imuseDigital->pause(true);
}
_scumm->_sound->pauseBundleMusic(true);
_scumm->_videoFinished = false;
_scumm->_insaneState = true;
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 width = MIN(_width, _scumm->_realWidth);
int height = MIN(_height, _scumm->_realHeight);
// In theory, this will always be true. In reality, there may be
// several pending updates because the computer wasn't fast enough to
// process them all. In that case, skip the frame to catch up.
if (--_pending_updates <= 0) {
_scumm->_system->copy_rect(_data, _width, 0, 0, width, height);
_scumm->_system->update_screen();
} else {
warning("ScummRenderer: Skipping frame %d to catch up", getFrame());
}
_scumm->processKbd();
}
bool ScummRenderer::prematureClose() {
return _scumm->_videoFinished || _scumm->_saveLoadFlag;
}
bool ScummRenderer::update() {
_pending_updates++;
return true;
}

View file

@ -1,65 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#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"
class ScummMixer;
class Scumm;
class Mixer;
class ScummRenderer : public BaseRenderer {
private:
Scumm *_scumm;
ScummMixer *_smixer;
uint32 _insaneSpeed;
volatile int _pending_updates;
public:
ScummRenderer(Scumm *scumm, uint32 speed);
virtual ~ScummRenderer();
virtual bool wait(int32 ms);
bool update();
protected:
virtual bool initFrame(const Point &size);
virtual byte *lockFrame(int32 frame);
virtual void clean();
virtual bool startDecode(const char *fname, int32 version, int32 nbframes);
virtual bool setPalette(const Palette & pal);
virtual void save();
virtual Mixer *getMixer();
virtual bool prematureClose();
};
#endif

489
scumm/smush/smush_font.cpp Normal file
View file

@ -0,0 +1,489 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include <stdafx.h>
#include "common/util.h"
#include "common/engine.h"
#include "common/file.h"
#include "scumm/scumm.h"
#include "smush_font.h"
SmushFont::SmushFont(bool use_original_colors, bool new_colors) :
_nbChars(0),
_color(-1),
_new_colors(new_colors),
_original(use_original_colors) {
for(int i = 0; i < 256; i++)
_chars[i].chr = NULL;
}
SmushFont::~SmushFont() {
for(int i = 0; i < _nbChars; i++) {
if(_chars[i].chr)
delete []_chars[i].chr;
}
}
bool SmushFont::loadFont(const char *filename, const char *directory) {
debug(2, "SmushFont::loadFont() called");
File file;
file.open(filename, directory);
if (file.isOpen() == false) {
warning("SmushFont::loadFont() Can't open font file: %s/%s", directory, filename);
return false;
}
uint32 tag = file.readUint32BE();
if (tag != 'ANIM') {
debug(2, "SmushFont::loadFont() there is no ANIM chunk in font header");
return false;
}
if (_dataSrc != NULL) {
free(_dataSrc);
_dataSrc = NULL;
}
uint32 length = file.readUint32BE();
_dataSrc = (byte *)malloc(length);
file.read(_dataSrc, length);
file.close();
if (READ_BE_UINT32(_dataSrc) != 'AHDR') {
debug(2, "SmushFont::loadFont() there is no AHDR chunk in font header");
free(_dataSrc);
_dataSrc = NULL;
return false;
}
_nbChars = READ_LE_UINT16(_dataSrc + 10);
int32 offset = READ_BE_UINT32(_dataSrc + 4) + 8;
for (int l = 0; l < _nbChars; l++) {
if (READ_BE_UINT32(_dataSrc + offset) == 'FRME') {
offset += 8;
if (READ_BE_UINT32(_dataSrc + offset) == 'FOBJ') {
_chars[l].width = READ_LE_UINT16(_dataSrc + offset + 14);
_chars[l].height = READ_LE_UINT16(_dataSrc + offset + 16);
_chars[l].chr = new byte[_chars[l].width * _chars[l].height + 1000];
decodeCodec(_chars[l].chr, _dataSrc + offset + 22, READ_BE_UINT32(_dataSrc + offset + 4) - 14);
offset += READ_BE_UINT32(_dataSrc + offset + 4) + 8;
} else {
debug(2, "SmushFont::loadFont(%s, %s) there is no FOBJ chunk in FRME chunk %d (offset %x)", filename, directory, l, offset);
break;
}
} else {
debug(2, "SmushFont::loadFont(%s, %s) there is no FRME chunk %d (offset %x)", filename, directory, l, offset);
break;
}
}
free(_dataSrc);
_dataSrc = NULL;
return true;
}
int SmushFont::getCharWidth(byte v) {
if(v >= _nbChars)
error("invalid character in SmushFont::charWidth : %d (%d)", v, _nbChars);
return _chars[v].width;
}
int SmushFont::getCharHeight(byte v) {
if(v >= _nbChars)
error("invalid character in SmushFont::charHeight : %d (%d)", v, _nbChars);
return _chars[v].height;
}
int SmushFont::getStringWidth(char *str) {
int ret = 0;
while(*str) {
ret += getCharWidth(*str++);
}
return ret;
}
int SmushFont::getStringHeight(char *str) {
int ret = 0;
for(int i = 0; str[i] != 0; i++) {
int h = getCharHeight(str[i]);
ret = MAX(ret, h);
}
return ret;
}
void SmushFont::decodeCodec(byte *dst, byte *src, int length) {
int size_line, num;
byte *src2 = src;
byte *dst2 = dst;
byte val;
do {
size_line = READ_LE_UINT16(src2);
src2 += 2;
length -= 2;
while (size_line != 0) {
num = *src2++;
val = *src2++;
memset(dst2, val, num);
dst2 += num;
length -= 2;
size_line -= 2;
if (size_line != 0) {
num = READ_LE_UINT16(src2) + 1;
src2 += 2;
memcpy(dst2, src2, num);
dst2 += num;
src2 += num;
length -= num + 2;
size_line -= num + 2;
}
}
dst2--;
} while (length > 1);
}
int SmushFont::drawChar(byte *buffer, int dst_width, int x, int y, byte chr) {
int w = _chars[chr].width;
int h = _chars[chr].height;
byte *src = _chars[chr].chr;
byte *dst = buffer + dst_width * y + x;
if(_original) {
for(int32 j = 0; j < h; j++) {
for(int32 i = 0; i < w; i++) {
char value = *src++;
if(value) dst[i] = value;
}
dst += dst_width;
}
} else {
char color = (_color != -1) ? _color : 1;
if (_new_colors == true) {
for(int j = 0; j < h; j++) {
for(int i = 0; i < w; i++) {
char value = *src++;
if(value == -color) {
dst[i] = 0xFF;
} else if(value == -31) {
dst[i] = 0;
} else if(value) {
dst[i] = value;
}
}
dst += dst_width;
}
} else {
for(int j = 0; j < h; j++) {
for(int i = 0; i < w; i++) {
char value = *src++;
if(value == 1) {
dst[i] = color;
} else if(value) {
dst[i] = 0;
}
}
dst += dst_width;
}
}
}
return w;
}
static char **split(char *str, char sep) {
char **ret = new char *[62];
int n = 0;
const char *i = str;
char *j = strchr(i, sep);
while(j != NULL) {
assert(n < 60);
ret[n] = new char[j - i + 1];
memcpy(ret[n], i, j - i);
ret[n++][j - i] = 0;
i = j + 1;
j = strchr(i, sep);
}
ret[n] = new char[strlen(i) + 1];
memcpy(ret[n], i, strlen(i));
ret[n++][strlen(i)] = 0;
ret[n] = 0;
return ret;
}
void SmushFont::drawSubstring(char *str, byte *buffer, int dst_width, int x, int y) {
for(int i = 0; str[i] != 0; i++)
x += drawChar(buffer, dst_width, x, y, str[i]);
}
void SmushFont::drawStringAbsolute(char *str, byte *buffer, int dst_width, int x, int y) {
debug(9, "SmushFont::drawStringAbsolute(%s, %d, %d)", str, x, y);
while(str) {
char line[256];
char *pos = strchr(str, '\n');
if(pos) {
memcpy(line, str, pos - str - 1);
line[pos - str - 1] = 0;
str = pos + 1;
} else {
strcpy(line, str);
str = 0;
}
drawSubstring(line, buffer, dst_width, x, y);
y += getStringHeight(line);
}
}
void SmushFont::drawStringCentered(char *str, byte *buffer, int dst_width, int dst_height, int y, int xmin, int width, int offset) {
debug(9, "SmushFont::drawStringCentered(%s, %d, %d)", str, xmin, y);
if ((strchr(str, '\n') != 0)) {
char *z = strchr(str, '\n');
*z = 0;
}
char **words = split(str, ' ');
int nb_sub = 0;
while(words[nb_sub])
nb_sub++;
int *sizes = new int[nb_sub];
int i = 0, max_width = 0, height = 0, nb_subs = 0;
for(i = 0; i < nb_sub; i++)
sizes[i] = getStringWidth(words[i]);
char **substrings = new char *[nb_sub];
int *substr_widths = new int[nb_sub];
int space_width = getCharWidth(' ');
i = 0;
while(i < nb_sub) {
int substr_width = sizes[i];
char *substr = new char[1000];
strcpy(substr, words[i]);
int j = i + 1;
while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
substr_width += sizes[j++] + space_width;
}
for(int k = i + 1; k < j; k++) {
strcat(substr, " ");
strcat(substr, words[k]);
}
substrings[nb_subs] = substr;
substr_widths[nb_subs++] = substr_width;
if(substr_width > max_width)
max_width = substr_width;
i = j;
height += getStringHeight(substr);
}
delete []sizes;
for(i = 0; i < nb_sub; i++) {
delete []words[i];
}
delete []words;
max_width = (max_width + 1) >> 1;
int x = xmin + width / 2;
x += offset - dst_width / 2;
if(x < max_width) x = max_width;
if(x + max_width > dst_width) {
x = dst_width - max_width;
}
if(y + height > dst_height) {
y = dst_height - height;
}
for(i = 0; i < nb_subs; i++) {
int substr_width = substr_widths[i];
drawSubstring(substrings[i], buffer, dst_width, x - substr_width / 2, y);
y += getStringHeight(substrings[i]);
delete []substrings[i];
}
delete []substr_widths;
delete []substrings;
}
void SmushFont::drawStringWrap(char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int width) {
debug(9, "SmushFont::drawStringWrap(%s, %d, %d)", str, x, y);
if ((strchr(str, '\n') != 0)) {
char *z = strchr(str, '\n');
*z = 0;
}
char ** words = split(str, ' ');
int nb_sub = 0;
while(words[nb_sub])
nb_sub++;
int *sizes = new int[nb_sub];
int i = 0, max_width = 0, height = 0, nb_subs = 0, left_x;
for(i = 0; i < nb_sub; i++)
sizes[i] = getStringWidth(words[i]);
char **substrings = new char *[nb_sub];
int *substr_widths = new int[nb_sub];
int space_width = getCharWidth(' ');
i = 0;
while(i < nb_sub) {
int substr_width = sizes[i];
char *substr = new char[1000];
strcpy(substr, words[i]);
int j = i + 1;
while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
substr_width += sizes[j++] + space_width;
}
for(int k = i + 1; k < j; k++) {
strcat(substr, " ");
strcat(substr, words[k]);
}
substrings[nb_subs] = substr;
substr_widths[nb_subs++] = substr_width;
i = j;
height += getStringHeight(substr);
}
delete []sizes;
for(i = 0; i < nb_sub; i++) {
delete []words[i];
}
delete []words;
if(y + height > dst_height) {
y = dst_height - height;
}
for(i = 0; i < nb_subs; i++)
max_width = MAX(max_width, substr_widths[i]);
if(max_width + x > dst_width)
left_x = dst_width - max_width + getCharWidth(' ');
else
left_x = x;
if(max_width + left_x > dst_height)
left_x = dst_width - max_width;
for(i = 0; i < nb_subs; i++) {
drawSubstring(substrings[i], buffer, dst_width, left_x, y);
y += getStringHeight(substrings[i]);
delete []substrings[i];
}
delete []substr_widths;
delete []substrings;
}
void SmushFont::drawStringWrapCentered(char *str, byte *buffer, int dst_width, int dst_height, int x, int32 y, int width) {
debug(9, "SmushFont::drawStringWrapCentered(%s, %d, %d)", str, x, y);
int max_substr_width = 0;
if ((strchr(str, '\n') != 0)) {
char *z = strchr(str, '\n');
*z = 0;
}
char **words = split(str, ' ');
int nb_sub = 0;
while(words[nb_sub])
nb_sub++;
int *sizes = new int[nb_sub];
int i = 0, height = 0, nb_subs = 0;
for(i = 0; i < nb_sub; i++)
sizes[i] = getStringWidth(words[i]);
char **substrings = new char *[nb_sub];
int *substr_widths = new int[nb_sub];
int space_width = getCharWidth(' ');
i = 0;
width = MIN(width, dst_width);
while(i < nb_sub) {
int substr_width = sizes[i];
char *substr = new char[1000];
strcpy(substr, words[i]);
int j = i + 1;
while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
substr_width += sizes[j++] + space_width;
}
for(int k = i + 1; k < j; k++) {
strcat(substr, " ");
strcat(substr, words[k]);
}
substrings[nb_subs] = substr;
substr_widths[nb_subs++] = substr_width;
max_substr_width = MAX(substr_width, max_substr_width);
i = j;
height += getStringHeight(substr);
}
delete []sizes;
for(i = 0; i < nb_sub; i++) {
delete []words[i];
}
delete []words;
if(y + height > dst_height) {
y = dst_height - height;
}
x = (dst_width - max_substr_width) / 2;
for(i = 0; i < nb_subs; i++) {
int substr_width = substr_widths[i];
drawSubstring(substrings[i], buffer, dst_width, x + (max_substr_width - substr_width) / 2, y);
y += getStringHeight(substrings[i]);
delete []substrings[i];
}
delete []substr_widths;
delete []substrings;
}

67
scumm/smush/smush_font.h Normal file
View file

@ -0,0 +1,67 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef SMUSH_FONT_H
#define SMUSH_FONT_H
#include "common/scummsys.h"
class SmushFont {
private:
int _nbChars;
byte _color;
bool _new_colors;
bool _original;
byte *_dataSrc;
struct {
int width;
int height;
byte *chr;
} _chars[256];
public:
SmushFont(bool use_original_colors, bool new_colors);
~SmushFont();
protected:
int getCharWidth(byte c);
int getStringWidth(char *str);
int getCharHeight(byte c);
int getStringHeight(char *str);
int drawChar(byte *buffer, int dst_width, int x, int y, byte chr);
void drawSubstring(char *str, byte *buffer, int dst_width, int x, int y);
void decodeCodec(byte *dst, byte *src, int length);
public:
bool loadFont(const char *filename, const char *directory);
void setColor(byte c) { _color = c; }
void drawStringCentered(char *str, byte *buffer, int dst_width, int dst_height, int y, int xmin, int width, int offset);
void drawStringWrap(char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int width);
void drawStringWrapCentered(char *str, byte *buffer, int dst_width, int dst_height, int x, int32 y, int width);
void drawStringAbsolute(char *str, byte *buffer, int dst_width, int x, int y);
};
#endif

166
scumm/smush/smush_mixer.cpp Normal file
View file

@ -0,0 +1,166 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include <stdafx.h>
#include "common/util.h"
#include "smush_mixer.h"
#include "channel.h"
#include "sound/mixer.h"
#include "scumm/scumm.h"
#include "scumm/sound.h"
#include "scumm/imuse.h"
SmushMixer::SmushMixer(SoundMixer *m) :
_mixer(m),
_soundFrequency(22050),
_nextIndex(_mixer->_beginSlots) {
for(int32 i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
_channels[i].id = -1;
_channels[i].chan = NULL;
_channels[i].first = true;
}
}
SmushMixer::~SmushMixer() {
}
SmushChannel *SmushMixer::findChannel(int32 track) {
debug(9, "SmushMixer::findChannel(%d)", track);
for(int32 i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
if(_channels[i].id == track)
return _channels[i].chan;
}
return NULL;
}
bool SmushMixer::addChannel(SmushChannel *c) {
int32 track = c->getTrackIdentifier();
int i;
debug(9, "SmushMixer::addChannel(%d)", track);
for(i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
if(_channels[i].id == track)
warning("SmushMixer::addChannel(%d) : channel already exist !", track);
}
if(_nextIndex >= SoundMixer::NUM_CHANNELS)
_nextIndex = _mixer->_beginSlots;
for(i = _nextIndex; i < SoundMixer::NUM_CHANNELS; i++) {
if(_channels[i].chan == NULL || _channels[i].id == -1) {
_channels[i].chan = c;
_channels[i].id = track;
_channels[i].first = true;
_nextIndex = i + 1;
return true;
}
}
for(i = _mixer->_beginSlots; i < _nextIndex; i++) {
if(_channels[i].chan == NULL || _channels[i].id == -1) {
_channels[i].chan = c;
_channels[i].id = track;
_channels[i].first = true;
_nextIndex = i + 1;
return true;
}
}
warning("_nextIndex == %d\n", _nextIndex);
for(i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
warning("channel %d : %p(%d, %d) %d %d\n", i, (void *)_channels[i].chan,
_channels[i].chan ? _channels[i].chan->getTrackIdentifier() : -1,
_channels[i].chan ? _channels[i].chan->isTerminated() : 1,
_channels[i].first, _channels[i].mixer_index);
}
error("SmushMixer::add_channel() : no more channel available");
return false;
}
bool SmushMixer::handleFrame() {
debug(9, "SmushMixer::handleFrame()");
for(int i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
if(_channels[i].id != -1) {
if(_channels[i].chan->isTerminated()) {
delete _channels[i].chan;
_channels[i].id = -1;
_channels[i].chan = NULL;
} else {
int32 rate;
bool stereo, is_short;
_channels[i].chan->getParameters(rate, stereo, is_short);
int32 size = _channels[i].chan->availableSoundData();
int32 flags = stereo ? SoundMixer::FLAG_STEREO : 0;
if(is_short) {
short *data = new int16[size * (stereo ? 2 : 1) * 2];
_channels[i].chan->getSoundData(data, size);
if(_channels[i].chan->getRate() == 11025) size *= 2;
size *= stereo ? 4 : 2;
if(_silentMixer == false) {
if(_channels[i].first) {
_channels[i].mixer_index = _mixer->playStream(NULL, -1, data, size, rate, flags | SoundMixer::FLAG_16BITS);
_channels[i].first = false;
} else {
_mixer->append(_channels[i].mixer_index, data, size, rate, flags | SoundMixer::FLAG_16BITS);
}
}
delete []data;
} else {
int8 *data = new int8[size * (stereo ? 2 : 1) * 2];
_channels[i].chan->getSoundData(data, size);
if(_channels[i].chan->getRate() == 11025) size *= 2;
size *= stereo ? 2 : 1;
if(_silentMixer == false) {
if(_channels[i].first) {
_channels[i].mixer_index = _mixer->playStream(NULL, -1, data, size, rate, flags | SoundMixer::FLAG_UNSIGNED);
_channels[i].first = false;
} else {
_mixer->append(_channels[i].mixer_index, data, size, rate, flags | SoundMixer::FLAG_UNSIGNED);
}
}
delete []data;
}
}
}
}
return true;
}
bool SmushMixer::stop() {
debug(9, "SmushMixer::stop()");
for(int i = _mixer->_beginSlots; i < SoundMixer::NUM_CHANNELS; i++) {
if(_channels[i].id != -1) {
delete _channels[i].chan;
_channels[i].id = -1;
_channels[i].chan = NULL;
}
}
return true;
}

View file

@ -19,24 +19,34 @@
*
*/
#ifndef SMUSH_CONFIG_H
#define SMUSH_CONFIG_H
#include <stdafx.h>
#include <scummsys.h>
#ifndef NDEBUG
#define DEBUG
#endif
#include "sound/mixer.h"
#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
class SmushChannel;
class SmushMixer {
private:
#endif
SoundMixer *_mixer;
struct {
int id;
SmushChannel *chan;
bool first;
int mixer_index;
} _channels[SoundMixer::NUM_CHANNELS];
int _nextIndex;
int _soundFrequency;
public:
SmushMixer(SoundMixer *);
virtual ~SmushMixer();
SmushChannel *findChannel(int32 track);
bool addChannel(SmushChannel *c);
bool handleFrame();
bool stop();
bool update();
bool _silentMixer;
};

File diff suppressed because it is too large Load diff

105
scumm/smush/smush_player.h Normal file
View file

@ -0,0 +1,105 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2003 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#ifndef SMUSH_PLAYER_H
#define SMUSH_PLAYER_H
#include "common/util.h"
#include "chunk.h"
#include "codec37.h"
#include "codec47.h"
class SmushFont;
class SmushMixer;
class StringResource;
class SmushPlayer {
private:
Scumm *_scumm;
int _version;
int32 _nbframes;
SmushMixer *_smixer;
int16 _deltaPal[0x300];
byte _pal[0x300];
StringResource *_strings;
SmushFont *_sf[5];
Codec37Decoder _codec37;
Codec47Decoder _codec47;
int dst_width, dst_height;
FileChunk *_base;
byte *_frameBuffer;
bool _codec37Called;
bool _skipNext;
bool _subtitles;
bool _skips[37];
int32 _frame;
int _IACTchannel;
byte _IACToutput[4096];
int32 _IACTpos;
bool _storeFrame;
int _soundFrequency;
bool _alreadyInit;
int _speed;
bool _outputSound;
public:
int _width, _height;
byte *_data;
bool _smushProcessFrame;
SmushPlayer(Scumm *, int, bool);
~SmushPlayer();
void updatePalette(void);
void parseNextFrame();
void init();
void deinit();
void setupAnim(const char *file, const char *directory);
void initCodecs();
void updateScreen();
void play(const char *filename, const char *directory);
void setPalette(byte *palette);
protected:
bool readString(const char *file, const char *directory);
void clean();
void checkBlock(const Chunk &, Chunk::type, uint32 = 0);
void handleAnimHeader(Chunk &);
void handleFrame(Chunk &);
void handleNewPalette(Chunk &);
void handleFrameObject(Chunk &);
void handleSoundBuffer(int32, int32, int32, int32, int32, int32, Chunk &, int32);
void handleImuseBuffer(int32, int32, int32, int32, int32, int32, Chunk &, int32);
void handleSoundFrame(Chunk &);
void handleSkip(Chunk &);
void handleStore(Chunk &);
void handleFetch(Chunk &);
void handleImuseAction(Chunk &);
void handleTextResource(Chunk &);
void handleDeltaPalette(Chunk &);
void readPalette(byte *, Chunk &);
};
#endif