diff options
| -rw-r--r-- | graphics/animation.cpp | 8 | ||||
| -rw-r--r-- | graphics/animation.h | 3 | ||||
| -rw-r--r-- | sword1/animation.cpp | 222 | ||||
| -rw-r--r-- | sword1/animation.h | 65 | ||||
| -rw-r--r-- | sword1/credits.cpp | 339 | ||||
| -rw-r--r-- | sword1/credits.h | 68 | ||||
| -rw-r--r-- | sword1/logic.cpp | 39 | ||||
| -rw-r--r-- | sword1/sword1.cpp | 9 | ||||
| -rw-r--r-- | sword1/sword1.h | 2 | 
9 files changed, 706 insertions, 49 deletions
| diff --git a/graphics/animation.cpp b/graphics/animation.cpp index ff0968e18a..1e472e0608 100644 --- a/graphics/animation.cpp +++ b/graphics/animation.cpp @@ -46,7 +46,7 @@ BaseAnimationState::~BaseAnimationState() {  } -bool BaseAnimationState::init(const char *name) { +bool BaseAnimationState::init(const char *name, void *audioArg) {  #ifdef USE_MPEG2  	char tempFile[512]; @@ -130,7 +130,7 @@ bool BaseAnimationState::init(const char *name) {  	ticks = _sys->getMillis();  	// Play audio -	bgSoundStream = AudioStream::openStreamFile(name); +	bgSoundStream = createAudioStream(name, audioArg);  	if (bgSoundStream != NULL) {  		_snd->playInputStream(&bgSound, bgSoundStream, false, -1, 255, 0, false); @@ -144,6 +144,10 @@ bool BaseAnimationState::init(const char *name) {  #endif  } +AudioStream *BaseAnimationState::createAudioStream(const char *name, void *arg) { +	return AudioStream::openStreamFile(name); +} +  bool BaseAnimationState::decodeFrame() {  #ifdef USE_MPEG2  	mpeg2_state_t state; diff --git a/graphics/animation.h b/graphics/animation.h index 727c8bd298..5227827cf9 100644 --- a/graphics/animation.h +++ b/graphics/animation.h @@ -117,7 +117,7 @@ public:  	BaseAnimationState(SoundMixer *snd, OSystem *sys, int width, int height);  	virtual ~BaseAnimationState(); -	bool init(const char *name); +	bool init(const char *name, void *audioArg = NULL);  	bool decodeFrame();  #ifndef BACKEND_8BIT  	void invalidateLookup(bool rebuild); @@ -126,6 +126,7 @@ public:  protected:  	bool checkPaletteSwitch();  	virtual void drawYUV(int width, int height, byte *const *dat) = 0; +	virtual AudioStream *createAudioStream(const char *name, void *arg);  #ifdef BACKEND_8BIT  	void buildLookup(int p, int lines); diff --git a/sword1/animation.cpp b/sword1/animation.cpp index 0e4531bdd6..c856b6a411 100644 --- a/sword1/animation.cpp +++ b/sword1/animation.cpp @@ -21,12 +21,14 @@  #include "common/stdafx.h"  #include "common/file.h" +#include "sword1/sword1.h"  #include "sword1/animation.h" -#include "sound/audiostream.h" - +#include "sword1/credits.h" +#include "sound/vorbis.h"  #include "common/config-manager.h"  #include "common/str.h" +  namespace Sword1 {  AnimationState::AnimationState(Screen *scr, SoundMixer *snd, OSystem *sys) @@ -38,11 +40,9 @@ AnimationState::~AnimationState() {  #ifdef BACKEND_8BIT -  void AnimationState::setPalette(byte *pal) {  	_sys->setPalette(pal, 0, 256);  } -  #endif  void AnimationState::drawYUV(int width, int height, byte *const *dat) { @@ -50,28 +50,95 @@ void AnimationState::drawYUV(int width, int height, byte *const *dat) {  	_scr->plotYUV(lut, width, height, dat);  #else  	plotYUV(lookup, width, height, dat); +#endif +} + +void AnimationState::updateScreen(void) { +#ifndef BACKEND_8BIT  	_sys->copyRectToOverlay(overlay, MOVIE_WIDTH, 0, 40, MOVIE_WIDTH, MOVIE_HEIGHT);  #endif +	_sys->updateScreen(); +} + +OverlayColor *AnimationState::giveRgbBuffer(void) { +#ifdef BACKEND_8BIT +	return NULL; +#else +	return overlay; +#endif +} + +bool AnimationState::soundFinished(void) { +	return !bgSound.isActive(); +} + +AudioStream *AnimationState::createAudioStream(const char *name, void *arg) { +	if (arg) +		return (AudioStream*)arg; +	else +		return AudioStream::openStreamFile(name);  }  MoviePlayer::MoviePlayer(Screen *scr, SoundMixer *snd, OSystem *sys)  	: _scr(scr), _snd(snd), _sys(sys) { +		for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++) +			_logoOvls[cnt] = NULL; +		_introPal = NULL; +} + +MoviePlayer::~MoviePlayer(void) { +	if (_introPal) +		free(_introPal); +	for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++) +		if (_logoOvls[cnt]) +			free(_logoOvls[cnt]);  }  /**   * Plays an animated cutscene. - * @param filename the file name of the cutscene file + * @param id the id of the file   */ -void MoviePlayer::play(const char *filename) { +void MoviePlayer::play(uint32 id) {  #ifdef USE_MPEG2  	AnimationState *anim = new AnimationState(_scr, _snd, _sys); -	bool initOK = anim->init(filename); +	AudioStream *stream = NULL; +	if (SwordEngine::_systemVars.cutscenePackVersion == 1) { +		if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) { +			// these sequences are language specific +			char sndName[20]; +			sprintf(sndName, "%s.snd", _sequenceList[id]); +			File *oggSource = new File(); +			if (oggSource->open(sndName)) { +				SplittedAudioStream *sStream = new SplittedAudioStream(); +				uint32 numSegs = oggSource->readUint32LE(); // number of audio segments, either 1 or 2. +				// for each segment and each of the 7 languages, we've got fileoffset and size +				uint32 *header = (uint32*)malloc(numSegs * 7 * 2 * 4); +				for (uint32 cnt = 0; cnt < numSegs * 7 * 2; cnt++) +					header[cnt] = oggSource->readUint32LE(); +				for (uint32 segCnt = 0; segCnt < numSegs; segCnt++) { +					oggSource->seek( header[SwordEngine::_systemVars.language * 2 + 0 + segCnt * 14]); +					uint32 segSize = header[SwordEngine::_systemVars.language * 2 + 1 + segCnt * 14]; +					AudioStream *apStream = makeVorbisStream(oggSource, segSize); +					if (!apStream) +						error("Can't create Vorbis Stream from file %s", sndName); +					sStream->appendStream(apStream); +				} +				free(header); +				stream = sStream; +			} else +				warning("Sound file \"%s\" not found", sndName); +			initOverlays(id); +			oggSource->decRef(); +		} +	} +	bool initOK = anim->init(_sequenceList[id], stream); +    uint32 frameCount = 0;  	if (initOK) {  		while (anim->decodeFrame()) { -#ifndef BACKEND_8BIT -			_sys->updateScreen(); -#endif +			processFrame(id, anim, frameCount); +			anim->updateScreen(); +			frameCount++;  			OSystem::Event event;  			while (_sys->pollEvent(event)) {  				switch (event.event_code) { @@ -95,10 +162,143 @@ void MoviePlayer::play(const char *filename) {  			}  		}  	} - +	while (!anim->soundFinished()) +		_sys->delayMillis(100);  	delete anim; +#endif // USE_MPEG2 +} + +void MoviePlayer::insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal) { +	if (ovl != NULL) +		for (uint32 cnt = 0; cnt < 640 * 400; cnt++) +			if (ovl[cnt]) +				buf[cnt] = pal[ovl[cnt]]; +} +void MoviePlayer::processFrame(uint32 animId, AnimationState *anim, uint32 frameNo) { +#if defined(USE_MPEG2) && !defined(BACKEND_8BIT) +	if ((animId != 4) || (SwordEngine::_systemVars.cutscenePackVersion == 0)) +		return; +	OverlayColor *buf = anim->giveRgbBuffer(); +	if ((frameNo > 397) && (frameNo < 444)) { // Broken Sword Logo +		if (frameNo <= 403) +			insertOverlay(buf, _logoOvls[frameNo - 398], _introPal); // fade up +		else if (frameNo <= 437) +			insertOverlay(buf, _logoOvls[(frameNo - 404) % 6 + 6], _introPal); // animation +		else { +			insertOverlay(buf, _logoOvls[5 - (frameNo - 438)], _introPal); // fade down +		} +	} +#endif +} + +bool MoviePlayer::initOverlays(uint32 id) { +#if defined(USE_MPEG2) && !defined(BACKEND_8BIT) +	if (id == SEQ_INTRO) { +		ArcFile ovlFile; +		if (!ovlFile.open("intro.dat")) { +			warning("\"intro.dat\" not found"); +			return false; +		} +		ovlFile.enterPath(SwordEngine::_systemVars.language); +		for (uint8 fcnt = 0; fcnt < 12; fcnt++) { +			_logoOvls[fcnt] = ovlFile.decompressFile(fcnt); +			if (fcnt > 0) +				for (uint32 cnt = 0; cnt < 640 * 400; cnt++) +					if (_logoOvls[fcnt - 1][cnt] && !_logoOvls[fcnt][cnt]) +						_logoOvls[fcnt][cnt] = _logoOvls[fcnt - 1][cnt]; +		} +		uint8 *pal = ovlFile.fetchFile(12); +		_introPal = (OverlayColor*)malloc(256 * sizeof(OverlayColor)); +		for (uint16 cnt = 0; cnt < 256; cnt++) +			_introPal[cnt] = _sys->RGBToColor(pal[cnt * 3 + 0], pal[cnt * 3 + 1], pal[cnt * 3 + 2]); +	} +	return true;  #endif  } +SplittedAudioStream::SplittedAudioStream(void) { +	_queue = NULL; +} + +SplittedAudioStream::~SplittedAudioStream(void) { +	while (_queue) { +		delete _queue->stream; +		FileQueue *que = _queue->next; +		delete _queue; +		_queue = que; +	} +} + +int SplittedAudioStream::getRate(void) const { +	if (_queue) +		return _queue->stream->getRate(); +	else +		return 22050; +} + +void SplittedAudioStream::appendStream(AudioStream *stream) { +	FileQueue **que = &_queue; +	while (*que) +		que = &((*que)->next); +	*que = new FileQueue; +	(*que)->stream = stream; +	(*que)->next = NULL; +} + +bool SplittedAudioStream::endOfData(void) const { +	if (_queue) +		return _queue->stream->endOfData(); +	else +		return true; +} + +bool SplittedAudioStream::isStereo(void) const { +	if (_queue) +		return _queue->stream->isStereo(); +	else +		return false; // all the BS1 files are mono, anyways. +} + +int SplittedAudioStream::readBuffer(int16 *buffer, const int numSamples) { +	int retVal = 0; +	int needSamples = numSamples; +	while (needSamples && _queue) { +		int retSmp = _queue->stream->readBuffer(buffer, needSamples); +		needSamples -= retSmp; +		retVal += retSmp; +		buffer += retSmp; +		if (_queue->stream->endOfData()) { +			delete _queue->stream; +			FileQueue *que = _queue->next; +			delete _queue; +			_queue = que; +		} +	} +	return retVal; +} + +const char * MoviePlayer::_sequenceList[20] = { +    "ferrari",  // 0  CD2   ferrari running down fitz in sc19 +    "ladder",   // 1  CD2   george walking down ladder to dig sc24->sc$ +    "steps",    // 2  CD2   george walking down steps sc23->sc24 +    "sewer",    // 3  CD1   george entering sewer sc2->sc6 +    "intro",    // 4  CD1   intro sequence ->sc1 +    "river",    // 5  CD1   george being thrown into river by flap & g$ +    "truck",    // 6  CD2   truck arriving at bull's head sc45->sc53/4 +    "grave",    // 7  BOTH  george's grave in scotland, from sc73 + from sc38 $ +    "montfcon", // 8  CD2   monfaucon clue in ireland dig, sc25 +    "tapestry", // 9  CD2   tapestry room beyond spain well, sc61 +    "ireland",  // 10 CD2   ireland establishing shot europe_map->sc19 +    "finale",   // 11 CD2   grand finale at very end, from sc73 +    "history",  // 12 CD1   George's history lesson from Nico, in sc10 +    "spanish",  // 13 CD2   establishing shot for 1st visit to Spain, europe_m$ +    "well",     // 14 CD2   first time being lowered down well in Spai$ +    "candle",   // 15 CD2   Candle burning down in Spain mausoleum sc59 +    "geodrop",  // 16 CD2   from sc54, George jumping down onto truck +    "vulture",  // 17 CD2   from sc54, vultures circling George's dead body +    "enddemo",  // 18 ---   for end of single CD demo +    "credits",  // 19 CD2   credits, to follow "finale" sequence +}; +  } // End of namespace Sword1 diff --git a/sword1/animation.h b/sword1/animation.h index b1a0ecc6a0..078311b739 100644 --- a/sword1/animation.h +++ b/sword1/animation.h @@ -26,10 +26,35 @@  #include "sword1/screen.h"  #include "sword1/sound.h" +#include "sound/audiostream.h" +namespace Sword1 { +enum { +	SEQ_FERRARI = 0, +	SEQ_LADDER, +	SEQ_STEPS, +	SEQ_SEWER, +	SEQ_INTRO, +	SEQ_RIVER, +	SEQ_TRUCK, +	SEQ_GRAVE, +	SEQ_MONTFCON, +	SEQ_TAPESTRY, +	SEQ_IRELAND, +	SEQ_FINALE, +	SEQ_HISTORY, +	SEQ_SPANISH, +	SEQ_WELL, +	SEQ_CANDLE, +	SEQ_GEODROP, +	SEQ_VULTURE, +	SEQ_ENDDEMO, +	SEQ_CREDITS +}; -namespace Sword1 { +#define INTRO_LOGO_OVLS 12 +#define INTRO_TEXT_OVLS 8  class AnimationState : public Graphics::BaseAnimationState {  private: @@ -38,6 +63,9 @@ private:  public:  	AnimationState(Screen *scr, SoundMixer *snd, OSystem *sys);  	~AnimationState(); +	void updateScreen(); +	OverlayColor *giveRgbBuffer(void); +	bool soundFinished();  private:  	void drawYUV(int width, int height, byte *const *dat); @@ -45,19 +73,48 @@ private:  #ifdef BACKEND_8BIT  	void setPalette(byte *pal);  #endif + +protected: +	virtual AudioStream *createAudioStream(const char *name, void *arg);  };  class MoviePlayer { +public: +	MoviePlayer(Screen *scr, SoundMixer *snd, OSystem *sys); +	~MoviePlayer(void); +	void play(uint32 id);  private: +	void insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal); +	void processFrame(uint32 animId, AnimationState *anim, uint32 frameNo); +	bool initOverlays(uint32 id); +	void decompressRle(uint8 *src, uint8 *dest, uint32 srcSize);  	Screen *_scr;  	SoundMixer *_snd;  	OSystem *_sys; +	static const char *_sequenceList[20]; +	uint8 *_logoOvls[INTRO_LOGO_OVLS]; +	OverlayColor *_introPal; +}; + +struct FileQueue { +	AudioStream *stream; +	FileQueue *next; +}; + +class SplittedAudioStream : public AudioStream {  public: -	MoviePlayer(Screen *scr, SoundMixer *snd, OSystem *sys); -	void play(const char *filename); +	SplittedAudioStream(void); +	~SplittedAudioStream(void); +	void appendStream(AudioStream *stream); +	virtual int readBuffer(int16 *buffer, const int numSamples); +	virtual bool isStereo(void) const; +	virtual bool endOfData(void) const; +	virtual int getRate(void) const; +private: +	FileQueue *_queue;  }; -} // End of namespace Sword2 +} // End of namespace Sword1  #endif diff --git a/sword1/credits.cpp b/sword1/credits.cpp new file mode 100644 index 0000000000..07d56ae96f --- /dev/null +++ b/sword1/credits.cpp @@ -0,0 +1,339 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003-2004 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 "credits.h" +#include "screen.h" +#include "common/file.h" +#include "sound/mixer.h" +#include "common/util.h" +#include "sound/audiostream.h" + +#include "sword1.h" + +#define CREDITS_X 480 +#define CREDITS_Y 300 +#define BUFSIZE_Y 640 + +#define START_X ((640 - CREDITS_X) / 2) +#define START_Y ((480 - CREDITS_Y) / 2) + +#define SCROLL_TIMING (2000 / 59) // 29.5 frames per second + +#define LOGO_FADEUP_TIME (133 * 1000) +#define LOGO_FADEDOWN_TIME (163 * 1000) + +namespace Sword1 { + +enum { +	FONT_PAL = 0, +	FONT, +	TEXT, +	REVO_PAL, +	REVO_LOGO, +	F_EOF +}; + +enum { +	FNT_LFT = 0,   // left column +	FNT_RGT,	   // right column +	FNT_CEN,	   // centered +	FNT_BIG = 64,  // big font +	FNT_EOL = 128, // linebreak +	FNT_EOB = 255  // end of textblock +}; + + +CreditsPlayer::CreditsPlayer(OSystem *pSystem, SoundMixer *pMixer) { +	_system = pSystem; +	_mixer = pMixer; +	_smlFont = _bigFont = NULL; +} + +bool spaceInBuf(uint16 blitSta, uint16 blitEnd, uint16 renderDest) { +	if (blitEnd > blitSta) { +		if ((renderDest > blitEnd) || (renderDest + 15 < blitSta)) +			return true; +	} else { +		if ((renderDest > blitEnd) && (renderDest + 15 < blitSta)) +			return true; +	} +	return false; +} + +void CreditsPlayer::play(void) { +	AudioStream *bgSoundStream = AudioStream::openStreamFile("credits"); +	if (bgSoundStream == NULL) { +		warning("\"credits.ogg\" not found, skipping credits sequence"); +		return; +	} +	ArcFile credFile; +	if (!credFile.open("credits.dat")) { +		warning("\"credits.dat\" not found, skipping credits sequence"); +		return; +	} + +	uint8 *palSrc = credFile.fetchFile(FONT_PAL, &_palLen); +	for (uint32 cnt = 0; cnt < _palLen; cnt++) +		_palette[(cnt / 3) * 4 + cnt % 3] = palSrc[cnt]; +	_palLen /= 3;	 +     +	generateFonts(&credFile); + +	uint8 *textData = credFile.fetchFile(TEXT); +	textData += READ_LE_UINT32(textData + SwordEngine::_systemVars.language * 4); + +	uint8 *screenBuf = (uint8*)malloc(CREDITS_X * BUFSIZE_Y); +	memset(screenBuf, 0, CREDITS_X * BUFSIZE_Y); +	_system->copyRectToScreen(screenBuf, 640, 0, 0, 640, 480); +	_system->setPalette(_palette, 0, _palLen); +	_system->updateScreen(); + +	// everything's initialized, time to render and show the credits. +	PlayingSoundHandle bgSound; +	_mixer->playInputStream(&bgSound, bgSoundStream, true, 0); + +	int relDelay = 0; +	uint16 scrollY = 0; +	uint16 renderY = BUFSIZE_Y / 2; +	uint16 clearY = 0xFFFF; +	bool clearLine = false; +	while (((*textData != FNT_EOB) || (scrollY != renderY)) && !SwordEngine::_systemVars.engineQuit) { +		if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio +			if (scrollY < BUFSIZE_Y - CREDITS_Y) +				_system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y); +			else { +				_system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, BUFSIZE_Y - scrollY); +				_system->copyRectToScreen(screenBuf, CREDITS_X, START_X, START_Y + BUFSIZE_Y - scrollY, CREDITS_X, CREDITS_Y - (BUFSIZE_Y - scrollY)); +			} +			_system->updateScreen(); +		} else +			warning("frame skipped"); + +		while (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY) && (*textData != FNT_EOB)) { +			if (*textData & FNT_EOL) { +				renderY = (renderY + 16) % BUFSIZE_Y; // linebreak +				clearLine = true; +				*textData &= ~FNT_EOL; +			} +			if (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY)) { +				if (clearLine) +					memset(screenBuf + renderY * CREDITS_X, 0, 16 * CREDITS_X); +				clearLine = false; +				renderLine(screenBuf, textData + 1, renderY, *textData); +				if (*textData & FNT_BIG) +					renderY += 16; +				while (*++textData != 0) // search for the start of next string +					; +				textData++; +			} +			if (*textData == FNT_EOB) +				clearY = renderY; +		} +		if ((*textData == FNT_EOB) && spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, clearY)) { +			memset(screenBuf + clearY * CREDITS_X, 0, 16 * CREDITS_X); +			clearY = (clearY + 16) % BUFSIZE_Y; +		} + +		relDelay += SCROLL_TIMING; +		delay(relDelay - (int32)_mixer->getSoundElapsedTime(bgSound)); +		scrollY = (scrollY + 1) % BUFSIZE_Y; +	} +	free(_smlFont); +	free(_bigFont); +	_smlFont = _bigFont = NULL; +	free(screenBuf); +	 +	// credits done, now show the revolution logo +	uint8 *revoBuf = credFile.decompressFile(REVO_LOGO); +	uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen); +	_palLen /= 3; +	while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !SwordEngine::_systemVars.engineQuit) { +		_system->updateScreen(); +		delay(100); +	} +	memset(_palette, 0, 256 * 4); +	_system->setPalette(_palette, 0, 256); +	_system->copyRectToScreen(revoBuf, 480, START_X, START_Y, CREDITS_X, CREDITS_Y); +	_system->updateScreen(); + +	fadePalette(revoPal, true, _palLen); +	while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !SwordEngine::_systemVars.engineQuit) { +		_system->updateScreen(); +		delay(100); +	} +	fadePalette(revoPal, false, _palLen); +	delay(3000); + +	if (SwordEngine::_systemVars.engineQuit) +		_mixer->stopAll(); +	free(revoBuf); +} + +void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) { +	int8 fadeDir = fadeup ? 1 : -1; +	int fadeStart = fadeup ? 0 : 12; + +	int relDelay = _system->getMillis(); +	for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !SwordEngine::_systemVars.engineQuit; fadeStep += fadeDir) { +		for (uint16 cnt = 0; cnt < len * 3; cnt++) +			_palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12; +		_system->setPalette(_palette, 0, 256); +		_system->updateScreen(); +		relDelay += 1000 / 12; +		delay(relDelay - _system->getMillis()); +	} +} + +void CreditsPlayer::renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags) { +	uint8 *font; +	uint16 fntSize = 16; +	if (flags & FNT_BIG) { +		font = _bigFont; +		fntSize = 32; +		flags &= ~FNT_BIG; +	} else  +		font = _smlFont; + +	uint16 width = getWidth(font, line); +	uint16 xBufPos = (flags == FNT_CEN) ? (CREDITS_X - width) / 2 : ((flags == FNT_LFT) ? (234 - width) : 255); +	uint8 *bufDest = screenBuf + yBufPos * CREDITS_X + xBufPos; +	while (*line) { +		uint8 *chrSrc = font + _numChars + (*line - 1) * fntSize * fntSize; +		for (uint16 cnty = 0; cnty < fntSize; cnty++) { +			for (uint16 cntx = 0; cntx < fntSize; cntx++) +				bufDest[cnty * CREDITS_X + cntx] = chrSrc[cntx]; +			chrSrc += fntSize; +		} +		bufDest += font[*line++ - 1]; +	} +} + +uint16 CreditsPlayer::getWidth(uint8 *font, uint8 *line) { +	uint16 width = 0; +	while (*line) +		width += font[*line++ - 1]; +	return width; +} + +void CreditsPlayer::generateFonts(ArcFile *arcFile) { +	_bigFont = arcFile->decompressFile(FONT); +	_numChars = *_bigFont; +	memmove(_bigFont, _bigFont + 1, _numChars * (32 * 32 + 1)); +	_smlFont = (uint8*)malloc(_numChars * (32 * 32 + 1)); +	uint8 *src = _bigFont + _numChars; +	uint8 *dst = _smlFont + _numChars; +	for (uint16 cnt = 0; cnt < _numChars; cnt++) { +		_smlFont[cnt] = (_bigFont[cnt]++ + 1) / 2; // width table +		for (uint16 cnty = 0; cnty < 16; cnty++) { +			for (uint16 cntx = 0; cntx < 16; cntx++) { +				uint8 resR = (uint8)((_palette[src[0] * 4 + 0] + _palette[src[1] * 4 + 0] + _palette[src[32] * 4 + 0] + _palette[src[33] * 4 + 0]) >> 2); +				uint8 resG = (uint8)((_palette[src[0] * 4 + 1] + _palette[src[1] * 4 + 1] + _palette[src[32] * 4 + 1] + _palette[src[33] * 4 + 1]) >> 2); +				uint8 resB = (uint8)((_palette[src[0] * 4 + 2] + _palette[src[1] * 4 + 2] + _palette[src[32] * 4 + 2] + _palette[src[33] * 4 + 2]) >> 2); +				*dst++ = getPalIdx(resR, resG, resB); +				src += 2; +			} +			src += 32; +		} +	} +} + +uint8 CreditsPlayer::getPalIdx(uint8 r, uint8 g, uint8 b) { +	for (uint16 cnt = 0; cnt < _palLen; cnt++) +		if ((_palette[cnt * 4 + 0] == r) && (_palette[cnt * 4 + 1] == g) && (_palette[cnt * 4 + 2] == b)) +			return (uint8)cnt; +	assert(_palLen < 256); +	_palette[_palLen * 4 + 0] = r; +	_palette[_palLen * 4 + 1] = g; +	_palette[_palLen * 4 + 2] = b; +	return (uint8)_palLen++; +} + +void CreditsPlayer::delay(int msecs) { + +	OSystem::Event event; +	uint32 start = _system->getMillis(); +	do { +		while (_system->pollEvent(event)) { +			switch (event.event_code) { +			case OSystem::EVENT_QUIT: +				SwordEngine::_systemVars.engineQuit = true; +				break; +			default: +				break; +			} +		} +		if (msecs > 0) +			_system->delayMillis(10); +	} while ((_system->getMillis() < start + msecs) && !SwordEngine::_systemVars.engineQuit); +} + +ArcFile::ArcFile(void) { +	_buf = NULL; +} + +ArcFile::~ArcFile(void) { +	if (_buf) +		free(_buf); +} + +bool ArcFile::open(const char *name) { +	File arc; +	if (!arc.open(name)) +		return false; +	_bufPos = _buf = (uint8*)malloc(arc.size()); +	arc.read(_buf, arc.size()); +	arc.close(); +	return true; +} + +void ArcFile::enterPath(uint32 id) { +	_bufPos += READ_LE_UINT32(_bufPos + id * 4); +} + +uint8 *ArcFile::fetchFile(uint32 fileId, uint32 *size) { +	if (size) +		*size = READ_LE_UINT32(_bufPos + (fileId + 1) * 4) - READ_LE_UINT32(_bufPos + fileId * 4); +	return _bufPos + READ_LE_UINT32(_bufPos + fileId * 4); +} + +uint8 *ArcFile::decompressFile(uint32 fileId) { +	uint32 size; +	uint8 *srcBuf = fetchFile(fileId, &size); +	uint8 *dstBuf = (uint8*)malloc(READ_LE_UINT32(srcBuf)); +	uint8 *srcPos = srcBuf + 4; +	uint8 *dstPos = dstBuf; +	while (srcPos < srcBuf + size) { +		uint16 len = READ_LE_UINT16(srcPos); +		memset(dstPos, 0, len); +		dstPos += len; +		srcPos += 2; +		if (srcPos < srcBuf + size) { +			uint8 len = *srcPos++; +			memcpy(dstPos, srcPos, len); +			dstPos += len; +			srcPos += len; +		} +	} +	return dstBuf; +} + +}; // end of namespace Sword1 diff --git a/sword1/credits.h b/sword1/credits.h new file mode 100644 index 0000000000..5a4364ad3a --- /dev/null +++ b/sword1/credits.h @@ -0,0 +1,68 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003-2004 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 BS1CREDITS_H +#define BS1CREDITS_H + +#include "common/util.h" +class SoundMixer; +class OSystem; + +namespace Sword1 { + +class ArcFile { +public: +	ArcFile(void); +	~ArcFile(void); +	bool open(const char *name); +	uint8 *fetchFile(uint32 fileId, uint32 *size = NULL); +	uint8 *decompressFile(uint32 fileId); +	void enterPath(uint32 id); +	void backToRoot(void) { _bufPos = _buf; }; +private: +	uint8 *_bufPos; +	uint8 *_buf; +}; + +class CreditsPlayer { +public: +	CreditsPlayer(OSystem *pSystem, SoundMixer *pMixer); +	void play(void); +private: +	void generateFonts(ArcFile *arcFile); +	void renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags); +	void fadePalette(uint8 *srcPal, bool fadeup, uint16 len); +	void delay(int msecs); +	uint16 getWidth(uint8 *font, uint8 *line); +	uint8 getPalIdx(uint8 r, uint8 g, uint8 b); +	uint8 _palette[256 * 4]; +	uint32 _palLen; +	uint8 _numChars; + +	OSystem *_system; +	SoundMixer *_mixer; + +	uint8 *_smlFont, *_bigFont; +}; + +}; // end of namespace Sword1 + +#endif // BS1CREDITS_H diff --git a/sword1/logic.cpp b/sword1/logic.cpp index 660ee3517c..571535465d 100644 --- a/sword1/logic.cpp +++ b/sword1/logic.cpp @@ -34,6 +34,7 @@  #include "sword1/music.h"  #include "sword1/swordres.h"  #include "sword1/animation.h" +#include "sword1/credits.h"  #include "sword1/debug.h" @@ -940,37 +941,13 @@ int Logic::fnSetPaletteToCut(Object *cpt, int32 id, int32 c, int32 d, int32 e, i  int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int32 e, int32 f, int32 z, int32 x) { -  static const char *sequence_list[20] = { -    "ferrari",  // 0  CD2   ferrari running down fitz in sc19 -    "ladder",   // 1  CD2   george walking down ladder to dig sc24->sc$ -    "steps",    // 2  CD2   george walking down steps sc23->sc24 -    "sewer",    // 3  CD1   george entering sewer sc2->sc6 -    "intro",    // 4  CD1   intro sequence ->sc1 -    "river",    // 5  CD1   george being thrown into river by flap & g$ -    "truck",    // 6  CD2   truck arriving at bull's head sc45->sc53/4 -    "grave",    // 7  BOTH  george's grave in scotland, from sc73 + from sc38 $ -    "montfcon", // 8  CD2   monfaucon clue in ireland dig, sc25 -    "tapestry", // 9  CD2   tapestry room beyond spain well, sc61 -    "ireland",  // 10 CD2   ireland establishing shot europe_map->sc19 -    "finale",   // 11 CD2   grand finale at very end, from sc73 -    "history",  // 12 CD1   George's history lesson from Nico, in sc10 -    "spanish",  // 13 CD2   establishing shot for 1st visit to Spain, europe_m$ -    "well",     // 14 CD2   first time being lowered down well in Spai$ -    "candle",   // 15 CD2   Candle burning down in Spain mausoleum sc59 -    "geodrop",  // 16 CD2   from sc54, George jumping down onto truck -    "vulture",  // 17 CD2   from sc54, vultures circling George's dead body -    "enddemo",  // 18 ---   for end of single CD demo -    "credits",  // 19 CD2   credits, to follow "finale" sequence -    // etc. -  }; - -  MoviePlayer player(_screen, _mixer, _system); - -  player.play(sequence_list[sequenceId]); - -	//_scriptVars[NEW_PALETTE] = 1; -	/* the logic usually calls fnFadeDown before playing the sequence, so we have to -	   set NEW_PALETTE now to force a palette refresh */ +	if ((SwordEngine::_systemVars.cutscenePackVersion == 1) && (sequenceId == SEQ_CREDITS)) { +		CreditsPlayer player(_system, _mixer); +		player.play(); +	} else { +		MoviePlayer player(_screen, _mixer, _system); +		player.play(sequenceId); +	}  	return SCRIPT_CONT;  } diff --git a/sword1/sword1.cpp b/sword1/sword1.cpp index f64a77f219..f5f1f8bad4 100644 --- a/sword1/sword1.cpp +++ b/sword1/sword1.cpp @@ -1134,6 +1134,15 @@ void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or  			error(msg);  		}  	} + +	// check cutscene pack version +	_systemVars.cutscenePackVersion = 0; +#ifdef USE_MPEG2 +	if (test.open("intro.snd")) { +		_systemVars.cutscenePackVersion = 1; +		test.close(); +	} +#endif  }  int SwordEngine::go() { diff --git a/sword1/sword1.h b/sword1/sword1.h index 52db32e867..f7f21803f1 100644 --- a/sword1/sword1.h +++ b/sword1/sword1.h @@ -63,6 +63,8 @@ struct SystemVars {  	uint8	showText;  	uint8	language;  	bool    isDemo; + +	uint8	cutscenePackVersion;  };  class SwordEngine : public Engine { | 
